release-cycle
Skill0 starsChanged 10 days agoApache-2.0View on GitHub
Turn the roadmap's To do queue in Linear into a shipped release. Coordinator stays small; parallel worktree agents implement; merge to a release branch, debug-build for manual evaluation, iterate, then release per docs/releasing.md.
- Commits and pushes
In this repository4 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- drive-plumeSkill
- implementSkill
- roadmapSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 3 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 25
Write the package table into the plan file before launching anything.
- Distinctive: line 60
Do not poll. Completion notifications arrive on their own.
- Very specific: line 109
Only after the user approves.
- Distinctive: line 115
Leave the draft uncommitted, so no draft ever reaches the history.
- Very specific: line 124
Do not install: Every install updates through Sparkle or Homebrew, so never run scripts/install-release.sh as part of a release.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Release cycle
Run this when the user says "make the next release" or asks to work through the roadmap queue. You are the coordinator. Keep your own context small: read only the roadmap (through the roadmap skill), docs/releasing.md, and agent reports. Delegate every implementation, build, and verification to subagents.
Inputs
- Optional: extra items beyond the To do queue. Recommend two or three cheap, high-value Backlog issues — prefer small estimates — and ask which to include. Always ask about a
Needs decisionissue before pulling it in — the decision in its description has to be settled first. - Target version. Default: bump the minor for a feature release, the patch for fixes only.
1. Plan the packages
Pull main first (git pull --ff-only) and read the latest tag. A checkout can sit releases behind, and planning against it gets both the footprints and the version wrong. The next version follows the latest tag, not the version the user names from memory.
Invoke the roadmap skill to list the To do queue, and read each issue's description. Group the queued issues into work packages so that no two packages edit the same files. An issue names files only where they matter, so read the code to find the real footprint before clustering.
- S-only groups (estimate 2) go to Sonnet; anything M or larger (estimate 3+), unsized, or touching the headless wire protocol, goes to Opus. Always set
modelexplicitly. - Cross-cutting passes (accessibility identifiers, a styling sweep) touch every view. Run them after the merge, on the release branch, not in parallel.
- Note the seams where packages share a file anyway (
ChatTabView,ChatComposerare the usual ones) and tell each agent which other agents are in that file so they keep their footprint minimal.
Write the package table into the plan file before launching anything.
Once the plan is approved, create the release issue as a placeholder through the roadmap skill. Title it Release <version>, put it in team Plume, project Admin, and set it to In Progress. Its description is GitHub release: *link added on publish.*. Its relatedTo lists the previous release's Release <version> issue and every issue planned for this release. Add an issue to it if it joins mid-cycle, and remove one if it drops out.
<prefix> in the commands below is the branch prefix of whoever runs the cycle, such as ryanm. Pass it to every agent.
2. Launch implementers
One Agent call per package, all in one message, with isolation: "worktree" and the chosen model. Each prompt carries the package description plus the rule block below verbatim.
You are running inside a dedicated git worktree of <repo root>. First run `pwd` to learn your
worktree root. HARD BOUNDARY: every file you read, edit, build, or run a command against must live
under that root. Never cd out of it, never touch the parent repo or sibling worktrees.
Read CLAUDE.md at your worktree root first and follow it. Your assigned Linear issues state the items; read each one, then read the code before planning.
- Create a branch: `git checkout -b <prefix>/<slug>`. Commit on it, early and often.
- NEVER run `git stash`. The stash ref is shared by every worktree, so a concurrent agent's pop takes your
entry and you get theirs. Use `git worktree`-local means instead: commit a WIP, or copy files aside.
- Verify with `xcodebuild -scheme Plume -destination 'platform=macOS' build` and
`xcodebuild -scheme Plume -destination 'platform=macOS' test -only-testing:PlumeTests`.
Confirm test names scroll past. Two suites fail in ANY worktree for environmental reasons:
`SessionJSONLReaderTests.encodingResolvesADirectoryClaudeCodeHasUsed` and `SurfaceCommandTests`.
Report those as environmental; anything else is yours to fix. Add tests for pure logic.
- Roadmap: do NOT touch Linear. Report which issue identifiers you completed; the coordinator moves
them to Done.
- Comments: terse, why-only, per CLAUDE.md. No changelog-style comments.
- If you hit a decision only the user can make, stop and report it rather than guessing.
- Do not take screenshots. (Only one agent may screenshot at a time; the coordinator runs any visual check as a single serial pass after the merge.)
Report back: branch name, worktree absolute path, commit SHAs, a one-paragraph summary, test
results, and anything left unverified.Do not poll. Completion notifications arrive on their own. Use the wait to write or refine this skill and the plan.
3. Merge to a release branch
git checkout -b <prefix>/release-<version> main
git merge --no-ff <prefix>/<slug> # smallest package first, largest lastIf an agent used the auto-generated worktree-agent-* branch instead of creating <prefix>/<slug>, merge that branch by name; the worktree list shows which is which. A trivial conflict you resolve yourself. A non-trivial one goes to a Sonnet agent with both sides and the two package summaries. Build after the last merge before moving on.
Then run the cross-cutting packages (step 1). An isolation: "worktree" agent forks from origin/main, not from your current branch — in the 0.13.0 run that was a commit dozens behind local main, since nothing had been pushed, so tell it to start with git checkout -B <prefix>/<slug> <prefix>/release-<version> before editing (a plain git checkout <prefix>/release-<version> fails because the primary checkout already has that branch out), or its annotations land on stale files and every shared file conflicts. Merge it the same way.
An issue is Done once the user has reviewed and approved it directly, or once it merges into main, which needs the user's confirmation. Merging into a release branch is not Done. Move each issue to Done through the roadmap skill once it qualifies.
Hand-offs from implement agents
An agent running the implement skill may send a branch with SendMessage once the user approves it. The message names the issue, branch, worktree, commits, base, signing state and changelog bullets. Merge it like a package, re-signing any unsigned commit. Then reply to the sender with SendMessage, naming the merge SHA, so it can clean up its worktree. Its issue stays open until the release reaches main.
Clean up as each package lands
Remove a package's worktree and branch as soon as its work is on the release branch, rather than saving it all for after the release. A dozen stale worktrees make git worktree list useless for seeing what is still live, and every one of them holds a full DerivedData-adjacent checkout.
git worktree unlock <path> # agent worktrees are created locked
git worktree remove --force <path>
git worktree prune
git branch -D <prefix>/<slug> worktree-agent-<id>git branch --merged is the check, but it answers about commits, not content. A branch whose work reached the release branch by cherry-pick or by a re-signing rebase reads as unmerged, because its original SHAs are not ancestors. Confirm with git diff <branch>..HEAD --stat instead — an empty diff means the content landed and the branch is safe to delete.
Remove each removed worktree's DerivedData and debug data too. Quit its debug app first (only the PID from pgrep -f "^<app>/Contents/MacOS/Plume"). Its DerivedData is the ~/Library/Developer/Xcode/DerivedData/Plume-* whose info.plist has WorkspacePath equal to <worktree>/Plume.xcodeproj; read it with /usr/libexec/PlistBuddy -c 'Print :WorkspacePath' <dir>/info.plist. Delete only an exact match, never the primary checkout's. Its debug data is ~/Library/Application Support/Plume.debug-<worktreeName>/.
Keep the worktree of any package whose work is not finished, even if some of it merged. A package that was partly cherry-picked still holds the dropped commits, and they are the starting point for the follow-up agent.
4. Debug build for manual evaluation
Delegate to a Sonnet verifier, on the release branch in the primary checkout:
- Debug build, then
PlumeTests. Report failures verbatim. - Launch the built
Plume.appfrom DerivedData (-showBuildSettings | awk '$1 == "BUILT_PRODUCTS_DIR"'). Debug writes toPlume.debug/(Plume.debug-<worktree>/from a worktree), so it runs beside the installed app. - Launch it with
env -u CLAUDE_CODE_CHILD_SESSION -u CLAUDECODE. The app inherits the shell that started it and passes that to every terminal tab it spawns, so launching from an agent's shell leaves each tab'sclaudereading itself as a nested session and skipping its transcript — the chat UI then shows nothing. - Walk the process tree from Plume's own PID and read the unified log for errors. Never
pgrep -x Plumeor global-grepclaude.
Tell the user the app is running and give a per-package checklist of what to try. Each round of feedback becomes targeted agents on the release branch (Sonnet for tweaks, Opus for behavior bugs), then rebuild and relaunch through the verifier.
5. Release
Only after the user approves. Follow docs/releasing.md; do not duplicate it here.
- Draft the release notes as an unreleasable section. Write a new top section in
CHANGELOG.mdheaded## Draft: <version> (<build>). That section becomes the GitHub release body, and the update window shows it, so the user reviews and finishes it by hand.package-release.shrefuses to package while the top heading saysDraft:.- Draft from what shipped: this cycle's Done issues, plus
git log <last-tag>..HEAD --no-merges --format='%s'for work that had no issue. - End it with a
### Recentlylist of a few highlights from the previous three or so releases. The update window shows only the newest section, so this is what reaches a user who skipped releases. - Match the existing sections' voice. Use user-facing bullets that lead with the change ("Send images in chat", "Fix …"), with sub-bullets for detail. Leave out internal work (refactors, test-only changes, tooling) unless a user would notice it.
- Leave the draft uncommitted, so no draft ever reaches the history.
- Draft from what shipped: this cycle's Done issues, plus
- Bump
MARKETING_VERSIONandCURRENT_PROJECT_VERSIONin the app target's Debug and Release blocks only, to the numbers in the draft heading. Commit the bump alone (git add Plume.xcodeproj/project.pbxproj), leavingCHANGELOG.mdout of the commit. - Tell the user the draft is ready for review, and wait. They edit the section and remove
Draft:from the heading to approve it. Then confirm the top heading is exactly## <version> (<build>), and commitCHANGELOG.mdon its own. - Merge the release branch into
main(--no-ff), then move every shipped issue still open to Done through theroadmapskill. - Delegate the Release build and tests to Sonnet, telling it not to install —
xcodebuild -configuration Release clean build, thenPlumeTests, then verify the built bundle inBUILT_PRODUCTS_DIR(PlistBuddy, codesign, otool) rather than the installed one. - If commits are signed here (
git config commit.gpgsignprintstrue), check every one is signed before anything is pushed:git log --format='%G? %h %s' <last-tag>..main | grep -v '^G'must print nothing. Agents fall back to--no-gpg-signwhen the signing agent locks mid-run, and re-signing after the fact means rewriting every later commit and force-pushing the tag. Re-sign the offenders on the release branch before merging it (git rebase --force-rebase --rebase-merges mainrecreates and signs everything; resolve replayed conflicts by taking the file from the original merge commit, and confirm withgit diff <old-tip> HEAD --quietthat the tree is unchanged). - Tag
v<version>onmain's HEAD — the release merge — and pushmainwith the tag.package-release.shrefuses unless the tag points atHEAD. - Publish through Sparkle and Homebrew, per
docs/releasing.md→ Sharing a build:scripts/package-release.sh(DMG, appcast, draft GitHub release), then the user publishes the draft, thenscripts/update-tap.sh <version>. Ask before publishing and before bumping the tap; both are outward-facing. - Once the release is published, finish the
Release <version>placeholder from step 1. Put the GitHub release link in its description, and check thatrelatedTonames every issue that shipped plus the previous release's issue, so the releases form a chain. Then mark it Done. - Do not install. Every install updates through Sparkle or Homebrew, so never run
scripts/install-release.shas part of a release. - Clean up anything step 3 left:
git worktree listandgit branch --list '<prefix>/*'should hold nothing from this cycle, and noPlume-*DerivedData folder should point at a removed worktree.
Gotchas
git stashis shared across worktrees. In the first run, three agents stashed to measure a test baseline and popped each other's work; one recovered fromgit fsck --unreachable. The rule block now forbids it. If it happens anyway,git stash listlabels usually say whose work an entry holds; restore withgit checkout <stash> -- <paths>.-only-testingwith a name matching nothing prints** TEST SUCCEEDED **having run nothing. Confirm names scrolled past.- Tell every agent to run its verification in the foreground. Three agents in the 0.3.3 run handed a build or test to a background watcher and ended their turn waiting for a notification that never came — one of them left finished work uncommitted. They resume fine with a message saying to poll in the foreground instead, but it costs a round trip each time. Say it in the prompt.
- A failed push is not a failed commit. If your SSH key lives in a password manager's agent,
git pushsigns through it, so a locked agent fails withsign_and_send_pubkey: signing failedandPermission denied (publickey). There is no--no-gpg-signequivalent — the only fix is unlocking, so ask. This is unrelated to the commit-signing fallback in CLAUDE.md, and the commits themselves may all be signed while the push still fails. - A schema change meets the installed store for the first time on the first launch after updating. Watch the log for a
Plume.store.<timestamp>.bakmove. - Roadmap edits: only the coordinator writes to Linear. An issue is Done once the user has reviewed and approved it directly, or once it merges into
main, which needs the user's confirmation. Merging into a release branch is not Done. An agent's turn ending is not Done either. - The installed Plume runs
git statuson this repo on a timer, so a long rebase in the primary checkout can hitindex.lock: File exists.git rebase --continuepicks up where it stopped; quit Plume first for anything long. - Six parallel
xcodebuilds are slow but each worktree gets its own DerivedData. Do not try to share one.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

