---
name: release
description: Run the target project's release ceremony
phase: null
order: null
dependencies: []
outputs: []
conditional: null
stateless: true
category: tool
knowledge-base: [release-management, version-strategy]
argument-hint: "<version or --dry-run or rollback>"
---

## Purpose

Run the target project's release ceremony. Analyze conventional commits to
suggest version bumps, generate changelogs from commit history and optional
Beads tasks, run quality gates, and execute the release artifacts that project
defines. Depending on the project, that may include tags, hosted releases,
package publishes, deployments, or registry updates. Supports dry-run mode and
rollback.

## Inputs

$ARGUMENTS — parsed as:

| Argument | Mode |
|----------|------|
| _(empty)_ | **Standard** — auto-suggest bump, confirm, execute |
| `major`, `minor`, or `patch` | **Explicit** — use specified bump, skip suggestion |
| `current` | **Current** — use the version already in files, no additional bump |
| `--dry-run` | **Dry Run** — all analysis, zero mutations |
| `rollback` | **Rollback** — jump directly to the Rollback section |

Combine flags freely (e.g., `minor --dry-run`).

## Expected Outputs

- Version files updated to new version
- `CHANGELOG.md` updated with grouped commit entries
- Release artifacts defined by the target project (for example: git tag, hosted release, package publish, deployment)
- Single commit with message `chore(release): vX.Y.Z`

## Instructions

### Phase 0: Project Detection

Gather project context before proceeding. Check each item and record findings:

#### 0.1 Git State

1. Confirm the working tree is clean (`git status --porcelain`). If there are uncommitted changes, **stop** and tell the user: "Working tree has uncommitted changes. Commit or stash them before releasing."
2. Record the current branch name (`git branch --show-current`).
3. Check whether optional release tooling is available when the project needs it (for example `gh` for GitHub-hosted releases). If a required tool is missing, record that gap and stop before the publish/deploy phase.
4. Fetch tags: `git fetch --tags`.

#### 0.2 Version File Detection

Scan the project root for version files. For each found file, record the current version:

| File | How to Read Version |
|------|-------------------|
| `package.json` | `.version` field |
| `pyproject.toml` | `[project].version` or `[tool.poetry].version` |
| `Cargo.toml` | `[package].version` |
| `.claude-plugin/plugin.json` | `.version` field |
| `pubspec.yaml` | `version:` field |
| `setup.cfg` | `[metadata].version` |
| `version.txt` | Entire file contents (trimmed) |

If **no** version files are found, note this — the release may rely on tags or other non-version-file artifacts only.

#### 0.3 Project Context

- Check for `.beads/` directory — enables Beads integration in release notes.
- Check for existing `CHANGELOG.md`.
- List existing `v*` tags: `git tag -l 'v*' --sort=-v:refname | head -5`.
- Inspect the project's release workflow docs and automation (`README.md`, release docs, manifest scripts, CI workflows) to determine which release artifacts apply. Record whether the project expects any of:
  - version tag
  - hosted release page (GitHub/GitLab/etc.)
  - package publish (npm, PyPI, crates.io, etc.)
  - deployment or registry update
  - a PR-based release lane instead of direct tagging from the current branch

If the release process is not clear from the repository, stop and ask the user before publishing or deploying anything.

#### 0.4 Mode Selection

Parse `$ARGUMENTS` to determine the mode:

| Argument | Mode |
|----------|------|
| _(empty)_ | **Standard** — auto-suggest bump, confirm, execute |
| `major`, `minor`, or `patch` | **Explicit** — use specified bump, skip suggestion |
| `current` | **Current** — use the version already in files, no additional bump |
| `--dry-run` | **Dry Run** — all analysis, zero mutations |
| `rollback` | **Rollback** — jump directly to the Rollback section |

If `--dry-run` is combined with a bump type (e.g., `minor --dry-run`), use both: explicit bump + dry-run mode.

If the mode is **Rollback**, skip to the **Rollback** section below.

#### 0.5 First-Release Detection

If **no** `v*` tags exist:

1. Tell the user: "No previous releases found. This will be your first release."
2. Ask: "What should the initial version be?" Suggest `0.1.0` (pre-release) or `1.0.0` (stable).
3. Record the chosen version. Skip Phase 1 (version analysis) — go directly to Phase 2.

#### 0.6 Version Mismatch Detection

**Skip if:** First-release mode (Phase 0.5) or `current` mode.

If `current` mode was specified: use the version from files as the release version, skip Phase 1 and Phase 4 (version bump) — proceed directly to Phase 2 (quality gates).

Otherwise, compare the version in files against the last tag:

- If the version in files **is greater than** the version from the last tag (e.g., files say `0.2.0`, last tag is `v0.1.0`):
  1. Ask: "Version files show `<file-version>` but the last tag is `<last-tag>`. It looks like the version was already bumped (perhaps via `/scaffold:version-bump`). Release `<file-version>` as-is, or analyze commits for a further bump?"
  2. **"Release as-is"**: Use `<file-version>` as the release version. Skip Phase 1 and Phase 4 — proceed to Phase 2.
  3. **"Bump further"**: Proceed normally through Phase 1, bumping from the current file version.

- If the versions match or files are less than/equal to the last tag: proceed normally.

---

### Phase 1: Version Analysis

**Skip this phase if:** First-release mode (Phase 0.5) or Explicit mode.

#### 1.1 Collect Commits

Get commits since the last tag:

```
git log <last-tag>..HEAD --oneline --no-merges
```

#### 1.2 Parse Conventional Commits

Categorize each commit:

| Pattern | Bump |
|---------|------|
| `feat:` or `feat(scope):` | minor |
| `fix:` or `fix(scope):` | patch |
| `BREAKING CHANGE:` in body or `!:` suffix | major |
| `perf:`, `refactor:`, `docs:`, `chore:`, `style:`, `test:`, `build:`, `ci:` | patch (non-feature change) |

Apply the **highest-wins** rule: if any commit triggers major, the suggestion is major; otherwise if any triggers minor, the suggestion is minor; otherwise patch.

#### 1.3 Present Analysis

Show the user:

```
Commits since <last-tag>: <count>
  feat:  <count> commits
  fix:   <count> commits
  other: <count> commits
  BREAKING: <yes/no>

Suggested bump: <major|minor|patch>
  <current-version> → <new-version>
```

Ask: "Confirm this bump, or override? (major / minor / patch / confirm)"

If **no conventional commits** were found, fall back: "No conventional commits found. What type of bump? (major / minor / patch)"

Record the confirmed version.

---

### Phase 2: Pre-Release Validation

#### 2.1 Detect Quality Gates

Look for quality gate commands in this order (use the first match):

1. `Makefile` with `check` target — `make check`
2. `Makefile` with `test` target — `make test`
3. `package.json` with `test` script — `npm test`
4. `Cargo.toml` exists — `cargo test`
5. `pyproject.toml` or `setup.cfg` — `pytest`
6. None found — warn and skip

#### 2.2 Run Quality Gates

**In dry-run mode:** Show which command would run but do not execute. Skip to Phase 3.

Run the detected quality gate command. Report the result.

- **If it passes:** "Quality gates passed. Proceeding."
- **If it fails:** "Quality gates failed. Fix the issues and re-run `/scaffold:release`. To force release despite failures, re-run with the `--force` flag." **Stop here** unless `--force` was passed.

---

### Phase 3: Changelog & Release Notes

#### 3.1 Group Commits

Group commits since the last tag (or all commits for first release) by type:

```markdown
## [vX.Y.Z] - YYYY-MM-DD

### Added
- feat: description (commit-hash)

### Fixed
- fix: description (commit-hash)

### Changed
- refactor: description (commit-hash)
- perf: description (commit-hash)

### Other
- chore: description (commit-hash)
```

Omit empty sections. Use the commit's first line (without the type prefix) as the description.

#### 3.2 Beads Integration (conditional)

If `.beads/` exists:

1. Run `bd list --status closed --json` (canonical). If `bd` is unavailable in this environment, skip the autogenerated closed-tasks section — manual changelog entry expected.
2. Cross-reference closed tasks with the commit range (match task IDs like `bd-xxxx` or `scaffold-xxx` in commit messages).
3. If matches found, append a section:

```markdown
### Completed Tasks
- bd-<id>: Task title
- bd-<id2>: Task title
```

If `.beads/` does not exist or no tasks match, silently skip this section.

#### 3.3 Write Changelog

**In dry-run mode:** Display the changelog preview but do not write to disk. Skip to Phase 6.

- If `CHANGELOG.md` exists: prepend the new entry after the `# Changelog` heading (or after any header block).
- If `CHANGELOG.md` does not exist: create it with:

```markdown
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/).

## [vX.Y.Z] - YYYY-MM-DD
...
```

#### 3.4 Save Release Notes

Store the generated changelog entry (without the file header) for use as the hosted release body in Phase 5 when the target project creates one.

---

### Phase 4: Version Bump & Commit

**In dry-run mode:** Show which files would change and the commit message. Skip to Phase 6.

#### 4.1 Update Version Files

For each version file detected in Phase 0.2, update the version to the new value.

#### 4.2 Sync Lock Files

If applicable:
- `package-lock.json` exists — run `npm install --package-lock-only`
- `Cargo.lock` exists — run `cargo update -w`

#### 4.3 Commit

Stage all changed files and commit:

```
git add <changed-files>
git commit -m "chore(release): vX.Y.Z"
```

If Beads is configured (`.beads/` exists) and a task is active, reference the
task ID in the commit body, never the subject line (D7):
```
git commit -m "chore(release): vX.Y.Z" -m "Closes bd-<id>"
```

---

### Phase 5: Release Artifacts

**In dry-run mode:** Show what would happen. Skip to Phase 6.

#### 5.1 Determine Flow

Follow the target project's documented release lane if one exists.

- If the repo docs or automation require a release PR, release branch, or merge-first flow, use that instead of making up a direct tag flow.
- If the repo provides no release-lane guidance, use this fallback:
  - **`main` or `master`**: direct flow
  - **Any other branch**: PR flow

#### 5.2 Direct Flow

1. Create the release commit in Phase 4.
2. If the project uses version tags, create the expected tag (default: annotated `vX.Y.Z`).
3. Push the required refs for the project workflow.
4. Execute the project-defined release artifacts in dependency order. Common examples:
   - Hosted release page: create it using the repo's documented tool and the saved release notes.
   - Package publish: run the documented ecosystem publish command only when the repo clearly defines it.
   - Deployment or registry update: run only when it is part of the project's documented release process.
5. If push or any artifact step is blocked by branch protection, missing tooling, or missing credentials, stop and tell the user exactly what remains rather than guessing.

#### 5.3 PR Flow

1. Push the release branch: `git push -u origin HEAD`
2. If the project uses PR-based releases and the relevant CLI is available, open the release PR with the changelog entry as the body.
3. Tell the user the exact post-merge release actions derived from the project's docs and automation. Include only the artifacts that apply to this project.

---

### Phase 6: Post-Release Summary

Show the final summary:

```
Release vX.Y.Z complete!

  Version files updated: <list>
  Changelog: CHANGELOG.md updated
  Release artifacts completed: <list>

  To undo this release: /scaffold:release rollback
```

In dry-run mode:

```
Dry-run complete — no changes were made.

  Would bump: <current> → <new>
  Would update: <version-files>
  Would create: CHANGELOG.md entry
  Would execute: <project-specific release artifacts>

Run /scaffold:release to execute.
```

---

### Rollback

Undo the most recent release. This is a **destructive operation** with safety guards.

#### R.1 Identify Latest Release

1. Find the most recent tag: `git tag -l 'v*' --sort=-v:refname | head -1`
2. If no tags exist: "No releases found. Nothing to roll back." **Stop.**

#### R.2 Safety Confirmation

Tell the user: "To confirm rollback of `<tag>`, type the exact tag name (e.g., `v1.3.0`):"

- If the user types the correct tag name — proceed.
- If the user types anything else — "Tag name does not match. Rollback cancelled." **Stop.**

#### R.3 Execute Rollback

Perform each step. If any step fails, continue with remaining steps and report all results at the end.

1. **Delete hosted release** if the project created one and the appropriate CLI/API is available.

2. **Delete remote tag:**
   ```
   git push origin :refs/tags/<tag>
   ```

3. **Delete local tag:**
   ```
   git tag -d <tag>
   ```

4. **Revert version bump commit** (if the most recent commit message matches `chore(release): <tag>`):
   ```
   git revert HEAD --no-edit
   git push origin HEAD
   ```

5. **Handle project-specific publish/deploy rollback** only if the repository documents it. If that rollback is manual or ambiguous, stop and tell the user exactly what remains.

#### R.4 Report Results

Show what succeeded and what failed:

```
Rollback of <tag>:
  Hosted release: deleted (or failed: <error> / not applicable)
  Remote tag: deleted
  Local tag: deleted
  Version bump commit: reverted

Rollback complete.
```

If any step failed, include manual cleanup instructions for that step.

---

## Process Rules

1. **Never skip quality gates** without explicit user `--force`.
2. **Dry-run: zero mutations** — no file writes, no git operations, no hosted-release API calls, no publishes, and no deploys.
3. **Beads integration is optional** — silently skip if `.beads/` doesn't exist.
4. **Release artifacts are project-specific** — only run tag/publish/deploy steps that the target project documents.
5. **Every confirmation must be explicit** — don't assume "yes" from silence.
6. **Rollback requires exact tag name** — not just "yes" or "confirm".

## After This Step

When this step is complete, tell the user:

---
**Release complete** — version bumped, changelog updated, and the target project's release artifacts were handled.

**Next (if applicable):**
- If follow-up tasks are needed: Run `/scaffold:quick-task` — Create a focused task for post-release work.
- If the release needs undoing: Run `/scaffold:release rollback` — Undo the most recent release and any clearly documented release artifacts.
- For development milestone checkpoints without releasing: Run `/scaffold:version-bump` — Bump version and changelog only.

**Pipeline reference:** `/scaffold:prompt-pipeline`

---
