A library-first, daemonless OCI toolkit for Elixir — everything you can do to a container image except run it.
Stevedore handles OCI artifacts at rest (as bytes): fetch, inspect, copy, mirror, build, modify, analyze, sign, verify, and serve images. Running them (namespaces, mounts, cgroups) is out of scope.
Layers
The library is a pure core with optional shells:
- Core data types —
Stevedore.Reference,Stevedore.Digest,Stevedore.MediaType,Stevedore.Descriptor,Stevedore.Manifest,Stevedore.Config, andStevedore.Archive. - The
docker://client —Stevedore.Registry(requires the optional:reqdep) plusStevedore.Authfor the bearer-token flow. - The
Stevedore.Storeseam — content-addressed blob I/O, withStore.LocalandStore.Memory.
The functions below are the high-level verbs. See docs/EXAMPLES.md for a cookbook of
task-oriented recipes.
Nothing here starts a process; adding :stevedore as a dependency is weightless.
Summary
Functions
Copies an image from source to dest, preserving digests. Returns {:ok, %{digest: ...}}.
Deletes the manifest named by endpoint (a transport-prefixed string or {transport, ref}).
Fetches and parses the manifest for ref from its registry.
Lists the tags in ref's repository.
Computes the digest of a manifest from its raw bytes (or a Stevedore.Manifest.t/0).
Starts the standalone /v2 registry server (Stevedore.Server).
Copies many images from a declarative list of jobs. Each job is {source, dest} or a map with
:source/:dest (and optional per-job :opts). Returns a result per job.
Functions
@spec copy(Stevedore.Copy.endpoint(), Stevedore.Copy.endpoint(), keyword()) :: {:ok, %{digest: Stevedore.Digest.t()}} | {:error, term()}
Copies an image from source to dest, preserving digests. Returns {:ok, %{digest: ...}}.
Endpoints are transport-prefixed strings (docker://, oci:, dir:, docker-archive:,
oci-archive:, static:) or {transport, ref} tuples. Options: :all (copy a whole index),
:platform/:platforms (select from an index), plus transport options like :creds.
Examples
Stevedore.copy("docker://alpine:3.20", "oci:./alpine:3.20")
Stevedore.copy("docker://alpine:3.20", "docker://ghcr.io/me/alpine:3.20", all: true)
@spec delete( Stevedore.Copy.endpoint(), keyword() ) :: :ok | {:error, term()}
Deletes the manifest named by endpoint (a transport-prefixed string or {transport, ref}).
@spec inspect( Stevedore.Reference.t(), keyword() ) :: {:ok, Stevedore.Manifest.t() | binary() | Stevedore.Config.t()} | {:error, term()}
Fetches and parses the manifest for ref from its registry.
Options:
:raw— return the raw manifest bytes instead of aStevedore.Manifest.t/0.:config— fetch and parse the image config, returning aStevedore.Config.t/0(selecting the host platform, or:platform, whenrefis a multi-arch index).:platform— a keyword (os/architecture/variant) used with:configon an index.- plus any
Stevedore.Registryoption (:creds,:scheme, …).
@spec list_tags( Stevedore.Reference.t(), keyword() ) :: {:ok, [String.t()]} | {:error, term()}
Lists the tags in ref's repository.
@spec manifest_digest(binary() | Stevedore.Manifest.t()) :: Stevedore.Digest.t()
Computes the digest of a manifest from its raw bytes (or a Stevedore.Manifest.t/0).
Examples
iex> digest = Stevedore.manifest_digest(~s({"schemaVersion":2}))
iex> digest.algorithm
:sha256
@spec start_link(keyword()) :: Supervisor.on_start()
Starts the standalone /v2 registry server (Stevedore.Server).
The only thing in Stevedore that boots a process tree, and only when called. Requires the
optional :bandit/:plug deps. See Stevedore.Server for options (:store, :port,
:authorize, …).
@spec sync( [{Stevedore.Copy.endpoint(), Stevedore.Copy.endpoint()} | map()], keyword() ) :: {:ok, [{term(), term()}]}
Copies many images from a declarative list of jobs. Each job is {source, dest} or a map with
:source/:dest (and optional per-job :opts). Returns a result per job.