Release
SkillDev toolsCut a production release by promoting canary to main. Use when asked to cut, ship, or publish a release, tag a version, or push canary to production.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Release skill
What this skill tells your AI
The instructions your AI receives, as published by nrjdalal/zerostarter in .agents/skills/release/SKILL.md and read by ahel’s review.
Releases ship by promoting canary to main. The release number is decided before the merge by .github/workflows/auto-canary-into-main.yml; everything after it (changelog, tag, GitHub release) is automated by .github/workflows/auto-release.yml, and .github/workflows/cli-release.yml publishes the CLI, from the tag once the release is cut and as a canary prerelease on pushes before it; cutting a release is one deliberate merge, because main deploys to production.
How it works
- Work reaches
canarythrough squash-merged PRs (canaryis the default branch). - Every push to
canaryrunsauto-canary-into-main.yml, which opens (or reuses) a draft PRcanary -> maintitledci(release): 🚀 merge canary into main, and then moves the rootpackage.jsonversion forward to what the window has earned so far (bun run release:version --write: changelogen's bump applied to the last tag's version, kept if the tree is already ahead), committingci(version): bump to vX.Y.Zwhen it moves. It skips whenmainis missing orcanaryis not ahead of it. - Merging that PR into
mainwith a merge commit firesauto-release.yml(trigger: a PR intomainwhose head branch iscanary, merged). It then, working oncanary:- takes the version from the tree (
bun run release:versionprints the decision: the larger of the tree and what the window earned from the last tag) and runschangelogenfrom the lastv*tag for the changelog section, - regenerates
.github/assets/graph-build.svgfrom a fresh production build, - commits
ci(changelog): update changelog and bump versiondirectly tocanary, - tags
vX.Y.Zat the merge boundary and pushes branch + tag atomically, - publishes a GitHub release whose notes mirror the changelog section.
- takes the version from the tree (
The notes are derived after the merge; the version is already in the tree, so main and production carry the released number on the merge itself.
Versioning
- Default: the bump
changelogencomputes from the window's commits, applied to the last tag's version: at 0.x a feature is a patch (0.1.7 -> 0.1.8) and a breaking commit a minor; past 1.0 the usual semver. The draft-PR workflow writes it intopackage.jsonon every human push tocanary(ci(version): bump to vX.Y.Z), so previews show the upcoming number and production shows it on the release merge. A missing tag counts asv0.0.0, which is a fresh fork's first window. - To ship a chosen version (for example a minor
0.2.0): hand-setversionin the rootpackage.jsononcanarybefore cutting the release. It stays as long as it is ahead of what the window earns; a breaking window lifts a smaller pin to the minor it earns. A tree below the last tag stops both workflows loudly (package.json is at X, below the last release vY), and a version equal to the last tag is treated as untouched. - The changelog drops
ci-type commits (changelog.config.json). A release needs at least one commit that is neitherci(changelog)norci(version)and at least one-entry in the new section, orauto-releaseno-ops (No releasable changelog content).
Cutting a release
1. Confirm the content is on canary
Every PR meant for this release is squash-merged into canary. Check nothing that should ship is still open:
gh pr list --base canary --state open
2. (Optional) Pin the version
For anything bigger than the window earns, set version in the root package.json on canary first, via a normal PR, ahead of the last v* tag. Otherwise skip this: the tree already holds the number the window has earned.
3. Find the release PR
gh pr list --head canary --base main --state open
If it is missing (canary just became ahead, or the workflow has not run yet), trigger it and re-list:
gh workflow run auto-canary-into-main.yml --ref canary
4. Merge to production
Mark it ready and merge with a merge commit (never squash). This is the production action; do it only on the user's explicit go-ahead.
gh pr ready <n>
gh pr merge <n> --merge
5. Verify
gh run list --workflow=auto-release.yml -L 1 # wait for success
gh release list -L 1 # new vX.Y.Z, marked Latest
The ci(changelog): ... commit and the new tag land on canary, so pull canary to pick them up. Production deploys from main. Done when the vX.Y.Z tag exists, the GitHub release is published as latest, and production serves the new build.
Notes
- Merge method is load-bearing.
canaryPRs squash; thecanary -> mainrelease PR merges with a merge commit somainkeeps shared history withcanaryand future release diffs stay clean. Themainruleset enforces this. - The version bump is a token push. The draft-PR workflow pushes
ci(version)with the workflow token, which starts no further workflows: no loop, and the bump commit carries no checks of its own until the next human merge.main's ruleset asks for a review, not status checks, so a window with a single PR still releases; a fork that requires status checks onmainsees its release PR wait for one more merge. - Never tag or push a release by hand.
auto-releaseowns tagging and the atomic branch + tag push; a hand-cut tag collides and fails the next run. - The changelog commit lands on
canarydirectly, not through a PR (it is mechanical, generated from already-reviewed PR titles). Pullcanaryafter a release. - Backfill is automatic. If a prior run pushed the commit and tag but died before publishing, the next run recreates the missing GitHub release instead of double-bumping.
- A window of only
chore(deps)commits cannot release. changelogen hardcodes dropping non-breakingchore(deps)from the changelog (beyond whatchangelog.config.jsoncan override), so the new section has no entries andauto-releaseno-ops withNo releasable changelog content. Title dependency refreshesbuild(deps)(thegh-commitskill carries the rule), or land a releasable commit in the same window and re-run.
Signals
- GitHub stars
- 63
- Forks
- 11
- Last commit
- Sep 2026
- Hacker News mentions
- 20
Advanced
- Catalog kind
- skill
- Gateway key
release-nrjdalal- Source
- github.com/nrjdalal/zerostarter