Hooks and Automation

Hooks turn "please always run the formatter" from a hope into a guarantee — deterministic shell commands that fire on Claude Code's lifecycle events, no matter what the model decides.

Prompting and CLAUDE.md shape what Claude Code tends to do, but they’re probabilistic — the model usually follows them. For things that must happen every time, you want determinism. Hooks provide it: user-defined shell commands that Claude Code runs automatically at specific points in its lifecycle. They’re how you enforce policy, automate the boring, and wire the agent into your existing tooling with certainty rather than hope. This post is about using them.

What hooks are

A hook is a command you register to run on a lifecycle event. Instead of asking the model to remember to do something, the hook always does it. The events cover the key moments in an agent’s loop — notably:

Because hooks are just shell commands, they can do anything your shell can: run a formatter, run tests, lint, log, send a notification, or block an action.

What hooks are great for

The canonical uses cluster around guarantees and automation:

The gotcha: the power of hooks is that they run deterministically with your permissions — which is also the risk. A hook is arbitrary code that executes automatically; a careless or malicious hook can do real damage without a prompt. Only add hooks you understand, keep them simple, and be cautious with hooks from untrusted sources.

Hooks vs. prompting vs. permissions

These three controls do different jobs, and using the right one matters:

The pattern: use CLAUDE.md for “please prefer,” permissions for “ask me first,” and hooks for “always/never, no exceptions.” Reaching for a hook when a CLAUDE.md line would do adds brittle machinery; relying on a CLAUDE.md line when you need a guarantee (a compliance rule, a protected path) leaves a gap the model can slip through.

The gotcha: trying to enforce a hard rule (“never touch the migrations folder”) through CLAUDE.md wording alone is unreliable — the model usually complies, but “usually” isn’t a guarantee. If it must never happen, a PreToolUse hook that blocks it is the right tool.

Keeping hooks maintainable

Hooks are configuration that lives with the project (committed, like the rest of post 3’s setup), so treat them as code:

Committing hooks to the repo means the whole team gets the same automatic formatting, the same guardrails, and the same checks — turning individual discipline into enforced team policy.

A worked example: format-on-edit and a protected path

The two canonical first hooks, conceptually:

PostToolUse (after an Edit/Write to a *.go file):
   run:  gofmt -w "$file"   (and maybe goimports)
   → every file Claude Code touches is formatted, always, with zero review attention

PreToolUse (before an Edit/Write):
   check: is the target path under internal/pb/ (generated code)?
   if yes → block with "refusing to edit generated protobuf; edit the .proto instead"
   → a hard guarantee the model cannot bypass, unlike a CLAUDE.md line it may overlook

The first hook removes formatting from your review surface entirely — you never again comment on gofmt. The second is the important distinction: a CLAUDE.md rule “don’t edit generated files” is followed usually; a PreToolUse hook that inspects the path and blocks the action makes “never” actually mean never. That’s the whole reason hooks exist alongside prompting — determinism where it matters.

The gotcha: because the PostToolUse formatter runs on every matching edit, a slow or heavy command there (say, rebuilding the whole project) taxes every single action the agent takes. Scope the hook to the changed file and keep it to seconds — format the file, don’t rebuild the world.

A realistic starter set

Most teams converge on a small, high-value set: auto-format on edit, run the linter/tests after changes to catch breakage in the loop, block edits to generated or protected paths, and a notification when the agent needs attention. That handful removes a whole category of “did it remember to…” review and makes the agent’s behavior consistent and safe. Add more only when a real, repeated need appears — hook sprawl is its own maintenance burden.

Key takeaways

Further reading