Skip to content
Christian Monge

Claude Code

Claude Code Hooks: Rules That Always Run

What Claude Code hooks are for, the five worth setting up first, how they differ from instructions in CLAUDE.md, and the mistakes that make a session unusable.

cmChristian Monge4 min read
A frosted glass pipeline with three small white ceramic clamps attached, each clamp glowing electric blue

Claude Code hooks are shell commands that run automatically at fixed points in a session. That is the whole mechanism. What makes them worth understanding is the distinction they create: a hook runs every time, while an instruction written in a file is followed most of the time.

For anything where "most of the time" is expensive, that gap is the entire argument.

What Claude Code hooks are for

Three categories, and it is worth being clear about which one you are in before you write anything.

Enforcement. Rules that must not be skipped. Format after every edit. Run the test suite for the area you touched. Refuse to execute a command from your denylist. These are the ones that pay back immediately, because they remove a class of mistake rather than reducing it.

Context. Loading information at the start of a session so you do not paste it again: current branch, environment, which services are running.

Signals. Notifying you when a long task finishes, or logging what happened for later review.

Enforcement is where almost all the value is. The other two are convenience.

The five worth setting up first

Format after edit. Run your formatter on files that changed. Removes an entire category of diff noise and the review comments that come with it.

Test after change. Run the tests relevant to what was touched, not the whole suite. The feedback arrives while the reasoning is still fresh, which is when it is cheapest to act on.

Block dangerous commands. A denylist for anything you never want run: force pushes to main, destructive database commands, deletions outside the project. This is the hook that saves a bad afternoon.

Load context at session start. Branch, environment, anything you would otherwise type in the first message.

Notify on completion. For long-running work you have walked away from.

Start with the first three. They are the ones that change behaviour rather than convenience.

Hooks versus the other configuration layers

Claude Code gives you several places to put a rule, and choosing wrong is how people end up with configuration that fights itself.

CLAUDE.md is for context and conventions: what this project is, how it is structured, which commands to use, what to leave alone. The model reads it and generally complies. Perfect for guidance, wrong for guarantees.

Hooks are for guarantees. Deterministic, unconditional, no judgement involved.

Skills are for repeatable procedures with steps. A hook is a reflex; a skill is a method.

Subagents are for delegated work that needs its own context.

The test I use: if the rule has an exception, it belongs in CLAUDE.md. If it never has an exception, it is a hook.

Claude skills vs subagents vs MCP covers the full comparison.

Writing one that does not ruin your session

Hooks run constantly, so their cost is multiplied by everything you do. Four rules keep them from becoming the problem.

Fast. Under a second. A three-second hook on every edit is a tax you will pay hundreds of times a day and eventually disable in frustration.

Quiet. Print nothing on success. Every line of hook output competes with your actual work for context.

Specific. Run the tests for the area that changed, not the full suite. Format the file that was edited, not the repository.

Tested. Run the command yourself first, including on the weird case. A hook that errors on files with spaces in the name will find one.

Also: exit codes matter. A non-zero exit from a blocking hook stops the action, which is exactly what you want from the denylist and exactly what you do not want from a formatter that fails on an unrelated file.

Where they fit in a real setup

My default for a project I will spend real time in:

  1. CLAUDE.md with the project description, the commands, the conventions and the things not to touch.
  2. Format and test hooks so the mechanical standards are never a discussion.
  3. A denylist hook for the handful of commands that should never run.
  4. Skills for procedures I repeat weekly.
  5. Subagents for wide searches and independent review.

That order matters. People who start with hooks before writing CLAUDE.md end up encoding rules in shell scripts that would have been one sentence of context.

A hook is code you now maintain

The thing people forget is that a hook becomes part of your development environment permanently, and everyone who clones the project inherits it.

Treat it accordingly. Keep hooks in version control with the project rather than in a personal settings file, so a colleague does not get different behaviour from the same repository. Comment the non-obvious ones, because a shell command that blocks an action with no explanation is infuriating to debug six months later. And review them when the project changes: a test hook pointing at a directory that was renamed fails silently, and silent failure is worse than no hook, because you stopped checking manually the day you wrote it.

The denylist deserves particular care. Write it narrowly and test each pattern against both the command you want blocked and the similar command you want allowed. An over-broad pattern that blocks half your legitimate git usage teaches people to bypass the whole mechanism.

The mistakes I see

Hooks that duplicate CLAUDE.md. If the model already follows it reliably, a hook adds latency for nothing.

Blocking hooks with bugs. A denylist with an over-broad pattern blocks legitimate work and the failure looks like the tool misbehaving.

Chatty hooks. Logging success on every call fills the context with noise you paid for.

Running everything. The full test suite after every edit sounds rigorous and is why people turn hooks off.

The short version

Use hooks for the rules that must never be skipped, CLAUDE.md for the ones that need judgement. Start with format, test and a denylist. Keep them fast, silent on success, narrow in scope and tested on the ugly case.

If you want the whole configuration built properly, how to use Claude Code covers the fundamentals and my Claude Code course covers the setup I use on client work.

Frequently asked questions

What are Claude Code hooks?

Shell commands that run automatically at defined points in a session, such as before or after a tool is used. They are configured in your settings and they execute deterministically, which makes them the right place for rules you cannot afford to have skipped.

Why use a hook instead of writing the rule in CLAUDE.md?

CLAUDE.md is guidance the model reads and generally follows. A hook is code that always executes. Use CLAUDE.md for conventions and context, and a hook for anything where an occasional miss is expensive, such as running the formatter or blocking a destructive command.

Which hooks should I set up first?

Format after edit, run the relevant tests after a change, and block commands you never want executed. Those three cover most of the value. Add a session-start context loader and a notification hook only once the first three are stable.

Can a hook break my session?

Yes, and it is the main risk. A hook that is slow runs on every action and makes everything sluggish. A hook that prints a lot fills the context with noise. A hook with a bug can block legitimate work. Keep them fast, quiet and tested before you rely on them.

Sources

  1. 01Claude Code documentation
  2. 02Claude Code settings reference
  3. 03Model Context Protocol
cm

Christian Monge

Builds AI second brains with Obsidian and Claude Code, co-founded the competitive-intelligence SaaS Pengu Insights, and trains teams in English and Spanish from Madrid.

More about me

Claude Code Course

Learn it live, on your own work.

Four weeks, small cohort, real repos. You leave with skills, subagents and MCP workflows you actually use.

Join the course waitlist

Keep reading