Skip to main content

Distribution & Release Runbook

How AoA is intended to ship: Docker images on GHCR plus scoped npm packages, automated through GitHub Actions and gated by post-publish smoke tests.
Current status (2026-07-20): no MeteoriteLabs @armyofagents/* package is available from the public npm registry. The release workflow is disabled, release PR #227 closed without merging, and its post-publish smoke job did not run. Source checkout is the supported installation path until a release is published and the exact install command passes a clean-container smoke test.

Decision locks (Phase H)

Artifact destinations

  • Docker: ghcr.io/${{ github.repository }}:<tag>. A default-branch push publishes latest and the git sha. A deliberately created v* tag also activates {{version}} (for example 0.1.0) and {{major}}.{{minor}} (for example 0.1).
  • NPM (configured, not yet published): public @armyofagents/* workspace packages on npmjs.org, including the intended @armyofagents/cli package that provides the aoa binary. The local release script derives the owned package set from non-private @armyofagents/* pnpm workspaces; it excludes private workspaces.
GHCR follows the repository owner because the workflow uses ${{ github.repository }}. A future owner or npm scope change requires a separate release decision.

Required secrets

Configured in GitHub repo Settings → Secrets and variables → Actions: GHCR push uses GITHUB_TOKEN with packages: write permission — no extra secret needed.

Release runbook (Changesets flow)

  1. Developer creates a .changeset/*.md file:
    Pick affected packages, bump type (patch / minor / major), write a one-line description.
  2. PR merges to main (or current porting branch). The Changesets action in release.yml opens or updates a “Version Packages” PR aggregating all unprocessed .changeset/*.md files. That PR contains the package.json version bumps + generated CHANGELOG.md entries.
  3. Reviewing + merging the Version Packages PR retriggers release.yml. The Changesets action invokes pnpm changeset publish, which publishes each public package to npmjs.org and creates per-package tags such as @armyofagents/cli@0.2.8 (plus package-specific GitHub releases).
  4. docker.yml also runs for the merge push to main. Multi-arch buildx (amd64 + arm64) publishes latest and sha tags to GHCR. Its version and major.minor patterns activate only for a separate v* tag; Changesets does not create that repository-level tag automatically. Do not claim a versioned GHCR image exists unless a v* tag was deliberately created and the corresponding Docker run succeeded.
  5. After a successful publish, release-smoke.yml runs as the post-publish-smoke job in release.yml (gated on changesets/action published == 'true'). It is configured to pull @armyofagents/cli@latest inside a freshly-built smoke Docker image and run the complete Playwright release-smoke project. Until that package exists, this lane cannot validate a release. CI cannot automate a real Google account, so the founder-entry scenario uses the explicit local identity, saves a profile, creates an organization, and verifies health before the environment filesystem probe. Separate scenarios exercise scoped memory through Tasks and Discussions. Diagnostics are uploaded as the release-smoke-post-publish artifact and retained for 14 days.
scripts/release.sh remains as a local-only escape hatch for one-shot bumps outside CI. NOT invoked by the workflow.

Rollback runbook

3-step Changesets-aware flow (NOT a 1-step dist-tag repointer like the upstream project’s):
  1. npm deprecate each package returned by the shared owned-workspace package discovery at that package’s current manifest version with a message (default: "Reverted by rollback-latest.sh on <ISO timestamp>"; override with --message <text>). This surfaces a deprecation warning on subsequent installs and does not unpublish.
  2. Delete local + remote git tag v<current_version>.
  3. Optional (--revert-commit): git revert --no-edit HEAD if HEAD subject matches chore: release v<current_version>. Creates a new commit; does NOT rewrite history.
Rollback assumes the bad version is the latest published. To roll back further, re-run with the prior version listed in the deprecation messages.

Manual release-smoke (canary)

release-smoke.yml is wired to release.yml only for the published-stable path. To smoke a canary or re-run smoke against any published version: GitHub → Actions → “Release Smoke” workflow → “Run workflow” → pick:
  • aoa_version: canary (latest canary dist-tag) or latest (stable)
  • host_port: defaults to 3232
  • artifact_name: defaults to release-smoke
Auto-firing on every canary push was deliberately not wired — would burn CI minutes. Trigger manually after a canary publish if smoke verification matters.

Local Docker testing

Before pushing release-affecting changes:
docker:smoke requires a working docker daemon and pulls from npm — won’t work against unpublished local changes. Use it after a canary publish to verify the published artifact end-to-end.

SemVer vs CalVer

AoA uses SemVer; the upstream project uses CalVer. First AoA version is 0.1.0, signaling “pre-1.0 evolving — APIs may change between minors.” Bump rules:
  • patch (0.1.0 → 0.1.1): bug fixes, no API changes
  • minor (0.1.0 → 0.2.0): backward-compatible features (relaxed pre-1.0 — minors may include API changes)
  • major (0.1.0 → 1.0.0): API breaking changes; 1.0 declares stability commitment
Pre-1.0, minor bumps signal “this changed shape” rather than strict additivity. Post-1.0 (deferred decision) the discipline tightens.

Known gaps / Phase I follow-ups

  • Repository owner or npm scope change — image destination follows ${{ github.repository }}; an npm scope change needs a separate Changesets-driven publish.
  • Canary auto-wiring — release-smoke.yml exposes workflow_call but release.yml’s post-publish-smoke only fires on stable publish. Canary stays manual.
  • Desktop installer (Electron/Tauri) — out of Phase H per H.D1; separate phase.
  • Expanded smoke coverage (H.D6) — the founder-entry scenario stops at the environment step because continuing performs a real container filesystem probe and later verifies a local Commander CLI. Other scenarios already cover scoped memory through Tasks and Discussions. A future lane can supply the container-specific founder fixtures and add MCP inbound, budget, and artifact coverage.
  • GHCR image signing (cosign) — Phase I+ security hardening.
  • arm/v7 Docker support — tied to Phase I.12 Pi-local adapter.
  • Release notes automation (parse conventional commits) — Phase I.
  • compute_next_version + list_public_package_info + set_public_package_version in release-lib.sh — dead code since H.2-part-2 (release.sh port) was SKIPPED (Changesets handles versioning). Decide in Phase I cleanup: delete vs. keep as reference.
  • Package ownership — release and rollback share workspace discovery and include only public packages in the @armyofagents/* scope. The private private workspaces are outside the publish graph.