agentleFS
bostonaholicbostonaholic/team/.claude/skills/version-bump/SKILL.md

version-bump

Skill11 starsChanged 4 months agoMITView on GitHub

Use for version bumps on explicit request or as the pre-merge step of a PR land. Never infer from finished, reviewed, green, or draft-ready work. Assigns SemVer.

25 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use security-audit and commit.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • CloudflareSkill

    security-audit

    Security guidance and vulnerability review for codebases, APIs, services, CLI tools, libraries, and daemons. Use for security questions, focused reviews, vulnerability research, security audits, or pen tests. Run the complete workflow only for explicit codebase audit or pen-test requests, full/comprehensive/end-to-end reviews, or requested report artifacts.

    Also in 3 projects that use this

  • SentrySkill

    commit

    Create commit messages following Sentry conventions. Use when committing code changes, writing commit messages, or formatting git history. Follows conventional commits with Sentry-specific issue references.

    Also in 3 projects that use this

The file

We split this skill into the rules it gives an agent

8 rules. 0 are common, 6 are distinctive, and 2 are very specific to this project.

  • 0

    Common

    Most of the 22 edited versions we read keep these.

  • 6

    Distinctive

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Very specific:

    Run the script with HEAD_SHA = the local branch tip and BASE_SHA = the fetched origin/<default> tip — never a pre-computed merge-base, and …

    line 56
  2. Distinctive:

    Every other exit-1 verdict in this list stops.

    line 89
  3. Very specific:

    If the version starts 0., none of those three binds.

    line 124
  4. Distinctive:

    Ask these in order. The first yes wins.

    line 130
  5. Distinctive:

    Every line must show the new version.

    line 187
  6. Distinctive:

    Run it after the changelog cut (so the dated section exists) and before committing:

    line 218
  7. Distinctive:

    If any check fails, stop before committing and fix the cut.

    line 242
  8. Distinctive:

    Commit the bump as its own commit in the PR branch:

    line 246

“Common” is measured: kept by at least 6 in 10 of the 22 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Version Bump — version a project at land time

This repository's own versioning procedure. AGENTS.md declares it as the pre-merge step, so the land command runs it before merging. Tagging and the GitHub release are not part of it; release-on-merge.yml does that on merge. When invoked directly, run this skill before the land command, against the version of main you intend to land onto. When a land command invokes this skill, return to it after step 8.

Precondition — explicit land intent

Why: the bump is computed against the base branch's tip at this moment; a bump made before the land goes stale when another PR merges, and the pre-merge guard then denies the merge.

This skill fires only on explicit land intent, meaning one of:

  • The user asked to land: "ship it", "land the PR", "land this".
  • The user asked for the bump itself: "bump the version", "version this PR".
  • A land command is already in flight and reached the project's pre-merge steps.

Never infer land intent. None of the following is a cue to bump:

  • The work is finished, the review passed, or CI is green.
  • A draft PR is about to be opened, or was just opened. A drafted PR carries no version: the bullet goes under ## [Unreleased] and nothing else moves.
  • The invariant script exited 1. That exit states a precondition for merging, expected for a runtime PR's whole review lifetime, never a request to bump now.

With no land intent, stop and say so. Report that the branch will need a bump before it can merge, and wait for the user. Do not bump "to be helpful".

Steps

0. Runtime-vs-dev gate — does this PR warrant a bump at all?

Run this before everything else. Most steps below only apply if it says yes.

The quick look is orientation only — it never decides the exit: git diff "origin/<default>...HEAD" --name-only. The decision comes from the invariant run, the same invocation contract the pre-merge guard enforces:

  1. Resolve the default branch by asking GitHub (gh repo view), falling back to the local origin/HEAD ref. Never a guessed main. If both fail, stop: no verdict.
  2. git fetch origin <default> must succeed. Never degrade to a stale base for a verdict.
  3. The fetched origin/<default> tip must be an ancestor of the branch tip. If the branch is behind, stop: rebase onto origin/<default> and re-enter step 0.
  4. Run the script with HEAD_SHA = the local branch tip and BASE_SHA = the fetched origin/<default> tip — never a pre-computed merge-base, and never a hand-rolled two-dot diff.
DEFAULT=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name 2>/dev/null)
DEFAULT=${DEFAULT:-$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|^refs/remotes/origin/||')}
[ -n "$DEFAULT" ] || { echo "cannot resolve the default branch — no verdict"; exit 1; }
git fetch origin "$DEFAULT" || { echo "fetch failed — no verdict"; exit 1; }
git merge-base --is-ancestor "refs/remotes/origin/$DEFAULT" HEAD \
  || { echo "behind base — rebase onto origin/$DEFAULT, re-enter step 0"; exit 1; }
HEAD_SHA=$(git rev-parse HEAD) BASE_SHA=$(git rev-parse "refs/remotes/origin/$DEFAULT") \
  .claude/scripts/version-bump-required.sh

Read the outcome by exact output match — the signal rule, default-deny:

  • Exit 0, stdout starting OK: runtime_changed=false bumped=false → dev-only and final. DO NOT BUMP. Skip every step below. Leave the version untouched, do not cut the changelog, and land with the plain conventional title (<type>: <subject>). On a re-entry whose PR title still carries a stale vX.Y.Z prefix from an earlier bump, strip it now (gh pr edit --title) — the title backstop never strips a stale prefix, and this is the one step-8 action a no-bump exit still owes. Then go straight to the land command. This exit requires that OK line — the quick look alone never authorizes it.
  • Exit 0, stdout starting OK: runtime_changed=true bumped=true → already bumped (a recovery re-entry). Never re-bump — proceed to the land command.
  • Exit 1, verdict containing cannot merge until version-bump runs at land time → bump warranted. It is actionable here only because the land-intent precondition already passed; read outside a land it states a merge precondition and nothing more.
    • On a branch with no chore(version) commit: continue to step 1. Every other exit-1 verdict in this list stops.
    • On a branch already carrying a chore(version) commit: the bump went stale (a rebase moved the fork point). Stop — drop the bump commit, undo the changelog cut, reset the title, and re-enter step 0.
  • Exit 1, verdict containing must land with no bump → wrongful bump. Stop — drop the commit, undo the cut, and re-run step 0.
  • Anything else — a non-semver version, a merge-base or diff failure, or unrecognized output — stops in both directions. Surface the message verbatim. A hard script error never means "keep going".

This is a hard gate, not a judgment call.

1. Decide the bump level

Reached only when step 0 said a bump is warranted; the only question is how big the bump is.

# Re-derive the base: shell variables do not persist from step 0's call.
DEFAULT=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name 2>/dev/null)
DEFAULT=${DEFAULT:-$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|^refs/remotes/origin/||')}
: "${DEFAULT:?cannot resolve the default branch}"
git log "origin/$DEFAULT..HEAD" --oneline
git diff "origin/$DEFAULT...HEAD" --stat

SemVer 2.0.0, quoted verbatim. Items 6, 7, and 8 each carry an x > 0 precondition:

ItemNormative ruleScope
6PATCH "MUST be incremented if only backward compatible bug fixes are introduced. A bug fix is defined as an internal change that fixes incorrect behavior."x.y.Z | x > 0
7MINOR "MUST be incremented if new, backward compatible functionality is introduced to the public API."x.Y.z | x > 0
8MAJOR "MUST be incremented if any backward incompatible changes are introduced to the public API."X.y.z | X > 0

If the version starts 0., none of those three binds. Item 4 governs: "Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable." Item 5: "Version 1.0.0 defines the public API." The spec assigns no level pre-1.0, so the decision below uses the same observable-change rule before and after 1.0.0.

Ask these in order. The first yes wins. Judge the change, never the commit subject:

  1. Can a plugin user observe the difference? → minor. Anything that changes what they type, what they get back, or what the project does on their behalf is observable: a command's name or arguments (argument-hint), documented behavior, whether a step prompts them, an artifact's format or frontmatter schema, an agent's model, or tool access. New and changed capability both land here.
  2. Otherwise → patch: internal-only and backward compatible — prose that clarifies without changing an instruction, a comment, restructuring that preserves behavior. Item 6 requires both qualifiers, not just a fix: subject. Expect patch to be rare for projects that ship instructions a model reads. Do not widen patch to make the cadence feel familiar.

major is unreachable while the version starts 0. A breaking change pre-1.0 is a minor, not a major. If a change looks like it warrants major, that is a signal to ask whether it is time to declare 1.0.0 — a deliberate decision, never a side effect of this skill.

State the chosen level and which question decided it. A level that needed a judgment call means the observability question was not actually answered — answer it rather than asking the user.

2. Compute the next version

bash .claude/scripts/next-version.sh <level>

3. Bump every version string

The version lives in every file below:

FileOccurrences
.claude-plugin/plugin.json1 (version)
.claude-plugin/marketplace.json2 (metadata.version and plugins[0].version)
.codex-plugin/plugin.json1 (version)
.cursor-plugin/plugin.json1 (version): what Cursor reports
package.json1 (version)
plugin.json (repo root)1 (version): what Antigravity reports

Each host shows the version in its own manifest: Codex reads .codex-plugin/plugin.json in preference to the Claude manifest; Antigravity reads the root plugin.json, which sits at the root rather than in a directory of its own because that host resolves skills/ and agents/ as siblings of its manifest. A stale one makes the same release look like two different versions depending on the host.

Edit every file, then prove it:

grep -rn '"version"' package.json plugin.json .claude-plugin/plugin.json \
  .claude-plugin/marketplace.json .codex-plugin/plugin.json .cursor-plugin/plugin.json

Every line must show the new version. None may still show the old one.

4. Cut the changelog section

In CHANGELOG.md (Keep a Changelog format, entry style per skills/team-pr/references/changelog.md):

  • Move the entire [Unreleased] body into a new ## [X.Y.Z] - YYYY-MM-DD (today's date) section inserted directly below ## [Unreleased]. Leave ## [Unreleased] in place, now empty again.
  • Re-point the link-reference footer:
    • [Unreleased] compare base → vX.Y.Z...HEAD
    • Add [X.Y.Z]: https://github.com/<owner>/<repo>/compare/v<prev>...vX.Y.Z

This section becomes the GitHub release notes verbatim — write it for a reader deciding if the upgrade is worth it. Any links must be absolute URLs: relative paths (e.g. docs/versioning.md) render as dead links on the release page.

Empty [Unreleased]. A PR that reached this step changed runtime files; an empty [Unreleased] on it means nobody wrote the user-facing bullet. Derive at least one bullet from the PR's runtime commits (feat:/fix:/perf:/security:, in that entry style). Never write an empty section (release-on-merge.yml errors on empty release notes).

Empty [Unreleased] and no runtime change is not this case: that PR must have stopped at step 0, with no bump and no changelog cut. Do not invent a bullet to justify a bump that step 0 already declined. Go back and land plain.

5. Land-time consistency assertion

Run it after the changelog cut (so the dated section exists) and before committing:

bash .claude/scripts/check-version-consistency.sh
node -e "['.claude-plugin/plugin.json','.claude-plugin/marketplace.json','.codex-plugin/plugin.json','.cursor-plugin/plugin.json','.agents/plugins/marketplace.json','plugin.json','package.json'].forEach(f=>JSON.parse(require('fs').readFileSync(f)));console.log('JSON OK')"

The released-section and footer-compare-link invariants hold only after the cut, so assert them inline here:

V=$(jq -r .version .claude-plugin/plugin.json)
OWNER_REPO=$(gh repo view --json nameWithOwner --jq .nameWithOwner)
ESC=$(sed 's/\./\\./g' <<<"$V")
grep -qE "^## \[$ESC\] - [0-9]{4}-[0-9]{2}-[0-9]{2}$" CHANGELOG.md \
  || { echo "::error::no '## [$V] - YYYY-MM-DD' section — the cut did not land"; exit 1; }
grep -qE "^\[$ESC\]: https://" CHANGELOG.md \
  || { echo "::error::no footer compare link for $V"; exit 1; }
grep -q "\[Unreleased\]: https://github.com/$OWNER_REPO/compare/v$V...HEAD" CHANGELOG.md \
  || { echo "::error::[Unreleased] footer does not compare from v$V"; exit 1; }
echo "OK: land-time consistency holds"

If any check fails, stop before committing and fix the cut.

6. Commit

Commit the bump as its own commit in the PR branch:

git add .claude-plugin/plugin.json .claude-plugin/marketplace.json \
  .codex-plugin/plugin.json .cursor-plugin/plugin.json plugin.json package.json \
  CHANGELOG.md
git commit -m "chore(version): X.Y.Z"

7. Assert the bump invariant

Re-run the invariant run from step 0 — the head is now the branch tip carrying the chore(version) commit. Require exit 0 with stdout starting OK: runtime_changed=true bumped=true.

This runs before any remote change (the title edit in step 8 is remote). On any other outcome, stop: drop the chore(version) commit, undo the changelog cut, and land plain — nothing has left the machine, so the recovery is purely local.

8. Title the PR

vX.Y.Z <type>: <subject> — e.g. v1.4.0 feat: add a design review gate. Set it on the existing PR (gh pr edit --title). The PR title sync workflow is a backstop — do not rely on it.

A re-entry path that runs after a title already exists must reset it: the stale-bump recovery re-titles with the recomputed version, and a re-entry that ends at "no bump" strips the vX.Y.Z prefix explicitly — the title backstop never strips a stale prefix.

Return to the land command to push, wait for CI, and squash-merge.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.