CLI hooks: process CWD drifts away from project root mid-session, causing bare-relative hook commands to resolve against the wrong directory (Windows, 2.1.113)

Resolved 💬 4 comments Opened Apr 20, 2026 by ThatDragonOverThere Closed May 26, 2026

Summary

Claude Code CLI does not pin the hook execution CWD to the project root. In a long session where a sub-agent causes the process CWD to drift into a subdirectory (e.g. .claude/claims/ after writing a claim JSON), subsequent hook firings resolve bare relative commands like python .claude/hooks/foo.py against the drifted CWD — producing paths like .claude\claims\.claude\hooks\foo.py that don't exist. Hooks then fail with [Errno 2] No such file or directory.

Repro

  1. Project with .claude/settings.json containing hook commands like:

``json
{ "command": "python .claude/hooks/reject_deferral_phrases.py" }
``

  1. Long session on Windows, CC 2.1.113.
  2. Spawn a sub-agent that writes files into .claude/claims/ (e.g. via a Python helper that cd's or resolves paths into that subdirectory).
  3. After enough sub-agent activity, the main CC process CWD drifts to C:\<project>\.claude\claims\.
  4. Trigger a hook — PreToolUse:Edit on any file edit, or PreCompact via /compact.
  5. Hook fails:

``
can't open file 'C:\<project>\.claude\claims\.claude\hooks\<script>.py': [Errno 2] No such file or directory
``

Observed (2026-04-19, 2.1.113, Windows)

  • 17:28 PT: BEACH_LEDGER write, PreToolUse:Edit hook reject_deferral_phrases.py fails with doubled path.
  • 17:43 PT: /loop wakeup hits context limit (separate bug — #50920 — autoCompact did not fire).
  • User types /compact to recover → PreCompact hooks (pre_compact_block_check.py, pre_compact_save.py) BOTH fail with the same doubled path → compaction blocked → session dies unrecoverably.

Impact

  • Hooks fail silently during normal tool use (policy hooks like deferral-phrase rejection are not enforced — unsafe).
  • Catastrophic in combination with context-limit exhaustion (#50920): the /compact recovery workaround is unusable because PreCompact hooks fail the same way. A session that hits the context wall can't be saved.
  • Affects any project that follows the common python .claude/hooks/foo.py pattern in settings.json — i.e. the form shown in most example configs.

Expected

CC should either:

  1. Pin the hook execution CWD to the project root (don't inherit the main process CWD, which is allowed to drift), OR
  2. Resolve hook command paths relative to the project root regardless of CWD, OR
  3. Loudly refuse to run a hook command whose first path-like argument doesn't exist at the resolved location and surface the project-root-relative suggestion.

Workaround (local)

Prefix every hook command with $CLAUDE_PROJECT_DIR/:

{ "command": "python \"$CLAUDE_PROJECT_DIR/.claude/hooks/foo.py\"" }

Works, but is a landmine for new users — the example configs and the vast majority of community setups use the bare-relative form.

Related

  • #42065 (CLOSED + LOCKED) — Windows hook relative paths with .. fail intermittently. Same class of bug, slightly different trigger. Lock bot instructed re-filing.
  • #42687 (OPEN) — MCP servers don't receive cwd or CLAUDE_PROJECT_DIR. Adjacent.
  • #50920 (OPEN) — CLI autoCompact no-fire on scheduled task wake. Orthogonal bug — but this CWD issue blocks that bug's documented workaround.

Environment

  • Claude Code CLI: 2.1.113
  • Platform: Windows
  • Project: trading system with heavy sub-agent workflow (ram-safety-auditor writes claim JSONs into .claude/claims/)

Happy to run diagnostics if useful — e.g., a hook that dumps os.getcwd() + env to confirm the CWD-drift mechanism before the doubled path is generated.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗