Help us improve
Share bugs, ideas, or general feedback.
From claude-swe-workflows
Discovers and executes a project's release procedure with preflight checks and step-by-step confirmation. Proposes version bump from CHANGELOG and halts on first failure.
npx claudepluginhub chrisallenlane/claude-swe-workflows --plugin claude-swe-workflowsHow this skill is triggered — by the user, by Claude, or both
Slash command
/claude-swe-workflows:releaseopusThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Executes the project's release procedure with safety guards appropriate to a high-blast-radius operation. Discovers the procedure from the project itself rather than dictating one, always runs `/review-release` as preflight, and never pushes past a BLOCKER. Plans before executing; halts on first failure rather than guessing at recovery.
Runs release validation, generates changelogs from git history, bumps versions, creates annotated tags, and verifies CI on the exact SHA.
Automates releases for projects using Keep a Changelog and GitHub: bump detection, CHANGELOG promotion, merge to main, tag, and GitHub Release with a single confirmation gate.
Generates SemVer-compliant version bumps and changelog entries from git diffs. Use when cutting releases, tagging, or publishing with precise change summaries.
Share bugs, ideas, or general feedback.
Executes the project's release procedure with safety guards appropriate to a high-blast-radius operation. Discovers the procedure from the project itself rather than dictating one, always runs /review-release as preflight, and never pushes past a BLOCKER. Plans before executing; halts on first failure rather than guessing at recovery.
Scope of action: local repo and configured remotes. The skill pushes commits, pushes tags, and (when the procedure includes them) publishes to package registries. It does not attempt automatic rollback of partially-executed releases.
Reversibility note: local steps (version bump, commit, local tag) are reversible with git reset / git tag -d. The remote push is effectively irreversible once anyone has fetched. Package-registry publication is irreversible (most registries permit yank but not delete). The skill names each step's reversibility class in the plan.
High blast radius warrants high friction. Tagging and pushing a release is the kind of action that should never happen by accident. The skill is generous with confirmation prompts and pessimistic about partial-failure recovery. Auto-execution is never the default.
Composition, not duplication. Preflight checking is /review-release's job. This skill always invokes it and fail-stops on red. It does not re-implement the checklist or offer to skip it.
Discover the procedure, don't invent it. Release procedure is project-specific — make release, npm publish, cargo publish, gh release create, a custom CI workflow, or some combination. The skill searches the conventional surfaces before falling back to asking the user. If asked, it offers durable capture so the next release is fully automated.
Halt on first failure. Release sequences are not atomic. A failure halfway through (e.g., tag pushed but npm publish failed) leaves the project in a partial state. The skill stops at the first failure and surfaces the partial state for human decision rather than pushing through or guessing at rollback.
┌────────────────────────────────────────────────────────┐
│ RELEASE │
├────────────────────────────────────────────────────────┤
│ 1. Detect repo context │
│ 2. Discover release procedure │
│ 3. If procedure not found: offer durable capture │
│ 4. Determine target version (propose from CHANGELOG) │
│ 5. Idempotence check (scan for partial prior run) │
│ 6. Run /review-release as preflight (fail-stop) │
│ 7. Construct release plan (commands + reversibility) │
│ 8. Present plan + confirm │
│ 9. Execute step-by-step (one pause at local→remote │
│ boundary; halt on first failure) │
│ 10. Final summary │
└────────────────────────────────────────────────────────┘
Run all of the following; abort cleanly on any failure:
git rev-parse --is-inside-work-tree. Abort if not.git symbolic-ref refs/remotes/origin/HEAD, then check for main, then master. Ask the user if none detected.git branch --show-current.git status --porcelain. Abort if dirty with the suggestion: "Commit or stash before releasing." Releases from a dirty tree are unsafe.git fetch, then check git rev-list --count HEAD..@{u}. If behind, abort with the suggestion to pull. If ahead, note this (it's expected if the release commit is being prepared locally, but flag it).Search the following surfaces in order. Stop at the first hit, but record every hit (procedure may span multiple surfaces — e.g., Makefile target + RELEASING.md narrative):
release, publish, or tag target. Read the recipe.release, publish, prepublish*, version*, postversion..github/workflows/release.yml or similar CI release config.git log --tags --simplify-by-decoration --pretty="format:%d %s" to infer pattern from prior releases (tag format like v1.2.3 vs 1.2.3, accompanying commit message convention like chore: release v1.2.3).Record what was found and where. Prefer executable sources over prose — a Makefile target is the authoritative procedure if it exists.
If step 2 found no procedure (no executable target, no prose doc, no CI workflow, no git-tag pattern beyond bare history):
If the user opts to record, write the file/target now and commit it as a separate commit before proceeding with the release (chore: document release procedure). The recording commit is part of pre-release hygiene, not part of the release itself.
If the user declines to describe the procedure, abort with the suggestion that they invoke the steps manually for this release and re-run /release next time once a procedure is documented.
CHANGELOG.md (or equivalent — CHANGES, HISTORY.md, etc.) and locate the unreleased section.git log <last-tag>..HEAD --oneline) for breaking-change markers (BREAKING CHANGE:, feat!:, fix!:, etc.) and conventional commit types (feat:, fix:, chore:).feat: commits but no breaking changes.vX.Y.Z but the user typed 1.3.0, normalize and confirm.If no CHANGELOG exists, skip the proposal step and ask the user directly for the target version.
Scan for evidence of a partial prior run at the target version:
git tag --list <target-tag> — non-empty means a local tag already exists.git ls-remote --tags origin <target-tag> — non-empty means the tag was already pushed.gh is available). gh release view <target-tag> — success means a GitHub release exists.npm, npm view <pkg>@<version>. For cargo, the publish step itself will fail with a clear error.If any artifact is found, surface it and present three options:
/review-release)Announce the action: "Running /review-release as preflight."
Invoke /review-release with the target version. Wait for completion.
Fail-stop on red. If /review-release reports unresolved BLOCKERs, abort the release workflow:
"Preflight failed with N BLOCKERs. Resolve them (or run
/implement//bug-fixto address) and re-run/release."
Do not present a "force release" option. The no-escape-hatches rule applies.
Carry warnings forward. If only WARNINGs remain after preflight, surface them in the plan presentation (step 8) so the user has the full picture when deciding whether to proceed.
If /review-release itself made changes (e.g., auto-removed debug artifacts) and the user committed them, the working-tree state has changed since step 1. Re-verify cleanness and up-to-date status before proceeding.
Build an ordered command list from the procedure discovered in step 2 (or recorded in step 3) and the target version from step 4. For each step, record:
git checkout -- <file> undoes.git reset / git tag -d undoes.Typical plan (customized to the discovered procedure):
Update version in every manifest file that carries a version field — reversible. Do not assume a single canonical manifest; multiple manifests routinely co-exist and must stay in lockstep. Common combinations:
package.json (plus package-lock.json after npm install).Cargo.toml (plus Cargo.lock after cargo build).pyproject.toml (plus setup.py / setup.cfg / __version__ constants)..claude-plugin/plugin.json and .claude-plugin/marketplace.json — the latter is the distribution artifact; the two must agree.VERSION = "X.Y.Z"), badges in README, and similar.Scan for files containing the current version string (git grep -F "<old-version>") to catch occurrences the conventional list misses. Each hit is a potential bump site; include in the plan or explicitly justify excluding.
Update CHANGELOG.md unreleased section with version and date — reversible
Commit version bump (chore: release vX.Y.Z) — reversible-locally
Create annotated tag (git tag -a vX.Y.Z -m "Release vX.Y.Z") — reversible-locally
Push commit to origin — irreversible-on-publish
Push tag to origin — irreversible-on-publish
Publish to package registry (npm publish, cargo publish, etc.) — irreversible-on-publish
Create GitHub release (gh release create vX.Y.Z --generate-notes) — partially-reversible
If step 5's idempotence check found existing artifacts and the user chose "resume," mark already-done steps as [skip] rather than removing them — visible context for the user.
Present the full plan in a single block:
## Release Plan: vX.Y.Z
Branch: main (clean, up-to-date with origin)
Last tag: v1.2.3
Preflight: /review-release passed (2 warnings — see below)
Steps:
1. [reversible] Update package.json version → 1.3.0
2. [reversible] Update CHANGELOG.md (set date to 2026-05-18)
3. [reversible-locally] git commit -m "chore: release v1.3.0"
4. [reversible-locally] git tag -a v1.3.0 -m "Release v1.3.0"
───── local → remote boundary (final confirmation prompt before this line) ─────
5. [irreversible-on-publish] git push origin main
6. [irreversible-on-publish] git push origin v1.3.0
7. [irreversible-on-publish] npm publish
8. [partially-reversible] gh release create v1.3.0 --generate-notes
Preflight warnings (carried over from /review-release):
- CHANGELOG: stale entries from v1.2.0 not removed
- DEPENDENCY: foo-lib pinned to ^2.0.0 (security advisory CVE-2026-1234)
Proceed?
Use AskUserQuestion. Options:
Do not offer "edit the plan inline." If the user wants different steps, they update the procedure source (Makefile, RELEASING.md) and re-run.
For each step:
One mid-execution pause: the local→remote boundary. After the last reversible-locally step and before the first irreversible-on-publish step, pause and ask:
"Local steps complete (version bumped, committed, tagged). About to push to remote — final confirmation?"
This is the only intra-execution prompt. If the user proceeds, execute the remaining steps without further prompts. If the user aborts, report the local-only state and exit cleanly — the user can git reset --hard HEAD~1 && git tag -d vX.Y.Z to fully undo, or push manually later.
On success:
## Release Complete: vX.Y.Z
### Executed (in order)
1. Bumped version in package.json (1.2.3 → 1.3.0)
2. Updated CHANGELOG.md (added date 2026-05-18 to unreleased section)
3. Committed: "chore: release v1.3.0" (sha 7a8b9c0)
4. Tagged v1.3.0
5. Pushed main to origin
6. Pushed tag v1.3.0 to origin
7. Published to npm
8. Created GitHub release v1.3.0
### Links
- Tag: https://github.com/<org>/<repo>/releases/tag/v1.3.0
- npm: https://www.npmjs.com/package/<pkg>/v/1.3.0
### Carry-over warnings (from preflight)
- CHANGELOG: stale entries from v1.2.0 — consider addressing post-release
- DEPENDENCY: foo-lib security advisory — consider an immediate patch release
On halt mid-execution:
## Release Halted: vX.Y.Z
### Completed
1. Bumped version in package.json
2. Updated CHANGELOG.md
3. Committed: "chore: release v1.3.0" (sha 7a8b9c0) — local only
4. Tagged v1.3.0 — local only
### Failed
Step 5: git push origin main
Error: permission denied (publickey)
### Current state
- Local repo has the release commit and tag.
- Neither commit nor tag is on origin.
- No package-registry publication.
- No GitHub release.
### Recovery options
- Fix push authentication and re-run /release. The idempotence check will
detect the local tag and offer to resume from step 5.
- Or, to fully abandon this attempt:
git tag -d v1.3.0
git reset --hard HEAD~1
The skill must never:
/review-release preflight./review-release BLOCKER.git push --force or git push --force-with-lease for any release operation.These invariants are categorical. The skill does not offer flags to override them.
Abort the workflow:
/review-release reports unresolved BLOCKERs.Do NOT abort for:
/review-release reports WARNINGs only (carry them forward into the plan)./review-release as preflight (step 6). No shortcut, no skip./tidy-docs if /review-release flagged stale documentation as a warning. Does not invoke automatically./bug-fix or /implement if the user wants to address /review-release BLOCKERs before re-running./release is a leaf skill, not an orchestrator: it composes one sub-skill linearly. It does not iterate over multiple skills or make dynamic decisions across them.
> /release
Detected: main branch = "master", current = "master", working tree clean,
up-to-date with origin.
Discovering release procedure...
✓ Makefile target `release` found
✓ Tag convention from history: vX.Y.Z
✓ Conventional commit pattern: "chore: pre-release cleanup for vX.Y.Z"
Determining target version...
Last tag: v10.0.0
Commits since last tag: 12 (1 feat:, 3 fix:, 8 chore:/docs:)
Proposing: v10.1.0 (minor bump — 1 feat: commit)
Confirm version?
> v10.1.0
Idempotence check... no prior artifacts for v10.1.0. Clean slate.
Running /review-release as preflight...
[/review-release output streams]
Preflight result: PROCEED WITH CAUTION — 2 warnings, 0 blockers.
## Release Plan: v10.1.0
Branch: master (clean, up-to-date with origin)
Last tag: v10.0.0
Preflight: /review-release passed (2 warnings — see below)
Steps:
1. [reversible] Update version in .claude-plugin/plugin.json → 10.1.0
2. [reversible] Update version in .claude-plugin/marketplace.json → 10.1.0
3. [reversible] Update CHANGELOG.md (set date to 2026-05-18)
4. [reversible-locally] git commit -m "chore: release v10.1.0"
5. [reversible-locally] git tag -a v10.1.0 -m "Release v10.1.0"
───── local → remote boundary ─────
6. [irreversible-on-publish] git push origin master
7. [irreversible-on-publish] git push origin v10.1.0
8. [partially-reversible] gh release create v10.1.0 --generate-notes
Preflight warnings:
- CHANGELOG: minor formatting inconsistency in v10.0.0 entry (pre-existing)
- DOCS: README.md release count may be outdated
Proceed?
> Proceed
Step 1 of 8: Updating .claude-plugin/plugin.json version → 10.1.0... done.
Step 2 of 8: Updating .claude-plugin/marketplace.json version → 10.1.0... done.
Step 3 of 8: Updating CHANGELOG.md date → 2026-05-18... done.
Step 4 of 8: Committing... done (sha 4d5e6f7).
Step 5 of 8: Tagging v10.1.0... done.
Local steps complete (version bumped in both manifests, committed, tagged).
About to push to remote — final confirmation?
> Proceed
Step 6 of 8: git push origin master... done.
Step 7 of 8: git push origin v10.1.0... done.
Step 8 of 8: gh release create v10.1.0 --generate-notes... done.
## Release Complete: v10.1.0
### Executed
1. Bumped version to 10.1.0 in .claude-plugin/plugin.json
2. Bumped version to 10.1.0 in .claude-plugin/marketplace.json
3. Updated CHANGELOG.md
4. Committed: "chore: release v10.1.0" (sha 4d5e6f7)
5. Tagged v10.1.0
6. Pushed master
7. Pushed tag v10.1.0
8. Created GitHub release v10.1.0
### Links
- Tag: https://github.com/chrisallenlane/claude-swe-workflows/releases/tag/v10.1.0
### Carry-over warnings
- CHANGELOG: minor formatting in v10.0.0 entry (pre-existing)
- DOCS: README.md release count may need update — consider /tidy-docs