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.