Claude Code hooks: why "just tell it not to" doesn't hold up

작성자

카테고리:

← 피드로
DEV Community · VincentChabran · 2026-08-03 개발(SW)

If you’ve spent time customizing Claude Code, you’ve probably written a line like this in your CLAUDE.md: “always run the formatter after editing a file” or “never touch .env or any .pem/.key file.” It works — until a long session, a big diff, or a context window full of other instructions makes that one line easy to deprioritize. The model isn’t being careless; a system prompt is advisory. Every instruction in it competes with everything else in context for attention, and instructions written early tend to fade as the conversation grows.

That’s a structural limit, not a prompting mistake. And it means anything you actually need to happen every single time — not “usually,” not “when the model remembers to” — doesn’t belong in a prompt at all.

What a hook actually is

Claude Code hooks are shell commands wired to specific points in the tool’s lifecycle: after a file edit, before a tool runs, when Claude finishes responding, when it needs your permission, at the start of a session. They execute as code, deterministically, regardless of what’s in the conversation or what the model “decided” to prioritize that turn. The model doesn’t get a vote — the hook just runs.

That distinction matters more than it sounds. A CLAUDE.md rule is a request you’re hoping gets honored. A hook is a guarantee, because it’s not the model doing the enforcing.

Where the line actually falls

Not everything belongs in a hook. The useful split is:

  • Must always happen, no judgment required → hook. Reformatting a file after every edit. Blocking writes to a credentials file before they land. Running your test suite the moment Claude stops and printing a one-line pass/fail. Pinging your desktop when Claude is waiting on you. Logging that a session started, with a timestamp, every time.
  • Benefits from reasoning about the specific case → prompt / subagent. Deciding whether a diff has a security problem, what a docstring should say, how to restructure a function — that’s judgment, and judgment is what the model is for. Trying to hardcode that into a shell script just moves the fragility somewhere worse.

Getting this backwards is the common failure mode: people write increasingly elaborate CLAUDE.md instructions trying to force deterministic behavior out of a probabilistic system, when a five-line shell hook would have made the question moot.

A cheap companion: visibility instead of enforcement

A statusline doesn’t enforce anything — it’s just a line under your prompt showing which model, which directory, which git branch you’re currently in. It matters for a much smaller reason: once you’re running more than one Claude Code session in parallel (a common outcome of subagents and worktrees), “which one is this again” becomes a real source of mistakes. Cheap to add, easy to forget you need until you’re context-switching between four terminals.

The takeaway

Before adding another paragraph to your CLAUDE.md, ask whether what you actually want is a rule the model should weigh, or a guarantee that shouldn’t depend on it weighing anything at all. If it’s the latter, write a hook instead.

(Written with AI assistance.)

A working set of these — auto-format on edit, a secret-file guard that blocks writes to .env/*.pem/*.key before they happen, run-tests-on-stop, desktop notifications, and session logging — plus 12 slash commands, 6 subagents, and a git-aware statusline, is packaged as the Claude Code Power Pack (copy-paste into .claude/, €29): https://vincentdu2a.gumroad.com/l/bqndfi. It’s an independent, unofficial project — not affiliated with, endorsed by, or sponsored by Anthropic. “Claude” and “Claude Code” are trademarks of Anthropic.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다