[BUG] Worktree guard refuses git -C ~/… in user ! commands; reason withheld under Remote Control
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
In a session that EnterWorktree binds to a worktree, a user ! command fails when it runs git -C ~/<path>. The worktree command guard refuses it before spawn, because it treats a ~ path as "computed at runtime". The same command with an absolute path or with "$HOME/<path>" runs. I tested the three path forms with git status; the refusal text names only the -C path.
Three problems combine:
- The guard rejects
~but accepts$HOME. Tilde expansion is static;$HOMEis the runtime value. - The guard applies to commands that the user types with
!. Those commands are the user's own pass-through, not agent tool calls. - When the session is connected through Remote Control, the user's own terminal shows only
Command failed: shell command failed (detail withheld on this connection). The refusal reason goes only to the debug log. Without--debug-file, the user cannot see why the command failed.
Result: ! git -C ~/other-repo push failed in about 50 ms with no reason shown. The same push ran in a plain terminal and in a session without a worktree binding.
What Should Happen?
! <command>runs the command as typed, or shows the real refusal reason in the user's terminal.- The guard handles
~/paththe same way as$HOME/path(both resolve before spawn). - The guard does not apply the agent worktree-isolation policy to user
!commands, or it says so in the visible error.
Error Messages/Logs
Transcript, user terminal:
<bash-stderr>Command failed: shell command failed (detail withheld on this connection)</bash-stderr>
Debug log (--debug-file):
[WARN] [worktree] blocked shell exec: command guard refused (This session is isolated in the worktree /path/to/repo.feature, but this command points git at a directory computed at runtime (-C ~/other-repo), which can't be verified before it runs. Refusing to run it — a worktree-isolated session's git operations must target its own worktree. Run the equivalent from /path/to/repo.feature without the redirect.): cwd=/path/to/repo.feature isolationRoot=/path/to/repo.feature
[ERROR] bash spawn failure detail: This session is isolated in the worktree /path/to/repo.feature, but this command points git at a directory computed at runtime (-C ~/other-repo), ...
Steps to Reproduce
- Have a repository with a linked worktree, for example
~/repoand~/repo.feature. Have a second, unrelated repository, for example~/other-repo. - Start
claude --debug-file /tmp/cc.txtin~/repo, with Remote Control connected. - Ask Claude to call
EnterWorktreewithpath: ~/repo.feature(absolute path). - Type
! git -C ~/other-repo status. Result:Command failed: shell command failed (detail withheld on this connection). - Type
! git -C /Users/<you>/other-repo status. Result: normalgit statusoutput. - Type
! git -C "$HOME/other-repo" status. Result: normalgit statusoutput. - Run
grep 'command guard refused' /tmp/cc.txt. It shows the refusal for step 4 only.
In a session without EnterWorktree, step 4 runs normally.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.291 (Claude Code). Also reproduced on 2.1.289.
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Ghostty with tmux, zsh
Additional Information
The guard also refuses the agent's own Bash tool call git -C ~/other-repo status. For that tool call the model receives the full refusal reason. Only the user ! path replaces the reason with the withheld message.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗