Bump Version
Bump a native addon package's version in package.json and write the matching CHANGELOG.md entry,
so /release can publish it. Defaults to a minor bump.
$ARGUMENTS is <package-name> [major|minor|patch] — the package directory name under packages/,
plus an optional explicit bump level.
Usage
/bump-version llm-llamacpp # minor (default): 0.39.0 -> 0.40.0
/bump-version llm-llamacpp patch # 0.39.0 -> 0.39.1
/bump-version ocr-ggml minor
/bump-version translation-nmtcpp major # never chosen automatically — must be explicit
When to use this skill
Use it when work has merged to main for an addon package and the package still carries the previous
version — i.e. the feature is on main but unreleasable because nothing bumped it. This is the routine
gap that /addon-changelog and /release both refuse to fill:
/addon-changelogwrites the changelog but refuses to bump — it stops with aVERSION BUMP REQUIREDbanner ifpackage.jsonis unchanged vsmain./releasevalidates the bump then stops and tells you to bump first.
Do not use it for:
| Case | Use instead |
|---|---|
SDK/TS pods: sdk, cli, rag, logging, error, ai-sdk-provider |
/sdk-changelog |
Back-porting a fix onto a shipped release-* line |
/release-patch |
A qvac-fabric bump across all 7 consumers |
/rollout-phase-b |
| Publishing an existing bump | /release |
Refusals — stop, do not edit anything
- SDK pods. Their root
CHANGELOG.mdis machine-generated byscripts/sdk/generate-changelog-sdk-pod.cjs(rebuildRootChangelog()); a hand-edit is destroyed on the next generator run. Tell the user to run/sdk-changelogand stop. - Version not higher than npm
latest. Report both numbers and stop. - Working branch is a
release-*branch. That is/release-patchterritory — a release branch must stay a byte-exact copy of its base. Stop. - Package has no
CHANGELOG.md. Ask the user before creating one.
fabric is NOT a refusal. An earlier version of this skill refused it, claiming its release read
packages/fabric/release-notes/v<ver>.md via create-github-release-fabric.yml. That workflow does
not exist and is referenced nowhere; on-merge-fabric.yml passes
changelog-path: packages/fabric/CHANGELOG.md, and that file is current and correctly bracketed.
packages/fabric/release-notes/ holds only a v0.1.0.md leftover and is not the release source.
Treat fabric like any other addon.
Step 1 — Read the real current version
Never trust the local checkout; it is routinely days or thousands of commits behind.
git -C <repo> fetch origin main
git -C <repo> show origin/main:packages/<pkg>/package.json
Read version from that output. Cross-check the published version:
npm view @qvac/<pkg> dist-tags.latest
Expect npm to equal or trail origin/main. If origin/main is already ahead of npm, a bump is
already pending — say so and confirm with the user before adding another.
Step 2 — Find what changed since the last bump
Resolve the previous release tag (see Step 6 — do not guess it from the directory name), then:
git -C <repo> log <prev-tag>..origin/main --oneline -- packages/<pkg>/
If the tag is missing, fall back to the last commit that touched
packages/<pkg>/package.json and diff from there. Harvest PR numbers from the commit subjects
((#1234)) for the ### Pull Requests list, and read the PR titles:
gh pr view <number> --repo tetherto/qvac --json title,body
Drop any PR whose diff does not touch packages/<pkg>/. Read the actual source diff for the
user-visible behaviour — do not paraphrase commit messages, which go stale. (A real example: a merged
commit advertised an opt-in env var that did not exist in the merged code.)
Step 3 — Choose the bump level
Honour an explicit major|minor|patch argument. Otherwise default to minor, and state the
reasoning before editing. The de-facto rule from this repo's history:
| Change | Level |
|---|---|
| New public API, new config key, new supported model, changed default | minor |
| Bug fix only | patch |
qvac-fabric dependency bump |
minor for 0.x, major for >=1.0 — see /rollout-phase-b |
| Breaking change | major — never selected automatically |
Never auto-select major. For a package already at major ≥ 1 still default to minor here; a major
bump must be an explicit user decision, passed as the major argument.
translation-nmtcpp is the only current post-1.0 addon (9.0.0). Its history used to be
inconsistent — the same rollout landed as both minor and major — but 8.3.1 → 9.0.0 (#3567), a
dependency-floor alignment with no breaking API change, settled it: post-1.0 packages take the major
on a fabric rollout. /rollout-phase-b codifies that and passes major explicitly, which satisfies
the never-auto-select rule.
Note that for a 0.x package a minor bump is technically the SemVer breaking-change signal; this repo leans on that deliberately, so a minor default is correct rather than conservative.
Print the decision before touching files:
llm-llamacpp: 0.39.0 -> 0.40.0 (minor)
reason: adds new supported finetuning architectures (new accepted config values)
Step 4 — Bump package.json
Edit packages/<pkg>/package.json with the Edit tool, changing only the version field. Nothing
else in that file, and no other file — in particular never vcpkg.json (that is a dependency floor,
not the package version) and never vcpkg-configuration.json's default-registry.baseline.
Step 5 — Write the CHANGELOG entry
Insert at the top of packages/<pkg>/CHANGELOG.md, directly below the preamble and above the previous
version heading. The dominant addon shape:
## [<version>] - <YYYY-MM-DD>
<optional 1-3 sentence intro — worth it for a feature release, skip for a one-line fix>
### Added
- <bullet; backtick identifiers; use -> for transitions; explain why it matters, not just what changed>
### Pull Requests
- [#3509](https://github.com/tetherto/qvac/pull/3509) - <PR title>
Rules:
- The heading must be bracketed — literally
## [0.40.0].## 0.40.0,##[0.40.0]and### [0.40.0]all fail the extractor at.github/actions/verify-changelog-notes/action.yml, whose awk is$0 ~ "^## \\[" version "\\]". This is the single most common way this task goes wrong. - Use the date the bump lands,
YYYY-MM-DD. - Section headings are level-3:
### Added,### Changed,### Fixed. Pick by intent — new capability isAdded, altered behaviour or a dependency bump isChanged, a defect fix isFixed. Do not use the level-2## Features/## Bug Fixesstyle;/addon-changelog's own documentation still shows it, but that documentation is stale and no current addon entry uses it. - The body must be non-empty until the next
^## [, or the extractor errors withChangelog section for version X is empty. ## [Unreleased]blocks exist inocr-ggml,tts-ggmlanddecoder-audio. Insert the new dated entry below the Unreleased block. Do not fold Unreleased content into your version, and do not insert above it — that makes the extractor slice your body off at## [Unreleased]. Precedent: commitdfd1fd7ebonocr-ggml.- Match the file's existing preamble. Some packages have a Keep-a-Changelog + SemVer preamble, some
just
# Changelog. Do not add one that was not there. - If the version documents work someone else merged, describe the merged code, and say so if a commit message contradicts it.
Step 6 — Report what happens next
Look up the git tag by reading repo_name: from .github/workflows/on-merge-<pkg>.yml. Never derive
the tag from the directory name — several are counter-intuitive:
| Package | Tag |
|---|---|
llm-llamacpp |
llamacpp-llm-v<ver> (reversed) |
embed-llamacpp |
llamacpp-embed-v<ver> (reversed) |
vla-ggml |
vla-v<ver> (no -ggml) |
translation-nmtcpp |
bare v<ver> |
ocr-ggml |
ocr-ggml-v<ver> |
classification-ggml |
classification-ggml-v<ver> |
Addons get a git tag only, no GitHub Release — on-merge-<pkg>.yml calls create-release-tag.yml
since #2602. Do not promise a Releases-page entry; only the SDK publishes one.
Then tell the user the next step is /release <pkg>, which cuts release-<pkg>-<version>, dispatches
on-merge-<pkg>.yml, and pauses at the human-only npm approval gate.
Step 7 — Verify before committing
grep -nE "^## \[<version>\]" packages/<pkg>/CHANGELOG.md
git -C <repo> diff --stat origin/main
- The
grepmust match. This is the extractor's own regex — if it does not match, the release fails later, not now. package.jsonversion must equal the heading version exactly.- The diff must show exactly two files:
package.jsonandCHANGELOG.md. Anything else means something was swept in.
Then commit on a branch off origin/main — never on main, never on a release-* branch:
git -C <repo> worktree add -b <TICKET>/bump-<pkg>-<version> <path> origin/main
Commit title follows the repo convention TICKET prefix[tags]: subject, with chore as the prefix
(precedent: chore: bump llm-llamacpp to 0.38.1):
QVAC-12345 chore: bump <pkg> to <version> for <reason>
Add no [api] tag unless the public API or config surface actually changed — widening the set of
accepted values is not an API change. Add no AI signature or Co-Authored-By trailer.
PR body uses the repo's four-section format: problem / how / tested / breaking changes.
What CI actually enforces
Be accurate about this; two in-repo docs are wrong.
For addons, release-merge-guard (.github/actions/release-merge-guard/) asserts exactly three
things:
- the branch matches
release-<slug>-x.y.z; package.jsonversion equals the version in the branch name;CHANGELOG.mdwas modified (skipped on initial branch push and onworkflow_dispatch).
It does not validate the heading text for addons, and no CI check anywhere compares the new
version against the previous one. So a malformed heading will not fail the guard — it fails /release
Step 1, and would fail the release-body extractor for the SDK and the two lib packages that still use
it.
Write the bracketed heading regardless: /release, /addon-changelog, /release-patch and
/release-fabric-consumers all assume it.
Do not copy from ci-validation.mdc:234 (claims the guard checks the heading, and shows an unbracketed
## x.y.z) or from /addon-changelog's level-2 section example. Both are stale.
Bash discipline
Per repo CLAUDE.md: no heredocs, no $() command substitution, no &&/||/; chaining, no pipes or
redirects. Use Read / Write / Edit / Grep / Glob instead of cat / sed / grep / find, and
git -C <path> instead of cd. Put anything longer than a single command in a script file and run
bash <file>.
Error handling
release-merge-guardfails on merge — version not bumped, the branch name does not match the version, orCHANGELOG.mdwas not modified./releaseStep 1 fails — the changelog heading is missing or unbracketed. Fix the heading.- npm publish rejects the version — it already exists. Check
npm view @qvac/<pkg> versionsand pick the next free one. - Never weaken, skip, or delete a test to get a bump through.