Add cmux-worktree-reaper for orphaned agent worktrees
Merged
TE
18d ago+600+600+012345678901234567890123456789-0-0-0123456789
Summary
web/services/vms/hygiene/cmux-worktree-reaperremoves agent worktrees whose owner is gone. An owner counts as live when its marker pid runs, a Claude session in~/.claude/sessionswith a live pid has its cwd there, any process has a cwd, file or binary inside, or anything outside build output, its git state or its transcript changed within--ttl-hours(3).- Clean, fully pushed worktrees go with a plain
git worktree remove. - A worktree with uncommitted, untracked or unpushed work is held and reported.
--show-fileslists what a backup would carry. --backupis opt-in and stays off until Leo approves it. It commits the work from a copy of the index, never including gitignored files, and refuses if a file name or its content looks like a secret, or if gitleaks is missing or finds anything. Only then does it push towip/<session>/<branch>, read the ref back, and remove the worktree.keep DIR [REASON]/unkeep DIRpin a worktree, which then only shows in the report.mark DIR [SESSION]writes the owner marker into the worktree's git dir.- It skips locked worktrees, rebases or merges in progress, dirty submodules and worktrees that hold another worktree. It runs report-only unless
--apply, and every action goes to~/.local/state/cmux-worktree-reaper/log.jsonl.
Design: manaflow-ai/cmuxterm-hq#2562.
Testing
bun test tests/vm-worktree-reaper.test.ts on Huge Blue: 11 pass. The keep test passed again after the HOME fix.
Observed / Not run
- Observed: the tests above, plus a report-only run over 172 worktrees on Huge Blue.
- Not run: macOS (lsof path) and the launchd/systemd timer wiring, which comes in a follow-up.
Changelog
none
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Adds cmux-worktree-reaper, a hygiene tool that removes agent worktrees whose owner is gone. Report-only unless --apply; every action is logged to ~/.local/state/cmux-worktree-reaper/log.jsonl.
- Clean, fully pushed worktrees go with a plain
git worktree remove; worktrees with uncommitted, untracked, or unpushed work are held and reported. --backupstays off until approved: it commits the work from a copy of the index, never includes gitignored files, refuses when a file name or content looks like a secret—scanning every commit the push would publish—or when gitleaks is missing or finds something, then pushes towip/<session>/<branch>and removes the worktree.keep DIR [REASON]/unkeep DIRpin a worktree;mark DIR [SESSION]writes the owner marker into the worktree's git dir.- Skips locked worktrees, rebases or merges in progress, dirty submodules, worktrees holding another worktree, nested repositories, and gitignored non-build files; does nothing when open files can't be enumerated.
- 11 tests cover removal, backup, secret refusal, and liveness.
Summary by CodeRabbit
- New Features
- Added a worktree cleanup utility that reports eligible worktrees and can remove clean, inactive worktrees when explicitly enabled.
- Pinned, active, or otherwise protected worktrees are retained. Worktrees with changes or unpushed commits are held unless a backup is requested.
- Backups are pushed before removal; worktrees remain in place if backup checks fail or the push cannot be confirmed.
- Cleanup actions can be recorded in a log.