Cut Stable Release
Purpose
Run the local git-side workflow for a stable coco release. This skill prepares
the stable release commit and tag only; npm publish happens later when a GitHub
Release is created for the tag.
Use this for tags like v2.0.0. Use $cut-rc-release for RC tags like
v2.0.0-rc.0.
Safety
- Work from a clean dedicated release worktree. If
git status -sb shows local
changes, stop.
- Do not run
changeset publish and do not create a GitHub Release from this
skill.
- Stable release tags must not contain
.changeset/pre.json; the repo
validator enforces this.
- For stable-from-RC releases, preserve the selected RC as the source cutoff.
The stable commit may change only Changesets metadata, package manifests,
and package changelogs.
- Keep
master work that landed after the RC out of the stable tag. Back-merge
the stable release metadata into master after the release cut.
- Treat
dry run, dry-run, --dry-run, preview, or rehearsal as a
request to create the local commit and tag but skip pushing.
- Networked git commands usually need escalation.
Choose The Path
- Direct stable release: start from
master with pending changesets and no RC
cycle.
- Final stable after RCs: start from the existing
release/X.Y.Z-rc branch,
require its HEAD to be the selected RC tag, then create one stable metadata
commit directly on that cutoff. master may have advanced independently.
Direct Stable Workflow
Confirm the worktree is clean and on master:
git status -sb
git branch --show-current
Sync master:
git fetch origin master --tags
git pull --ff-only origin master
Confirm there are pending changesets:
find .changeset -maxdepth 1 -type f -name '*.md' ! -name 'README.md' | sort
If this is empty, stop rather than creating a no-op release.
Generate stable versions and changelogs:
bunx changeset version
Continue at "Commit And Tag".
Stable From RC Workflow
Confirm the worktree is clean and on the RC branch:
git status -sb
git branch --show-current
The branch should be release/X.Y.Z-rc.
Sync the branch and tags:
RELEASE_BRANCH="$(git branch --show-current)"
git fetch origin "$RELEASE_BRANCH" --tags
git pull --ff-only origin "$RELEASE_BRANCH"
Select the RC cutoff at branch HEAD:
RC_CUTOFF_TAG="$(git tag --points-at HEAD --list 'v*-rc.*' --sort=-v:refname | head -n 1)"
test -n "$RC_CUTOFF_TAG"
RC_CUTOFF_COMMIT="$(git rev-parse "$RC_CUTOFF_TAG^{commit}")"
test "$(git rev-parse HEAD)" = "$RC_CUTOFF_COMMIT"
Stop if the branch has commits after the selected RC. Runtime or repository
changes after an RC require a new RC; they do not belong in the stable
metadata commit.
Confirm .changeset/pre.json is present, then exit prerelease mode and
generate stable versions:
test -f .changeset/pre.json
bunx changeset pre exit
bunx changeset version
Continue at "Commit And Tag" with RELEASE_BRANCH, RC_CUTOFF_TAG, and
RC_CUTOFF_COMMIT available in the shell.
Commit And Tag
Derive release metadata from the versioned files:
eval "$(.agents/skills/cut-stable-release/scripts/derive-stable-release-metadata.sh)"
printf '%s\n' "$NEW_PACKAGE_VERSION" "$NEW_RELEASE_TAG" "$COMMIT_MESSAGE"
For stable-from-RC, confirm that the stable tag matches the RC line:
[[ "$RC_CUTOFF_TAG" == "${NEW_RELEASE_TAG}-rc."* ]]
Validate the committed release state and build:
env RELEASE_TAG="$NEW_RELEASE_TAG" RELEASE_PRERELEASE=false PRERELEASE_TAG=rc \
bun scripts/check-release.ts
bun install --frozen-lockfile
bun run build
Review the diff before committing:
git diff --name-only
git diff --stat
if [[ -n "${RC_CUTOFF_COMMIT:-}" ]]; then
.agents/skills/cut-stable-release/scripts/check-stable-cutoff.sh \
"$RC_CUTOFF_COMMIT"
fi
Expect only .changeset/, packages/*/package.json, and
packages/*/CHANGELOG.md release-file changes. Stop if unrelated files
changed.
Commit and tag:
git add .changeset packages/*/package.json packages/*/CHANGELOG.md
git commit -m "$COMMIT_MESSAGE"
if [[ -n "${RC_CUTOFF_COMMIT:-}" ]]; then
.agents/skills/cut-stable-release/scripts/check-stable-cutoff.sh \
"$RC_CUTOFF_COMMIT" HEAD
fi
git tag "$NEW_RELEASE_TAG"
Push according to the selected path.
Direct stable normal mode:
git push --atomic origin master "refs/tags/$NEW_RELEASE_TAG"
Stable from RC normal mode:
git push --atomic origin "$RELEASE_BRANCH" "refs/tags/$NEW_RELEASE_TAG"
Dry-run mode:
git status -sb
git log --decorate --oneline -1
git show --stat --decorate --no-patch HEAD
git tag --list "$NEW_RELEASE_TAG"
Report the package version, tag, commit SHA, and whether this was direct
stable or stable-from-RC. For stable-from-RC, also report the cutoff tag,
cutoff commit, release branch, that master was intentionally unchanged,
whether the release branch plus tag were pushed or left local, and that the
normal back-merge into master remains a separate follow-up.
Back-Merge After A Stable RC Release
The stable tag remains on the direct child of the selected RC cutoff. After the
release branch and tag are pushed, merge the stable release commit back into
current master through the repository's normal review or merge process. A
normal merge commit is expected because master can contain post-cutoff work.
This back-merge records stable versions and consumed changesets on master; it
does not change the stable tag or add post-cutoff work to the release.
Treat the back-merge as a separate operation that requires its own user
authorization. Do not perform it during a dry run.
Notes
- If validation fails, fix the release files before tagging. Do not bypass
scripts/check-release.ts.
- For stable-from-RC, stop if the stable candidate is not a direct child of the
selected RC or changes files outside the permitted release metadata paths.
- If runtime source must change, cut another RC before stable finalization.
1---2name: cut-stable-release3description: Cut a coco stable release from `master` or finalize a selected RC cutoff from an existing `release/X.Y.Z-rc` branch while `master` continues independently. Use when the user asks to create a stable `vX.Y.Z` release, preserve an RC's runtime source, finalize Changesets prerelease metadata, validate and build the release, commit and tag it, and push the source branch plus tag. Supports dry-run, preview, and rehearsal requests by stopping before push.4---56# Cut Stable Release78## Purpose910Run the local git-side workflow for a stable coco release. This skill prepares11the stable release commit and tag only; npm publish happens later when a GitHub12Release is created for the tag.1314Use this for tags like `v2.0.0`. Use `$cut-rc-release` for RC tags like15`v2.0.0-rc.0`.1617## Safety1819- Work from a clean dedicated release worktree. If `git status -sb` shows local20 changes, stop.21- Do not run `changeset publish` and do not create a GitHub Release from this22 skill.23- Stable release tags must not contain `.changeset/pre.json`; the repo24 validator enforces this.25- For stable-from-RC releases, preserve the selected RC as the source cutoff.26 The stable commit may change only Changesets metadata, package manifests,27 and package changelogs.28- Keep `master` work that landed after the RC out of the stable tag. Back-merge29 the stable release metadata into `master` after the release cut.30- Treat `dry run`, `dry-run`, `--dry-run`, `preview`, or `rehearsal` as a31 request to create the local commit and tag but skip pushing.32- Networked git commands usually need escalation.3334## Choose The Path3536- Direct stable release: start from `master` with pending changesets and no RC37 cycle.38- Final stable after RCs: start from the existing `release/X.Y.Z-rc` branch,39 require its HEAD to be the selected RC tag, then create one stable metadata40 commit directly on that cutoff. `master` may have advanced independently.4142## Direct Stable Workflow43441. Confirm the worktree is clean and on `master`:4546 ```bash47 git status -sb48 git branch --show-current49 ```50512. Sync `master`:5253 ```bash54 git fetch origin master --tags55 git pull --ff-only origin master56 ```57583. Confirm there are pending changesets:5960 ```bash61 find .changeset -maxdepth 1 -type f -name '*.md' ! -name 'README.md' | sort62 ```6364 If this is empty, stop rather than creating a no-op release.65664. Generate stable versions and changelogs:6768 ```bash69 bunx changeset version70 ```71725. Continue at "Commit And Tag".7374## Stable From RC Workflow75761. Confirm the worktree is clean and on the RC branch:7778 ```bash79 git status -sb80 git branch --show-current81 ```8283 The branch should be `release/X.Y.Z-rc`.84852. Sync the branch and tags:8687 ```bash88 RELEASE_BRANCH="$(git branch --show-current)"89 git fetch origin "$RELEASE_BRANCH" --tags90 git pull --ff-only origin "$RELEASE_BRANCH"91 ```92933. Select the RC cutoff at branch HEAD:9495 ```bash96 RC_CUTOFF_TAG="$(git tag --points-at HEAD --list 'v*-rc.*' --sort=-v:refname | head -n 1)"97 test -n "$RC_CUTOFF_TAG"98 RC_CUTOFF_COMMIT="$(git rev-parse "$RC_CUTOFF_TAG^{commit}")"99 test "$(git rev-parse HEAD)" = "$RC_CUTOFF_COMMIT"100 ```101102 Stop if the branch has commits after the selected RC. Runtime or repository103 changes after an RC require a new RC; they do not belong in the stable104 metadata commit.1051064. Confirm `.changeset/pre.json` is present, then exit prerelease mode and107 generate stable versions:108109 ```bash110 test -f .changeset/pre.json111 bunx changeset pre exit112 bunx changeset version113 ```1141155. Continue at "Commit And Tag" with `RELEASE_BRANCH`, `RC_CUTOFF_TAG`, and116 `RC_CUTOFF_COMMIT` available in the shell.117118## Commit And Tag1191201. Derive release metadata from the versioned files:121122 ```bash123 eval "$(.agents/skills/cut-stable-release/scripts/derive-stable-release-metadata.sh)"124 printf '%s\n' "$NEW_PACKAGE_VERSION" "$NEW_RELEASE_TAG" "$COMMIT_MESSAGE"125 ```126127 For stable-from-RC, confirm that the stable tag matches the RC line:128129 ```bash130 [[ "$RC_CUTOFF_TAG" == "${NEW_RELEASE_TAG}-rc."* ]]131 ```1321332. Validate the committed release state and build:134135 ```bash136 env RELEASE_TAG="$NEW_RELEASE_TAG" RELEASE_PRERELEASE=false PRERELEASE_TAG=rc \137 bun scripts/check-release.ts138 bun install --frozen-lockfile139 bun run build140 ```1411423. Review the diff before committing:143144 ```bash145 git diff --name-only146 git diff --stat147 if [[ -n "${RC_CUTOFF_COMMIT:-}" ]]; then148 .agents/skills/cut-stable-release/scripts/check-stable-cutoff.sh \149 "$RC_CUTOFF_COMMIT"150 fi151 ```152153 Expect only `.changeset/`, `packages/*/package.json`, and154 `packages/*/CHANGELOG.md` release-file changes. Stop if unrelated files155 changed.1561574. Commit and tag:158159 ```bash160 git add .changeset packages/*/package.json packages/*/CHANGELOG.md161 git commit -m "$COMMIT_MESSAGE"162 if [[ -n "${RC_CUTOFF_COMMIT:-}" ]]; then163 .agents/skills/cut-stable-release/scripts/check-stable-cutoff.sh \164 "$RC_CUTOFF_COMMIT" HEAD165 fi166 git tag "$NEW_RELEASE_TAG"167 ```1681695. Push according to the selected path.170171 Direct stable normal mode:172173 ```bash174 git push --atomic origin master "refs/tags/$NEW_RELEASE_TAG"175 ```176177 Stable from RC normal mode:178179 ```bash180 git push --atomic origin "$RELEASE_BRANCH" "refs/tags/$NEW_RELEASE_TAG"181 ```182183 Dry-run mode:184185 ```bash186 git status -sb187 git log --decorate --oneline -1188 git show --stat --decorate --no-patch HEAD189 git tag --list "$NEW_RELEASE_TAG"190 ```1911926. Report the package version, tag, commit SHA, and whether this was direct193 stable or stable-from-RC. For stable-from-RC, also report the cutoff tag,194 cutoff commit, release branch, that `master` was intentionally unchanged,195 whether the release branch plus tag were pushed or left local, and that the196 normal back-merge into `master` remains a separate follow-up.197198## Back-Merge After A Stable RC Release199200The stable tag remains on the direct child of the selected RC cutoff. After the201release branch and tag are pushed, merge the stable release commit back into202current `master` through the repository's normal review or merge process. A203normal merge commit is expected because `master` can contain post-cutoff work.204This back-merge records stable versions and consumed changesets on `master`; it205does not change the stable tag or add post-cutoff work to the release.206207Treat the back-merge as a separate operation that requires its own user208authorization. Do not perform it during a dry run.209210## Notes211212- If validation fails, fix the release files before tagging. Do not bypass213 `scripts/check-release.ts`.214- For stable-from-RC, stop if the stable candidate is not a direct child of the215 selected RC or changes files outside the permitted release metadata paths.216- If runtime source must change, cut another RC before stable finalization.