agentsclimarketplace

Version bump

Skill bostonaholic/team/.claude/skills/version-bump

Drive a feature from idea to PR with a team of Claude Code agents.

Install
npx -y skills add bostonaholic/team --skill version-bump

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Version the Team plugin at land time (DEV-internal, not distributed): decide the SemVer level, compute the next free version against current `main`, update all five version strings, cut the `[Unreleased]` changelog body into a dated `## [X.Y.Z]` section, run the land-time consistency assertion, and commit `chore(version): X.Y.Z`. This is the Team-internal bumper; the generic runtime `/shipit` skill then pushes, waits for CI, and squash-merges. Use when landing a Team PR, or when the user asks to "bump the version" or "version this PR".

SKILL.md

10.0 KB, as published. Nobody here has run it

Version Bump — version a Team PR at land time

Follow skills/progress-tracking/SKILL.md: this procedure has more than two steps — seed one todo item per step below before starting and mark each complete as you go.

This skill versions the Team plugin itself at land time. It is dev-only (lives under .claude/, never distributed to plugin users). Tagging and the GitHub release are not part of this procedure — release-on-merge.yml does both automatically when the PR merges. Full policy: docs/versioning.md.

The dev land process

Landing a Team PR is two steps, in order:

  1. Bump (this skill). Run version-bump against current main. It picks the level, assigns the next free version, and bumps the five version strings. It cuts the [Unreleased] changelog into a dated ## [X.Y.Z] section, runs the land-time consistency assertion, and commits chore(version): X.Y.Z.
  2. Land (the generic /shipit skill). Run the distributed runtime /shipit skill to push the branch, wait for CI, and squash-merge. shipit is project-agnostic — it does no versioning. This skill is the Team-internal bumper it composes with.

Run this skill before /shipit, against the version of main you intend to land onto.

The bump is conditional, not universal. Step 0 below decides if this PR warrants a bump at all. Only PRs that change the distributed plugin bump. A dev-only PR (CI, docs, tests, evals, .claude/ tooling) lands with no bump and no changelog cut. Run step 0, see it say "no bump", and go straight to /shipit with the plain conventional title.

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 version, changelog, and GitHub release exist for plugin end users — people who install Team and run /team. They are driven only by changes to the distributed plugin. Contributor-facing / plugin-developer infrastructure does not move the version, no matter what conventional-commit type it carries.

Using the Runtime vs. Development split in CLAUDE.md:

  • Runtime (bump-worthy): agents/, skills/, hooks/, and host manifest content.claude-plugin/, .codex-plugin/, .agents/plugins/ — meaning a real change to a manifest, not the bare "version" field. Every host's manifest ships to that host's end users, so a Codex-only manifest change is as much a runtime change as a Claude Code one.
  • Development (never bumps): .github/, .claude/, docs/, tests/, evals/, package.json/bun.lock tooling — everything that only validates or builds the plugin.

Check what this PR actually changed:

.github/scripts/version-bump-required.sh   # HEAD_SHA/BASE_SHA from the PR; deterministic gate
# or, locally, just look:
git diff origin/main...HEAD --name-only
  • No runtime files changed → 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>). Precedent: 710d44c (CI), 7d2e218 (docs), 0821129 (evals feat:) all landed plain. Then go straight to /shipit.
  • Runtime files changed → continue to step 1.

This is a hard gate, not a judgment call. The same check runs deterministically in CI, through .github/scripts/version-bump-required.sh, which tests/version-bump-required.test.ts pins. It fails the PR if a dev-only diff bumped, or a runtime diff did not.

1. Decide the bump level

Reached only when step 0 said a bump is warranted (the PR changed runtime files). The level question is never "does this bump?" — step 0 already answered that — only "how big is the bump?"

git log origin/main..HEAD --oneline
git diff origin/main...HEAD --stat

Pick the highest-impact runtime change in the PR:

  • major — breaking change to the plugin's contract (commands, artifact formats, hook behavior).
  • minor — new backward-compatible capability (feat:).
  • patch — everything else (fix:, docs:, chore:, refactor:, test:, ci:).

The conventional-commit type only picks the level. It never overrides step 0. A ci:/test:/docs:/chore: commit that ships no runtime change never reaches this table — it already stopped at step 0 with no bump.

State the chosen level and the reasoning. If genuinely ambiguous, ask.

2. Compute the next version

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

This prints bump(<default branch>'s version, level)deterministic, a pure function of the base and the level, with no open-PR scan. The base is read from the remote's default branch (resolved through origin/HEAD, not a hardcoded main). Under the land-time model the version is assigned against current main and landing is serialized, so bump(main, level) is always free. A concurrent race is handled by /shipit (rebase + recompute) and release-on-merge.yml's duplicate-tag backstop.

3. Bump all five version strings

The version lives in five places across four files:

FileOccurrences
.claude-plugin/plugin.json1 (version)
.claude-plugin/marketplace.json2 (metadata.version and plugins[0].version)
.codex-plugin/plugin.json1 (version)
package.json1 (version)

Codex reads .codex-plugin/plugin.json in preference to the Claude manifest, and shows the version it finds there. A stale one makes the same release look like two different versions depending on the host.

Edit all four files, then prove it:

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

All five lines must show the new version. Zero may still show the old one.

4. Cut the changelog section

This moves the accumulated [Unreleased] body into a new dated section. It is the inverse of release-on-merge.yml's awk extraction, because you write the section the release workflow later reads. In CHANGELOG.md (Keep a Changelog format, entry style per skills/changelog/SKILL.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/bostonaholic/team/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 (see skills/changelog/SKILL.md).

Empty-[Unreleased] edge case. A PR that reached this step passed step 0, so it did change 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: per skills/changelog/SKILL.md 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

After the changelog cut and before committing, run the consistency check — it must run after the cut (so the dated section exists to validate). This is the in-tree replacement for the retired version-gate.yml:

bun test tests/version-consistency.test.ts
node -e "['.claude-plugin/plugin.json','.claude-plugin/marketplace.json','.codex-plugin/plugin.json','.agents/plugins/marketplace.json','package.json'].forEach(f=>JSON.parse(require('fs').readFileSync(f)));console.log('JSON OK')"

The tripwire asserts strict semver, that all five strings agree, and that the host manifests agree on the plugin and marketplace names. Additionally assert inline the released-section + footer-compare-link invariants (these hold only after the cut, so they live here, not in the tripwire):

V=$(jq -r .version .claude-plugin/plugin.json)
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/bostonaholic/team/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, for clean reverts:

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

7. Title the PR

vX.Y.Z <type>: <subject> — e.g. v0.6.0 feat: add the shipit land skill. Set it on the existing PR (gh pr edit --title). The PR title sync workflow corrects drift, but it is a backstop — do not rely on it.

Then run /shipit (step 2 of the dev land process) to push, wait for CI, and squash-merge.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.