Skip to content

Releasing

Cut a Chickpea release: the source gates, attended acceptance, and publishing a tag that never moves.

Updated View as Markdown

A release is a SemVer tag such as v0.1.0 plus a matching GitHub release, cut from one exact commit. Merging to main changes source and deploying changes one running deployment; neither publishes a release, and Chickpea publishes no npm package. This page covers the three gates (source, attended acceptance, publish), the export allowlist, the model catalog’s immutable revisions, and what release notes must contain.

Prerequisites

  • A clean checkout of the exact candidate commit, with no private environment files. Never .env, .dev.vars, SQLite databases, credential keyrings, setup links, or live transcripts.
  • Node 24.20.0. .nvmrc pins the single release-verification baseline. Only Node 24.x is supported, minimum 24.20.0. Update the pin for later patch/security releases and verify it once, without a second runtime sweep.
  • An approved disposable deployment and Slack workspace for acceptance. Not a production workspace, and not another task’s environment.
  • Repository settings in place. Force pushes and deletions blocked on main, GitHub Actions disabled with no required workflow checks, Dependabot alerts and security updates on, private vulnerability reporting on.
  • Explicit authorization to tag and publish that exact commit.

Run the source gates

Start from the clean checkout. Run the checks serially, once on the pinned Node 24 baseline, because tests inspect generated artifacts and a concurrent build makes them read a partially written artifact.

nvm install && nvm use
npm ci
npm audit --omit=dev
npm run verify:regression -- --mode release

The release command restores artifacts and runs authoring, Admin, local workerd, lockfile, and committed-source export checks. The export installs, builds, and runs the full root/CLI suite plus offline turn, durability, and provider checks. Those checks run once inside the export; the outer command does not repeat them. Use --record <private-run.json> with the existing verification notebook to keep logs and checkpoint evidence. Missing evidence, stale configuration, unresolved failures, and the final merge-result check remain release gates.

  • Commit first. verify:oss-export reads committed HEAD. Release mode refuses dirty source or private environment files; an earlier commit’s pass does not validate new changes.

  • verify:cf-smoke takes several minutes. It builds both Cloudflare profiles and runs the core profile in local workerd, and it treats .wrangler-state in that directory as disposable.

  • No hosted run counts. There is no GitHub workflow that runs or deploys a release. Record the local results with the change or the release evidence.

What verify:oss-export checks

The verifier reads the tracked file list at HEAD, extracts that archive into a temporary directory it prints as SCRATCH=<path>, and then:

  • Scans every tracked file for denied terms. Private project and company names, local home-directory paths, and, in the live-verification sources, Slack tokens, provider API keys, and Slack coordinate IDs.
  • Blocks unlisted documents. A tracked path under docs/ that is not on the allowedPublicDocs list fails with OSS export contains forbidden public-source paths:.
  • Blocks unlisted binaries. Image and media extensions fail unless the path is on the allowedBinaryFiles list with a matching SHA-256 digest.
  • Blocks local agent and tool state. Tracked paths under evidence/, screenshots/, transcripts/, tmp/, and the agent-state dot directories never ship, apart from one allowed skill file.
  • Requires the license files and public package metadata. LICENSE and NOTICE must exist, and package.json must stay private with an Apache-2.0 license, a description, and a repository.
  • Rebuilds the archive from nothing. npm ci, npm run build, npm run test:ci, the offline Flue turn, verify:durability, verify:providers, and a deployment dry run, all inside the scratch directory.

A pass prints OSS export verification passed and deletes the scratch directory. Set KEEP_EXPORT_SCRATCH=1 to keep it for inspection.

Adding a public document to the release means adding its path to the allowlist in scripts/verify-oss-export.mjs in the same change. A new runtime image goes on the binary allowlist with its digest, and into src/assets/public-assets.ts so Node serves it.

Record the compressed upload size

The deployment dry run at the end of verify:oss-export is the measurement. To take it by hand, run npm run deploy -- --dry-run; the deploy wrapper uploads nothing on a dry run and passes wrangler’s output through untouched.

  • Record the compressed upload size from that dry run, not the size of the repository or node_modules.
  • Keep headroom below the advertised plan’s Worker limit. The current bundle exceeds the Free plan’s 3 MiB limit, which is why Chickpea advertises Workers Paid.
  • A dynamic import still contributes its uploaded chunk to that limit.
  • Do not advertise Free compatibility unless the release artifact fits those limits and the relevant runtime checks pass.

Rebuild the model catalog when its source changed

catalog/current.json is generated from catalog/source.json. Do not edit it by hand.

  • npm run catalog:build with no arguments only checks. It prints Catalog revision <n> is deterministic and immutable., or fails with catalog/current.json is not the deterministic output of catalog/source.json.
  • npm run catalog:build -- --write writes catalog/current.json and catalog/releases/revision-<n>.json. The revision file is written exclusively: rewriting a published revision with different bytes fails with Immutable release already exists with different bytes:.
  • Bump revision in catalog/source.json when entries change. A published revision keeps its bytes forever.
  • The source gates above do not include this check. Run npm run verify:model-catalog yourself when the catalog changed; it rebuilds the catalog and runs the catalog tests.

Run attended acceptance

Fake-backend tests and local workerd give deterministic coverage. They do not establish real Slack and Admin acceptance, so this gate is a live run against a disposable environment. Keep identities, bindings, secrets, and evidence outside the public repository.

  1. Choose the approved disposable deployment and Slack workspace before you install anything.
  2. Install the exact candidate from a fresh public source checkout with no local private files.
  3. Exercise each advertised target and Slack lane. Name any lane you did not test instead of claiming general acceptance.
  4. Complete Slack installation, first-Owner sign-in, provider and model selection, and a real DM or mention that receives a reply from the candidate deployment.
  5. Confirm a second user cannot reach Owner-only configuration or another Agent’s personal connection. Check an approved connector flow if the release advertises one.
  6. Restart or redeploy, then confirm sign-in, existing state, and Slack delivery still work. Check retry and deduplication behavior without claiming exactly-once delivery.
  7. On Cloudflare, verify an approved schedule fires and stops when paused. Test the coding sandbox if this release advertises the optional profile.
  8. For a second or later release, test the documented upgrade from the prior supported version and the stated recovery procedure. A fresh install does not replace upgrade testing.
  9. Remove only the fixtures and resources this run created. Record the source commit, the target and version, observed outcomes, limitations, and cleanup.

Write the release notes

The notes are the operator’s contract for that version. They must cover:

  • Prerequisites and installation links, so an operator can install the tagged source the documented way.
  • Changes and known limitations in this version.
  • Supported upgrade origins. State the supported starting versions and the required operator actions. There is no implied upgrade path from an unlisted experimental schema.
  • Migrations, and whether a downgrade is safe. If the notes do not declare a downgrade safe, operators use the tested recovery procedure instead.
  • Recovery limits. Reverting code does not undo a schema migration or recover deleted data.
  • Experimental status. For a 0.x release, say so, and decide whether GitHub’s prerelease flag applies.

Verify

Confirm all of this before you create the tag.

  • package.json, the lockfile, and the tag carry the same version. The tag is v0.1.0, not v0.01.
  • The candidate commit is on main, and the local checks were rerun or confirmed on that final commit.
  • Attended acceptance ran against this commit, with untested lanes named rather than implied.
  • The release notes cover every item above.
  • You hold explicit authorization to tag and publish this exact commit.

Publish

  1. Land the release preparation through a GitHub pull request or a maintainer-authorized local merge into root main, verified before pushing.
  2. Create the version tag and the GitHub release together, on the authorized commit.
  3. Download the release’s source archive and confirm it installs by the documented path.
  4. Publish no secrets and no private acceptance evidence.

Next steps

Navigation

Type to search…

↑↓ navigate↵ selectEsc close