Improve worktree leftover visibility and Windows lock recovery for isolation: "worktree"
Summary
When the Agent tool is invoked with isolation: "worktree" (or --worktree CLI flag) and the agent makes any changes, Claude Code intentionally preserves the worktree (per documented contract: "automatically cleaned up if the agent makes no changes; otherwise the path and branch are returned"). This is correct for review purposes, but in practice the leftover worktrees accumulate without any session-level visibility — users discover them weeks later. On Windows the situation is worse: even when the user manually attempts cleanup, external processes (Search Indexer, Defender, etc.) hold file handles on the now-empty directory, and git worktree remove / Remove-Item -Recurse -Force / cmd rd /s /q / .NET Directory.Delete all fail with the same IOException: process cannot access the file because it is being used by another process.
Current behavior (verified, Claude Code 2.1.92, Windows, Git Bash)
- Session uses
Agent({ isolation: "worktree", ... })or--worktree. Worktree is created at.claude/worktrees/<random>with branchclaude/<random>. - Agent makes any change (even unintentional, e.g. updating
.claude/settings.local.json). Auto-cleanup is skipped. WorktreeRemovehook fires with no decision control (observability only, per docs). Hook cannot retry, force-delete, or escalate.- If user manually runs
git worktree remove, Windows file lock causes silent fail in many cases. Empty directory persists indefinitely. - No SessionStart-level surfacing of accumulated leftovers — user has to look at
.claude/worktrees/directly.
Proposed improvements
- Leftover visibility on session start — when entering the main worktree of a repo with N+ registered auto-isolation worktrees (or orphan directories under
.claude/worktrees/), surface a one-line notice ("3 leftover worktrees from previous sessions — review withgit worktree listor/cleanup-worktrees"). Configurable threshold (default: 1).
WorktreeRemovehook decision control — let the hook returndecision: "retry"/decision: "force"/decision: "skip"instead of being purely observability-only. Enables hooks to recover from Windows locks (e.g., wait + retry, fall back to PowerShell forced delete, defer to next session).
- Explicit user notification on auto-cleanup failure — when Claude Code's automatic worktree removal hits an OS error (Windows file lock, permission denied), surface a
systemMessageto the user instead of silent debug-only logging. Include the exact path and a copy-paste manual cleanup command.
- Built-in
/cleanup-worktreescommand — one-command audit + best-effort cleanup of leftover auto-isolation worktrees from the main worktree, with explicit reporting of what was cleaned vs. what is locked vs. what was preserved due to uncommitted changes.
- Optional:
worktree.autoCleanupOnChangessetting — for users who prefer auto-cleanup even when changes exist (with a warning message preserving the diff in a stash or patch file). Opt-in to retain current default safety.
Why this matters
The Agent tool's isolation: "worktree" is genuinely useful for parallel/exploratory work. The current contract is reasonable. But the missing pieces — visibility + Windows recovery + hook decision power — turn a single forgotten leftover into months of accumulated cruft, especially for users who heavily use subagents on Windows.
Workaround in use
Custom ~/.claude/hooks/worktree-leftover-notice.sh (SessionStart user matcher) that scans for orphan directories, registered auto-isolation worktrees, and reflog leftovers under .git/logs/refs/heads/claude/, then injects an additionalContext notice. Effective as visibility, but it cannot recover the Windows-locked empty directories — that requires (2) or (3) above.
Environment
- Claude Code: 2.1.92
- OS: Windows 10/11
- Shell: Git Bash (MSYS)
- superpowers plugin: 5.0.7 (no
isolation: "worktree"frontmatter found in any plugin skill — confirms isolation trigger isAgenttool option, not plugin behavior)
Related issues
This proposal touches on themes in several existing issues. They each address a slice; this one bundles the visibility + Windows recovery + hook decision control angle.
- #26725 "Stale worktrees are never cleaned up" — closest match, general stale worktree accumulation
- #49065 "[FEATURE] Add option to disable automatic worktree creation in desktop app" — Windows desktop angle
- #46444 "Critical: Claude Code worktree auto-cleanup permanently deleted 10 days of uncommitted project work without any warning" — opposite failure mode (over-aggressive cleanup), supports proposal (5)'s "preserve diff" requirement
- #55435 "agent-runner: prune .claude/worktrees/agent-* on session/branch end" — agent worktree prune enhancement
- #50889 "Worktrees from
isolation: \"worktree\"auto-reap when subagent returns without changes, breaking SendMessage resume" — current "no changes → reap" contract has its own failure mode - #34137 "[BUG] Worktree cleanup prompt isn't used when custom worktree hooks are enabled" — hook contract gap (related to proposal 2)
- #57378 "WorktreeRemove hook silently suppresses the /exit 'keep or remove' picker" — WorktreeRemove hook UX gap (related to proposal 2)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗