4.4 KiB
Containers — publish OCI images
Read before publishing an OCI image, updating a container tag, choosing Blossom storage, or constructing a gateway pull reference. Protocol background: https://ngit.dev/protocol/software-publishing
Model
ngit container publish (alias ngit oci publish) uploads the OCI blobs
reachable from the tagged entries of an OCI image layout to Blossom, then signs
a kind-30624 addressable event mapping tags to manifest digests. The event is
bound to the current kind-30617 git repository, so run it inside that repository
with a signer who is a confirmed maintainer. Gateways are read-only:
docker pull ncontainer.io/<npub>/<repository>:<tag>
Publish
Export an OCI image layout first, for example
podman push myimage oci:/tmp/myimage:latest, then publish every tagged root:
ngit container publish myimage \
--layout /tmp/myimage \
--blossom-server https://blossom-one.example \
--blossom-server https://blossom-two.example \
--relay wss://relay.example \
--source https://example.com/myimage \
--json
A checked-in .ngit/containers.yaml lets
ngit container publish myimage --json select an entry:
schema: 1
publication:
blossom_servers: [https://blossom-one.example, https://blossom-two.example]
relays: [wss://relay.example]
containers:
myimage:
layout: artifacts/myimage
source: https://example.com/myimage
Relative paths resolve from the repository root. --manifest PATH selects
another file; --no-manifest ignores the default and requires --layout. A
loaded manifest must define NAME. CLI layout and metadata override the entry,
a non-empty CLI Blossom list replaces the configured list, and CLI relays extend
configured relays. Signer selection, --replace, and output mode stay on the
command line.
Behaviour to know:
NAMEis one lowercase OCI repository-name component.- Tags come from
org.opencontainers.image.ref.nameannotations inindex.json; filenames and git tags are irrelevant.index.jsonitself is never uploaded; ngit merges the layout's tags into the tag map fetched from the latest kind-30624 event. - Without
--blossom-server, ngit uses the publisher's latest kind-10063 server list. A single server means no redundancy. Every blob is checked on every server, missing copies are uploaded with bounded retries and verified, and the event is signed once each blob has at least one confirmed copy; incomplete replication is reported per server. --relayextends the repository's relays; account and default relays are not added. ngit reads the repository relays before and after uploading and needs at least one success each time. A total preflight failure or a concurrent-update refusal is safe to retry: uploaded blobs are content-addressed. Keep a known state-bearing repository relay reachable when changing relay sets, because a healthy empty relay cannot reveal an event stranded elsewhere and a publish could then omit old tags.
Merge versus replace
Ordinary publication updates the tags found in the new layout and retains older
tags, previous server hints, omitted metadata, and unknown event tags.
--replace publishes only the new layout's tags and selected servers, drops
omitted description, source, and unknown tags, and sets the title to --title
or NAME. Use it only when the user explicitly wants complete replacement.
JSON
A successful result has command: "container.publish", a warnings array, and
result fields: repository, git_repository, npub, name, naddr,
manifest_path (or null), raw-hex event_id (unlike collaboration commands'
nevent ids), tags and updated_tags, per-blob SHA-256, size, and per-server
placement, final blossom_servers, and per-relay accepted. Success means at
least one relay accepted the event; inspect every result.relays[].accepted
when full fanout matters. Failures use command_status: "error" with
error.details holding per-blob and per-server outcomes and possible orphan
blobs.
Limits
ngit accepts OCI and Docker v2 manifests and indexes using SHA-256, uploads only
blobs reachable from tagged roots, and rejects missing, oversized, deeply
nested, or mismatched graphs. It snapshots one blob at a time, so allow
temporary disk roughly equal to the largest layer. It does not build images,
push to registries, run a gateway, chunk layers, pull, list, or delete remote
blobs or tags. Software release assets use the separate ngit release model.