src/main/resources/targets/claude/skills/core/ops/x-release/SKILL.md
Orchestrates complete release flow using Git Flow release branches with approval gate, PR-flow (gh CLI) and deep validation: version bump (auto-detect or explicit), release branch creation from develop, deep validation (coverage, golden files, version consistency), version file updates, changelog generation, release commit, release PR via gh (optionally reviewed by x-review-pr), human approval gate with persistent state file, tag on main after merged PR, back-merge PR to develop with conflict detection, and cleanup. Supports hotfix releases from main, dry-run mode, resume via --continue-after-merge, in-session pause via --interactive, GPG-signed tags, skip-review opt-out, and custom state file path.
npx skillsauth add edercnj/claude-environment x-releaseInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
/x-release — auto-detect version bump from Conventional Commits
/x-release major|minor|patch — explicit bump type
/x-release 2.1.0 — explicit version
/x-release minor --dry-run — preview plan without executing
/x-release minor --dry-run --interactive — interactive dry-run, pauses before each phase
/x-release patch --hotfix — hotfix release from main
/x-release patch --skip-tests — skip test validation
/x-release --continue-after-merge — resume after release PR manually merged
/x-release --status — show current release status (read-only)
/x-release --abort — abort active release with cleanup
| Flag | Description |
|------|-------------|
| Bump type or X.Y.Z | major, minor, patch, or explicit version. Auto-detect from Conventional Commits if omitted (see references/auto-version-detection.md). VERSION_NO_BUMP_SIGNAL when no qualifying commits found. VERSION_INVALID_FORMAT when explicit version fails ^\d+\.\d+\.\d+$. |
| --dry-run | Preview plan without executing any changes |
| --hotfix | Create hotfix release from main instead of develop |
| --continue-after-merge | Resume from APPROVAL_PENDING state after PR merged. Requires existing state file. |
| --interactive | Opt-in to gate menus (PROCEED/FIX-PR/ABORT) at Phase 8. With --dry-run: pauses before each phase. Default: non-interactive (Rule 20, EPIC-0061). |
| --non-interactive | DEPRECATED — was CI opt-in; now equals default. Emits WARN. Removed in 2 releases. |
| --skip-review | Skip x-review-pr fire-and-forget in OPEN-RELEASE-PR |
| --ci-watch | Opt-in: poll CI on release PR via x-watch-pr-ci; abort on CI failure |
| --signed-tag | Create GPG-signed tag (git tag -s) instead of annotated |
| --skip-tests | Skip VALIDATE-DEEP test execution (warning emitted) |
| --no-publish | Create release locally without pushing |
| --no-github-release | Skip GitHub Release prompt in Phase 11 (CI path) |
| --state-file <path> | Override state file path (default: ai/releases/release-state-X.Y.Z.json) |
| --abort [--yes] | Abort active release: close PRs, delete branches, remove state file. --yes skips confirmations. |
| --status | Show current release status read-only; exit 0 |
13-phase workflow:
0. RESUME-DETECT → 1. DETERMINE → 1.5. PRE-FLIGHT → 2. VALIDATE-DEEP
→ 3. BRANCH → 4. UPDATE → 5. CHANGELOG → 6. COMMIT → 7. OPEN-RELEASE-PR
→ 7.5. CI-WATCH (opt-in) → 8. APPROVAL-GATE → 9. TAG → 10. BACK-MERGE-DEVELOP
→ 11. PUBLISH → 12. CLEANUP → 13. SUMMARY
Phase VALIDATE-DEEP (replaces Step 2): 10 checks; advances state file phase: VALIDATED. --skip-tests skips checks 4, 5, 6; checks 1, 2, 3, 7, 8 are always-mandatory; check 9 conditional on {{GENERATION_COMMAND}} presence; check 10 bypassed with --skip-integrity.
| # | Check | Command | Error Code |
|---|-------|---------|-----------|
| 1 | Working dir clean | git status --porcelain | VALIDATE_DIRTY_WORKDIR |
| 2 | Correct base branch | git branch --show-current | VALIDATE_WRONG_BRANCH |
| 3 | [Unreleased] CHANGELOG section non-empty | parse CHANGELOG.md | VALIDATE_EMPTY_UNRELEASED |
| 4 | Build passes | {{BUILD_COMMAND}} | VALIDATE_BUILD_FAILED |
| 5 | Coverage ≥ {{COVERAGE_LINE_THRESHOLD}}% line / {{COVERAGE_BRANCH_THRESHOLD}}% branch | coverage report | VALIDATE_COVERAGE_LINE / VALIDATE_COVERAGE_BRANCH |
| 6 | Golden files current | {{GOLDEN_TEST_COMMAND}} | VALIDATE_GOLDEN_DRIFT |
| 7 | No hardcoded version | grep -r CURRENT_VERSION | VALIDATE_HARDCODED_VERSION |
| 8 | Cross-file version consistency | diff version files | VALIDATE_VERSION_MISMATCH |
| 9 | Generation dry-run | {{GENERATION_COMMAND}} | VALIDATE_GENERATION_DRIFT |
| 10 | Integrity drift | drift analysis | INTEGRITY_DRIFT |
Thirteen phases (Rule 25 REGRA-001, EPIC-0055). Each numbered phase opens with a PRE gate + TaskCreate, closes with a POST/FINAL gate + TaskUpdate(completed). Phases 0, 1.5, 7.5 are exempted from gates (resume-detect, pre-flight, and optional CI-Watch). Full per-phase implementation in references/full-protocol.md.
Open a phase tracker (close with TaskUpdate(id: phase0TaskId, status: "completed") after resume check):
TaskCreate(subject: "RELEASE › Phase 0 - Resume Detect", activeForm: "Detecting release resume state")
Check for existing state.json (--state-file override or default ai/releases/release-state-X.Y.Z.json). If --continue-after-merge: load state, verify phase == APPROVAL_PENDING. Handle --status (read-only, exit 0) and --abort. See references/full-protocol.md §Phase 0.
Persist interactiveMode to release state (EPIC-0068 — consumed by Stop hook enforce-continuous-flow.sh):
Skill(skill: "x-internal-update-status", args: "--file ai/releases/release-state-{version}.json --type release --id <VERSION> --field interactiveMode --value <interactive|non-interactive>")
Value: "interactive" when --interactive passed or CLAUDE_LEGACY_INTERACTIVE=1; otherwise "non-interactive" (Rule 20 default, EPIC-0061).
TaskUpdate(id: phase0TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-1-Determine")
TaskCreate(subject: "RELEASE › Phase 1 - Determine", activeForm: "Determining release version")
Detect bump type from Conventional Commits (feat:→MINOR, fix:→PATCH, !:→MAJOR) or apply explicit argument. Validate X.Y.Z format. Emit VERSION_NO_BUMP_SIGNAL when no qualifying commits. Write initial state.json with version, bumpType, phase: DETERMINED. See references/auto-version-detection.md.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-1-Determine --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase1TaskId, status: "completed")
<!-- phase-no-gate: pre-flight is a lightweight advisory check with no artifact output -->
Open a phase tracker (close with TaskUpdate(id: phase15TaskId, status: "completed") after checks):
TaskCreate(subject: "RELEASE › Phase 1.5 - Pre-Flight", activeForm: "Running pre-flight checks")
Advisory checks: git remote reachable, no active release branch of same version, enough disk space for worktree. Warn on issues; do not abort. See references/full-protocol.md §Phase 1.5.
TaskUpdate(id: phase15TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-2-ValidateDeep")
TaskCreate(subject: "RELEASE › Phase 2 - Validate Deep", activeForm: "Running deep validation checks")
Run the 10-check VALIDATE-DEEP matrix (see table above). Advance state to phase: VALIDATED. Errors: VALIDATE_DIRTY_WORKDIR, VALIDATE_BUILD_FAILED, VALIDATE_COVERAGE_LINE, VALIDATE_COVERAGE_BRANCH, VALIDATE_GOLDEN_DRIFT, VALIDATE_EMPTY_UNRELEASED, VALIDATE_HARDCODED_VERSION, VALIDATE_VERSION_MISMATCH, VALIDATE_GENERATION_DRIFT, INTEGRITY_DRIFT. See references/full-protocol.md §Phase 2.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-2-ValidateDeep --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase2TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-3-Branch")
TaskCreate(subject: "RELEASE › Phase 3 - Branch", activeForm: "Creating release branch")
Invoke x-create-git-branch to create release/X.Y.Z from develop (or hotfix/X.Y.Z from main when --hotfix). Idempotent: no-op if branch already exists. Advance state to phase: BRANCHED. See references/full-protocol.md §Phase 3.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-3-Branch --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase3TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-4-Update")
TaskCreate(subject: "RELEASE › Phase 4 - Update", activeForm: "Updating version files")
Bump version in all version-bearing files (pom.xml, version constants, etc.) to X.Y.Z. Cross-validate all files agree. Advance state to phase: UPDATED. See references/full-protocol.md §Phase 4.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-4-Update --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase4TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-5-Changelog")
TaskCreate(subject: "RELEASE › Phase 5 - Changelog", activeForm: "Generating changelog entry")
Invoke x-generate-release-changelog to promote [Unreleased] section to [X.Y.Z] - DATE. Advance state to phase: CHANGELOG_UPDATED. See references/full-protocol.md §Phase 5.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-5-Changelog --expected-artifacts CHANGELOG.md")
TaskUpdate(id: phase5TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-6-Commit")
TaskCreate(subject: "RELEASE › Phase 6 - Commit", activeForm: "Committing release artifacts")
Commit version bumps + CHANGELOG via x-commit-changes with message chore(release): X.Y.Z. Push release/X.Y.Z to origin. Advance state to phase: COMMITTED. See references/full-protocol.md §Phase 6.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-6-Commit --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase6TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-7-OpenReleasePR")
TaskCreate(subject: "RELEASE › Phase 7 - Open Release PR", activeForm: "Opening release PR to main")
Create PR release/X.Y.Z → main via gh pr create. If --skip-review absent: fire x-review-pr in background (fire-and-forget). Advance state to phase: PR_OPEN. Record prNumber in state. See references/full-protocol.md §Phase 7.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-7-OpenReleasePR --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase7TaskId, status: "completed")
<!-- phase-no-gate: optional CI-watch poll loop; skipped unless --ci-watch flag present -->
Open a phase tracker only when --ci-watch is set (close with TaskUpdate after poll completes):
TaskCreate(subject: "RELEASE › Phase 7.5 - CI Watch", activeForm: "Polling CI on release PR")
MANDATORY TOOL CALL — NON-NEGOTIABLE (Rule 24 + Rule 45): Invoke the x-watch-pr-ci skill via the Skill tool on prNumber. On CI_FAILED (exit 20) or TIMEOUT (exit 30): abort release with corresponding error. On success (exit 0): advance to Phase 8. See references/full-protocol.md §Phase 7.5.
Skill(skill: "x-watch-pr-ci", args: "--pr-number {prNumber}")
TaskUpdate(id: phase75TaskId, status: "completed")
Bash command: $CLAUDE_PROJECT_DIR/.claude/hooks/telemetry-phase.sh start x-release Phase-Approval-Gate
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-8-ApprovalGate")
TaskCreate(subject: "RELEASE › Phase 8 - Approval Gate", activeForm: "Awaiting release approval")
Persist state with phase: APPROVAL_PENDING. Present EPIC-0043 gate menu (PROCEED / FIX-PR / ABORT) unless --non-interactive. On PROCEED: advance to Phase 9 (TAG). On FIX-PR: Skill(skill: "x-fix-pr", args: "<prNumber>") then loop (max 3 cycles). See references/approval-gate-workflow.md.
Bash command: $CLAUDE_PROJECT_DIR/.claude/hooks/telemetry-phase.sh end x-release Phase-Approval-Gate ok
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-8-ApprovalGate --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase8TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-9-Tag")
TaskCreate(subject: "RELEASE › Phase 9 - Tag", activeForm: "Tagging release on main")
After PR merged: tag main HEAD as vX.Y.Z (annotated, or GPG-signed with --signed-tag). Push tag. Error: TAG_EXISTS. Advance state to phase: TAGGED. See references/full-protocol.md §Phase 9.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-9-Tag --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase9TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-10-BackMerge")
TaskCreate(subject: "RELEASE › Phase 10 - Back Merge Develop", activeForm: "Back-merging release into develop")
Create PR release/X.Y.Z → develop via gh pr create --auto-merge. On conflict: emit BACK_MERGE_CONFLICT; see references/backmerge-strategies.md for resolution flow. Advance state to phase: BACK_MERGED. See references/full-protocol.md §Phase 10.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-10-BackMerge --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase10TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-11-Publish")
TaskCreate(subject: "RELEASE › Phase 11 - Publish", activeForm: "Publishing GitHub release")
Unless --no-github-release: create GitHub Release via gh release create vX.Y.Z --notes-from-tag. Unless --no-publish: push any remaining artifacts. Advance state to phase: PUBLISHED. See references/full-protocol.md §Phase 11.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-11-Publish --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase11TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-12-Cleanup")
TaskCreate(subject: "RELEASE › Phase 12 - Cleanup", activeForm: "Cleaning up release branch")
Delete release/X.Y.Z branch locally and on origin. Remove state file. Advance state to phase: COMPLETED. See references/full-protocol.md §Phase 12.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode post --skill x-release --phase Phase-12-Cleanup --expected-artifacts ai/releases/release-state-{version}.json")
TaskUpdate(id: phase12TaskId, status: "completed")
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode pre --skill x-release --phase Phase-13-Summary")
TaskCreate(subject: "RELEASE › Phase 13 - Summary", activeForm: "Generating release summary")
Print Git Flow cycle explainer (see references/git-flow-cycle-explainer.md). Emit final release summary: version, tag, PR numbers, durations. Advance state to COMPLETED.
Skill(skill: "x-internal-verify-phase-gates", model: "haiku", args: "--mode final --skill x-release --phase Phase-13-Summary --expected-artifacts CHANGELOG.md")
TaskUpdate(id: phase13TaskId, status: "completed")
| Artifact | Path/Description |
|----------|-----------------|
| Release branch | release/X.Y.Z (or hotfix/X.Y.Z with --hotfix) |
| Release PR | release/X.Y.Z → main; URL in state file |
| Back-merge PR | release/X.Y.Z → develop via BACK-MERGE-DEVELOP phase; conflict-aware flow in references/backmerge-strategies.md |
| Git tag | vX.Y.Z on main HEAD after RESUME-AND-TAG via OPEN-RELEASE-PR → APPROVAL-GATE → APPROVAL_PENDING (annotated or GPG-signed) |
| State file | ai/releases/release-state-X.Y.Z.json; schema in references/state-file-schema.md; initialized with schemaVersion: 2 (.schemaVersion != 2 emits Expected: 2 error) |
| CHANGELOG | Updated CHANGELOG.md via x-generate-release-changelog |
| Code | Condition |
|------|-----------|
| VERSION_NOT_FOUND | No previous tag found; cannot auto-detect |
| DIRTY_WORKDIR | Uncommitted changes detected in VALIDATE-DEEP |
| COVERAGE_BELOW_THRESHOLD | Line < 95% or branch < 90% in VALIDATE-DEEP |
| CHANGELOG_NOT_UPDATED | [Unreleased] section empty in VALIDATE-DEEP |
| APPROVAL_GATE_ABORTED | Operator selected ABORT in Phase 8 menu |
| CI_FAILED | --ci-watch detected CI failure (exit 20) or timeout (exit 30) |
| BACK_MERGE_CONFLICT | develop diverged from release branch; manual resolution required |
| TAG_EXISTS | Git tag vX.Y.Z already present on remote |
| ABORT_NO_RELEASE | --abort called but no state file exists |
| GATE_FIX_LOOP_EXCEEDED | 3 consecutive FIX-PR cycles in Phase 8 without convergence |
Complete per-phase implementation (Phases 0-13 with decision tables, bash commands, version-detection algorithm, VALIDATE-DEEP 10-check matrix, back-merge conflict-resolution flow, SUMMARY Git Flow cycle explainer) in
references/full-protocol.md. Additional references:approval-gate-workflow.md,auto-version-detection.md,backmerge-strategies.md,state-file-schema.md,interactive-flow-walkthrough.md,prompt-flow.md,git-flow-cycle-explainer.md.
tools
Documentation automation v2: stack-aware generation from documentation.targets.
development
Generates or updates CI/CD pipelines per project stack with actionlint validation.
tools
Generates ADRs from architecture-plan mini-ADRs with sequential numbering and index update.
development
Formats source code; first step of the pre-commit chain (format -> lint -> compile).