Publishing Packages
What you'll accomplish: Create, build, lint, and publish packages to a registry with automatic provenance.
Package workflow
Every package published to a Hoziron registry receives a cryptographic provenance signature automatically. The registry signs on behalf of the authenticated publisher — no local signing keys needed.
A carrier operator publishes only to their own registry — their private, self-hosted registry, or the registry bundled with their own Hoziron instance. catalog.hoziron.com, Hoziron's shared public registry, only accepts publishes from Hoziron staff; a carrier's API key will not have publish rights there. Everything below assumes you're publishing to a registry you control.
1. Scaffold
hoziron-cli package init --type competency --name my-package
Package types (PackageTypeArg): skill, competency, agent-template, workflow-template, integration. There is no tool package type — a skill is the tool-bundling unit; see the glossary.
For a REST/SOAP carrier integration package (ADR-057), scaffold the JSON adapter contract + Starlark transform starter files instead of mcp.json:
hoziron-cli package init --type integration --name my-carrier-adapter --contract rest-soap
Current REST/SOAP dispatch coverage (Issue #587): only kind = "single" ops actually dispatch today — two_phase, async_callback, and SOAP are rejected with a clear error at both install time and call time, not silently mishandled. Only auth.kind values "none" and "bearer" are implemented; oauth2_client_credentials, basic, and api_key are rejected at connect time. Build against this contract, but don't assume two-phase/SOAP ops or non-bearer auth work yet in this build.
2. Write the MANIFEST.toml
[package]
type = "competency"
name = "my-package"
version = "1.0.0"
description = "What this package does"
license = "MIT"
min_platform_version = "0.5.0"
[package.author]
name = "Your Company"
email = "platform@company.com"
[package.metadata]
keywords = ["insurance", "claims"]
categories = ["insurance"]
[dependencies]
postgresql-connector = "^2.0"
3. Build
hoziron-cli package build ./my-package/
Produces a deterministic .hpkg archive (tar.gz, reproducible builds). Computes a SHA-256 content hash of the payload directory for integrity verification.
4. Lint
hoziron-cli package lint ./my-package/
Validates name, version, description, license, dependencies, and taxonomy categories.
5. Publish
hoziron-cli package publish ./my-package/ --notes "Initial release: claim intake + document OCR"
hoziron-cli package publish runs the full pipeline: lint → build → upload, from a source directory (not a pre-built .hpkg — for that, use hoziron-cli catalog publish <path-to.hpkg> instead, which skips straight to upload). --notes is required — a short, human-readable summary of what changed, like a GitHub Release note. Omit it and you'll be prompted interactively, unless --json is set, in which case it must be supplied on the command line. --skip-lint skips the lint step; --registry <name> overrides scope-based routing and the default publish registry.
Publishing a fork of a package that originated on another registry, and recording the lineage:
hoziron-cli package publish ./my-package/ --notes "Fork: added ZA-specific validation" \
--derived-from-registry https://catalog.hoziron.com \
--derived-from-name claims-intake \
--derived-from-version 1.2.0
The origin registry's content hash for that version is looked up live, not taken on trust from the local flags alone.
On upload, the registry:
- Authenticates the publisher via their API key
- Validates the manifest (semantics, taxonomy, license compatibility)
- Computes the archive hash (SHA-256 of the .hpkg tarball)
- Signs the provenance payload:
name:version:publisher_id:archive_hash:timestamp - Stores the archive and provenance metadata
Publish target resolution:
- Explicit
--registry <name>flag - Scope-based routing (
@scope/nameprefix) default_publish_registryconfig field
Provenance
Every published package includes:
| Field | Description |
|---|---|
publisher_id | The authenticated identity (API key name) |
publisher_role | RBAC role at time of publish |
archive_hash | SHA-256 of the .hpkg tarball |
registry_signature | Ed25519 signature over the provenance payload |
registry_key_id | Which registry key signed it |
signed_at | Timestamp of signature |
This guarantees: every package in the catalog has a verifiable chain of custody back to an authenticated publisher.
Verification
Verify package integrity locally (content hash):
hoziron-cli package verify ./my-package/
Verify provenance (publisher identity + registry signature):
hoziron-cli package verify ./my-package/ --provenance
The --provenance flag contacts the registry to fetch the signature metadata and the registry's public key, then verifies the Ed25519 signature locally.
Viewing the full lineage chain
hoziron-cli catalog provenance claims-intake
Shows the package's version history on the current registry (publisher, signed-at timestamp, release notes), and if a version carries a derived_from fork snapshot, walks the chain back toward the origin registry — fetching its live history when reachable, falling back to the recorded snapshot when it isn't.
Authentication
Publishing always requires authentication (registry:publish / package:publish — Admin, Operator, or Developer). Bootstrap your first API key on a fresh registry with no keys yet — see Private registries § Bootstrapping a fresh private registry for the hoziron-cli catalog registry bootstrap wrapper, or call the registry's POST /keys directly:
curl -X POST http://registry:4210/keys \
-H 'Content-Type: application/json' \
-d '{"name": "ci-publisher", "role": "developer"}'
The token is resolved in this order, per registry: (1) an inline token field in config, (2) the HOZIRON_REGISTRY_TOKEN environment variable (a global fallback, handy for CI where every registry call should use the same credential), (3) auth_token_env — the vault first, then the named env var from config. For a per-registry credential, prefer auth_token_env (see Private registries); reserve HOZIRON_REGISTRY_TOKEN for CI pipelines that only ever talk to one registry.
Size limit
Maximum package size: 50 MB (enforced by the registry on upload).
Registry signing key
The registry's public key is available at:
curl http://registry:4210/signing-key
# → {"key_id": "registry-abcd1234", "public_key": "ed25519:...", "algorithm": "ed25519"}
Clients use this to verify provenance signatures offline after downloading a package.
Next steps
Related: