/release
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.
$ npx -y skills add max-sixty/worktrunk --skill release --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/release
Context preview
The summary Claude sees to decide when to auto-load this skill.
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.
SKILL.md
release.SKILL.mdname: 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. **Sync the release branch with `main`**: The release worktree's branch lags `main` between releases — it's only reset to `main` after a release lands. Cutting from a stale branch silently drops everything merged since. Fast-forward to the tip of `main` before anything else:
git fetch origin
git merge --ff-only origin/main
`--ff-only` advances the branch when it's a strict ancestor of `origin/main` and **fails** (rather than creating a merge commit or discarding work) if it has diverged — reconcile manually before continuing. This is the release-branch equivalent of `wt up`, spelled out because the `up` alias rebases each branch onto its own upstream (`origin/release`), not `main`. Note the resulting commit SHA: this is the tip the changelog covers, and step 12 checks the changelog against everything that reaches `main` before the tag. 2. **Run tests**: Two gates — the local suite and the full cross-platform suite.
- Local: `cargo run -- hook pre-merge --yes`.
- Cross-platform: dispatch the `nightly` workflow on the cut-from tip and wait for it to go green. This is where a release gets its full linux/macos/windows validation: the PR path (`ci.yaml`) is moving to cargo-affected selection and will stop running the full `test` matrix, while `nightly` hosts `full-tests` (the full 3-OS suite) alongside feature-powerset, release-target, nix-flake, and minimal-versions. Benchmarks aren't part of `nightly` — they run in their own `benchmarks.yaml` and gate nothing.
gh workflow run nightly.yaml --ref main
# Registration lags the dispatch, and a prior release may have left a
# stale completed workflow_dispatch run — filter to the in-flight one.
sleep 5
RUN=$(gh run list --workflow=nightly.yaml --event=workflow_dispatch --branch=main --limit 5 --json databaseId,status --jq 'map(select(.status != "completed")) | .[0].databaseId')Launch a ci-reporter to monitor `$RUN` to completion (avoid `gh run watch` — it can hang). Fix any failure before continuing. 3. **Check current version**: Read `version` in `Cargo.toml` 4. **Review commits**: Check commits since last release to understand scope of changes. Audit the cumulative diff for the data-loss surface (see [Data-Loss Surface Review](#data-loss-surface-review)) before proceeding. 5. **Check library API compatibility (advisory)**: Run `cargo semver-checks check-release -p worktrunk` (install with `cargo install cargo-semver-checks --locked` if missing) as a bump-level input, not a compat gate — worktrunk ships breaking library changes freely. If it reports breaking changes, that's fine; under semver the bump must still be minor (pre-1.0) or major (post-1.0). See "Library API Compatibility" below. 6. **Credit contributors**: Check for external PR authors and issue reporters (see "Credit External Contributors" and "Credit Issue Reporters" below) 7. **Determine release type**: Pick the bump from the changes (including semver-checks result). Ask the user only if the choice is genuinely ambiguous (see below). 8. **Bump version** (must run on a clean tree — before editing CHANGELOG):
cargo release X.Y.Z -p worktrunk -x --no-publish --no-push --no-tag --no-verify --no-confirm && cargo check
This bumps `Cargo.toml` and `Cargo.lock`, then auto-commits. We'll reset this commit in step 10 to fold in the CHANGELOG. 9. **Update CHANGELOG**: Add `## X.Y.Z` section at top with changes (see MANDATORY verification below) 10. **Commit**: Reset the auto-commit from step 8, stage everything, and create the final release commit:
git reset --soft HEAD~1 && git add -A && git commit -m "Release vX.Y.Z"
11. **Merge to main**: push the release branch, open a PR, wait for CI, and merge it. Keep the worktree — the remaining steps run from it. Then move the branch onto the merged tip:
git fetch origin && git reset --keep origin/main
The PR squash-merges, so the branch is no longer an ancestor of `main` and step 1's `--ff-only` can't advance it; `--keep` moves it across and still fails if anything is uncommitted. `main` can advance during the CI wait; step 12 catches anything that lands before the tag. 12. **Verify the changelog covers `main`, then tag and push**: the tag decides what ships — `release.yaml` builds the binaries and the GitHub release notes from the tree at the tag, so everything reachable from it is in the release. The merge squashes onto whatever `main` tip exists at merge time, so a commit that lands during the PR's CI wait is already an ancestor of the release commit and ships whether or not the changelog mentions it (the easy miss is a follow-up that reworks a feature this release already documents). List what reached `main` since the cut-from tip (step 1):
git fetch origin
git log --oneline <cut-from-commit>..origin/mainClean means the changelog at `origin/main` documents every user-facing commit listed. With no drift the list is one line, the `Release vX.Y.Z (#NNNN)` squash commit. Review anything else that drifted in during the window and fold what's user-facing into the changelog with a follow-up squash PR, then re-fetch and re-run. The list only grows across passes — the drifted commits stay, joined by the follow-up's own squash commit — so each pass re-checks coverage over a longer list.
Once clean, tag `origin/main`. The check and the tag then name the same ref, and it's main's tip, so the tag is reachable from `main`:
git tag vX.Y.Z origin/main && git push origin vX.Y.Z
13. **Wait for the release workflow**: The tag push triggers `release.yaml`. Launch a ci-reporter agent to mon
Read more
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. **Sync the release branch with `main`**: The release worktree's branch lags `main` between releases — it's only reset to `main` after a release lands. Cutting from a stale branch silently drops everything merged since. Fast-forward to the tip of `main` before anything else:
git fetch origin git merge --ff-only origin/main
`--ff-only` advances the branch when it's a strict ancestor of `origin/main` and **fails** (rather than creating a merge commit or discarding work) if it has diverged — reconcile manually before continuing. This is the release-branch equivalent of `wt up`, spelled out because the `up` alias rebases each branch onto its own upstream (`origin/release`), not `main`. Note the resulting commit SHA: this is the tip the changelog covers, and step 12 checks the changelog against everything that reaches `main` before the tag. 2. **Run tests**: Two gates — the local suite and the full cross-platform suite.
- Local: `cargo run -- hook pre-merge --yes`.
- Cross-platform: dispatch the `nightly` workflow on the cut-from tip and wait for it to go green. This is where a release gets its full linux/macos/windows validation: the PR path (`ci.yaml`) is moving to cargo-affected selection and will stop running the full `test` matrix, while `nightly` hosts `full-tests` (the full 3-OS suite) alongside feature-powerset, release-target, nix-flake, and minimal-versions. Benchmarks aren't part of `nightly` — they run in their own `benchmarks.yaml` and gate nothing.
gh workflow run nightly.yaml --ref main
# Registration lags the dispatch, and a prior release may have left a
# stale completed workflow_dispatch run — filter to the in-flight one.
sleep 5
RUN=$(gh run list --workflow=nightly.yaml --event=workflow_dispatch --branch=main --limit 5 --json databaseId,status --jq 'map(select(.status != "completed")) | .[0].databaseId')Launch a ci-reporter to monitor `$RUN` to completion (avoid `gh run watch` — it can hang). Fix any failure before continuing. 3. **Check current version**: Read `version` in `Cargo.toml` 4. **Review commits**: Check commits since last release to understand scope of changes. Audit the cumulative diff for the data-loss surface (see [Data-Loss Surface Review](#data-loss-surface-review)) before proceeding. 5. **Check library API compatibility (advisory)**: Run `cargo semver-checks check-release -p worktrunk` (install with `cargo install cargo-semver-checks --locked` if missing) as a bump-level input, not a compat gate — worktrunk ships breaking library changes freely. If it reports breaking changes, that's fine; under semver the bump must still be minor (pre-1.0) or major (post-1.0). See "Library API Compatibility" below. 6. **Credit contributors**: Check for external PR authors and issue reporters (see "Credit External Contributors" and "Credit Issue Reporters" below) 7. **Determine release type**: Pick the bump from the changes (including semver-checks result). Ask the user only if the choice is genuinely ambiguous (see below). 8. **Bump version** (must run on a clean tree — before editing CHANGELOG):
cargo release X.Y.Z -p worktrunk -x --no-publish --no-push --no-tag --no-verify --no-confirm && cargo check
This bumps `Cargo.toml` and `Cargo.lock`, then auto-commits. We'll reset this commit in step 10 to fold in the CHANGELOG. 9. **Update CHANGELOG**: Add `## X.Y.Z` section at top with changes (see MANDATORY verification below) 10. **Commit**: Reset the auto-commit from step 8, stage everything, and create the final release commit:
git reset --soft HEAD~1 && git add -A && git commit -m "Release vX.Y.Z"
11. **Merge to main**: push the release branch, open a PR, wait for CI, and merge it. Keep the worktree — the remaining steps run from it. Then move the branch onto the merged tip:
git fetch origin && git reset --keep origin/main
The PR squash-merges, so the branch is no longer an ancestor of `main` and step 1's `--ff-only` can't advance it; `--keep` moves it across and still fails if anything is uncommitted. `main` can advance during the CI wait; step 12 catches anything that lands before the tag. 12. **Verify the changelog covers `main`, then tag and push**: the tag decides what ships — `release.yaml` builds the binaries and the GitHub release notes from the tree at the tag, so everything reachable from it is in the release. The merge squashes onto whatever `main` tip exists at merge time, so a commit that lands during the PR's CI wait is already an ancestor of the release commit and ships whether or not the changelog mentions it (the easy miss is a follow-up that reworks a feature this release already documents). List what reached `main` since the cut-from tip (step 1):
git fetch origin
git log --oneline <cut-from-commit>..origin/mainClean means the changelog at `origin/main` documents every user-facing commit listed. With no drift the list is one line, the `Release vX.Y.Z (#NNNN)` squash commit. Review anything else that drifted in during the window and fold what's user-facing into the changelog with a follow-up squash PR, then re-fetch and re-run. The list only grows across passes — the drifted commits stay, joined by the follow-up's own squash commit — so each pass re-checks coverage over a longer list.
Once clean, tag `origin/main`. The check and the tag then name the same ref, and it's main's tip, so the tag is reachable from `main`:
git tag vX.Y.Z origin/main && git push origin vX.Y.Z
13. **Wait for the release workflow**: The tag push triggers `release.yaml`. Launch a ci-reporter agent to mon
Worktrunk is a CLI for Git worktree management, designed for parallel AI agent workflows
Other skills on worktrunk.
- /running-tend
Worktrunk-specific guidance for tend CI workflows. Adds codecov polling, Rust test commands, labels, and review criteria on top of the generic tend-* skills. Use when operating in CI.
Open skill - /writing-user-outputs
CLI output formatting standards for worktrunk. Load before editing any code that calls warning_message, hint_message, error_message, info_message, eprintln, or println, or that produces strings the user will see (CLI help, progress UI, snapshot text). Documents ANSI color
Open skill - /worktrunk
Guidance for Worktrunk (the `wt` CLI) — git worktree management, hooks, and config. Load when editing .config/wt.toml or ~/.config/worktrunk/config.toml; adding, modifying, or debugging hooks (post-merge, post-start, pre-commit, pre-merge, post-switch, etc.); configuring commit
Open skill - /wt-switch-create
Create a new worktrunk worktree (optionally in another repo) and switch this session's working directory into it. Use when launching a session that should work in its own worktree.
Open skill - /worktrunk
Guidance for Worktrunk (the `wt` CLI) — git worktree management, hooks, and config. Load when editing .config/wt.toml or ~/.config/worktrunk/config.toml; adding, modifying, or debugging hooks (post-merge, post-start, pre-commit, pre-merge, post-switch, etc.); configuring commit
Open skill - /wt-switch-create
Create a new worktrunk worktree (optionally in another repo) and switch this session's working directory into it. Use when launching a session that should work in its own worktree.
Open skill

