[BUG] Desktop worktree Write/Edit guard blocks files in a separate git repo nested under the base checkout
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet (related, not the same case: #95776, #95389)
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
In a desktop-app session isolated in a worktree, the Write/Edit worktree guard blocks writes to files that belong to a different git repository nested inside the base repo's folder. The guard treats any path under the base checkout's directory as "the base repo checkout" without asking git which repository owns the path.
Layout (paths generalized):
~/work/company/ <- repo A (base checkout); `products/` is gitignored here
~/work/company/.claude/worktrees/session-x/ <- this session's worktree of repo A
~/work/company/products/app/ <- repo B, its own .git, unrelated to repo A
~/work/company/products/app/.claude/worktrees/feature-y/ <- a worktree of repo B
A Write to ~/work/company/products/app/.claude/worktrees/feature-y/notes/x.md is blocked with:
This session is running in an isolated git worktree at~/work/company/.claude/worktrees/session-x, but~/work/company/products/app/.claude/worktrees/feature-y/notes/x.mdis 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:~/work/company/.claude/worktrees/session-x/products/app/.claude/worktrees/feature-y/notes/x.md
The target is not in repo A's checkout. git -C <target dir> rev-parse --show-toplevel --git-common-dir returns repo B's worktree and products/app/.git. The suggested replacement path does not exist and cannot exist, because products/ is gitignored in repo A.
Side effect: agents work around the block by writing the file through a Bash heredoc, which the guard does not see (the same Edit-vs-Bash asymmetry reported in #95776). So the guard adds friction here without adding protection, and it teaches the agent to route around it.
What Should Happen?
Before blocking, the guard should resolve the repository that owns the target (for example git rev-parse --git-common-dir from the nearest existing parent directory). It should block only when that common dir equals the session repo's common dir and the target is outside the session worktree. A path owned by a different repository should be allowed, or at least not described as the base repo checkout.
Error Messages/Logs
See the quoted block message above.
Steps to Reproduce
- Create repo A with a gitignored subfolder, and create repo B (
git init) inside that subfolder. - Open repo A in the Claude desktop app (Code tab) with a worktree-isolated session.
- Ask Claude to Write any file inside repo B, either repo B's main checkout or one of its worktrees.
- The Write is blocked as "in the base repo checkout", with a nonexistent suggested path.
Seen twice in real sessions on 2026-09-25. I have not reproduced it in a throwaway repo, because the guard is in the desktop app and does not run under the headless CLI. From reading the bundled app code, the check is a path-containment test against the base repo root with no repository-identity check, which matches the behaviour above.
Claude Model
Opus
Is this a regression?
I don't know
Claude Code Version
Desktop app 2.9939.2; Claude Code 2.1.282
Platform
Anthropic API
Operating System
macOS 26.6.2
Terminal/Shell
Claude desktop app (Code tab)
Additional Information
Related guard issues with the same root cause (path containment instead of repository identity): #95776 (a separate registered worktree under <base>/.claude/), #95389 (the guard keeps its original binding after EnterWorktree(path=...)).
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗