Docs navigation
Get started
AI agents
Connect
Operate
Day to day
When it breaks
Govern access
Team & account
Access
Identity concepts
Provider guides
Account
Host your own registry
An emisar pack registry is a static file tree over
HTTPS. Host it in a bucket, nginx, MinIO, or an artifact store.
packctl
builds the tree, and each pack installs from an immutable URL pinned to the hash
you reviewed.
Registry paths become v1 compatibility surfaces. Read Compatibility and deprecation before you publish a stable internal endpoint.
Distribution and trust are separate. The runner checks the supplied sha256
hash at install and again when it loads the pack, and the control plane auto-trusts
only entries from its configured catalog. Other packs remain pending until
an admin trusts their exact version and hash.
Use your coding agent
The author-pack
skill walks your agent through authoring, publishing, and installing from your own registry.
Author an emisar action pack, publish it to my own pack registry, and install it hash-pinned on a runner. Use the author-pack skill: https://raw.githubusercontent.com/AndrewDryga/emisar/main/skills/author-pack/SKILL.md
Works in Claude Code, Codex, or any agent that reads Markdown skills. Read the skill first .
This page starts from packs you already authored. The format is in Author your own pack, and every field is in the Pack reference.
1. Get packctl#
packctl
builds and publishes registries. It is deliberately a
separate
binary
from emisar, so your fleet hosts never carry publish code or publisher
credentials. Only the workstation or CI job that builds the registry does. It
shares the runner's pack loader, so published content hashes match
emisar pack validate
byte-for-byte.
Build it from the same signed release tag your runners were installed
from. Then the tool that hashes a pack is the one whose loader will
enforce that hash. An unpinned
go install …@latest
builds whatever the default branch holds that minute.
git clone --depth 1 --branch runner-v<version> \\ https://github.com/andrewdryga/emisar.git emisar-src cd emisar-src/runner && go build -o ~/.local/bin/packctl ./cmd/packctl
2. Build the registry tree#
--base-url
is wherever you will host it. Tarball URLs in the catalog are built on it:
packctl catalog build --packs ./packs --out ./dist \ --base-url https://packs.acme.internal
The output is the whole registry: immutable versioned and content-addressed artifacts, plus four mutable pointer objects. The facade aliases let the runner's name-based commands use a static host:
v1/catalog.json latest catalog (mutable pointer) v1/catalog/<sha256>.json immutable catalog snapshot v1/suggest.json lean suggest index (mutable pointer) packs.json catalog facade alias (mutable pointer) packs/suggest.json suggest facade alias (mutable pointer) v1/schemas/*.vN.schema.json immutable versioned schemas v1/packs/<id>/<version>/<sha256>/pack.tar.gz immutable pack tarball
3. Host it anywhere#
packctl can publish directly to GCS. It protects immutable objects with
upload preconditions, so existing objects are never overwritten. It updates the four
mutable objects afterward and writes v1/catalog.json last:
GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token) \ packctl catalog publish --dir ./dist --bucket acme-pack-registry
For S3, MinIO, nginx, or another static host, sync the plain file tree with your
preferred tool. Keep the upload plan private, upload immutable objects first, and
write v1/catalog.json last:
aws s3 sync ./dist s3://acme-pack-registry \ --exclude "manifest.json" \ --exclude "v1/catalog.json" --exclude "v1/suggest.json" \ --exclude "packs.json" --exclude "packs/suggest.json" aws s3 cp ./dist/v1/suggest.json s3://acme-pack-registry/v1/suggest.json aws s3 cp ./dist/packs.json s3://acme-pack-registry/packs.json aws s3 cp ./dist/packs/suggest.json s3://acme-pack-registry/packs/suggest.json aws s3 cp ./dist/v1/catalog.json s3://acme-pack-registry/v1/catalog.json
4. Install fleet-wide#
Install the pack from its immutable tarball URL, pinned to the hash from catalog.json. The runner rejects a different hash. Use the same URL and
hash on every runner, and update by installing the new version's immutable URL.
sudo emisar pack install \ https://packs.acme.internal/v1/packs/billing-tools/0.4.0/<sha256>/pack.tar.gz \ --hash sha256:<reviewed>
Trust the exact pack version and hash on the Packs page. Actions use account trust, not the download host.
5. Publish the next version#
Always build against the currently published catalog so history carries forward.
--previous
enforces immutability: a pack whose files changed for an
already-published id@version
fails the build. Raise the version instead. On a
critical fix, republish, then revoke trust on the old version in Packs. The control plane refuses new dispatches for it, and the runner separately
checks the delivered hash against its installed files.
curl -fsS https://packs.acme.internal/v1/catalog.json -o current.json packctl catalog build --packs ./packs --out ./dist \ --base-url https://packs.acme.internal --previous current.json
What your registry changes#
- emisar works unchanged. Runners advertise installed packs no matter where they came from, and trust, policy, approvals, and audit treat a private pack exactly like a published one.
-
Pack downloads can stay inside your network.
Mirror the public registry tree, or build one from your own checkout of the public
packs/source. -
Suggestions and the console still work.
emisar pack suggest --catalogtakes your registry'sv1/catalog.jsonURL: it matches this host against your packs and prints each one's immutable install line, hash and all. The console lists your private packs like any others, because a runner advertises every installed pack. -
Install by URL, not by name.
Install from the immutable tarball URLs in step 4. Once installed,
pack diff redis --registry https://packs.acme.internalpreviews the current version andpack update redis --registry https://packs.acme.internalapplies it; both verify the catalog's content hash. First installs by plain name andpack diff --tostill need the public registry's download routes. - To retire a version, revoke its trust. Revoke it in Packs, and the control plane refuses dispatch for that version.