Skip to main content

Release

One GigaLoom release binds Python, npm, Git, and embedded Web assets. The only hand-edited identity is release/version.toml; scripts/release.py generates and verifies release/release.json and every ecosystem projection. For the first stable Native Agent Gateway release the exact identity is:

SurfaceIdentity
Canonical release0.9.1
Git tagv0.9.1
PyPIgigaloom==0.9.1
npm@gigaloom/web@0.9.1

The root Python metadata, npm metadata, generated manifest, changelog skeleton, package-documentation snippets, and release/artifact-set.toml must match the canonical file exactly. CI fails when any projection is edited by hand.

Bump a version

From the repository root, run one hermetic source-to-projection operation:

git switch -c release/0.8.0-alpha.1
./scripts/release bump 0.8.0-alpha.1

bump updates every version projection with in-process rollback, then verifies the result, including the packaged product inventory. Its JSON receipt lists the exact changed paths and the remaining human and external gates. It does not build, commit, tag, publish, or call a provider. Running it again for the same version is a byte-identical no-op.

Use ./scripts/release diff <version> to review a proposed version without writing and ./scripts/release show to inspect the canonical identity. The legacy prepare command remains compatible. verify remains an independent CI and tag-boundary check; it is unnecessary immediately after a successful bump.

Tag policy

New releases use only the standard v<release> tag. Create the protected tag at the exact reviewed main commit. The tag starts the immutable candidate build; publication begins only after its build, parity, checksum, denylist, and attestation gates pass. Neither workflow creates, moves, or repairs a tag.

Historical prefix-shaped tags remain history. Do not reuse those prefixes for new releases. Never move or delete a tag after either registry accepts the version. A bad unpublished tag is an audited repository-policy correction, not something the workflow guesses around.

Maintainer checklist

  1. Confirm the named GitHub and PyPI backup owners have accepted access with 2FA under the governance policy.
  2. Run the documented bump, complete both generated changelog skeletons, and review the exact changed paths from its receipt.
  3. Build frontend assets and run the complete non-live quality gate.
  4. Ensure the release commit is on main and the documented main/tag rulesets are active.
  5. Confirm PyPI and npm Trusted Publishers name the exact project/package, repository, publish workflow, and release-production environment. Confirm that the environment has no required-reviewer gate for automatic releases.
  6. Create the protected standard tag at that exact source SHA. The tag push builds and attests one candidate, then automatically starts publication from that same workflow run after success.
  7. Monitor the candidate, registry checks, and GitHub Release creation. Record the candidate run ID, full source SHA, and candidate-manifest.json SHA-256 for recovery.

Two-phase workflow

.github/workflows/publish-pypi.yml runs on a protected v* tag push to build and attest one retained candidate. It has no registry or GitHub Release publication step.

.github/workflows/release-publish.yml is a separate workflow protected by the release-production environment. A successful completion of the candidate workflow starts it through workflow_run; the resolver consumes that exact run ID and requires one unexpired artifact with the exact SHA-bound name. The protected job rechecks the tag, ancestry, metadata, checksums, byte parity, and legacy denylist and does not rebuild. Before an initial or missing-registry publication it also requires the exact GitHub Release tag to be vacant. It then checks public registry state before requesting OIDC credentials. After both registries are proven, the final boundary accepts either a vacant tag or one mutable exact-tag Release with zero uploaded assets. The latter is adopted without asset overwrite and its release-channel metadata is normalized. Manual dispatch remains recovery-only; it additionally requires the recorded run ID, SHA, tag, manifest digest, and recovery mode.

Choose exactly one mode:

  • initial: both versions are absent; publish npm with provenance, then PyPI;
  • recover-pypi: exact npm bytes exist and PyPI is absent; publish only PyPI;
  • recover-npm: exact PyPI files exist and npm is absent; publish only npm;
  • release-assets-only: both registries contain the exact candidate bytes; publish neither registry and create the GitHub Release last, or adopt one empty mutable exact-tag Release without overwriting assets.

Any unexpected existing filename or digest, malformed registry response, or registry outage stops the workflow. A successful registry is never republished during recovery. A pre-created GitHub Release stops the workflow before either registry write. Only after exact registry-byte proof may an explicit release-assets-only recovery adopt it, and only when the exact-tag Release is mutable and has no uploaded assets; every collision or immutable boundary fails closed.

Release channels

The release guard derives channels from the canonical manifest version. Alpha, beta, and release-candidate versions publish npm under the next dist-tag and create a GitHub Pre-release with Latest explicitly disabled. A stable version publishes npm under latest and explicitly marks its GitHub Release as Latest. PyPI keeps the manifest's native PEP 440 prerelease or stable version.

The existing @gigaloom/web package must bind release-publish.yml plus the release-production environment as its npm Trusted Publisher before the tag is created. Do not put an npm token in GitHub.

Rollback and recovery

Before any registry accepts a version, revert release automation or source and build a new candidate from a new commit. After npm or PyPI succeeds, the version and tag are immutable. Reuse only the exact retained candidate to finish the missing registry, or advance all release identities and issue a new version. Never rebuild a partial release, overwrite package files, or move its tag.

Public Trusted Publisher registration, tags, GitHub releases, and package publication are external mutations and remain separate authorized gates. See the repository's release recovery runbook.