release command
Cut a release the only sanctioned way — derive the target's declared version policy from the commit log, roll its changelog, compose an annotated tag, and optionally publish its exact declared assets. Takes the declared target's name as its only argument, or --dry-run to preview one with no write.
/ca:release$ca-release/ca-releaseAvailability is read from each shipped host catalog. Preview-only commands are marked on the page.
What it does
Section titled “What it does”This is the only sanctioned way a version tag gets created, and it holds no knowledge of any
particular project. Everything it needs — the tag prefix, which manifests carry the version, which
changelog to roll into, what counts as the payload, and any checks to run before tagging — is read
from a file the project declares at .codearbiter/release-targets.md. One row means a
single-artifact repository; several rows mean a monorepo where each artifact versions on its own.
It never invents a version number. It walks the commits in the selected target’s payload, classifies each by its Conventional Commits type, and applies whichever bump that history actually earns (a breaking change beats a feature, a feature beats a fix). The window is scoped to that target, so a sibling’s commit can never bump this one or land in its changelog. The changelog section is assembled the same mechanical way, pulled from commit footers rather than freehand summary, and a commit that should have carried one but didn’t is a hard stop rather than a gap silently papered over. Composing the tag locally and publishing it are two separate moments: nothing pushes to the remote or shows up as a GitHub Release until you explicitly authorize that second step.
/ca:release [target] | --dry-runThe main argument is the name of a row in the declared target file. It is optional when the file declares exactly one target and required when it declares more — with several declared, a bare invocation stops rather than guessing which one you meant.
--dry-run previews a release with nothing written: it resolves the row, derives the version, and
verifies changelog-footer completeness, then reports exactly what a real run would do and stops
before anything is edited, committed, or tagged. It combines with [target] exactly as a real run
does.
There is no version argument and no --auto. A number you type is a number nobody checked, and
preventing exactly that is the reason this lane exists — so the version comes from the commit history
and the declared manifests, every time, with no override. A project with no declared file yet enters
the skill’s back-fill lane, which proposes a row from what it can detect and writes nothing without
your confirmation.
Example
Section titled “Example”> /ca:release ca-codex
Resolved target `ca-codex` from .codearbiter/release-targets.md. tag series: ca-codex-v* payload: plugins/ca-codex/Working tree clean. Branch: release/prep (not the default branch — OK).Last tag in this series: ca-codex-v0.2.4 (a sibling's v2.8.13 is ignored).Scanning 9 commits in the payload...Classification: 2 feat, 4 fix, 3 chore -> minor bump.Derived version: 0.3.0. Declared manifest plugins/ca-codex/.codex-plugin/plugin.json reads 0.2.4 — will update.Changelog: all 6 feat/fix commits carry a CHANGELOG: footer.Declared pre-tag checks: 2 ran, both clean, tree unchanged.Composed annotated tag ca-codex-v0.3.0 locally. Nothing pushed — authorize to publish.When to reach for it
Section titled “When to reach for it”Reach for /ca:release once the target’s branch is clean and its suite is green and you’re ready to
cut a version. Work still in progress lands through /ca:feature or /ca:fix first — a release
aggregates what already passed, it doesn’t chase down anything new.
| Gate | When | Effect |
|---|---|---|
| target resolution | before anything is read or written | the target is looked up in the project’s declared release-targets file; an unrecognised or ambiguous name stops rather than being resolved to a guess |
| version derivation | before a tag is composed | the SemVer bump is computed mechanically from Conventional Commits in the target’s own payload — there is no way to supply a version by hand |
| changelog completeness | same phase as version derivation | every feat/fix/perf commit in the release window must carry its own changelog note; a missing one blocks rather than being auto-filled |
| publish authorization | after the tag is composed locally | the tag and the GitHub Release publish together, and only once you explicitly say to |
Related
Section titled “Related”Source
Section titled “Source”Source — plugins/ca/commands/release.md (v2.18.2)
---description: Cut a release the only sanctioned way — derive the target's declared version policy from the commit log, roll its changelog, compose an annotated tag, and optionally publish its exact declared assets. Takes the declared target's name as its only argument, or --dry-run to preview one with no write. The only path to a version tag.argument-hint: "[target] | --dry-run"---
# /ca:release — tagged release
The only permitted path to a version tag. A release is a deployment-readiness assertion: the codebase at this SHA satisfies the bar for shipping. `/ca:release` aggregates existing compliance — it does not duplicate it.
## Flow
Routes to the `release` skill, which resolves everything about the release from the project's **declared target file**, `${CLAUDE_PROJECT_DIR}/.codearbiter/release-targets.md` — the tag prefix, declared version policy, manifests, changelog, payload scope, optional checks, and optional exact release-asset inventory. Nothing about any target is written here.
`/ca:release` takes the target's name as its only argument. When the declared file names exactly one target, a bare `/ca:release` uses it; when it names more, the argument is required and the skill STOPs rather than guessing. A project with no declared file at all enters the skill's own back-fill lane, which proposes a row and writes nothing without explicit confirmation.
1. **Pre-flight** — declared row resolved, working tree clean, not on the default branch, suite green, no blocking `[CONFIRM-NN]` open. Resolve `LAST_TAG` within that target's own tag series and scope the commit window to the row's declared payload, so a sibling target's commit never bumps this one or lands in its changelog.2. **Version** — classify the window by Conventional Commits type and derive the next identity through the row's declared `version-policy` (`semver` by default). The base accounts for both the last compatible tag and every declared manifest. Every bumping commit must carry a `CHANGELOG:` footer; a missing one BLOCKs and is never auto-filled.3. **Surfaces** — roll the section into the declared changelog, update every declared manifest, and run the row's declared `pre-tag` checks. After those edits are committed, an optional `release-build` produces the declared exact release-asset inventory in an empty temporary directory; tracked-tree mutation or inventory drift BLOCKs before the tag.4. **Tag** — compose the annotated tag and report any verified asset inventory. Never push it or publish a Release without explicit user authorization. On authorization, upload only the verified inventory and require the published names to match exactly.
## Dry run
`/ca:release --dry-run [target]` runs Flow steps 1 and 2 above — Pre-flight in full, then Version'sread-only derivation: resolving the row, deriving the bump, classifying the window, and verifying`CHANGELOG:` footer completeness — then stops before step 3 and reports exactly what a real run woulddo: the target, the derived version and its rationale, the per-commit classification, and any blockerPre-flight or Version would itself have hit. Steps 3 (Surfaces) and 4 (Tag) never run: no changelogedit, no manifest bump, no commit, no declared `pre-tag` check execution, no tag. The report alsoprints the resolved row's fields verbatim, which doubles as a way to validate a freshly authored`${CLAUDE_PROJECT_DIR}/.codearbiter/release-targets.md` without tagging anything. Declared `pre-tag` checksare listed, not run — they assert against the manifests AFTER the bump this mode never performs, sorunning them early would report false failures against files `--dry-run` deliberately leavesuntouched, not a preview of anything real. A declared `release-build` and its asset templates are alsolisted but never executed or rendered into files. `release`'s own SKILL.md is authoritative for the exactstopping point.
## Arguments
- **`[target]`** — the name of a row in the declared target file (e.g. the name in `[ca]`). Optional only when exactly one target is declared. An unrecognised name STOPs; it is never resolved to a guess.- **`--dry-run`** — preview a release with no write; see "Dry run" above. Combines with `[target]` exactly as a real run does — required only when more than one target is declared.
There is no version or `--auto` argument. The version is always derived from the commit log and the declared manifests — supplying one by hand is the thing this lane exists to prevent.
## Routes to
`release` (`${CLAUDE_PLUGIN_ROOT}/skills/release/SKILL.md`), which is authoritative for the phase contents and gates summarized above.
## When NOT to use
- Tagging an in-progress branch → land work first via `/ca:feature` / `/ca:fix`.- Pushing an already-composed tag → that is a separate user-authorized step.- A changelog only → it is a phase output, not a standalone deliverable.- Creating a declared target file ahead of a release → that is `context-creation`'s job, or the skill's back-fill lane at release time.
## Hard gate
MUST NOT compose a tag on a red suite. MUST NOT guess the version — it is derived from the commit log and the declared manifests. MUST NOT auto-fill a missing `CHANGELOG:` footer. MUST NOT resolve an unrecognised or ambiguous target to a guess. MUST NOT write to the default branch or force-push. MUST NOT push the tag or publish a Release without explicit user authorization. MUST NOT write, commit, or tag anything under `--dry-run` — it stops before Version step 3's writes even reach the working tree. Any BLOCK may be bypassed only via `/ca:override`.