Worktree session allocator reuses idle worktree dirs, racing other sessions working in them

Status Open
Maintainer reply None cached
Activity 1 comment · opened Aug 1, 2026

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):

  1. 12:12 — Session A commits the salvaged work in that directory (via git -C), pushes, opens a PR. The directory is now clean.
  2. 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).
  3. 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.
  4. 13:31 — Session B checks out its own new branch claude/security-prs-review-0ae263 in 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/

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗