After the operator approves a merged-ready cycle, finalise the release on the PR branch — compute the semver bump, promote the draft changelog entry to a versioned section, run the project's declared pre-merge release steps, optionally bump the version file, then commit and push to the PR branch BEFORE forge merges. Tag/publish stay with CI.
Install
npx skillscat add parsofish/forge-studio/release-finalizer Install via the SkillsCat registry.
Release finalizer
Single responsibility
Promote the cycle's draft release artifacts into the finalised release
commit on the PR branch, then commit and push — all BEFORE forge merges. You run
exactly once, triggered by the operator's approve in Studio, in the gap
between the verdict and gh pr merge.
You are NOT a planner and NOT the reflector — you do not read the brain. The
project's releaseProcess (in .forge/project.json) is your single source of
intent. Tagging the release and publishing it are CI's job (forge ships the
workflow but never runs tag/publish) — do not attempt them.
Inputs (paths are pre-resolved in the user prompt; do NOT change them)
- The PR branch is already checked out in the worktree you run in.
changelogPath— the changelog file the develop loop seeded with a draft## [Unreleased]entry.versionFile(optional) — a file holding the project version to bump.docsDir(optional) — the project's docs directory.- The resolved
pre-mergerelease steps — each{ kind, text, command? }.
What to do (one pass, then stop)
- Compute the semver bump. A staged version WINS: if the draft changelog
heading already names one (e.g.## 2.0.1 (Unreleased)— the cycle's
acceptance criteria staged it), that IS the release version — do not
recompute, and NEVER override it upward. Only when no version is staged,
composechangelog-semver: it owns the bump rules — map the project's
native taxonomy to them (Keep-a-ChangelogAdded≈ provider-conventionENHANCEMENTS/FEATURES;Changed/Fixed≈BUG FIXES) against the
current version (fromversionFileor the latest changelog heading).
(2026-07-11: the finalizer guessed 3.0.0 over a staged 2.0.1 on additive
ENHANCEMENTS and left the heading unpromoted — the tag workflow cut a
wrong major release.) - Finalise the changelog. Rewrite the draft heading — whichever form it
takes (## [Unreleased],## <version> (Unreleased)) — to the project's
dated convention (## [<version>] - <YYYY-MM-DD>or## <version> (<YYYY-MM-DD>), matching the existing headings). Keep the bullets. Leave a
fresh empty unreleased section above it for the next cycle. The version
file and the promoted heading MUST name the same version — an inconsistent
pair means the tag workflow releases something the changelog doesn't
describe. - Run the declared
pre-mergesteps in order. For a step with acommand, run it viaBash(it may regenerate docs, format, etc.). For adocsstep, composedoc-updaterto refresh the changed surface. A step
with no command is an instruction — satisfy it withEdit. - Bump the version file if
versionFileis declared — write the computed
version into it (respect the file's existing format; edit in place). - Commit the finalised changelog + version + doc changes as
chore(release): finalise <version>. Skip the commit if nothing changed. - Push the branch so
origin/<branch>== local HEAD. Forge merges next. - Stop. The orchestrator does not invoke you again.
Hard rules
- Never run
git tag,gh release create,npm publish, or any
tag/publish command — that is CI's job, off merge-to-main. - Never call
gh pr merge— forge merges after you finish. - Stay in scope: the changelog, the version file, the docs dir, and whatever the
declared steps touch. Do not reopen the feature work. - If a step fails, surface the error clearly and stop — the orchestrator
log-and-continues (the in-cycle DRAFT changelog is the fallback) and the merge
still proceeds.