Semantic Versioning Release Process
Intro
Releases are routine, not heroic. Decide the version bump from the
nature of the changes, draft a changelog, update version files in
one commit, tag with vX.Y.Z, and publish. The goal is a release
anyone on the team can perform from the same checklist.
Overview
Determine the version bump
Semantic versioning has three numbers: MAJOR.MINOR.PATCH.
- Patch (0.1.0 → 0.1.1): bug fixes only, no API changes.
- Minor (0.1.0 → 0.2.0): new features, backward-compatible.
- Major (0.1.0 → 1.0.0): breaking changes.
Pre-1.0 projects bend the rules: minor bumps are allowed to break
compatibility, and patch bumps cover both features and fixes. Once
you ship 1.0, the rules become strict.
Pre-release checklist
- All tests pass on the main branch.
- No uncommitted changes in the working tree.
- Dependencies reviewed and up to date where appropriate.
- CHANGELOG or release notes drafted.
Draft the changelog
Group entries under Added, Changed, Fixed, and
Removed. Reference issue and PR numbers. Note breaking changes
prominently — call them out in their own section if a major bump
is involved.
The release flow (single turn, bulletproof)
A release is one continuous sequence — you do not stop halfway.
/pk-release vX.Y.Z runs every step below in order, in the same
turn, and is not considered done until the final verification
passes. See DEC-20260422_1348-SnowyWolf.
- Bump version in every relevant file (
aibox.lock,
Cargo.toml, pyproject.toml, package.json, lockfiles).
- Finalize CHANGELOG — rename the
[vX.Y.Z-candidate] section
to [vX.Y.Z] — YYYY-MM-DD; ensure Added/Changed/Fixed/Removed
grouping; call out breaking changes if a major bump.
- Regenerate provenance / transitive artifacts — for processkit,
scripts/stamp-provenance.sh vX.Y.Z.
- Commit the bump with message
chore(release): bump to vX.Y.Z.
- Tag the commit:
git tag -a vX.Y.Z -m "<tag summary>".
- Push branch then tag:
git push origin main && git push origin vX.Y.Z.
A tag push alone does not create a GitHub Release — it is a
git ref, not a distribution-channel artifact.
- Create the GitHub Release with notes extracted from the
CHANGELOG. The single canonical command:
gh release create vX.Y.Z \
--repo <org>/<repo> \
--title "vX.Y.Z — <one-line summary>" \
--notes-file <(awk -v v=X.Y.Z '
$0 ~ "^## \\[v" v "\\]" { f=1; next }
f && /^## \[/ { f=0 }
f
' CHANGELOG.md) \
--latest
- Verify the Release is live. This is the release's
completion gate:
gh release view vX.Y.Z --repo <org>/<repo>
If this exits non-zero, the release is incomplete — return
to step 7. Do not report the release as done until step 8
succeeds.
- Other channels (crates.io, PyPI, npm, container registry,
homebrew tap, etc.) — run after step 8 so the GitHub Release
remains the canonical artifact pointer.
Recovery pattern — if a tag was pushed in a prior session
without the Release, run gh release create and gh release view
for that tag directly; /pk-publish exists as an alias for this
recovery scenario.
pk-doctor release_integrity check (detection layer) — walks
every local v* git tag, probes GitHub for a matching Release, and
WARNs on any tag without one. Run /pk-doctor --category=release_integrity
after a release to confirm; run /pk-doctor routinely to catch any
historical gap. Requires gh CLI + auth; emits INFO when gh is
unavailable.
Example
User says: "Let's release — we fixed two bugs and added a feature."
The agent recommends a minor bump (because of the new feature),
drafts changelog entries grouped Added/Fixed, updates version
files, creates the bump commit, and tags it.
This skill also provides the /pk-release and /pk-publish commands
for direct invocation — see commands/pk-release.md and
commands/pk-publish.md.
Gotchas
Agent-specific failure modes — provider-neutral pause-and-self-check items:
- Bundling a breaking change into a patch or minor release. Consumers rely on semver guarantees to control when they take breaking changes. A breaking change in a patch release violates the contract and causes silent runtime failures in consumer code.
- Skipping the changelog because "git log has it". Git log is not a changelog. It lacks context, grouping, and the human judgment that makes a changelog useful. Every release needs a curated changelog with Added/Changed/Fixed/Removed sections.
- Bumping all version files in separate commits. A brief window where
Cargo.toml says 1.2.0 but pyproject.toml still says 1.1.0 is a broken state. Update all version files in a single atomic commit.
- Tagging before CI passes. A tag should point to a commit that has been fully built and tested. Tagging a commit that later fails CI means the published artifact may not match what was verified.
- Publishing from a developer machine without a clean checkout. Uncommitted local changes — WIP files, debug flags,
console.log statements — may sneak into the artifact. Publish from CI with a clean checkout or from a fresh clone.
- Re-tagging a published version to fix a mistake. Package registries (crates.io, PyPI, npm) prohibit or block re-publishing to an existing version. Cut a new patch version (e.g.
1.2.1) to fix a mistake in 1.2.0; never overwrite a tag.
- Pre-1.0 projects that promise stability they cannot keep. If the API is still moving, stay below 1.0 and say so. Cutting
1.0.0 too early creates a compatibility obligation that slows future improvements.
- Treating
git push --tags as "the release is out." Pushing a tag creates a git ref; it does not create a GitHub Release, a crates.io release, a PyPI release, or any other distribution-channel artifact. Downstream consumers (package managers, gh api, the Releases page, auto-sync tools like aibox) read from the channel, not the tag. Until gh release create (or the equivalent channel publish command) has run, the release is not visible. The flow above bakes this in: the release is not complete until step 8 (gh release view) succeeds. See DEC-20260422_1348-SnowyWolf.
- Stopping after
/pk-release prepare-like work. In an older split where /pk-release prepared and /pk-publish published, it was easy to do only half. The current flow is single-turn: /pk-release runs every step through GitHub-Release verification. /pk-publish remains only as a recovery alias for historical tags without Releases.
Full reference
When pre-1.0 ends
Cut 1.0 when the public API is something you are willing to
support without breaking. Until then, keep the version below 1.0
honestly — there is no shame in 0.17.0, and it signals to users
that the surface may still move.
Version bumps for special changes
| Change |
Bump |
| Bug fix that does not change behavior contract |
patch |
| Performance improvement, no API change |
patch |
| New feature behind a feature flag |
minor |
| New optional parameter with a default |
minor |
| Removing or renaming a public symbol |
major |
| Changing default behavior of an existing API |
major |
| Tightening input validation that rejects previously valid input |
major |
| Dependency bump that surfaces in your public API |
major |
Anti-patterns
- Bundling breaking changes into a patch release
- Skipping the changelog "because git log has it"
- Tagging a commit that was not built and tested
- Publishing from a developer machine without a clean checkout
- Re-tagging a published version to fix a mistake (cut a new
patch instead)
- Pre-1.0 projects that promise stability they cannot keep
1---2name: release-semver-33description: Semantic versioning releases — version bumps, changelogs, tags, publishing. Use when preparing a new release: deciding the version bump, drafting the changelog, tagging the commit, and publishing to the project's distribution channel.4---56# Semantic Versioning Release Process78## Intro910Releases are routine, not heroic. Decide the version bump from the11nature of the changes, draft a changelog, update version files in12one commit, tag with `vX.Y.Z`, and publish. The goal is a release13anyone on the team can perform from the same checklist.1415## Overview1617### Determine the version bump1819Semantic versioning has three numbers: MAJOR.MINOR.PATCH.2021- **Patch** (0.1.0 → 0.1.1): bug fixes only, no API changes.22- **Minor** (0.1.0 → 0.2.0): new features, backward-compatible.23- **Major** (0.1.0 → 1.0.0): breaking changes.2425Pre-1.0 projects bend the rules: minor bumps are allowed to break26compatibility, and patch bumps cover both features and fixes. Once27you ship 1.0, the rules become strict.2829### Pre-release checklist3031- All tests pass on the main branch.32- No uncommitted changes in the working tree.33- Dependencies reviewed and up to date where appropriate.34- CHANGELOG or release notes drafted.3536### Draft the changelog3738Group entries under **Added**, **Changed**, **Fixed**, and39**Removed**. Reference issue and PR numbers. Note breaking changes40prominently — call them out in their own section if a major bump41is involved.4243### The release flow (single turn, bulletproof)4445A release is **one continuous sequence** — you do not stop halfway.46`/pk-release vX.Y.Z` runs every step below in order, in the same47turn, and is not considered done until the final verification48passes. See DEC-20260422_1348-SnowyWolf.49501. **Bump version** in every relevant file (`aibox.lock`,51 `Cargo.toml`, `pyproject.toml`, `package.json`, lockfiles).522. **Finalize CHANGELOG** — rename the `[vX.Y.Z-candidate]` section53 to `[vX.Y.Z] — YYYY-MM-DD`; ensure Added/Changed/Fixed/Removed54 grouping; call out breaking changes if a major bump.553. **Regenerate provenance / transitive artifacts** — for processkit,56 `scripts/stamp-provenance.sh vX.Y.Z`.574. **Commit** the bump with message `chore(release): bump to vX.Y.Z`.585. **Tag** the commit: `git tag -a vX.Y.Z -m "<tag summary>"`.596. **Push** branch then tag: `git push origin main && git push origin vX.Y.Z`.60 A tag push alone does **not** create a GitHub Release — it is a61 git ref, not a distribution-channel artifact.627. **Create the GitHub Release** with notes extracted from the63 CHANGELOG. The single canonical command:64 ```bash65 gh release create vX.Y.Z \66 --repo <org>/<repo> \67 --title "vX.Y.Z — <one-line summary>" \68 --notes-file <(awk -v v=X.Y.Z '69 $0 ~ "^## \\[v" v "\\]" { f=1; next }70 f && /^## \[/ { f=0 }71 f72 ' CHANGELOG.md) \73 --latest74 ```758. **Verify** the Release is live. This is the release's76 completion gate:77 ```bash78 gh release view vX.Y.Z --repo <org>/<repo>79 ```80 If this exits non-zero, the release is **incomplete** — return81 to step 7. Do not report the release as done until step 882 succeeds.839. **Other channels** (crates.io, PyPI, npm, container registry,84 homebrew tap, etc.) — run after step 8 so the GitHub Release85 remains the canonical artifact pointer.8687**Recovery pattern** — if a tag was pushed in a prior session88without the Release, run `gh release create` and `gh release view`89for that tag directly; `/pk-publish` exists as an alias for this90recovery scenario.9192**pk-doctor `release_integrity` check (detection layer)** — walks93every local `v*` git tag, probes GitHub for a matching Release, and94WARNs on any tag without one. Run `/pk-doctor --category=release_integrity`95after a release to confirm; run `/pk-doctor` routinely to catch any96historical gap. Requires `gh` CLI + auth; emits INFO when `gh` is97unavailable.9899### Example100101User says: "Let's release — we fixed two bugs and added a feature."102The agent recommends a minor bump (because of the new feature),103drafts changelog entries grouped Added/Fixed, updates version104files, creates the bump commit, and tags it.105106This skill also provides the `/pk-release` and `/pk-publish` commands107for direct invocation — see `commands/pk-release.md` and108`commands/pk-publish.md`.109110## Gotchas111112Agent-specific failure modes — provider-neutral pause-and-self-check items:113114- **Bundling a breaking change into a patch or minor release.** Consumers rely on semver guarantees to control when they take breaking changes. A breaking change in a patch release violates the contract and causes silent runtime failures in consumer code.115- **Skipping the changelog because "git log has it".** Git log is not a changelog. It lacks context, grouping, and the human judgment that makes a changelog useful. Every release needs a curated changelog with Added/Changed/Fixed/Removed sections.116- **Bumping all version files in separate commits.** A brief window where `Cargo.toml` says `1.2.0` but `pyproject.toml` still says `1.1.0` is a broken state. Update all version files in a single atomic commit.117- **Tagging before CI passes.** A tag should point to a commit that has been fully built and tested. Tagging a commit that later fails CI means the published artifact may not match what was verified.118- **Publishing from a developer machine without a clean checkout.** Uncommitted local changes — WIP files, debug flags, `console.log` statements — may sneak into the artifact. Publish from CI with a clean checkout or from a fresh clone.119- **Re-tagging a published version to fix a mistake.** Package registries (crates.io, PyPI, npm) prohibit or block re-publishing to an existing version. Cut a new patch version (e.g. `1.2.1`) to fix a mistake in `1.2.0`; never overwrite a tag.120- **Pre-1.0 projects that promise stability they cannot keep.** If the API is still moving, stay below 1.0 and say so. Cutting `1.0.0` too early creates a compatibility obligation that slows future improvements.121- **Treating `git push --tags` as "the release is out."** Pushing a tag creates a git ref; it does **not** create a GitHub Release, a crates.io release, a PyPI release, or any other distribution-channel artifact. Downstream consumers (package managers, `gh api`, the Releases page, auto-sync tools like aibox) read from the channel, not the tag. Until `gh release create` (or the equivalent channel publish command) has run, the release is not visible. The flow above bakes this in: the release is not complete until step 8 (`gh release view`) succeeds. See DEC-20260422_1348-SnowyWolf.122- **Stopping after `/pk-release` prepare-like work.** In an older split where `/pk-release` prepared and `/pk-publish` published, it was easy to do only half. The current flow is single-turn: /pk-release runs every step through GitHub-Release verification. /pk-publish remains only as a recovery alias for historical tags without Releases.123124## Full reference125126### When pre-1.0 ends127128Cut 1.0 when the public API is something you are willing to129support without breaking. Until then, keep the version below 1.0130honestly — there is no shame in 0.17.0, and it signals to users131that the surface may still move.132133### Version bumps for special changes134135| Change | Bump |136|---|---|137| Bug fix that does not change behavior contract | patch |138| Performance improvement, no API change | patch |139| New feature behind a feature flag | minor |140| New optional parameter with a default | minor |141| Removing or renaming a public symbol | major |142| Changing default behavior of an existing API | major |143| Tightening input validation that rejects previously valid input | major |144| Dependency bump that surfaces in your public API | major |145146### Anti-patterns147148- Bundling breaking changes into a patch release149- Skipping the changelog "because git log has it"150- Tagging a commit that was not built and tested151- Publishing from a developer machine without a clean checkout152- Re-tagging a published version to fix a mistake (cut a new153 patch instead)154- Pre-1.0 projects that promise stability they cannot keep