Subdirectory launches skip repo-root .claude/settings.json hooks (fail-open) while permission grants still persist to the root

Status Open
Reported on v2.1.143
Maintainer reply None cached
Activity 0 comments · opened Jul 19, 2026

Summary

When Claude Code is launched from a subdirectory of a git repo, PreToolUse/SessionStart hooks defined in the repo root's .claude/settings.json do not execute at all — while permission-rule persistence ("don't ask again") still writes to the repo root's .claude/settings.local.json. The two subsystems resolve different roots, which looks like a regression rather than a design change (nothing in the changelog documents it).

Environment

  • Claude Code v2.1.215 (also observed startup on v2.1.212), macOS (Darwin 25.5.0)
  • Custom CLAUDE_CONFIG_DIR profile
  • Repo root .claude/settings.json defines PreToolUse (Bash/Edit/Write/Read/Glob/Skill matchers), PostToolUse, SessionStart, UserPromptSubmit, PreCompact hooks. Hook commands use the documented "$(git -C \"${CLAUDE_PROJECT_DIR:-.}\" rev-parse --show-toplevel)"/.claude/hooks/foo.sh pattern.

Repro / evidence

Same machine, same profile, same repo, same day:

  • Session launched from the repo root: transcript contains 592 "hookName":"PreToolUse:Bash" executions plus Edit/Read/Write hook events. A permission-granting hook (returns {"hookSpecificOutput":{"permissionDecision":"allow"}}) suppresses native prompts as expected.
  • Session launched from a subdirectory (<repo>/workshop/): transcript contains zero project hook executions — the only hook that ran was a plugin SessionStart hook. Every Bash command fell through to native permission prompts, including commands the hook would have allowed (verified by piping the same PreToolUse JSON into the hook binary manually — it returns allow).
  • Meanwhile, "don't ask again" grants made in the subdir-launched session were correctly persisted to <repo-root>/.claude/settings.local.json — so settings discovery still finds the root for permissions, but hook loading does not.

Subdirectory-launched sessions loaded root hooks correctly as of v2.1.143 (June 2026); the regression window is v2.1.143 → v2.1.215.

Impact

Repos that use root .claude/settings.json hooks as guardrails (permission gates, deploy guards, branch protection, audit logging) silently lose all of them in any subdir-launched session — a fail-open failure mode with no warning to the user or the model.

Expected

Either subdir launches load the root project settings' hooks (pre-2.1.143 behavior), or the divergence between hook loading and permission persistence is documented and a startup warning surfaces when project hooks are skipped.

View original on GitHub ↗