Skip to content

Why Hooks (not settings.json)

For the big picture — why this tool exists — see Why patronum.

Claude Code has a built-in permissions.deny mechanism in settings.json. It's the obvious first choice — but a growing number of community reports suggest it doesn't hold up well in practice.

The problem with settings.json

Issues have been filed across a range of scenarios: file reads, file writes, Bash commands, sub-agents, symlink traversal, and even managed settings from the Anthropic Console:

Not all of these may still be reproducible — but the breadth of the pattern is hard to dismiss. When you're protecting credentials or sensitive files, "usually works" isn't enough.

Why hooks are a better fit

PreToolUse hooks run as an executable before every tool call — a shell script, a Node script, a Python script, whatever fits your setup. They receive the tool name and input as JSON on stdin, and the response is simple:

  • exit 0 — allow the call
  • exit 2 — block it, with a reason on stderr

What makes this more than just another deny mechanism is visibility. Every blocked call is explicit and logged — you know exactly what fired, when, and why. There's no silent fallthrough, no ambiguity about whether a rule was applied.

Unlike a passive config rule, a hook is code you own — you decide what runs, what blocks, and what gets logged.

Further reading

  • Hooks Guide — practical introduction, common patterns, and lifecycle overview
  • Hooks Reference — complete technical reference: configuration schema, input/output formats, exit codes, matcher syntax, and all hook event types