Releasing
How a version reaches npm: the release skill, the tag-triggered publish workflow, the rulesets that gate it, and the drift check.
A release goes from a version bump on main to an npm publish with provenance. Each step is gated, and a person makes every decision.
The release skill
skills/release runs the maintainer side. It checks for a clean, up-to-date main, a repository.url, no file: dependencies and a passing npm test. Then it bumps the version with npm version --no-git-tag-version and moves the [Unreleased] changelog entries under the new version. The bump lands through a PR because main is protected. After the merge, the maintainer tags the merged commit and pushes the tag.
The generic release skill expects a project profile at .claude/release-profile.md. This repository does not have that file.
The publish workflow
Pushing a v* tag is the only trigger for publish.yml. It has no workflow_dispatch, so it always runs the workflow file from the tagged commit. The job:
- Runs in the
npm-publishprotected environment (publish.yml#L27), which needs a reviewer to approve it. - Refuses a tag whose commit is not an ancestor of
origin/main(publish.yml#L41). - Refuses a tag that does not match the
package.jsonversion (publish.yml#L82). - Upgrades to npm 11 for OIDC trusted publishing (publish.yml#L70), then runs
npm ciandnpm test. - Publishes with
npm publish --provenance --access public(publish.yml#L101), using theid-token: writepermission (publish.yml#L16) instead of a long-lived token.
Rulesets
docs/github-rulesets/ keeps the publish gates in version control. The release-tag-ruleset.json file lets only admins create, delete or move refs/tags/v* tags. apply.sh sets up the npm-publish environment and applies that ruleset. Branch protection for main is configured by hand in GitHub and is not in this directory.
Release drift
release-drift.yml runs once a day and on demand. It runs scripts/release-drift.mjs (release-drift.yml#L50) to catch a version that reached main but never reached npm: either a publish waiting for an approval nobody gave, or a bump with no tag pushed. A grace window (90 minutes) keeps a healthy release in progress from being reported.