| name | release-patch |
| description | Cut a patch release of Contrapunk (e.g. v1.1.0 -> v1.1.1). Use when the user says "ship a patch", "cut v1.X.Y", "release the fix", or asks to roll up shipped fixes into a release. Bumps version files, validates, pushes, watches the macOS .dmg build, tags, and creates the GitHub Release with hand-written notes covering all commits since the last tag. |
release-patch
Ship a Contrapunk patch release. The minor codename (e.g. "Kondo KITT" for v1.1.x) carries forward unchanged — only the patch number increments.
Prereqs (verify before starting)
- Working tree clean:
git status --short returns nothing.
- All fixes intended for the release are already committed on
main.
gh CLI is authenticated: gh auth status.
- Last tag retrievable:
git describe --tags --abbrev=0.
If any prereq fails, surface to the user and stop. Don't start a release with dirty state.
Steps
1. Compute the new version
LAST=$(git describe --tags --abbrev=0)
Confirm the bump with the user before proceeding if it's ambiguous (e.g. the last tag isn't on main's history).
2. Bump version in all these files
| File | Path | Line shape |
|---|
| Workspace root crate | Cargo.toml | version = "X.Y.Z" (line ~19, under [package]) |
| Tauri crate | src-tauri/Cargo.toml | version = "X.Y.Z" (line 3) |
| Plugin crate | plugin/Cargo.toml | version = "X.Y.Z" (line 3) |
| Tauri config | src-tauri/tauri.conf.json | "version": "X.Y.Z" (top-level, line 4) |
| UI package | ui/package.json | "version": "X.Y.Z" (line 3) |
Use Edit with explicit old_string/new_string per file. Don't sed -i blindly — there are many version = lines in Cargo.toml for transitive deps.
3. Regenerate Cargo.lock
cargo check --workspace --quiet
This bumps Cargo.lock to match. If the check fails, the version bump introduced a real compile error somewhere; fix it before continuing.
4. Commit
release: vX.Y.Z — <one-line theme>
Bumps version W.X.Y -> X.Y.Z across Cargo manifests
(contrapunk, contrapunk-tauri, contrapunk_plugin),
src-tauri/tauri.conf.json, ui/package.json, and the
auto-regenerated Tauri schema files.
Patch contents (since vLAST):
- <list each fix:/ci:/docs: commit subject>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files to git add explicitly (avoid git add -A):
Cargo.toml, Cargo.lock
src-tauri/Cargo.toml, src-tauri/tauri.conf.json
plugin/Cargo.toml
ui/package.json
src-tauri/gen/schemas/ (auto-regenerated by Tauri when conf changes)
5. Push main
git push origin main
This triggers .github/workflows/macos-build.yml on main for the bumped commit. Watch it succeed before tagging — if the .dmg build is broken, you want to find out now, not after the tag is published.
sleep 5
gh run list --workflow=macos-build.yml --limit 1
gh run watch <run-id>
Wait for conclusion: success. If it fails, investigate before tagging.
6. Tag and push the tag
git tag -a vX.Y.Z -m "vX.Y.Z — <theme>"
git push origin vX.Y.Z
The tag push retriggers macos-build.yml (its on.push.tags: ['v*'] rule). The new run will execute the Attach .dmg to GitHub Release step which creates a release and uploads the universal .dmg as an asset.
7. Edit release body with hand-written notes
The auto-created release has minimal body. Override it:
gh release edit vX.Y.Z --notes-file /tmp/release-notes.md
Notes template:
# Contrapunk vX.Y.Z — Kondo KITT (patch release)
## Bug fixes
- **Counterpoint species 2/3/4** now produce audibly different harmonies from species 1 even when the transport is stopped. Previously the engine silently fell back to species 1 whenever `counterpoint_beat_phase` was `None` — Tauri only pushed a phase while the transport was running, and the WASM/browser adapter never pushed one at all. Fix: synthetic beat counter inside `HarmonyEngine` auto-advances on every NoteOn; external transport still wins when set. (commit fb3e7b9)
## Platform support
- **macOS Intel + Apple Silicon universal .dmg** is now built by CI and attached to every release. Minimum macOS version is 11.0 (Big Sur), which covers Monterey 12.x on 2015+ Intel Macs. Download `Contrapunk_X.Y.Z_universal.dmg` from the assets below.
- **First launch on macOS**: the .dmg is unsigned. Right-click the app → Open, or run `xattr -dr com.apple.quarantine /Applications/Contrapunk.app` from Terminal.
## Internal
- UX audit of species + counterpoint controls (`.planning/todos/pending/ux-species-counterpoint-controls.md`) — recommendations for a follow-up release.
**Full diff**: vLAST...vX.Y.Z
8. Verify
gh release view vX.Y.Z --json assets,body --jq '{body, assets: [.assets[] | .name]}'
Confirm:
- Body matches the hand-written notes
- Assets include
Contrapunk_X.Y.Z_universal.dmg
- (Optional)
Contrapunk_X.Y.Z_universal.app.tar.gz if the .app bundle artifact was attached
Failure recovery
- Bump commit fails clippy hook: run
cargo clippy --workspace --all-targets -- -D warnings locally and fix. Don't use --no-verify to skip the hook.
- macOS build fails on
main push: leave the bump commit on main, fix the build failure as a separate commit, push again, wait for green, then tag.
- Tag pushed but release not created:
softprops/action-gh-release step may have failed. Check the run logs. You can manually create the release with gh release create vX.Y.Z --notes-file ... and re-upload the .dmg from the CI artifact.
- Wrong version committed: don't amend a pushed commit. Add a follow-up
release: fix vX.Y.Z version files commit, repeat the push/tag flow with a new patch number if the broken tag was already pushed (don't delete pushed tags).
When NOT to use this skill
- Minor releases (vX.Y.0 → vX.(Y+1).0) — those need a new codename and a different workflow (
monthly-release.yml). Don't try to repurpose this skill for them.
- Hotfix to a release branch — use the backport workflow (
backport.yml).