Free SKILL.md scraped from GitHub. Clone the repo or copy the file directly into your Claude Code skills directory.
npx versuz@latest install max-sixty-worktrunk-claude-skills-releasegit clone https://github.com/max-sixty/worktrunk.gitcp worktrunk/SKILL.MD ~/.claude/skills/max-sixty-worktrunk-claude-skills-release/SKILL.md---
name: release
description: Worktrunk release workflow. Use when user asks to "do a release", "release a new version", "cut a release", or wants to publish a new version to crates.io and GitHub.
metadata:
internal: true
---
# Release Workflow
## Steps
1. **Run tests**: `cargo run -- hook pre-merge --yes`
2. **Check current version**: Read `version` in `Cargo.toml`
3. **Review commits**: Check commits since last release to understand scope of changes
4. **Check library API compatibility**: Run `cargo semver-checks check-release -p worktrunk` (install with `cargo install cargo-semver-checks --locked` if missing). If it reports breaking changes, the bump must be minor (pre-1.0) or major (post-1.0). See "Library API Compatibility" below.
5. **Credit contributors**: Check for external PR authors and issue reporters (see "Credit External Contributors" and "Credit Issue Reporters" below)
6. **Confirm release type with user**: Present changes summary (including semver-checks result) and ask user to confirm patch/minor/major (see below)
7. **Bump version** (must run on a clean tree — before editing CHANGELOG):
```bash
cargo release X.Y.Z -p worktrunk -x --no-publish --no-push --no-tag --no-verify --no-confirm && cargo check
```
This bumps `Cargo.toml`, `Cargo.lock`, and applies `pre-release-replacements` (e.g., `SKILL.md`'s `version:` line), then auto-commits. We'll reset this commit in step 9 to fold in the CHANGELOG.
Then sync the SHA-256 digest of `SKILL.md` in `docs/static/.well-known/agent-skills/index.json` — `cargo-release` doesn't know that file derives from `SKILL.md`, so it stays stale until the docs-sync test rewrites it:
```bash
cargo test --test integration test_docs_are_in_sync || cargo test --test integration test_docs_are_in_sync
```
The first run rewrites the digest and exits non-zero; the second confirms sync. The regenerated `index.json` is then picked up by `git add -A` in step 9.
8. **Update CHANGELOG**: Add `## X.Y.Z` section at top with changes (see MANDATORY verification below)
9. **Commit**: Reset the auto-commit from step 7, stage everything, and create the final release commit:
```bash
git reset --soft HEAD~1 && git add -A && git commit -m "Release vX.Y.Z"
```
10. **Merge to main**: `/gpk` — opens a PR, waits for CI, merges via PR (preserves worktree)
11. **Tag the merge commit and push**: After `/gpk` squash-merges, the local branch HEAD is not the commit on main. Tag the PR's merge commit explicitly so the tag is reachable from main:
```bash
MERGE_SHA=$(gh pr view --json mergeCommit --jq '.mergeCommit.oid')
git tag vX.Y.Z "$MERGE_SHA" && git push origin vX.Y.Z
```
12. **Wait for the release workflow**: The tag push triggers `release.yaml`. Launch a ci-reporter agent to monitor the run through to completion (avoid `gh run watch` — it can hang); the run ID comes from:
```bash
gh run list --workflow=release.yaml --event=push --branch=vX.Y.Z --limit 1 --json databaseId --jq '.[0].databaseId'
```
`release.yaml` builds binaries and publishes to crates.io, Homebrew, and winget automatically.
## CHANGELOG Review
Check commits since last release for missing entries:
```bash
git log v<last-version>..HEAD --oneline
```
**IMPORTANT: Don't trust commit messages.** Commit messages often undersell or misdescribe changes. For any commit that might be user-facing:
1. Run `git show <commit> --stat` to see what files changed
2. If it touches user-facing code (commands, CLI, output), read the actual diff
3. Look for changes bundled together — a "rename flag" commit might also add new features
Common patterns where commit messages mislead:
- "Refactor X" commits that also change behavior
- "Rename flag" commits that add new functionality
- "Fix Y" commits that also improve error messages or add hints
- CI/test commits that include production code fixes
Notable changes to document:
- New features or commands
- User-visible behavior changes
- Bug fixes users might encounter
**Section order:** Improved, Fixed, Documentation, Internal. Documentation is for help text, web docs, and terminology improvements. Internal is for selected notable internal changes (not everything).
**Within each section, order by impact:**
1. Breaking/behavior changes (affect existing users' workflows)
2. New user-facing features and commands
3. Performance improvements users will notice
4. Minor enhancements and display changes
5. Niche/platform-specific improvements (Nix, Windows-only, etc.)
6. Developer/internal tooling exposed to users
**Breaking changes:** Note inline with the entry, not as a separate section:
```markdown
- **Feature name**: Description. (Breaking: old behavior no longer supported)
```
Skip: internal refactors, test additions (unless user-facing like shell completion tests).
### Length and tone
**Combine related bullets.** Several PRs that share a theme — e.g. three perf changes that together account for one user-visible speedup — belong in one bullet, not three. The reader cares about the net change, not the PR boundaries. Cite all the PRs in the trailing `([#a](...), [#b](...), [#c](...))` list.
**Be brief.** Each bullet should communicate the user-visible change in 1–3 sentences. Internal-section bullets in particular should be terse — usually one sentence. Drop the "why we did it this way" details unless they materially affect how the user thinks about the change. Code examples and exhaustive `Cmd::stream` / `OnceCell` / `DashMap`-style internals usually don't belong; they live in the PR description.
**No editorial framing.** Describe what changed, not what was wrong with the previous decision in subjective terms. Avoid words like "sledgehammer", "ugly", "noisy", "wrong" applied to past code. State the prior behavior neutrally and the new behavior plainly.
**Good:** "Removed `.pi/` from the default excludes list; users who need it can add it via `[step.copy-ignored]`."
**Bad:** "Removed `.pi/` — a sledgehammer fix from an unrelated debugging session that has no place as a project-agnostic default."
### Credit External Contributors
For any changelog entry where an external contributor (not the repo owner) authored the commit, add credit with their GitHub username:
```markdown
- **Feature name**: Description. ([#123](https://github.com/user/repo/pull/123), thanks @contributor)
```
Find external contributors:
```bash
git log v<last-version>..HEAD --format="%an <%ae>" | sort -u
```
Then for each external contributor's commit, find their GitHub username from the commit (usually in the email or PR).
### Credit Issue Reporters
When a fix or feature addresses a user-reported issue *in this repo*, thank the reporter — not just the PR author. Users who take time to report bugs, request features, or provide reproduction steps deserve recognition. (Don't credit reporters from upstream/external repos — only issues filed here.)
```markdown
- **Feature name**: Description. ([#456](https://github.com/user/repo/pull/456), thanks @reporter for reporting)
```
For fixes that reference issues:
```markdown
- **Bug fix**: Description. Fixes [#123](https://github.com/user/repo/issues/123). (thanks @reporter)
```
**Finding reporters — do ALL three steps:**
Issues may have been filed months before the fix. Bug reports also appear as PR comments, not just issues. These steps are complementary; each catches things the others miss.
1. **Extract every issue/PR reference from every commit** (PRIMARY):
```bash
git log v<last-version>..HEAD --format="%B" | grep -oE '#[0-9]+' | sort -un
```
For **each** referenced number: run `gh issue view N --json title,author,state`. This catches issues filed months ago — the most commonly missed credits.
2. **Check PR comments for bug reports** (catches reports that never became issues):
For feature PRs referenced in commits, check comment threads for users reporting problems:
```bash
gh pr view NNN --json comments --jq '.comments[] | "\(.author.login): \(.body[:150])"'
```
3. **Survey every issue opened or closed since last release** (catches unreferenced matches):
```bash
git log -1 --format=%cs v<last-version>
gh issue list --state all --search "created:>=<date>" --json number,title,author --limit 100
gh issue list --state closed --search "closed:>=<date>" --json number,title,author --limit 100
```
Cross-reference every title against changes in this release.
**When to credit:**
- Bug reports with clear reproduction steps (in issues OR PR comments)
- Feature requests that shaped the implementation
- Performance reports with measurements (like "takes 15s")
- Users who helped diagnose issues through discussion
Skip credit for: issues opened by the repo owner, trivial reports, or issues that were substantially different from what was implemented.
### Link Significant Features to Docs
For major features with dedicated documentation, include a docs link. Use full URLs so links work from GitHub releases:
```markdown
- **Hook system**: Shell commands that run at key points in worktree lifecycle. [Docs](https://worktrunk.dev/hook/) ([#234](https://github.com/user/repo/pull/234), thanks @contributor for the suggestion)
```
Link when there's substantial documentation the user would benefit from reading — new commands, feature pages, or Tips & Patterns sections. Skip for minor improvements.
### MANDATORY: Verify Each Changelog Entry
**After drafting changelog entries, you MUST spawn a subagent to verify each bullet point is accurate.** This is non-negotiable — changelog mistakes are a recurring problem.
The subagent should:
1. Take the list of drafted changelog entries
2. For each entry, find the commit(s) it describes and read the actual diff
3. Verify the entry accurately describes what changed
4. Check for missing changes that should be documented
5. Report any inaccuracies or omissions
**Subagent prompt template:**
```
Verify these changelog entries for version X.Y.Z are accurate.
Previous version: [e.g., v0.1.9]
Commits to check: git log v<previous>..HEAD
Entries to verify:
[paste drafted entries]
For EACH entry:
1. Find the relevant commit(s) using git log and git show
2. Read the actual diff, not just the commit message
3. Confirm the entry accurately describes the user-facing change
4. Flag if the entry overstates, understates, or misdescribes the change
Also check:
- Are there user-facing changes NOT covered by these entries?
- Verify each "thanks @..." attribution (right person, right role — author vs reporter)
Report format:
- Entry: [entry text]
Status: ✅ Accurate / ⚠️ Needs revision / ❌ Incorrect
Evidence: [what you found in the diff]
Suggested fix: [if needed]
```
**Do not finalize the changelog until the subagent confirms all entries are accurate.**
**If verification finds problems:** Escalate to the user. Show them the subagent's findings and ask how to proceed. Don't attempt to resolve ambiguous changelog entries autonomously — the user knows the intent behind their changes better than you do.
## Confirm Release Type
**Before proceeding with changelog and version bump, confirm the release type with the user.**
After reviewing commits, present:
1. Current version (e.g., `0.2.0`)
2. Brief summary of changes (new features, bug fixes, breaking changes)
3. Your recommendation for release type with reasoning
4. The three options: patch, minor, major
Use `AskUserQuestion` to get explicit confirmation. Example:
```
Current version: 0.2.0
Changes since v0.2.0:
- Added `state clear` command (new feature)
- Added `previous-branch` state key (new feature)
- No breaking changes
Recommendation: Minor release (0.3.0) — new features, no breaking changes
```
**Do not proceed until user confirms the release type.** The user may have context about upcoming changes or preferences that affect versioning.
## Version Guidelines
- **Second digit** (0.1.0 → 0.2.0): Backward incompatible changes
- **Third digit** (0.1.0 → 0.1.1): Everything else
Current project status: early release, breaking changes acceptable, optimize for best solution over compatibility.
## Library API Compatibility
Worktrunk is primarily a CLI, but it also publishes a library crate (`[lib]` in `Cargo.toml`) that downstream crates depend on. `cargo-semver-checks` compares the current public API against the last version published to crates.io and flags semver violations.
```bash
cargo semver-checks check-release -p worktrunk
```
Interpreting results:
- **No issues reported**: any bump level is valid from the library's perspective. Choose based on CLI changes and new features.
- **Breaking changes reported**: while pre-1.0, these require at minimum a minor bump (e.g., 0.37.0 → 0.38.0). A patch release is not allowed.
- **Tool fails to run** (e.g., missing baseline): likely the crate hasn't been published yet or the registry cache is stale. Try `cargo semver-checks check-release -p worktrunk --baseline-version <last-published>`.
This check validates the chosen bump — it doesn't distinguish patch vs. minor when no breakage exists. Continue using the commit review to decide between patch (fixes only) and minor (new features).