release-commit
Skill10 starsChanged 30 days agoApache-2.0View on GitHub
Use when a branch is promoted toward a release — dev/integration to stage/staging, stage to main/production — or a release candidate is cut or finalized, including bare asks like "stage로 올려줘", "릴리즈 해", "main 승격", "promote to main", "cut an rc"; and before answering how this repo's promotions work: the bump level and its trailer, a re-promotion, a promotion that cut no release candidate, the back-merge. Generic git-flow habit cuts no release candidate, and nothing reports it. Not for installing release CI (/flow-init).
- Commits and pushes
In this repository21 other files it gives its agents.
- .claude/CLAUDE.mdCLAUDE.md
- commitSkill
- design-apiSkill
- design-architectureSkill
- design-erdSkill
- design-sdsSkill
- design-srsSkill
- design-tableSkill
- doc-syncSkill
- flow-initSkill
- flowSkill
- flow-uninstallSkill
- harness-authoringSkill
- harness-deploymentsSkill
- harness-initSkill
- harness-insightSkill
- integrationSkill
- performanceSkill
- playwright-scaffoldSkill
- prose-reviewSkill
- wiki-initSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 2 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 132
No pending rc skips the back-merge.
- Very specific: line 154
3. Ask the user — where Step 0 answered
count >= 1: Ask the user (structured choice), every option labelled with the version the … - Very specific: line 169
When the current version is 0.x and the choice is major, warn that it jumps straight to 1.0.0.
- Distinctive: line 233
Wait for the release run on that push, then read the release state again:
- Very specific: line 264
Stop, and re-promote staging through Step 1 choosing patch or higher.
- Very specific: line 360
Merging a stale local staging ref: instead of the fetched origin/<staging> — finalize sees no pending rc, falls back to plain compute, and …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Release Commit — integration → staging → production
One promotion end to end: the gates it records, the commit that carries the bump level, the merge the release CI needs, and the back-merge that closes the cycle.
Source of truth: merge-strategy.md owns Merge
strategy; commit-discipline.md owns the message format;
risk-tiers.md owns the gate glossary, and the SessionStart hook
injects it, so that one is already in context. PR workflow, Merge commit messages and
Back-merge after release sit in promotion.md, which nothing
injects — read it and commit-discipline.md before running a promotion. This skill is the
procedure that applies them and does not restate them. Where a
rule file and this skill disagree, follow the rule file and tell the user this skill has
drifted. flow-tiers.yaml carries the per-tier
gate list the commit hook enforces — read it, nothing injects it.
Branch names come from flow-config.branches (integration / staging / production).
Interaction. Wherever this skill asks the user something, use the host's blocking question tool already in your tool list, matched by capability rather than by a host-specific name; if it is listed but not loaded, load it first with the host's tool-discovery primitive; only when no such tool is listed, or a question call errors, offer numbered options in chat and end your turn to wait for the reply — never answer the question yourself or skip it.
Input
- $ARGUMENTS —
staging(integration → staging) orrelease(staging → production). With neither, ask the user which promotion this is. Ahotfix/*branch/flowhands over takes neither: it runsreferences/hotfix.md.
Three more procedures sit in references/, each read only when it applies:
changelog.md at Step 2 item 5,
pr-mode.md when flow-config.merge_workflow.pull_request names
promotion or daily, and wiki-gate.md when the wiki gate
blocks a promotion commit.
Which gates need a marker
A promotion is gated at the commit on the target branch — the branch drives it, so no tier
marker is written. precommit, security-scan, wiki and doc-style are runtime gates the
commit hook runs itself: no marker to write, no skill behind them. The gates needing a recorded
marker are review and bump (Staging), security alone (Release) — Release runs no code
review at all, for the reason promotion.md gives under
Release.
Step 0 — Read the host's release model
The bump level reaches CI one of two ways, and the wrong assumption cuts no release candidate at all. Ask the rendered workflow, not a template list:
grep -c Release-Level .github/workflows/release.yml
grep -c next-version .github/workflows/release.ymlgrep -c exits 1 on zero matches. That non-zero exit is an answer — "no trailer", "no
shared next-version block" — not a failure; do not report it as an error.
- count >= 1 — the level can be forced. Every template
/flow-initrenders lands here — python-semantic-release, Node semantic-release, jreleaser, gitversion, cargo-release. The staging commit carriesRelease-Level: <choice>and CI applies it. - count >= 1,
next-versioncount 0 — a legacy render, older than the shared next-version block, that/flow-initnever overwrites:major | minor | patchalone, no finalize guard. Warn once, follow items 3 and 7's legacy lines, and tell the user to delete.github/workflows/release.ymland re-run/flow-init. - count 0 — a hand-written workflow that reads no trailer, so the level cannot be forced and the bump is whatever that workflow derives. Say so and skip the level question.
- no such file — no release CI is installed. Stop and tell the user to run
/flow-init.
Cross-check the host commit guide (flow-config.commit_guide, ships as
docs/operations/commit-versioning-guide.md): where it disagrees with the grep, the
workflow wins — report the stale guide in one line. No guide is a normal answer.
Step 1 — Staging (integration → staging)
Read the release state first — the code the release CI runs, over the same tag list:
git fetch --tags origin
python3 .claude/harness-tier/scripts/bump_version.py statepending: names the pending rc: the highest vX.Y.Z-rc.N whose base X.Y.Z has no
stable tag and sits above the highest stable tag. pending: none, with
continue: fails — … no pending rc to continue, is the answer "no pending rc", not an error.
The four level lines are the versions item 3 labels its options with. invalid choice: 'state'
means the host copy predates it: tell the user to re-run /flow-init. Keep the pending:
line: item 8 compares against it. Never read the pending rc off git describe: it follows one
branch's ancestry, and a staging whose release back-merge refused the fast-forward still sits
on the rc that release shipped.
A pending rc makes this a re-promotion: back-merge staging first. Integration takes staging's rc version commit before the review, so the review reads the pair after it. Fast-forward when integration is strictly behind:
git switch <integration> && git merge --ff-only origin/<integration>
git merge --ff-only origin/<staging>A refused fast-forward takes a merge commit instead — the row
merge-strategy.md gives this back-merge:
git merge --no-ff origin/<staging>Either way, push it before the review reads origin/<integration>:
git push origin <integration>No pending rc skips the back-merge.
1. Regression review. Dispatch subagent (general) — an independent agent (separate context,
runs its own shell commands), judged against flow-config.review_checklist plus the callers of
every changed public symbol. A promotion starts on a clean working tree, so the file list
comes from this promotion's own pair rather than from the workspace:
git fetch origin
git diff --name-only "origin/<staging>..origin/<integration>"Freshly fetched origin/ refs — a stale local ref shrinks the reviewed set in silence. Two
dots, not three: a commit on staging alone still surfaces, inverted, as a deletion. Staging
is the only promotion that reviews at all.
2. Compute a recommended level from the commit types over the promoted range
(commit-discipline.md Commit type → version impact;
where the tool derives its own bump, semantic-release version --print shows its pick, best
effort), under
the host guide's 0.x policy: major_on_zero=false, 1.0.0 only by an explicit decision.
3. Ask the user — where Step 0 answered count >= 1. Ask the user (structured choice),
every option labelled with the version the release-state block printed for it. The
recommendation never stands in for the answer: always ask.
- No pending rc — auto / patch / minor / major, defaulting to the recommendation.
autoleaves the level to the release tool: label it "commit-derived", with the level item 2 read off when it read one. Where the workflow setsAUTO_LEVEL: patch(the gitversion and jreleaser templates — those tools derive nothing),autoispatch: label it with that version. - Pending rc — continue / patch / minor / major,
continuefirst and recommended: it cuts the next rc of the same base,1.1.0-rc.2→1.1.0-rc.3. A forced level bumps the base again and skipsX.Y.Zas a stable release (patch→1.1.1-rc.1); say so in each forced option's description.autois not offered:continuenames the outcome rather than leaving it to the tool.
When the current version is 0.x and the choice is major, warn that it jumps straight to
1.0.0.
On a legacy host (Step 0) a first promotion offers patch / minor / major alone, and a re-promotion asks nothing: that workflow's no-trailer path continues the rc series, while a forced level there bumps the base again.
On a count 0 host, skip it: no workflow reads the trailer, so the answer would change
nothing and the bump is whatever the commit types derive. Item 5 still records bump.done —
the gate is fail-closed on that file, and the recommendation is what the promotion reports.
4. Warn if the release token cannot push (best effort, never blocks). With gh or a token
available:
bash .claude/harness-tier/scripts/check-token-write.shExit 10 → warn, with the Settings/PAT how-to. Exit 20, or no tool at all → skip silently.
5. Record the markers, one command per line — a brace form matches neither the exact
allowed-tools rules nor a reader's eye:
mkdir -p .claude/harness-tier/.flow
touch .claude/harness-tier/.flow/review.done
touch .claude/harness-tier/.flow/bump.done6. Merge integration into staging, leaving the commit unwritten. Start on an up-to-date staging — a re-promotion's back-merge left HEAD on integration:
git switch <staging> && git merge --ff-only origin/<staging>
git merge --no-ff --no-commit origin/<integration>7. Write that pending merge — invoke skill commit, passing the chosen level in the
arguments where item 3 asked for one. That is the only channel it has: bump.done is an
empty marker and nothing on disk carries the level. The commit skill appends
Release-Level: <choice> — every choice written out, auto included: an absent trailer runs
as auto too, but only a written one records that the level was asked. It gives the commit
the subject a promotion merge takes — Merge <integration>: <headline>, capital Merge, no
Conventional type (promotion.md Merge commit messages).
CI reads the trailer off HEAD: auto hands the bump to the release tool, any other choice
becomes the version the release-state block printed for it. A value outside
auto | continue | patch | minor | major, an empty one, two different ones, or continue
with no pending rc fails the release run — nothing falls back to a derived bump.
On a count 0 host, and on a legacy re-promotion, pass no level, and the commit takes no trailer: a trailer written where nothing reads it is a promise the release does not keep. Same subject form, same order.
Merge before commit, never after. CI reads git log -1 alone, so the trailer has to land
on HEAD: written first and merged after, it sits one commit back, and the run reads auto
with nothing to say it did.
8. Push, then confirm the rc was cut — on every host, count 0 included:
git push origin <staging>Wait for the release run on that push, then read the release state again:
git fetch --tags origin
python3 .claude/harness-tier/scripts/bump_version.py stateThe rc was cut when pending: names v plus the version the chosen option was labelled
with — the continue line's on a legacy re-promotion, and for auto or a count 0 host any rc
other than the first read's pending:. The same line, none or a failed run: no rc was cut
and the promotion is not finished — report it and stop. Under PR mode, check after the merge
(pr-mode.md).
A run that stops at the rc goes to End state from here — the ordinary case. bump.done
outlives it otherwise: the PostToolUse hook deletes the review and doc-sync markers only,
and /flow Phase 4 leaves a promotion's markers to this skill.
Step 2 — Release (staging → production)
1. Fetch first, and confirm staging carries a pending rc.
git fetch --tags origin
python3 .claude/harness-tier/scripts/bump_version.py stateorigin/<staging> must sit at the X.Y.Z-rc.N the rc CI pushed — merged before it lands,
finalize has no rc to strip and falls back to plain compute, losing the forced level — and
pending: must name that rc. none or another rc means a hotfix shipped X.Y.Z or a higher
base first, and finalize fails the run before writing anything:
vX.Y.Z already exists — a hotfix shipped this base, or vX.Y.Z is below the latest release.
Stop, and re-promote staging through Step 1 choosing patch or higher. A release run failing
with either error means the same thing.
2. Security review — /security-review over this promotion. It is the only review layer
here; do not add a code-review pass back.
3. Record the marker:
mkdir -p .claude/harness-tier/.flow
touch .claude/harness-tier/.flow/security.doneOne marker, not two. A review.done sitting here is Staging's, left behind by a run that
stopped at the rc — clear it (the End state's rm -f covers it) rather than reading it as
evidence for anything on this tier.
4. Merge the freshly fetched staging into production, leaving the commit unwritten, starting on an up-to-date production:
git switch <production> && git merge --ff-only origin/<production>
git merge --no-ff --no-commit origin/<staging>5. Write the stable changelog section into the open merge —
references/changelog.md: a deduplicated summary of every rc this
release folds in, approved by the user, which the release CI publishes as the release notes.
6. Write that pending merge — invoke skill commit; no level here. Finalize is
deterministic: it strips the rc token off the version staging already carries. Same subject
form as Staging (Merge <staging>: <headline>), and the same fixed order, for the same
reason: HEAD is the only commit CI reads. Then push — this is what fires finalize:
git push origin <production>Deploy is project-specific and not gated; the production-branch commit is the gate.
End state
Both promotions end here, a run that stopped at the rc included, and so does a hotfix. The back-merge follows a release alone — Release's or a hotfix's; the marker clearing is every run's.
Back-merge production → integration (Release). Not optional. Once the finalize CI has
pushed its chore(release) version-bump and marketplace-sha-pin commits to production:
git fetch origin
git switch <integration> && git merge --ff-only origin/<integration>
git merge --ff-only origin/<production>
git push origin <integration>Fast-forward when the branch is strictly behind, else --no-ff. Skipping this leaves the
released tag unreachable from integration, and the next version is computed wrong.
Then staging, --ff-only and nothing else:
git switch <staging> && git merge --ff-only origin/<staging>
git merge --ff-only origin/<production>
git push origin <staging>A refused fast-forward ends that step — never --no-ff (failure mode 4). Skip it and say
so in the run's own output; the next integration → staging promotion carries the release
commits forward on its own. Under PR mode the ruleset rejects the push instead, once the
merge has already moved local <staging>: that is a finish too — leave the ref where it stands
and git switch -. Rationale in promotion.md Back-merge after
release.
Clear the promotion's evidence markers, whichever this run recorded — rm -f is silent on
the ones it did not. The commit hook is fail-closed on them: it blocks the promotion commit
until each marker its tier requires exists. That is what makes a marker a forcing function
rather than a stamp — and what makes one left behind read to the next promotion as its own
passing evidence. A run that ended at Staging is where that bites: nothing else deletes
bump.done, so the next rc satisfies its fail-closed bump gate with no one choosing a level.
rm -f .claude/harness-tier/.flow/review.done .claude/harness-tier/.flow/bump.done .claude/harness-tier/.flow/security.done .claude/harness-tier/.flow/release-notes.mdDeleting evidence stays a deliberate prompt: no allowed-tools rule covers that rm. Under
PR mode, clear only after the PR is merged — a review-feedback commit pushed to that branch is
gated exactly like the first one, and the gate reads whether each marker file exists, so
clearing early leaves that commit blocked.
Failure modes
Each of these produces a release that looks finished and is not.
[skip ci]in the promotion merge message — the release job never runs, so there is no rc at all and nothing downstream reports a problem.- Merging a stale local staging ref instead of the fetched
origin/<staging>— finalize sees no pending rc, falls back to plain compute, and the forced level is lost (0.2.0where0.1.2was chosen). - A skipped production → integration back-merge — the released tag is unreachable from integration and the next version is miscomputed.
- Taking
--no-ffwhen staging's back-merge refuses the fast-forward — the merge commit carries no[skip ci], and the release workflow fires on a push to staging, so it cuts an rc nobody promoted. A refused fast-forward is a skip, not a fallback; the next integration → staging promotion carries the release commits forward. - Running
finalize_prerelease.pylocally — it writes the version intopyproject.tomland.claude-plugin/plugin.json. It is not a read-only probe, and CI is the only thing that runs it. - Leaving the evidence markers in place — the next promotion reads someone else's
review.done,bump.doneandsecurity.doneas its own pass.
Monorepo / multi-service
A promotion versions the whole repository at one version: modules are first-class in gates,
tests and per-target deploys, on lockstep versions. versioning has no per-service slot, and
nothing reads versioning.version_files — the release tool's own config stamps a version.
Never
- Never force a level through a
workflow_dispatch— no workflow here reads one (the sister plugin vway-kit's does): it forces nothing, and the promotion cuts no rc. - Never put
[skip ci]in a promotion merge. - Never offer a forced level as the way to fold a follow-up into a pending rc.
continueis that option;patch/minor/majorthere bump the base again and skipX.Y.Zas a stable release, so they are the user's explicit choice, never the default. - Never leave the trailer off a
count >= 1promotion but a legacy re-promotion. Write the choice,autoincluded, spelled exactly: a value outside the five fails the run. - Never spell a
git mergeflag through a variable. The commit hook reads the command text unexpanded, so a variable where a flag belongs makes it read "not a merge" and every merge-strategy check switches off in silence (CLAUDE.md Invariant 7).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

