Release Runbook
Table of Contents
- Purpose
- Prerequisites
- Gate Definitions
- No Bypass Policy
- Rollback Semantics
- Cross-Client Notes
- Related Documentation
Purpose
pm-skills releases require strict discipline: aggregate counters must match declared values; the pre-tag validator bundle must pass; CHANGELOG entries must follow CLAUDE.md hygiene; the tag must point at a commit that contains release-prep edits (not a pre-edit HEAD).
Historically, the runbook lived in the maintainer’s head plus partial release-plan checklists. Drift between releases produced incidents (e.g., the v2.13.1 plugin install path correction was a post-tag detection that required a fast patch ship). This runbook codifies the gates so drift is structurally impossible.
The pm-release-conductor sub-agent (v2.16.0+) automates the discipline. It reads this runbook at invocation time and walks each gate with the maintainer. Maintainers running releases manually follow the same gates; the conductor reduces friction.
flowchart TD
Start([Maintainer invokes /pm-release vX.Y.Z<br/>or runs runbook by hand]) --> Pre[Prerequisites check]
Pre -->|missing| PreFail[Pause: prep prerequisites first]
Pre -->|complete| G0
G0[G0: Pre-tag readiness<br/>validators + em-dash + counters + governance]
G0 -->|fail any sub-check| GFail[Pause: fix; re-enter gate]
G0 -->|all pass| G1
G1[G1: Adversarial review<br/>Codex / cross-LLM review status]
G1 -->|no review or P0 open| GFail
G1 -->|review stable, P0 closed| G2
G2[G2: Version bump + CHANGELOG prep<br/>via pm-changelog-curator]
G2 -->|hygiene violations| GFail
G2 -->|draft clean| G25
G25[G2.5: Commit release-prep + re-verify<br/>capture commit SHA]
G25 -->|re-verify fails| GFail
G25 -->|all green, SHA captured| G3
G3[G3: Tag + push<br/>tag points at G2.5-captured SHA per D22]
G3 -->|push fails| GFail
G3 -->|tag pushed| G4
G4[G4: Post-tag hygiene<br/>GitHub Release UI + post-tag artifact sweep]
G4 --> Done([Release shipped])
GFail -.->|maintainer attempt bypass| Refuse[Conductor refuses bypass<br/>per D8 + no-bypass policy]
Refuse -.-> GFail
The flowchart shows the happy path (left-to-right vertical sequence) plus the universal failure exit. The conductor refuses any bypass attempt at any gate (per master plan D8); the dotted arrow indicates a refusal cycle. G2.5 is the architectural invariant that prevents broken tags: the tag at G3 points at the SHA captured at G2.5, not at a pre-edit HEAD.
Prerequisites
Before invoking the runbook (manually or via /pm-release v{X.Y.Z}):
- Master plan exists at
docs/internal/release-plans/v{target}/plan_v{target}.mdwith status block reflecting current state - Release notes drafted at
docs/releases/Release_v{target}.md(or scheduled for G2) - Phase 0 Adversarial Review completed (Codex or alternate cross-LLM review run against the release-prep state)
- Current branch is
main(or designated release branch) - Local repo is up to date with
origin/main
Gate Definitions
G0: Pre-Tag Readiness
Goal: Confirm the codebase is in a releasable state. All validators green; em-dash sweep clean; aggregate counters match declared values; no cross-cutting governance issues.
Sub-checks (all must PASS):
- Working tree clean -
git status --porcelainempty (no uncommitted changes) - Pre-tag validator bundle green - run
bash scripts/pre-tag-validate.sh(Linux/macOS) orpwsh scripts/pre-tag-validate.ps1(Windows); exit 0 required. This canonical orchestration script runs the full enforcing validator-script inventory codified per thefeedback_pre-tag-validator-bundlememory rule (established 2026-05-16); consult the script for the current list, which changes as validators are added. The bundle covers validator scripts only - it is NOT the full release gate. The complete CI gate (verified green on the tag SHA at G3) additionally enforcesnpm run build, edit-link verification,validate-plugin-install, and cross-doc reference checks (see.github/workflows/validation.yml). - Em-dash sweep clean - run
scripts/check-em-dashes(canonical implementation per master plan D27); scope and allowlist owned by that script; zero non-allowlisted hits required - Aggregate counters match declared - re-derive skill count, command count, sub-agent count, validator count, family count; compare to declared values in
_agent-context/claude/CONTEXT.md,AGENTS.md,README.md. Zero drift. Implementation EXTENDScheck-landing-page-countsto cover internal-context surfaces per ci-plan v2.15.1 carry-in reconciliation. - Cross-cutting audit clean - chain to
pm-skill-auditorfor the full audit. Auditor returns layered output (full findings + Status Summary + Status YAML). Zero P0 findings required. P1+P2+P3 surfaced for maintainer judgment. - Required files exist - master plan at
docs/internal/release-plans/v{target}/plan_v{target}.mdexists and is marked READY TO TAG (or equivalent status); release notes draft exists or scheduled for G2
Blocker: any sub-check failure pauses G0. Maintainer resolves and re-runs G0.
G1: Adversarial Review Status
Goal: Confirm Phase 0 Adversarial Review is complete and findings dispositioned.
Sub-checks:
- Phase 0 review complete - maintainer attests the Codex (or alternate cross-LLM) adversarial review has been run against the release-prep state
- Findings dispositioned - all P0 findings closed; P1 findings closed OR explicitly deferred to next release with rationale; P2 + P3 acknowledged
- Review artifact exists (informational only) - if
_NOTES/ordocs/internal/release-plans/v{target}/review/contains the review record, the conductor reads it for context
Blocker: maintainer confirmation required. The conductor cannot auto-detect Phase 0 review status; this is a maintainer attestation gate.
G2: Version Bump + CHANGELOG Prep
Goal: Apply release-state edits to public-facing surfaces (plugin manifest, marketplace manifest, CHANGELOG, doc-site changelog mirror, README badges, plan status, release notes).
Sub-checks (conductor proposes each edit; maintainer confirms):
- plugin.json version field - edit
.claude-plugin/plugin.jsonversionto target version - Marketplace manifest version - edit
.claude-plugin/marketplace.json(or equivalent) to match - CHANGELOG.md header - chain to
pm-changelog-curatorfor a draft of entries; maintainer reviews + edits; new## [vX.Y.Z] - YYYY-MM-DDheader at top - docs/changelog mirror - update Astro-rendered changelog mirror to match
- README badges - version badges in
README.mdupdated to target version - Release plan status -
plan_v{target}.mdstatus block updated toSHIPPED YYYY-MM-DD - Release notes -
docs/releases/Release_v{target}.mdexists; conductor reads it; maintainer confirms quality - Hidden-comment leak check - grep CHANGELOG.md for
<!-- justification:(pm-changelog-curator debug comments). Fail if any remain; these are intended for maintainer audit only, not for committed CHANGELOG content.
Blocker: any sub-check failure pauses G2.
G2.5: Commit Release-Prep + Re-Verify
Goal: Commit G2 edits and verify the new HEAD is releasable. This gate exists because G2 edits files WITHOUT committing; if G3 tagged the un-committed HEAD, the tag would point at a commit that does NOT contain release metadata. G2.5 closes that gap.
Critical: this gate was added per Codex review finding R01 (closed by master plan D22). Skipping G2.5 reintroduces the broken-tag class of bug that v2.13.1 surfaced.
Sub-checks:
- Working tree contains G2 edits -
git status --porcelainshows the expected G2-edited files; no surprise changes - Stage G2 edits -
git addthe specific files G2 edited; verify staged contents match expected - Commit with release-prep message - conventional commit message:
chore(v{target}): release-prep edits for v{target}or maintainer-preferred form - Working tree clean post-commit -
git status --porcelainempty - Re-run G0 sub-checks against new HEAD - validators, em-dash sweep, aggregate counter audit, cross-cutting audit (chains to pm-skill-auditor again) all run against the commit that includes release-prep edits; zero P0 findings required
- CI green on new HEAD - push the new commit to the release branch on origin; verify CI runs and passes. Block on this; the tag must point at a CI-passing commit.
- Cross-reference commit SHA captured - record the SHA that G3 will tag
Blocker: any sub-check failure pauses G2.5. The conductor refuses to advance to G3 if working tree is not clean OR if CI is not green on the new commit.
G3: Tag + Push
Goal: Create the annotated tag on the SHA captured at G2.5 and push to origin.
Sub-checks:
- Tag target SHA confirmed - G3 tags the SHA captured at G2.5 sub-check 7 (the commit containing release-prep edits and verified by CI). The conductor refuses to tag any other SHA.
- Tag message authored - conductor presents a draft annotated-tag message (multi-paragraph: title + summary + headline changes)
- Maintainer approves message - explicit confirmation required
- Tag created -
git tag -a v{target} -m '<message>' {G2.5-captured-sha} - Push tag -
git push origin v{target}(requires explicit maintainer “ship it” confirmation) - CI re-runs on tag - tag push triggers a fresh CI run; the conductor monitors the run start (does NOT wait for completion at this gate; G4 handles post-tag verification)
Blocker: maintainer must confirm “ship it” before push. The conductor never pushes without this confirmation. The conductor also refuses to tag any SHA other than the one G2.5 captured.
G4: Post-Tag Hygiene
Goal: Verify the release artifact is healthy on origin. Surface post-tag incidents with severity grading.
Sub-checks (each produces a P0/P1/P2 incident on failure per master plan D23):
- Plugin install path check (P0 on fail) - smoke-test plugin install from the new tag. Failure = release artifact is broken; blocks “Release complete” output.
- Marketplace registration (P1 on fail) - confirm marketplace listing still resolves. Failure = discoverability incident; surfaced but does not block.
- GitHub Pages rebuild (P1 on fail) - confirm doc-stack rebuild was triggered. Failure = documentation incident; surfaced but does not block.
- GitHub Release UI body (P2 reminder) - conductor reminds maintainer to author the GitHub Release UI body; does NOT auto-create.
- Next-cycle stub (P2 reminder) - create
docs/internal/release-plans/v{next-minor}/plan_v{next-minor}.mdstub if not present. - Post-tag follow-up tasks logged (P2 reminder) - any deferred items captured in the next-cycle stub.
Blocker (per D23): P0 sub-check failures block the “Release complete” output. The conductor surfaces the failure as a post-tag incident and instructs the maintainer to either resolve OR explicitly log the issue as a known regression carried to v{next-patch}. The conductor refuses to emit “Release complete: v{target}” until either path is taken. P1 and P2 sub-checks are surfaced but do not block.
No Bypass Policy
--skip-gates was deliberately removed from v2.16.0 per master plan D24 (closes Codex review R05).
If a maintainer needs to bypass a gate:
- G0 sub-check failure: the right path is almost always to fix the underlying issue. If the failure is in a validator that the maintainer believes is wrong, the right path is to fix the validator OR add an allowlist entry, then re-run G0.
- G1 (adversarial review) for a hotfix: if a CVE-driven fast patch needs to ship before a full Codex review can run, the maintainer manually runs
/jp-ai-review --reviewagainst the patch state, makes a judgment call, and confirms at the G1 gate prompt. The conductor still requires the gate confirmation. - G2 hidden-comment leak check failure: strip the comments via
sed -i.bak '/<!-- justification:/d' CHANGELOG.mdand re-run G2. - G2 dirty-tree after partial edits: if the gate fails partway through (e.g., maintainer rejects sub-check 5 README badge edit after sub-checks 1-4 already applied), the working tree contains uncommitted release-prep changes. Two recovery paths: (a) commit the partial edits in a
wip(v{target}): partial release-prepcommit, decide on the rejected sub-check separately, then resume G2 from the failed sub-check forward; (b) discard the partial edits viagit restoreon each touched file and restart G2 from scratch. The conductor will refuse to advance to G2.5 with a dirty tree. - G2.5 post-push CI failure: if G2.5 sub-check 6 fails (CI red on the release-prep commit you just pushed), the release-prep commit exists on origin but is not safe to tag. Recovery: (a) DO NOT advance to G3 (the conductor refuses anyway). (b) Fix the underlying issue. (c) Either
git commit --amendthe release-prep commit +git push --force-with-leaseto update origin (preferred when no one has pulled the bad commit; preserves a single release-prep commit in history) OR add afix(v{target}): {issue}follow-up commit +git push(preferred when the bad commit may have been pulled; keeps an audit trail). (d) Re-run G2.5 sub-checks 5-7 against the new HEAD: re-chain to auditor, verify clean tree, verify CI green, re-capture SHA. (e) Advance to G3 only after the new SHA is verified. - G4 P0 incident: the right path is to ship a fast v{next-patch} OR explicitly log the issue as a known regression in the new cycle stub. The conductor refuses to emit “Release complete” until one of these paths is taken; it does NOT prevent you from manually marking the release complete - it just won’t do it for you.
v2.17+ may reintroduce --skip-gates restricted to non-release dry-run mode only.
Rollback Semantics
If a G4 P0 (plugin install path broken) cannot be resolved post-tag, the maintainer typically ships a fast v{next-patch} (e.g., v2.16.1) rather than reverting the tag. Tag reversion is destructive and not in v2.16 scope.
The conductor surfaces the v{next-patch} path as a recommendation but does NOT initiate it. Initiating a patch ship requires a fresh /pm-release v{next-patch} invocation with a new master plan stub.
For pre-G3 failures up through G2 (gates G0, G1, G2 only): there is nothing to roll back at the git level. The working tree may have uncommitted G2 edits; see “G2 dirty-tree after partial edits” in the No Bypass Policy section above for recovery paths.
For G2.5 failures (commit happened but CI failed OR a sub-check failed post-commit): the release-prep commit exists on the release branch on origin. The commit is NOT rolled back; it is amended forward or supplemented with a follow-up fix commit. See “G2.5 post-push CI failure” in the No Bypass Policy section above for the explicit recovery procedure. Branch reset is destructive and not recommended; the release-prep commit + any follow-up fix becomes part of the tagged history once G2.5 re-verification passes.
For G3 failures BETWEEN tag creation and push: tag exists locally only; deleting locally via git tag -d v{target} is safe. The conductor never reaches “Release complete” if push fails.
For G3 failures AFTER push but BEFORE G4 P0 detection: the tag exists on origin. If the maintainer detects the issue before any external consumer pulls the tag, force-deletion is technically possible (git push origin :v{target} + local delete) but destructive and not recommended for any pm-skills release that has been announced or marketplace-registered. Prefer the fast patch ship path.
Cross-Client Notes
The pm-release-conductor sub-agent is a Claude Code plugin feature. Non-Claude clients access conductor intent via the dispatch skill at skills/utility-pm-release-conductor/SKILL.md (VALIDATED on Codex CLI 0.128.0 on 2026-05-17 via the “reference + execute inline” chain composition pattern; evidence at docs/internal/release-plans/v2.16.0/gate-test-results_2026-05-17_codex.md).
The conductor’s chain composition (G0 chain to auditor, G2 chain to curator) requires the Agent tool, which is only available in Claude Code’s plugin sub-agent runtime. On non-Claude clients, the dispatch skill uses the “reference + execute inline” pattern: instead of chaining, it inlines the auditor + curator behaviors at G0 + G2.
The maintainer running this runbook BY HAND (without any sub-agent) follows the same gate definitions. The conductor reduces friction; it does not change the runbook itself.
Related Documentation
- Sub-agent implementation:
agents/pm-release-conductor.md(referential prompt; reads this runbook at invocation time) - Behavioral spec:
docs/internal/release-plans/v2.16.0/spec_pm-release-conductor.md - Dispatch skill (cross-client):
skills/utility-pm-release-conductor/SKILL.md(VALIDATED on Codex CLI 2026-05-17) - Pre-tag validator bundle:
scripts/pre-tag-validate.{sh,ps1}(G0 + G2.5 sub-check entry point) - Chain children:
agents/pm-skill-auditor.md,agents/pm-changelog-curator.md - Chain allowlist:
agents/_chain-permitted.yaml(lists onlypm-release-conductor) - Companion command:
commands/pm-release.md - v2.15.1 clean-worktree runbook (predecessor for the manual maintainer flow):
docs/internal/release-plans/runbook_clean-worktree-cut-tag-publish.md - Adversarial review user guide (G1 context):
docs/guides/adversarial-review.md - CHANGELOG hygiene rules (G2 context):
CLAUDE.md(repo root)