Releasing
For maintainers. Releases are alpha prereleases. Nothing is published except by pushing a v* tag, and only from the public agentscm/agentscm repository (the workflow skips any other repository, and build-provenance attestations need a public one).
- One time, before the first tag: add a tag ruleset so only maintainers can create
v*tags (the workflow cannot tell who pushed a tag); create thenpmenvironment with required reviewers; on npmjs.com, addagentscm/agentscm, workflowrelease.ymland environmentnpmas the package’s trusted publisher, withnpm publishallowed (no token is stored); turn on immutable releases in the repository settings, so a published release’s assets cannot be replaced while thenpmjob waits for approval. - On a branch, set
versioninCargo.toml, the root package entry inCargo.lock,packages/npm/package.jsonand the root path-dependency entry inui/dev-seed/mint/Cargo.lock, and giveCHANGELOG.mdan entry headed## <version> (<date>)with its known limits. Do not update unrelated dependencies while preparing the version. Open a pull request and add theci-extendedlabel so everyci-extendedsuite (hosted tests, Windows, container, end-to-end and live execution) runs on the candidate; wait for those workflow runs, not only the pull request’s checks list. - Before merging or tagging, qualify the candidate on clean native hardware. Run the CLI and container tests on Linux amd64 and arm64. On a clean Apple Silicon Mac with isolated ports, container names and volumes, test the staged native macOS binary and locally built
linux/arm64image through install, first quickstart, Hub health/UI, login/token/hooks, restart, no-op rerun, uninstall and reinstall with retained data. Use the installer-produced paths and checksums; do not disable provenance or checksum enforcement. Record this as local candidate qualification: public npm/GHCR acquisition and GitHub attestations can be checked only after publication. Preserve any existing Hub and its data throughout. After it merges, checkmainis green and that Dependabot andcargo denyhave nothing open for the release. - Tag the merge commit:
git tag -s v<version> -m v<version> && git push origin v<version>. The tag must equal theCargo.tomlversion, be onmain, and have a CHANGELOG entry, or the workflow stops before pushing anything. release.ymlbuildslinux/amd64onubuntu-24.04andlinux/arm64onubuntu-24.04-arm. Each image is loaded and fully exercised by.github/docker-smoke.shon its native runner before any push. The exact tested children are then pushed under commit-specific staging tags, receive build-provenance and SPDX SBOM attestations, and supply immutable digests to a downstream job. That job assembles a candidate index from those two digests, asserts that it contains exactly the tested amd64 and arm64 runnable children, and only then createsghcr.io/<owner>/agentscm:<version>and attests the index digest. Nolatesttag is published during alpha. The workflow then creates a GitHub prerelease from the CHANGELOG entry. A release publishes five binaries (Linux x86_64 and aarch64 musl, macOS arm64 and x86_64, Windows x86_64 msvc asagentscm-x86_64-pc-windows-msvc.exe), an attestedSHA256SUMS(the binaries only) andinstall.sh,LICENSE,NOTICEandTHIRD_PARTY_NOTICES.md(the binaries embed third-party code), and the npm packageagentscmunder the dist-taglatest(every release is a prerelease, sonpx agentscmneeds one; go back tonextfor prereleases after the first stable release). Every binary built on matching native hardware runs--version; the native Linux and macOS binaries also runlocal-validation reconcile --helpand require the authenticated-fetch flag to appear. The Windows binary does not support reconciliation, and macOS x86_64 is cross-compiled on arm64, so neither runs that command. These help checks establish only that the release binary exposes the command surface; they do not perform a reconciliation, exercise GitHub credentials or prove installer provenance. The npm job remains downstream of the verified image index and GitHub release. It waits for approval on thenpmenvironment; for a tag containing-dryit skips the publish, and for any other tag it publishes with npm trusted publishing. The job fails if npm does not accept it, so a green release always has the package published. See install for what users run.- Set the package to public once in the GHCR package settings and link it to the repository; confirm an anonymous pull works.
- Verify the published index reports exactly
linux/amd64andlinux/arm64, pull and run each child on matching native hardware, and repeat the clean Apple Silicon install from the public artifacts. Verify the index attestation withgh attestation verify oci://ghcr.io/<owner>/agentscm@<digest> --repo <owner>/agentscm --signer-workflow <owner>/agentscm/.github/workflows/release.yml --source-ref refs/tags/v<version> --deny-self-hosted-runners(afterdocker login ghcr.ioif the package is still private). Verify each child digest the same way and verify its SPDX predicate with--predicate-type https://spdx.dev/Document/v2.3. - A dry run is a tag containing
-dry(for examplev0.2.0-dry1) whose version inCargo.tomlmatches (0.2.0-dry1). It runs the whole workflow, including pushing the image and creating the prerelease, but skips the npm publish. Use it to exercise the workflow before a real tag, then delete the tag, the release and the image tag. The Windows binary build is first exercised by such a tag, so run a dry run before a real release that changes the Windows build. The Windows and macOS binaries are not code-signed or notarized; see install. - A bad release is superseded by a new version, never edited: delete the tag and release only if nothing has pulled the image.
Publishing identity
The release jobs require the immutable public repository ID, so a namespace rename does not
admit a fork or a repository created later under the former name. Before attesting install.sh
and publishing npm, .github/pin-release-installers.js embeds the current publishing repository,
exact version and signing workflow identity into the installers and npm repository metadata.
The current and planned organization names are allowlisted as well as the repository ID.
Historical releases, attestations and npm packages retain their original identities.
An organization rename also requires the operator to configure the exact new npm trusted
publisher (organization, repository, release.yml, npm environment and direct publish
permission) before any new release. Keep the previous publisher during qualification, then
remove it only after validating the new path. Updating source does not update npm settings,
publish a release, or prove historical attestation lookup works after a rename. Qualify an
old exact npm version with required provenance and an uncached binary after cutover; do not
turn off verification to work around a failure.
Activating the reusable local-validation workflow
The reusable .github/workflows/local-validation-reconcile.yml interface must not be adopted before its exact npm release exists. The current source-build verifier remains active until a release contains reconcile, path-scoped recipes and exempt paths, the opt-in authenticated GitHub fetch boundary, and the reusable workflow itself.
After npm publication succeeds, qualify the exact version from an empty directory and private home with AGENTSCM_REQUIRE_PROVENANCE=1 and AGENTSCM_TELEMETRY=off: run npx --yes --ignore-scripts --registry=https://registry.npmjs.org agentscm@VERSION local-validation reconcile --help with stdin closed, then invoke ~/.agentscm/bin/agentscm-VERSION --version directly and require the exact reported version. npx agentscm@VERSION --version is only the npm launcher’s shortcut and does not install or verify the binary.
Only after that acquisition check and the release’s required qualification should a follow-up change replace the source-build verifier or the adoption guide’s placeholders with the exact SemVer and full reusable-workflow commit SHA. Exercise a public repository first; private GitHub fetch, redirect and timeout behavior remains unqualified until it is run and recorded separately. Do not add an automatic source fallback to the reusable interface, accept a mutable tag/range, pass a PAT, GitHub App secret or OIDC input, or use secrets: inherit.
Third-party software in the container image
The image is based on Debian (debian:trixie-slim, pinned by digest in the
Dockerfile) and adds Debian’s git package. These packages are distributed
under their own licenses, including the GNU General Public License for git.
Each package’s copyright and license file is kept in the image under
/usr/share/doc/
Source code for the Debian packages in the image is available from Debian at https://sources.debian.org/ and https://snapshot.debian.org/ for the exact package versions. To list them, run:
docker run --rm --entrypoint dpkg-query ghcr.io/agentscm/agentscm:<version> -WOn request, for three years after we publish an image, we will provide the corresponding source for its GPL-licensed components. Email support@counterbranch.com and name the image tag and digest.
AgentSCM’s own license, NOTICE and Rust dependency notices are in the image at /usr/share/doc/agentscm/.
The release retains commit-specific sha-<commit>-amd64, sha-<commit>-arm64 and sha-<commit>-index-candidate tags for audit and recovery. They are staging identities; consumers should use the versioned index or its digest. Registry retention must preserve every child referenced by a supported release index.