Hooks fail open when CWD is invalidated (e.g. worktree deletion)
Summary
When the shell's working directory becomes invalid — whether from an external process deleting it OR from a command within the same session (e.g., git worktree remove) — all hooks fail with ENOENT: no such file or directory, posix_spawn '/bin/sh'. The harness treats these execution failures as "hook didn't block," so tool calls proceed without any hook-based enforcement.
Reproduction
- Launch Claude Code with a git worktree as the project root (or
cdinto one during the session) - Run
git worktree remove <path>from within the session, or delete the directory from another terminal - Issue any subsequent tool call
- Observe: hooks error out with posix_spawn ENOENT, but the tool call proceeds as if allowed
This also reproduces when the session itself runs git -C <parent> worktree remove <target> — the git command succeeds, the directory is gone, and every subsequent hook invocation fails open.
Expected behavior
- A hook that fails to execute (ENOENT, missing CWD, posix_spawn failure) should be distinguishable from a hook that ran and returned "allow." The harness should either:
- Block the tool call (fail-closed) when hooks cannot execute due to environment errors, OR
- Surface a visible warning that hook enforcement is degraded, OR
- Detect that CWD is invalid before attempting to spawn hooks, and enter a recovery state
- The harness should expose a mechanism to change the session's working directory — a shell-level hook, API call, or tool that lets the model, the user, or a hook script set the CWD that subsequent tool calls and hook invocations inherit. Currently there is no way to recover from an invalidated CWD without restarting the session. A
cd-equivalent that actually persists across tool calls would allow recovery (move to a valid directory) and prevent the unbounded fail-open window.
Actual behavior
- Hook execution errors are treated identically to "hook allowed the operation" (fail-open)
- No warning or indication that enforcement is absent
- Multiple consecutive tool calls proceed without any gate checking
- Recovery only happens when the Bash tool's shell detects the missing CWD and resets it (may be many turns later)
- There is no mechanism for anyone (model, user, hook) to change the session CWD to a valid path
Impact
Any hook-based enforcement (PreToolUse gates, PostToolUse tracking, UserPromptSubmit validation) is silently disabled for an unbounded window. The session continues operating as if no hooks are configured.
Environment
- Claude Code CLI, Linux 5.15
- Triggered by: git worktree removal (in-session or external), external directory deletion, any operation that invalidates the shell's CWD while the session is active