Release flow for agentonomous. For contribution workflow + branch model
see CONTRIBUTING.md.
main— tracks what's on npm. Each release is a tagged commit here.develop— integration branch; all work lands here first.demo— long-lived branch powering the public GitHub Pages demo. Promoted fromdevelopon demand (see Demo deployment) and deliberately decoupled frommainso docs/demo updates can ship without cutting a release.- Releases flow
develop→main, then a tag triggers the publish workflow.
- npm account with publish rights to the
agentonomouspackage. NPM_TOKENsecret configured in GitHub Actions (Settings → Secrets → Actions). The token must be an automation token (not a classic publish token) so npm's provenance attestation works.mainbranch protected; releases happen only via Changesets PRs landing onmain(and those PRs originate fromdeveloporrelease/*).
All three long-lived branches (main, develop, demo) should be
protected. Configure in Repo → Settings → Branches → Add rule. Apply the
same baseline to each, with the deltas noted below.
Baseline (all three):
- Require a pull request before merging; require at least 1 approving review.
- Require status checks to pass before merging; add the
CI gate (required check)job — it is the terminal aggregator that depends on every other required job in the workflow, so adding only this one check is sufficient. (For reference, the full leaf-job list as of d9b4b85:Format (Prettier),Lint (ESLint),Typecheck (tsc --noEmit),Lint workflows (actionlint),Audit production deps (npm audit),API docs (typedoc),Test core (Vitest, ubuntu-latest),Test tfjs (cpu on ubuntu-latest),Build & size budget,Demo build (examples/product-demo).) - Require branches to be up to date before merging.
- Disallow force pushes. Disallow deletions.
- Do not allow bypass for administrators (hold yourself to the same bar).
Per-branch additions:
main— do not add theRelease candidateworkflow as a required status check. Required checks in GitHub branch protection are enforced for every incoming PR, butrelease-candidate.ymlonly runs on pushes torelease/v*branches (or manual dispatch), so marking it required would wedge every non-release PR intomainon a check that never reports. Instead, reviewers verify the latestRelease candidaterun is green on the sourcerelease/v*branch before approving the release PR. Optional: require signed commits.develop— baseline is sufficient.demo— baseline is sufficient. Remember to adddemoto thegithub-pagesenvironment's deployment branch allow-list (see Demo deployment first-time setup) or the Pages deploy job is rejected at the environment gate even when CI is green.
The .claude/settings.json denies in this repo mirror these rules at the
Claude Code permission layer; branch protection is the source of truth
and applies to humans + bots alike.
Before shipping anything, verify the package looks right:
# Run the full pre-publish gate (format, lint, typecheck, test, build).
npm run verify
# Check the bundle-size budget (gzip).
npm run size
# Inspect what npm would actually publish.
npm run pack:drypack:dry prints the exact file list + tarball size. Only dist/,
README.md, and LICENSE should appear (per the files field in
package.json).
npm run size runs the size-limit budget against the built
dist/index.js and dist/integrations/excalibur/index.js (gzip). Budgets
live in the size-limit field of package.json. If a legitimate
feature pushes a bundle over budget, bump the limit in the same PR with
a one-line justification in the commit message.
Any branch matching release/v* (e.g. release/v1.0.0) is gated by the
.github/workflows/release-candidate.yml workflow on every push. It
runs on Node 22 and does everything CI does plus:
npm run size— the gzip bundle-size budget.- Pack + smoke install —
npm packinto a tarball, install it into a scratch project, and verify the shipped ESM resolves and exportsAgent. Catches "builds fine, broken once usersnpm install" bugs that repo-local tests can't see. npm publish --dry-run— validates the would-be publish (files list,publishConfig, registry auth surface) without actually pushing a version to npm.
The workflow can also be kicked off manually from
Actions → Release candidate → Run workflow against any release/v*
branch.
Every PR that changes library behavior should include a changeset:
npm run changesetThe CLI prompts for:
- Semver bump:
major/minor/patch. - A short summary (shows up in
CHANGELOG.md).
Commit the generated .changeset/<random>.md along with the PR. Multiple
changesets per PR are fine — they get merged at release time.
The .github/workflows/release.yml workflow runs on every push to main:
- A release PR is prepared on
develop(or arelease/vX.Y.Zbranch cut fromdevelop). It bumpspackage.json, regeneratesCHANGELOG.mdfrom the pending.changeset/entries, and consumes the changeset files. Open the PR with base =main. - Merging that PR into
mainruns the workflow, which now has no pending changesets and instead runsnpm run release(changeset publish→npm publish) and tagsvX.Y.Z. - npm provenance is attested automatically (
publishConfig.provenance: trueid-token: writepermission in the workflow + GitHub's OIDC token).
- After the tag lands, fast-forward
developwithmain(or open a back-merge PR) so the version bump + changelog propagate back for the next cycle.
No manual npm publish calls are needed in the normal path.
The initial release is a one-time setup. Everything below happens on
short-lived branches; do not push directly to main until the
final merge.
Pre-flight (once, before cutting release/v1.0.0):
- npm token. Confirm
NPM_TOKENis set in Settings → Secrets → Actions. Must be an automation token (not "Publish" classic) for provenance attestation to work. - Branch protection. Apply the rules in the checklist
above to
main,develop,demo. - Environment. Settings → Environments → (create)
npm-publishif you want to add manual approval before npm publishes; otherwise thereleasejob runs automatically on push tomain. Thegithub-pagesenvironment should already includedemo. - Sanity dry-run. Locally:
npm run verify && npm run size && npm pack --dry-run. All clean. - Changeset. The v1 changeset should describe the initial public
API surface. Bump is major (pre-1.0
0.x→1.0.0).Commit thenpm run changeset # Pick: major — summary: "Initial public release.".changeset/*.mdtodevelopvia a regular PR.
Release (on release/v1.0.0, cut from develop):
git switch develop && git pull origin developgit switch -c release/v1.0.0npx changeset version— bumpspackage.jsonto1.0.0, rewritesCHANGELOG.md, deletes consumed changesets.- Commit:
chore(release): v1.0.0. Push:git push -u origin release/v1.0.0. release-candidate.ymlruns. Wait for thePreflightjob to go green. If the publish dry-run fails, fix and re-push before moving on.- Open PR: base
main, headrelease/v1.0.0. Title:release: v1.0.0. Wait for CI + release-candidate green, at least one approving review. - Squash-merge via the GitHub UI.
release.ymlfires on the push tomain, runsnpm run release(changeset publish), tagsv1.0.0, publishes to npm with provenance.
Post-flight:
- Visit https://www.npmjs.com/package/agentonomous — v1.0.0 listed, "Signed by GitHub Actions" provenance badge present.
- In a scratch project:
npm install agentonomous@1.0.0and checkimport { Agent } from 'agentonomous'resolves. - Back-merge
main→developso the version bump + CHANGELOG propagate: open a PR basedevelop, headmain, merge-commit (no squash — we want the tag reachable fromdevelop). - Delete the
release/v1.0.0branch locally + remote. - Announce, celebrate, nap.
If CI is broken and you need to ship a patch urgently:
# 1. Bump the version locally.
npm version patch # or minor/major
# 2. Run the pre-publish gate (also triggered automatically).
npm run verify
# 3. Publish. Provenance only works from CI — a manual publish will
# show up on npm without the "Signed by" attestation badge.
npm publish --access publicPush the version-bump commit + tag immediately afterward:
git push && git push --tagsAfter a release lands:
- https://www.npmjs.com/package/agentonomous — new version listed, provenance badge present.
npm install agentonomous@latestin a scratch project resolves the expected version.npx agentonomous --helpis a no-op (this is a library, no CLI), but imports likeimport { createAgent } from 'agentonomous'typecheck under TS 6 strict.
The browser demo is decoupled from npm releases. It auto-deploys to GitHub
Pages via .github/workflows/pages.yml on every push to the long-lived
demo branch (plus manual workflow_dispatch runs):
- URL:
https://<owner>.github.io/agentonomous/ - Builds the library (
npm run build), then the example (cd examples/product-demo && npm install && npm run build), then uploadsexamples/product-demo/distas the Pages artifact. - The example's
vite.config.tsreadsPAGES_BASEat build time so assets resolve under the/agentonomous/subpath.
When you want a new demo live, promote develop onto demo via a PR.
Branch protection on demo (see first-time setup below) blocks direct
pushes, so this is the required path:
- Open a PR with base
demo, headdevelop. Title:demo: promote develop @ <short-sha>. - Wait for CI green. Reviews follow the same bar as
main. - Squash-merge via the GitHub UI. That's the deploy trigger —
pages.ymlruns on the resulting push.
If protection is temporarily lifted and the histories haven't diverged, a fast-forward also works:
git switch demo && git pull origin demo
git merge --ff-only develop
git push origin demoTriggering a rebuild without advancing the branch (e.g. Pages
cleared its artifact, or you want to re-deploy the current tip): use
Actions → Deploy demo to GitHub Pages → Run workflow against the
demo branch. No push, no merge, no protection bypass needed.
First-time setup (one-off):
- Repo → Settings → Pages → Source = GitHub Actions.
- Create the
demobranch fromdevelop(git switch -c demo develop && git push -u origin demo) before enabling protection, so the initial push isn't blocked. - Add branch protection for
demo: require PR, require CI green, disallow force-push. From this point on, promotions use the PR path above. - Repo → Settings → Environments →
github-pages→ Deployment branches and tags → adddemoto the allowed list (or switch to "Protected branches only" now thatdemois protected). GitHub creates this environment withmainpre-allowed; the deploy job is rejected at the environment gate untildemois added. - Open the first promotion PR (or dispatch the workflow) and watch the
Deploy demo to GitHub Pagesworkflow.
If a broken version ships:
# Deprecate the broken version with a message pointing at the fix.
npm deprecate agentonomous@X.Y.Z "Broken release; upgrade to X.Y.(Z+1)"Then publish the patch via the normal changeset flow. Never npm unpublish
— deprecated versions remain resolvable but warn consumers; unpublishing
breaks existing installs.