PreToolUse hooks in project .claude/settings.json are silently not registered
Claude Code version: 2.1.201
Summary: A PreToolUse hook defined in a project's .claude/settings.json never fires — the harness appears to drop the hooks key during config load while other keys in the same file (e.g. permissions) load and apply correctly.
Repro:
- Add to
.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Edit|Write|Grep|Bash",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/my-hook.sh\"" }
]
}
]
}
}
- Verify the script is valid standalone (e.g. pipe a matching
PreToolUseJSON payload into it directly — it behaves correctly). - Start a fresh
claudesession in the project (full process restart, not just a new chat) and trigger a matching tool call (e.g.Readon a path the hook should deny). - The tool call succeeds; the hook script is never invoked (confirmed via temporary logging added at the top of the script — no log entries appear).
Diagnostics:
/hooks→ PreToolUse: "No hooks configured for this event" (despite the config above being present and valid JSON).claude --debug hooksstartup log showsHooks: Found 0 total hooks in registry, in the same startup sequence whereApplying permission update: Adding N allow rule(s) to destination 'projectSettings'correctly reflects thepermissionsblock from the identical settings.json file.
Expected: The hook should be registered and invoked on matching tool calls.
Actual: The hooks key from project .claude/settings.json is never registered into the runtime hook registry, while other keys (permissions) from the same file load normally.
Ruled out: stale in-process config cache (confirmed genuine restart via process start time vs. file mtimes), settings.local.json override (no hooks key present there), hooks-specific trust gate (no such flag in ~/.claude.json; general hasTrustDialogAccepted already true), cwd vs. repo-root discovery (settings.json is correctly discovered/watched regardless of cwd — confirmed via debug log Watching for changes in setting files ...).