ZERO distribution should stay conservative until public names, signing, and support commitments are stable.
- GitHub Release artifacts
- Python wheel and source distribution generated by CI
- Rust CLI binaries for Linux and macOS
- Paper runtime container image tarball
- Combined
SHA256SUMS SBOM.spdx.jsonPROVENANCE.json- GitHub artifact attestations
- Installer script that verifies checksum and attestation before installing
- Homebrew formula in
Formula/zero.rb - Published PyPI package
zero-engine - Railway paper-runtime deployment path and template publish packet
- Railway Open Source Partner application packet
Docker Hub getzero/zero is the primary public container path. GHCR also uses
the product image name ghcr.io/zero-intel/zero and has anonymous pull
evidence. The container runtime remains paper-first by default, with live
operation behind explicit preflight gates.
Container channels require maintainer-owned package names, provenance, rollback procedure, public-pull verification, and support expectations before enablement.
| Channel | Candidate | Gate |
|---|---|---|
| PyPI | zero-engine |
name ownership, Trusted Publishing, signed release dry run |
| crates.io | zero-os, zero-* crates |
namespace review, README/license metadata, least-privilege token, cargo owner review |
| Homebrew | zero-intel/zero public repo tap |
Formula/zero.rb update from release checksums |
| GHCR | ghcr.io/zero-intel/zero |
published, anonymous pull verified |
| Docker Hub | getzero/zero |
published, anonymous pull verified |
| Railway template | ZERO Paper Runtime |
published at https://railway.com/deploy/zero-paper-runtime |
Railway is the first one-click hosted channel for ZERO because it matches the product boundary: paper-first runtime, durable journal volume, public URL, operator-owned billing, and no exchange private keys.
Current verified public demo: https://zero-production-5214.up.railway.app
Published Railway template: https://railway.com/deploy/zero-paper-runtime
The template packet is
contracts/distribution/railway-template.json.
It records the public demo URL, point-in-time verified deployment id, required
variables, volume mount, autodeploy config, doctor summary, and evidence
verification result.
Regenerate and check it after deployment-affecting changes:
scripts/railway_template_packet.py --output contracts/distribution/railway-template.json
scripts/railway_template_packet.py --checkThe marketplace template should not include live exchange credentials. It must
set ZERO_MODE=paper, mount /data, expose /health, and keep /live/preflight
in live_mode=refused.
The partner packet is
docs/railway-partner.md. It records the application URL,
submission message, support queue commitment, update policy, and evidence links
needed for Railway's Open Source Partner review.
Run the non-publishing registry gate before a release PR, namespace request, or package-channel launch:
just registry-readinessThe gate checks PyPI metadata, Cargo workspace metadata, per-crate publish metadata inheritance, optional live dependencies, and documentation guardrails. It does not publish to any package registry. A passing result means the repo is structured for registry review; publication state is recorded in the registry launch packet.
The checked launch packet is
contracts/distribution/registry-launch.json.
It records the current channel state: GitHub Releases are published, the public
Homebrew tap is ready, zero-engine is published on PyPI, zero-os and the
workspace crates are published on crates.io, GHCR is published with
legacy authenticated GHCR smoke evidence plus product-image anonymous pull
evidence, and Docker Hub getzero/zero is published with anonymous pull
evidence.
Regenerate and verify it with:
scripts/registry_launch_packet.py --output contracts/distribution/registry-launch.json
scripts/registry_launch_packet.py --check
scripts/mcp_registry_packet.py --output
scripts/mcp_registry_packet.py --check
scripts/mcp_registry_listing_check.py --jsonjust registry-readiness runs this check. The release workflow must not add
automated crates.io publication or default-on container publication until this
packet and the release notes include namespace ownership, least-privilege
publishing, clean install evidence, rollback steps, and support expectations.
GHCR and Docker Hub publication remain manual workflow paths; both public
container paths have anonymous pull evidence. PyPI publication
for zero-engine is already enabled through Trusted Publishing. crates.io
publication currently uses CRATESIO_API_TOKEN manually until tokenless
publishing is available.
The MCP Registry packet is separate from package registries because it is
metadata for agents, not an artifact host. ZERO commits server.json and
contracts/distribution/mcp-registry.json; the Official MCP Registry listing
is live for io.github.zero-intel/zero. The manual
.github/workflows/mcp-registry.yml workflow uses GitHub OIDC and fails closed
unless the PyPI package is public and carries the required mcp-name marker.
Package channels must be proven before use:
- PyPI:
zero-engineis published through PyPI Trusted Publishing from GitHub Actions, not a long-lived API token. - crates.io: every intended crate has a clear owner list,
cargo owner --listevidence after publication or reservation, and no crate name implies custody, guaranteed returns, or hosted execution. The CLI package iszero-osbecausezerois already occupied on crates.io; its installed binary remainszero. - Homebrew: the tap repository is public, formula review is linked, and the formula points to a tagged GitHub Release asset plus its checksum.
- GHCR:
ghcr.io/zero-intel/zero:0.1.2is published through the manual container workflow, multi-platform, and anonymous pull verified with digestsha256:048728c531aa79306e8e6b3618c61e3b4a6f74d80fff6da57deabb79bae4ed7b. - Docker Hub:
getzero/zero:0.1.2is published, multi-platform, and anonymous pull verified with digestsha256:d810ae677af04958a95b387e6fbc7ff15baa4d8488b26cfb76b31cc4ee300162. The product image keeps paper-first safety wording until live runtime evidence exists.
Before adding any package registry:
just cipasses locally.- GitHub CI, CodeQL, Secret Scan, and OpenSSF Scorecard pass on
main. - Release artifacts verify with
shasum -a 256 -c SHA256SUMS. scripts/release_verify.py <downloaded-release-dir>passes.just release-rehearsalproves tampered artifacts are rejected.- GitHub artifact attestations verify from a clean download directory.
just registry-readinesspasses.SBOM.spdx.jsonandPROVENANCE.jsonare present, checksummed, and parsed byscripts/release_verify.py.docs/threat-model.md,docs/incident-runbooks.md, anddocs/dependency-policy.mdare reviewed.- Rollback steps for the channel are documented in the release PR.
- No channel token is stored in repository files or local examples.
The committed formula must:
- install the
zeroCLI only; - point to a tagged GitHub Release asset;
- verify the release checksum;
- avoid private taps or private package registries;
- state that the engine defaults to paper mode;
- link to
docs/release.mdanddocs/safety-model.md.
Render the formula from a verified release directory:
scripts/homebrew_formula.py <downloaded-release-dir> --tag v0.1.2 --output Formula/zero.rb
scripts/homebrew_formula_check.pyThe renderer reads SHA256SUMS and refuses to emit a formula unless checksums
for both zero-linux and zero-macos are present. scripts/release_evidence.py <tag> also compares the formula rendered from the downloaded release against
the committed Formula/zero.rb, so release evidence fails if the public tap is
stale. The public repo can be used as a Homebrew tap without private registry
access:
brew tap zero-intel/zero https://github.com/zero-intel/zero
brew install zero-intel/zero/zero
zero --versionThe public tap is a Git repository. To verify a clean reinstall from the published formula:
brew uninstall zero || true
brew untap zero-intel/zero || true
brew tap zero-intel/zero https://github.com/zero-intel/zero
brew install zero-intel/zero/zero
zero --versionTo roll back to the previous formula commit on an operator machine:
tap_repo="$(brew --repo zero-intel/zero)"
git -C "$tap_repo" log --oneline -- Formula/zero.rb
git -C "$tap_repo" checkout <previous-formula-commit> -- Formula/zero.rb
brew reinstall --formula zero-intel/zero/zero
zero --version
brew pin zeroTo return to the current public formula:
brew unpin zero || true
tap_repo="$(brew --repo zero-intel/zero)"
git -C "$tap_repo" restore Formula/zero.rb
brew update
brew reinstall --formula zero-intel/zero/zero
zero --versionscripts/homebrew_formula_check.py proves the committed formula is generated
from the release checksum manifest and remains public-safe. just release-evidence <tag> goes further: it downloads the release, verifies
SHA256SUMS, verifies release metadata and attestations, rerenders the formula
from the clean download, and fails if the committed formula has drifted. These
checks name the already-published PyPI zero-engine package and crates.io
zero-os package plus the authenticated GHCR smoke evidence and Docker Hub
workflow readiness. They do not claim Docker Hub publication or public anonymous
GHCR pull access.
Run the dry-run path in normal CI and before release PRs:
just draft-release-rehearsalMaintainers can run the real GitHub draft-release rollback drill with:
scripts/draft_release_rehearsal.sh --executeThe execute mode creates a temporary draft prerelease, downloads all assets to a fresh directory, verifies the bundle, renders the Homebrew formula, then deletes the draft release and temporary tag. This proves the rollback motion without publishing a package registry, Homebrew tap, or production release.
After changing .github/workflows/release.yml, run the full tag-triggered
release workflow drill:
scripts/release_workflow_rehearsal.sh --executeThe drill creates a temporary prerelease tag on origin/main, waits for the
real release workflow, verifies the public-proof job and all artifact jobs,
downloads the generated draft GitHub Release, checks SHA256SUMS, runs
scripts/release_verify.py, verifies executable attestations, renders the
Homebrew formula, then deletes the draft release and tag. It does not publish
package registries, Homebrew taps, or production releases.
If a package is unsafe:
- Pull or deprecate the package where the registry permits it.
- Mark the GitHub Release as unsafe or move it back to draft.
- Publish a patched release with a new semver patch version.
- Add the incident to the release notes.
- Add a regression test or hardening-gate check for the failure class.
Do not ship a public channel that implies hosted custody, guaranteed returns, or production trading readiness. Package descriptions must say paper mode is the default and live mode is self-custodial.