doc/RELEASE-AUTOMATION-SETUP.md
This document covers the GitHub and npm setup required for the current Paperclip release model:
masterRepo-side files that depend on this setup:
.github/workflows/release.yml.github/CODEOWNERSNote:
pnpm install --no-frozen-lockfilepnpm-lock.yaml is refreshed by GitHub automation after manifest changes land on masterpnpm-lock.yaml before running scripts/release.sh, so the release script still sees a clean worktreeBefore touching GitHub or npm settings, merge the release automation code so the referenced workflow filenames already exist on the default branch.
Required files:
.github/workflows/release.yml.github/CODEOWNERSDo this for every public package that Paperclip publishes.
At minimum that includes:
paperclipai@paperclipai/server@paperclipai/uipackages/For each package:
paperclipai/paperclipnpm currently allows one trusted publisher configuration per package.
Configure:
.github/workflows/release.ymlRepository:
paperclipai/paperclipEnvironment name:
Why:
release.yml workflow handles both canary and stable publishingnpm-canary and npm-stable still enforce different approval rules on the GitHub sideTrusted publishing is configured on the npm package itself, not at the repo scope. That means a brand-new public package must not be auto-enrolled into CI publishing until its npm package exists and its trusted publisher has been configured.
Repo policy:
scripts/release-package-manifest.json"publishFromCi": true only when CI is expected to publish that package"publishFromCi": falseBootstrap sequence for a new package:
paperclipai/paperclip trusted publisher for .github/workflows/release.yml"publishFromCi": truePR CI enforces this by checking changed release-enabled package manifests against npm. That keeps master canary publishing healthy while preserving the no-long-lived-token model for normal CI releases.
After the workflows are live:
NPM_TOKENOnly after that should you remove old token-based access.
After trusted publishing works:
NPM_TOKEN secrets used for publishGoal:
Create three environments in the GitHub repository:
npm-canarynpm-betanpm-stablePath:
SettingsEnvironmentsNew environmentnpm-canaryRecommended settings for npm-canary:
npm-canarymasterReasoning:
master should be able to publish a canary automaticallyThe scheduled nightly lane also publishes under npm-canary: it is the same
trust level (fully automated, no human gate), its runs execute on master so
the branch rule is satisfied, and reusing the environment means the nightly
lane required no new environments and no npm trusted-publisher changes
(publishing still happens from release.yml, see section 2.2).
npm-betaRecommended settings for npm-beta:
npm-betamasterReasoning:
channel: beta dispatch. If the
workflow runs first, GitHub auto-creates the environment with no
protection rules, and that first beta would publish without approvalLike nightly, beta publishing lives in release.yml, so no npm
trusted-publisher changes are needed (see section 2.2).
npm-stableRecommended settings for npm-stable:
npm-stablemasterReasoning:
masterOpen the branch protection settings for master.
Recommended rules:
masterAt minimum, make sure workflow and release script changes cannot land without review.
This repo now includes .github/CODEOWNERS, but GitHub only enforces it if branch protection requires code owner reviews.
In branch protection for master, enable:
Require review from Code OwnersThen verify the owner entries are correct for your actual maintainer set.
Current file:
.github/CODEOWNERSIf @cryppadotta is not the right reviewer identity in the public repo, change it before enabling enforcement.
These files should always trigger code owner review:
.github/workflows/release.ymlscripts/release.shscripts/release-lib.shscripts/release-package-map.mjsscripts/create-github-release.shscripts/rollback-latest.shdoc/RELEASING.mddoc/PUBLISHING.mdIf you want stronger controls, add a repository ruleset that explicitly blocks direct pushes to:
.github/workflows/**scripts/release*Do not add a personal Claude or Anthropic token for automatic changelog generation.
Recommended policy:
This keeps LLM spending intentional and avoids a high-value token sitting in Actions.
After setup:
masterRelease workflow run triggered by that pushnpm-canary environmentcanary releasecanary/vYYYY.MDD.P-canary.N was pushedInstall-path check:
npm install --prefix "$(mktemp -d)" paperclipai@canary --no-audit --no-fund
The release script runs this clean-prefix install after publishing every workspace
package dependency-first and publishing paperclipai last. A package that is not
yet registry-visible stops the train before the channel entrypoint can advance.
After at least one good canary exists:
./scripts/release.sh stable --date YYYY-MM-DD --print-versionreleases/vYYYY.MDD.P.md on the source commit you want to promoteActions -> Releasesource_ref: the tested commit SHA or canary tag source commitstable_date: leave blank or set the intended UTC date like 2026-03-18
do not enter a version like 2026.318.0; the workflow computes that from the datedry_run: truedry_run: falsenpm-stable environment when promptedlatest points to the new stable versionvYYYY.MDD.P existsImplementation note:
create-github-release.sh with PUBLISH_REMOTE=originPUBLISH_REMOTE=public-gh explicitly when neededUse this policy going forward:
npm dist-tag, not unpublishCheck:
id-token: writeCheck:
publish job uses environment npm-stableCheck:
.github/CODEOWNERS is on the default branchmaster requires code owner review