Docs navigation
Get started
AI agents
Connect
The fleet
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.
go install github.com/andrewdryga/emisar/runner/cmd/packctl@latest
2. Build the registry tree#
--base-url
is wherever you will host it. Tarball URLs in the catalog join onto 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 two mutable pointers:
v1/catalog.json latest catalog (mutable pointer) v1/catalog/<sha256>.json immutable catalog snapshot v1/suggest.json lean suggest index (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, and it updates the
two mutable pointers 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. Upload immutable objects first, then the two mutable pointers:
aws s3 sync ./dist s3://acme-pack-registry \ --exclude "v1/catalog.json" --exclude "v1/suggest.json" aws s3 cp ./dist/v1/suggest.json s3://acme-pack-registry/v1/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
— bump 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.
Name-based commands —
pack install redis,pack update,pack diff— read the public registry's layout, which this tree does not have. Install from the immutable tarball URLs in step 4. - To retire a version, revoke its trust. Revoke it in Packs, and the control plane refuses dispatch for that version.