EnterWorktree intermittently moves the working directory but not the session root
Summary
EnterWorktree appears to apply only partially on some invocations: file operations relocate into the new worktree, but the session itself stays rooted at the original directory. The call returns its normal success message in both cases, and pwd reports the new worktree path in both cases, so from inside the session the two outcomes are indistinguishable.
I have 13 runs where every input I control was identical and the outcome split 9/4.
Environment
- Claude Code 2.1.220
- macOS 26.5.2 (Apple silicon)
- Sessions launched non-interactively into Terminal via
osascript, with--permission-mode dontAsk --settings <profile>.jsonand a slash command as the initial prompt - Target: a linked git worktree under
<repo>/.claude/worktrees/<name>
What I observed
Across 13 automated runs, each launched by an identical script and each executing the same skill:
- every run called
EnterWorktreeexactly once, with the correctname - every run had exactly one preceding tool call (
ToolSearch, to load the deferredEnterWorktreeschema) - the call happened 29–39s after session start in every run (killed 29–33s, completed 30–39s — fully overlapping)
- every run received the same success result:
Created worktree at <repo>/.claude/worktrees/<name> on branch <branch> - every run then ran
pwd, and all 13 returned the correct worktree path
Despite that, 9 of 13 sessions re-rooted and 4 did not.
How the difference is observable
The only signal I found is external to the session: Claude Code derives a session's transcript directory under ~/.claude/projects/ from the session root. Runs that genuinely re-rooted got a directory slugged from the worktree path; runs that did not kept writing under the original project slug, even though their file writes were landing in the worktree.
That directory appears 34–41s after launch, i.e. at the EnterWorktree call, so it reflects the call's outcome rather than anything later in the run.
Why it matters
The repository in question is a shared working tree used by concurrent sessions, so worktree isolation is a correctness property, not a convenience. Two consequences:
- A session can believe it is isolated, pass the obvious
pwdcheck, and still be half-attached to the original root. - In my runs the partial-application state correlated perfectly (4/4) with the launching process being stopped mid-run, orphaning the session. I want to be explicit that I have not established causation for that second point — the correlation is clean but the mechanism is unknown, and it may well be incidental.
What I'd suggest
Either make the re-rooting atomic (both move, or neither and the call reports failure), or expose the session's actual root so a caller can verify it. Today there is no in-session check that distinguishes the two outcomes — pwd succeeds in both.
Workaround, for anyone hitting the same thing
Stop relying on a running session relocating itself. Create the worktree with git worktree add beforehand and start the session with that directory as its cwd. The session is then correctly rooted from process start and nothing has to move. This removed the failure entirely for me.
🤖 Generated with Claude Code