Worktree session allocator reuses idle worktree dirs, racing other sessions working in them
Summary
When starting a new session with worktree isolation, Claude Code (desktop app) can assign the session to an existing idle worktree directory created by an earlier session, checking out a new branch inside it. The reuse test appears to be "directory is clean/idle", which races against anything else legitimately using that directory — including another live Claude Code session operating on it via git -C, or a user terminal.
What happened (observed 2026-08-01, macOS desktop app)
A repo had ~95 accumulated worktrees under .claude/worktrees/. Session A (mine) was doing worktree-hygiene work and salvaging an orphaned branch from a stale worktree directory sweet-goldwasser-735dae (last mtime July 5):
- 12:12 — Session A commits the salvaged work in that directory (via
git -C), pushes, opens a PR. The directory is now clean. - 12:36 — The user starts a new session ("Security PRs review"). The app assigns it
cwd = .claude/worktrees/sweet-goldwasser-735dae— the same directory — and detaches HEAD there (reflog:checkout: moving from claude/sweet-goldwasser-735dae to HEAD). - 13:25–13:28 — Session A, unaware, runs an interactive rebase in that directory (which mysteriously reports "detached HEAD" — the only visible symptom) and force-pushes the result.
- 13:31 — Session B checks out its own new branch
claude/security-prs-review-0ae263in the directory, yanking the working tree out from under anything else touching it.
Both sessions "won" by luck: the push captured the right tree seconds before the branch switch. If session B had started editing files during session A's rebase window, B's edits would have been silently committed into A's PR (or A's rebase would have destroyed B's uncommitted work).
This is a pattern, not a one-off — three of the user's ten most recent sessions run in recycled directories whose names don't match their branches (e.g. session branch claude/live-coaching-3193a2 in dir frosty-maxwell-054d3c).
Why "clean + idle" is a weak liveness test
- mtime/cleanliness says nothing about intent to use: a directory can be mid-operation between commands (clean is the normal state between git commands).
- Ironically, committing in a directory (the responsible thing to do before leaving it) is exactly what makes it eligible for reuse.
- On machines running many parallel sessions against one repo (orchestrator/swarm workflows), stale-but-referenced worktrees are common.
Suggested fixes (any of)
- Prefer minting a fresh worktree directory; treat reuse as opt-in.
- If reusing, take an explicit lease (lockfile in the dir, honored by all sessions) rather than inferring availability.
- At minimum, exclude directories whose branch has an open PR, and surface the reuse visibly in the session UI ("reusing worktree X") so users can tell why a directory changed hands.
Environment
- Claude Code desktop app (macOS, Darwin 25.5.0), worktree-isolated sessions
- Repo with many worktrees under
.claude/worktrees/
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗