Versioning Guide
Automated semantic versioning for BoB-managed projects — conventional-commit-driven
version bumps, git tags, CHANGELOG.md, and GitHub Releases. This is the
encyclopedic reference for the BoB-wide versioning capability (capability #275).
TL;DR — Add
"versioning": { "enabled": true }to your project manifest and runcdprov refresh. Commit with Conventional Commit messages. Merges to your main branch now cut versioned releases automatically.
Before this, releases across the fleet were manual or absent: bigbrain itself had
a single stale v1.0.0 tag and a 0.0.0 package.json. Versioning makes releases
declarative, reproducible, and consistent across every project — provisioned
from one source of truth rather than hand-copied CI.
The tool: commit-and-tag-version
Section titled “The tool: commit-and-tag-version”BoB standardizes on commit-and-tag-version
(the maintained fork of the deprecated standard-version):
- Minimal dependencies, language-agnostic, runs anywhere Node runs.
- Reads Conventional Commits → computes the next semver → bumps
package.json, regeneratesCHANGELOG.md, and creates a git tag.
Alternative considered — release-please (Google): a release-PR model that
avoids pushing release commits directly to the main branch (better when the main
branch is protected). Deferred because it is less “automatic” (requires merging a
release PR) and heavier to set up. Revisit if branch protection on the main branch
becomes a hard fleet-wide requirement. See capability #275 for the full decision.
How a release happens
Section titled “How a release happens”- You merge a commit to the main branch (e.g.
feat: add X). .github/workflows/auto-release.ymltriggers (scoped to the project’s source paths — see Trigger paths).commit-and-tag-versionbumps the version from the commits since the last tag, rewritesCHANGELOG.md, commitschore(release): X.Y.Z, and tagsvX.Y.Z.- The workflow pushes the commit + tag with
--follow-tags. - A GitHub Release is published from the new
CHANGELOG.mdsection.
The chore(release) commit is loop-guarded — it does not re-trigger the
workflow. A manual workflow_dispatch lets you force a patch/minor/major
bump.
Bump rules (Conventional Commits)
Section titled “Bump rules (Conventional Commits)”| Commit type | Bump | Appears in changelog under |
|---|---|---|
fix: |
patch | Bug Fixes |
feat: |
minor | Features |
feat!: / BREAKING CHANGE: |
major | ⚠ Breaking |
perf: |
patch | Performance |
refactor:, docs:, test:, build:, ci: |
patch* | their sections |
chore:, style: |
none | hidden |
* Non-feat/fix types contribute to the changelog but only bump when present
with other changes; a release with only chore: commits is a no-op.
Provisioning
Section titled “Provisioning”Versioning is an opt-in manifest capability (it is not a symlinked registry
item — cdprov only symlinks; versioning copies template files). It follows the
same pattern as the gh_project block.
1. Declare it in the manifest
Section titled “1. Declare it in the manifest”provisions/<project>.json:
{ "_meta": { "project": "my-app" }, "skills": [], "commands": [], "agents": [], "versioning": { "enabled": true, "tool": "commit-and-tag-version", "main_branch": "main", "node_version": "22", "trigger_paths": ["src/**", "package.json"] }}All fields except enabled are optional:
| Field | Default | Meaning |
|---|---|---|
enabled |
— (required) | true provisions versioning; false (or omitted block) is a no-op |
tool |
commit-and-tag-version |
version-bump engine (only value supported today) |
main_branch |
main |
branch the workflow triggers on |
node_version |
22 |
Node version in the release workflow |
trigger_paths |
(none) | push path filter; omitted ⇒ any push to main_branch |
The orchestrator populates this block for you (see below); you rarely hand-write it.
2. Reconcile
Section titled “2. Reconcile”cdprov refresh # or the /provision skillprovision_versioning() copies the template set into the project, never
clobbering existing files, and idempotently merges package.json:
| Template | Destination |
|---|---|
templates/versioning/auto-release.yml |
.github/workflows/auto-release.yml |
templates/versioning/.versionrc.json |
.versionrc.json |
templates/versioning/commitlint.config.cjs |
commitlint.config.cjs |
package.json gains a release script + the commit-and-tag-version
devDependency, and a 1.0.0 version if it was absent or 0.0.0.
3. Inspect
Section titled “3. Inspect”cdprov status # shows which versioning files are present / missingcdprov diff # dry run — what a refresh would create (writes nothing)Orchestrator integration
Section titled “Orchestrator integration”versioning is recommended by default for every project (the registry command
versioning is default: true) — fulfilling the “all BoB projects should include
versioning” goal of capability #275. When you run the orchestrator interview (or
scripts/orchestrator/recommend.js), the generated manifest includes a
versioning block with trigger_paths chosen for your project type.
Trigger paths
Section titled “Trigger paths”The push path filter is parameterized per project type so docs-only or unrelated changes don’t cut releases:
| Project type | trigger_paths |
|---|---|
cms (Drupal, …) |
docroot/** |
api, backend, web-app, library |
src/**, package.json |
cli |
src/**, bin/**, package.json |
framework (BoB-like) |
skills/**, commands/**, agents/**, registry/**, runbooks/**, scripts/**, hooks/**, bin/**, templates/**, schemas/**, profiles/**, Makefile, package.json |
research, mixed, any |
(none — any push to the main branch) |
The mapping lives in VERSIONING_TRIGGER_PATHS in
scripts/orchestrator/recommend.js. An existing versioning block in a
manifest is always preserved on re-run, so opt-outs and customizations survive.
Conventional-commit enforcement
Section titled “Conventional-commit enforcement”Automated bumping only works if commits follow the convention — a non-conventional
subject makes the release a silent no-op or a mis-bump. Enforcement is built into
BoB’s commit-msg git hook (templates/git/hooks/commit-msg, installed by cdi),
which does two jobs in order (git allows only one commit-msg hook):
- Strip AI boilerplate (
Co-Authored-By: Claude,🤖 Generated, …) — always. - Enforce Conventional Commits — only when the project has versioning config
(
.versionrc.jsonorcommitlint.config.*in the repo root). Projects without versioning keep the strip-only behavior, so nothing else is affected.
The enforcement step prefers node_modules/.bin/commitlint (using the provisioned
commitlint.config.cjs) when installed, and otherwise falls back to a built-in,
dependency-free check — so the convention is enforced even before npm install.
Issue-ref scopes (feat(#274): …), feat!: breaking markers, and
merge/revert/chore(release) subjects are all accepted; the chore(release) commit
that commit-and-tag-version creates passes cleanly and is loop-guarded in CI.
The commit skill already drafts Conventional Commit
messages, so commits made through /commit (or warp-drive) pass enforcement by
construction.
Known limitation: branch protection
Section titled “Known limitation: branch protection”The workflow pushes the release commit and tag directly to the main branch
using the default GITHUB_TOKEN. If branch protection is enabled on the main
branch without an exception for github-actions[bot], the push will fail. This is
the trade-off behind deferring release-please (the PR-model alternative). No
protection ⇒ it just works.
Reference implementation
Section titled “Reference implementation”bigbrain itself is the reference implementation (#274): see its
.github/workflows/auto-release.yml, .versionrc.json, and package.json
release script. The capability was then generalized into the provisionable
template set (#276) and wired into the orchestrator (#277).