- In short
- Hook implementation patterns are the reusable shapes for wiring hooks into Claude Code: you declare an event and a matcher in settings.json, point it at a command, and the command reads JSON on stdin and signals its decision through exit codes or structured output.
The anatomy every Claude Code hook examples share
Once you understand the two events, implementation is mostly about wiring. Every working hook has the same three moving parts: the lifecycle event it listens to, a matcher that narrows it to specific tools, and the command it runs. You declare all three in a settings file under a hooks block, and the official settings documentation confirms that this hooks key is where lifecycle event handlers live. Putting the block in a project settings.json means the whole team inherits the same enforcement automatically, which is what makes hooks a shared standard rather than a personal tweak.
Studying Claude code hook examples side by side, the pattern is consistent. Claude Code invokes your command at the chosen moment and pipes the execution details to it as JSON on standard input. Your command inspects that payload, does its work, and communicates back through its exit code and, optionally, a structured JSON object on standard output. Nothing about this is specific to any one rule; it is the substrate that all three patterns below are built on.
- Hook configuration
- A settings.json hooks block keyed by event name, where each entry pairs a matcher (which tools it applies to) with one or more commands. Claude Code runs the matched command at the event, passing execution details as JSON on stdin.
Matchers, events, and exit codes
The matcher is the selector. A PostToolUse entry with the matcher Edit|Write runs only after file edits; a PreToolUse entry matched to a specific tool runs only when that tool is about to be called. Getting the matcher right keeps a hook fast and focused, because it never fires on calls it does not care about. A matcher that is too broad turns every tool call into work; one that is too narrow misses cases you meant to cover.
The signalling channel is the exit code, with structured output for nuance. From a PreToolUse hook, exit 2 is a blocking error that stops the call and surfaces your stderr to the model. Exit 0 allows normal flow, or you can return a hookSpecificOutput object carrying a permissionDecision of allow, deny, ask, or defer. A PostToolUse hook cannot block, since the tool already ran, but it can still return structured fields such as additionalContext to feed the model a cleaned view of the result. Knowing which signal each event honours is the difference between a hook that works and one that silently does nothing.
Events beyond the two tool hooks
This page concentrates on PreToolUse and PostToolUse because they carry Task Statement 1.5, but they are only one band of a wider lifecycle, and a real implementation often spans more of it. The official hooks reference groups events by cadence. Tool-call events (PreToolUse, PostToolUse) fire around each tool invocation. Turn-level events such as UserPromptSubmit and Stop fire around a single agent turn, letting you inspect or rewrite a prompt before the model sees it, or react when the agent finishes responding. Session-level events such as SessionStart and SessionEnd fire once around an entire session, which is where you load setup context or clean up state afterwards.
The reassuring part is that the implementation contract does not change as you move across these bands. Whichever event you attach to, a command hook still receives event-specific JSON on standard input and still answers through its exit code and optional structured output, so the skeleton you learned for the two tool hooks transfers directly. The same holds in the Agent SDK, where hooks are configured under a hooks field on the agent options object, keyed by these same event names. Knowing the full event surface stops you forcing a tool hook to do a job a session or turn hook is built for, which is a common shape of wrong-event mistake the exam likes to test.
Reading the JSON payload defensively
Whatever pattern you are implementing, the command starts by parsing the JSON Claude Code pipes to it on standard input, and how you handle that input separates a robust hook from a fragile one. The payload gives you the tool name, the proposed or actual arguments, and, for a PostToolUse hook, the tool response. Real payloads are not always tidy: a field you expected may be absent, a value may be a string where you assumed a number, or a structure may be nested more deeply than your first draft handled.
A disciplined command never assumes. It validates the shape it received, coerces values explicitly, and has a defined behaviour for the case it did not anticipate. For an enforcing hook that default should be conservative, denying or escalating when it cannot confirm a request is safe; for a normalising hook it should pass the value through untouched rather than corrupt it. Treating the input as untrusted is not paranoia, it is the difference between a hook that silently misbehaves on an edge case and one you can rely on across the full range of calls an agent makes.
The three core patterns
The first pattern is normalisation. A PostToolUse hook matched to tools with inconsistent output reads the tool_response and rewrites it into one canonical shape, so the model always reasons over uniform data. This is the implementation of PostToolUse normalisation, and its defining feature is that it never blocks; it only reshapes.
The second pattern is threshold blocking. A PreToolUse hook matched to a powerful tool parses the proposed arguments, compares them against a limit, and denies the call when it would exceed that limit. This is tool call interception in code, and its defining feature is the pre-execution deny. The third pattern is compliance gating, a specialised block where the hook does not just check a number but verifies that a required precondition, such as an approval or a completed check, is satisfied before allowing a sensitive action to proceed.
Where the hooks block belongs
Placement is part of the pattern, not an afterthought. Because hooks can be declared in different settings files, you choose the location to match the scope of the rule. A guarantee the whole team must share, a deletion guard, a formatter, a compliance gate, belongs in the project settings.json that is checked into the repository, so every contributor and every CI run inherits it automatically. A purely personal convenience can live in a user-level settings file instead, where it shapes only your own sessions.
This mirrors the broader Claude Code configuration philosophy: shared standards are project-level, individual preferences are user-level. Getting the placement right is what turns a clever hook into a dependable control, because a safeguard that only exists on one developer's machine is not really a safeguard for the system. When a question describes a rule that everyone must follow, the implied home for it is the committed project configuration, and recognising that is part of implementing the pattern correctly rather than just writing the command.
Writing the command well
Because the command is ordinary code, ordinary engineering discipline applies. Read the JSON defensively: arguments may be missing or oddly typed, and a hook that throws on unexpected input can disrupt the agent. Make the logic total, so every input maps to a clear allow, deny, or transform, with a sensible default for the unexpected case. Keep it fast, since the hook sits on the critical path of a tool call and latency here is felt on every turn.
Above all, transform carefully. The headline exam trap for this knowledge point is a hook that modifies data incorrectly and introduces new errors. A normaliser that mangles a timezone, truncates a number, or drops a field is worse than no hook at all, because the model now confidently reasons over corrupted data it has no reason to distrust. Treat the transform as production code: cover it with tests, and verify it against real tool outputs before you rely on it.
Worked example
An engineer is asked to add two safeguards to a coding agent: format files after every edit, and block shell commands that delete directories recursively.
For the first safeguard, the engineer adds a PostToolUse hook with the matcher Edit|Write. The command receives the tool_response, runs the project formatter over the changed file, and returns. Because the edit has already happened, the hook is not trying to prevent anything; it is making the result consistent, so the model always sees formatted code regardless of what it originally wrote. This is the normalisation pattern applied to source files.
For the second safeguard, the engineer adds a PreToolUse hook matched to the Bash tool. The command reads the proposed command argument and checks it against a denylist of destructive patterns such as a recursive force-delete of a directory. When it matches, the hook exits 2 with an explanation, so the call never runs and the model is told why. This is the threshold-blocking pattern, except the threshold is a dangerous shape rather than a number.
The two hooks share the same skeleton and differ only where they must: a PostToolUse reshaper that never blocks, and a PreToolUse gate that does. Seeing both expressed in the same settings file, with the same stdin-and-exit-code contract, is the moment the implementation patterns stop being abstract. From here, composing several hooks into an ordered hook pipeline is a small step.
Both safeguards also illustrate how a matcher keeps a hook efficient. The formatter is scoped to Edit|Write, so it never wakes up on a read or a search, and the destructive-command guard is scoped to Bash, so it ignores file edits entirely. Without those matchers each hook would run on every tool call, adding latency to operations it has no opinion about. Choosing a matcher that is exactly as wide as the rule it enforces, no wider, is a quiet but real part of writing the pattern well, and it is the kind of detail a precise exam question will probe.
Common misreadings to avoid
Misconception
As long as a hook is wired to the right tool, the exact transform it applies is a minor detail.
What's actually true
Misconception
You can block a dangerous action with a PostToolUse hook by returning an error after the tool runs.
What's actually true
How it shows up on the exam
This knowledge point sits at the applied end of Task Statement 1.5, so its questions move past which hook and into how. You may be shown a partial configuration and asked what is wrong, or given a requirement and asked which event, matcher, and signal implement it. The credited answers track the three patterns precisely: a PostToolUse reshaper for normalisation, a PreToolUse deny for blocking, and a pre-execution gate for compliance. Distractors usually swap the event, lean on a prompt, or assume a transform is harmless.
A good habit is to name the three parts explicitly for any safeguard: event, matcher, signal. If you cannot fill in all three, you do not yet have a working hook. That discipline also carries into the harder scenarios, where you assemble these patterns into a compliance gate and reason about how they interact. When a question hands you a configuration that does nothing, walk those three parts in order: is the event capable of the action the rule needs, does the matcher actually select the tool in play, and is the signal one the event honours. The fault is almost always in one of the three.
A team wants every Bash command that touches the production database to be blocked unless it is read-only. They add a hook but it never stops anything. Their config uses the PostToolUse event with a matcher of Bash and exits 2 on a write. What is the actual problem?
People also ask
Where are Claude Code hooks configured?
What is a hook matcher?
What exit code blocks a tool in a hook?
Watch and learn
Official Anthropic Academy lessons first, then hand-picked walkthroughs. Videos load only when you press play.
Defining hooks
Why watch: Configuring hook events and matchers is the implementation-pattern knowledge this KP covers.
More videos for this concept
References & primary sources
Master this concept with Archie
Practice it inside an adaptive study session. Archie, your Socratic AI tutor, tracks your mastery with Bayesian Knowledge Tracing and schedules the perfect next review.