EnterWorktree(path=...) to a valid but non-nested worktree reports success and moves Bash cwd, but the Write/Edit guard silently keeps the original binding
Summary
EnterWorktree(path=...), called from a session already running in a linked worktree, reports success and correctly moves the Bash tool's cwd to the target — but only actually rebinds the Write/Edit cross-worktree guard when the target worktree is nested under .claude/worktrees/. For a target that is a valid, already-registered worktree of the same repository but lives outside .claude/worktrees/ (e.g. created directly under the repo root via git worktree add), the switch silently half-applies: Bash cwd updates, the success message is unconditional and gives no indication anything is incomplete, but Write/Edit continue to enforce the original launch worktree as the binding — and the guard's own error message misidentifies the new (valid, git-registered) worktree as "the base repo checkout," then suggests a "corrected" path that nonsensically nests the target worktree underneath the original launch worktree on disk.
Reproduction
Both cases below were run from the same session, launched pinned to worktree A (.claude/worktrees/unruffled-cray-b06846), in the same repository.
Case 1 — compliant target (nested under .claude/worktrees/):
git worktree adda second worktree at.claude/worktrees/bugrepro-teston a new branch.EnterWorktree(path=".../.claude/worktrees/bugrepro-test")→ reports success.Bashpwd→ correctly reports the new worktree.Writea new file inside the new worktree → succeeds, no guard error.
Case 2 — non-compliant target (a valid worktree of the same repo, NOT nested under .claude/worktrees/):
- A second worktree already exists at
<repo-root>/fewer-permission-prompts-allowlist(created viagit worktree adddirectly under the repo's parent directory, appears correctly ingit worktree liston its own branch). EnterWorktree(path="<repo-root>/fewer-permission-prompts-allowlist")→ reports success: "Entered worktree at ... The session is now working in the worktree."Bashpwd→ correctly reports the new worktree path.Writea new file inside the new worktree → refused:
> This session is running in an isolated git worktree at <repo-root>/.claude/worktrees/unruffled-cray-b06846, but <repo-root>/fewer-permission-prompts-allowlist/BUG_REPRO_TEST.md is in the base repo checkout. Edits there do not land on this session's branch and may corrupt the user's primary working copy. Use the worktree path instead: <repo-root>/.claude/worktrees/unruffled-cray-b06846/fewer-permission-prompts-allowlist/BUG_REPRO_TEST.md
- Repeated after
ExitWorktree(action: "keep")followed by a freshEnterWorktree(path=...)on the same target → byte-identical failure, ruling out simple staleness.
The corrected path suggested in step 4 does not reflect where the target worktree actually lives on disk — it nests the second worktree's relative path underneath the first worktree, which is not a real location and would not resolve to the target's actual git working tree if followed.
Expected behavior
Either:
EnterWorktree(path=...)should fully honor the switch for any worktree that is valid and registered ingit worktree listfor the same repository (matching what its own tool description implies for "entering an existing worktree" generally), rebinding theWrite/Editguard the same way it rebindsBash's cwd; or- If nesting under
.claude/worktrees/is a hard requirement for the guard to follow the switch,EnterWorktree(path=...)should say so and refuse (or clearly warn) rather than reporting unconditional success for a target it cannot fully switch into.
In either case, the guard's error message should correctly identify a valid linked worktree as such (not "the base repo checkout"), and any suggested "corrected path" should reflect where the target worktree actually resides on disk.
Actual behavior
EnterWorktree(path=...) unconditionally reports success and moves Bash's cwd for any git-valid target, but the Write/Edit guard's worktree binding is only updated for targets nested under .claude/worktrees/. For any other valid worktree of the same repo, the tools disagree about where the session is: Bash believes the switch happened, Write/Edit still enforce the pre-switch worktree, and the block message's own diagnosis (calling the target "the base repo checkout") and remediation (a path that nests the target under the original worktree) are both incorrect.
Environment
- OS: Windows 11 Enterprise 10.0.26200
- Claude Code CLI / Agent SDK session, main thread (not a subagent)
- Both worktrees are of the same git repository; the non-compliant one was created via
git worktree add(plus a--no-checkout+checkout -fworkaround for an unrelated Windows colon-in-filename issue), landing directly under the repo's parent directory rather than under.claude/worktrees/
Related issues
Two open issues describe adjacent but distinct symptoms of what may be the same underlying binding-update gap:
- #82354 —
Write/Editstay pinned to a subagent's launch-time worktree after it callsEnterWorktreeto switch into a new one it just created. - #87890 — after
EnterWorktree,PreToolUsehook subprocesses keep resolvingCLAUDE_PROJECT_DIR/cwd against the original directory rather than the new worktree (Windows).
Neither covers this specific case: a main-thread session switching via path to an existing, git-valid, already-registered worktree of the same repository that simply isn't nested under .claude/worktrees/, with the "base repo checkout" mislabel and the nonsensical nested "corrected" path.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗