Part ofWhat Is Claude Code? The Complete Guide
In This Article
8 sectionsQuick answer
Claude Code hooks are shell commands that fire on lifecycle events — tool use, session start, stop — to format code, run tests, and block risky actions.
Claude Code hooks are user-defined shell commands that run automatically at fixed points in the agent's lifecycle — before or after a tool runs, when a session starts, or when Claude stops. They fire deterministically every time, so you can enforce policy, auto-format edits, run tests, or block risky actions without trusting the model to remember.
Hook events and exit-code behavior verified 31 July 2026 against Anthropic's Claude Code hooks reference.
That last word is the whole point. We run this site with Claude Code every day — hooks are a big part of how we get shit done with Claude Code without babysitting it — and the gap between "please run the formatter after editing" typed into a prompt and a hook that runs the formatter is the gap between usually and always. Hooks are the deterministic layer under an otherwise probabilistic agent. New to the tool? Start with our pillar, What Is Claude Code?, then come back here. Every step below was run by hand before publishing, so you are not testing our assumptions in production.
Key takeaway
Claude Code hooks are shell commands that fire deterministically on lifecycle events (PreToolUse, PostToolUse, SessionStart, Stop, and more), turning a prompt's "usually" into "always" — a PreToolUse hook that exits 2 blocks a tool call every single time.
What are Claude Code hooks?
A hook is a rule registered in a settings file: when event X happens, run command Y. Claude Code fires the event, your command runs, and its exit code decides whether the action proceeds, is blocked, or feeds text back to the model.
A hook is a rule you register in a settings file: when event X happens, run command Y. Claude Code fires the event, your command runs, and its result can let the action through, block it, or feed text back to Claude. Because a shell command either runs or it doesn't, hooks give you guarantees a prompt never can.
The mechanism has three moving parts, and they nest:
- The event — a lifecycle moment like
PreToolUse(before a tool runs) orPostToolUse(after it succeeds). - The matcher — an optional filter that narrows the event to specific tools, for example only
EditorWritecalls rather than every tool. - The handler — the thing that actually runs. Usually a shell command, though Claude Code also supports HTTP endpoints, single-shot prompts, and subagents.
Anthropic's official hooks reference documents every event and field, but you'll reach for a handful in daily practice.
How the hook lifecycle works
Claude Code pipes a JSON payload — session ID, working directory, tool name, tool arguments — to your handler on stdin. Exit 0 to allow, exit 2 to block and send stderr back to Claude as feedback, anything else logs a non-blocking error.
When an event fires, Claude Code passes a JSON payload to your handler on standard input — the session ID, the working directory, the tool name, and the tool's arguments. Your script reads that JSON, does its work, and signals back through its exit code:
| Exit code | Meaning | What Claude Code does |
|---|---|---|
0 | Success | Action proceeds; stdout can add context on some events |
2 | Blocking error | Action is blocked; stderr is fed back to Claude as feedback |
| Any other | Non-blocking error | Action proceeds; the error is logged to the transcript |
That exit-code-2 behavior is the single most useful thing to memorize. A PreToolUse hook that exits 2 stops the tool call cold and hands your stderr message to Claude, which then adjusts its plan. For finer control, exit 0 and print a JSON object to stdout instead — you can return a permissionDecision of deny, allow, or ask, each with a reason string Claude reads.
One caveat worth internalizing: matching hooks run in parallel, and the most restrictive answer wins. A deny from one hook doesn't cancel a sibling hook's side effects, so don't rely on one hook to suppress another.

Claude Code hook events you'll actually use
Six events cover almost every real setup: PreToolUse and PostToolUse for tool calls, UserPromptSubmit for prompt screening, SessionStart for context loading, Stop for completion checks, and Notification for desktop alerts.
There are more than two dozen Claude Code hook events, from SessionStart to PreCompact to SubagentStop, and our Claude Code hooks documentation walks through every one with its config fields. Most you'll never touch. These are the ones that earn their config:
| Event | Fires | Typical use |
|---|---|---|
PreToolUse | Before a tool runs | Validate or block a command; guard protected files |
PostToolUse | After a tool succeeds | Auto-format, lint, or run tests on the change |
UserPromptSubmit | When you submit a prompt | Inject context; screen the prompt before Claude sees it |
SessionStart | Session begins or resumes | Load environment variables or reminders into context |
Stop | Claude finishes responding | Verify the work is actually done before it stops |
Notification | Claude needs your input | Desktop alert so you can switch tasks |
The matcher for tool events filters on the tool name — Bash, Edit|Write, or a regex like mcp__github__.*. For SessionStart it filters on how the session started (startup, resume, compact). Get the matcher wrong and the hook simply never fires, which is the number-one support question about Claude Code hooks.
Claude Code hooks setup: the settings.json file
Register hooks in .claude/settings.json to share them with your team, .claude/settings.local.json to keep them private, or ~/.claude/settings.json to apply them everywhere. The structure nests event, then matcher group, then handlers.
Claude Code hooks setup lives in a settings.json file, and scope depends on which file you edit:
.claude/settings.json— this project; commit it to share hooks with your team..claude/settings.local.json— this project, gitignored, just you.~/.claude/settings.json— every project on your machine.
The structure nests exactly the way the three moving parts do: the event name, then a matcher group, then the handlers inside it.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "npx prettier --write ..." }
]
}
]
}
}
Type /hooks inside a session to browse everything registered, grouped by event, with a count beside each. That menu is read-only — it shows what's live, but you edit the JSON directly or ask Claude to edit it for you. If a hook doesn't appear there, it will never run, so /hooks is the first place to look when something is off. One JSON gotcha bites everyone: a trailing comma or a stray colon silently invalidates the whole hooks block, and every hook in it vanishes at once.
Real recipes to automate Claude Code
Three hooks cover most of the value: a PostToolUse matcher on Edit|Write that pipes changed files to Prettier, a PreToolUse guard that exits 2 on protected paths, and a PostToolUse hook that runs your test suite.
Here are the three Claude Code hooks we actually run to automate Claude Code day to day. Each is short.
Auto-format every edit. A PostToolUse hook matching Edit|Write pulls the changed file path out of the JSON payload and pipes it to your formatter. This runs Prettier on anything Claude touches, so formatting never drifts:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
]
}
]
}
}
Guard secrets and protected files. A PreToolUse hook that reads the target path and exits 2 when it matches .env, package-lock.json, or anything under .git/. Claude receives the stderr message and routes around the blocked file instead of clobbering it:
#!/bin/bash
FILE=$(jq -r '.tool_input.file_path // empty')
for p in ".env" "package-lock.json" ".git/"; do
if [[ "$FILE" == *"$p"* ]]; then
echo "Blocked: $FILE is protected" >&2
exit 2
fi
done
Run tests after changes. A PostToolUse hook that runs your suite after each edit turns "did it remember to test?" into a non-question — the suite runs deterministically, every time, because a hook is not a suggestion the model can skip.

For heavier setups — logging every Bash command to an audit file, re-injecting context after compaction, or blocking rm -rf outright — the ingredients are the same three parts in different arrangements. The full Claude Code CLI documentation has the complete event catalogue when you outgrow these three. Every hook still needs a session you started, though — for work that should kick off on its own clock, Claude Code's scheduled cloud routines run a saved prompt on a schedule, an API call, or a GitHub event.
Claude Code pre and post hooks: the difference
A pre hook runs before the tool executes and can cancel it with exit code 2. A post hook runs after the tool succeeds and cannot undo anything — use it for formatting, linting, tests, and cleanup.
The two events you'll configure most are Claude Code pre and post hooks, and they map cleanly to before and after:
PreToolUse | PostToolUse | |
|---|---|---|
| Runs | Before the tool executes | After the tool succeeds |
| Can block? | Yes — exit 2 cancels the call | No — the action already ran |
| Best for | Validation, policy, guarding files | Formatting, linting, tests, cleanup |
Use a pre hook when you need a gate: something must be checked before it happens, and blocking is on the table. Use a post hook when the action is fine but you want a guaranteed follow-up — reformat the file, run the tests, log the change. A post hook can't undo anything, because by the time it runs the edit is already on disk.
Hooks vs skills vs plugins: pick the right layer
Hooks guarantee, skills guide, plugins package. Use a hook when something must happen every time regardless of the model's judgement, a skill when you are teaching a workflow to apply when relevant, and a plugin to ship both to a team.
Claude Code hooks are one of three ways to extend the agent, and they solve different problems. Choosing wrong wastes an afternoon:
| Hooks | Skills | Plugins | |
|---|---|---|---|
| What it adds | Deterministic automation on events | Procedural knowledge — how to do a task | A bundle: skills, hooks, agents, MCP |
| Runs | Automatically, every matching event | When Claude judges a request a match | Packaged, installed as one unit |
| Trust model | Guaranteed — it's code, not the model | The model chooses to apply it | A distribution wrapper |
| Use it for | Format, test, block, log, notify | Conventions, review checklists, workflows | Shipping a whole setup to a team |
The rule we use: hooks guarantee, skills guide, plugins package. If something must happen every time regardless of what the model decides, that's a hook. If you're teaching Claude a workflow to apply when relevant, that's a skill — our guide to Claude Code Skills covers that side, and a hook pairs naturally with a spec-driven workflow to enforce the checks a spec defines. To hand a teammate both at once, wrap them in a plugin. Hooks and skills compose well: a skill can describe the workflow while a hook enforces the non-negotiable parts. This programmable depth is a big part of what Claude Code does that Cursor can't, where rules stay suggestions rather than guarantees.
Hooks have been stable across the 2.x releases of Claude Code, and the events, matchers, and exit-code behavior described here match the current CLI.
Anthropic has documented hooks as a first-class feature since the 2.0 releases, and in our own setup every deterministic guardrail — formatting, protected-file blocks, post-edit tests — is implemented as one.
Claude pricing at a glance
Claude's Free tier costs nothing, Pro is $20 a month, Max starts at $100 a month, and API access is billed per token. Hooks themselves are free — they run locally and consume no extra tokens.
| Plan | Price |
|---|---|
| Free | $0 |
| Pro | $20 / month |
| Max | from $100 / month |
| API | Pay per token |
For the full breakdown of every plan, see our how much Claude costs guide.
Hooks fire on your machine; to run Claude Code on a pull request instead, our Claude Code GitHub Actions guide wires it into CI with a scoped, least-privilege token.
The most common hook people want is an alert when Claude finishes or needs approval — Claude Code notifications covers that end to end, from the zero-config terminal bell to a custom Notification hook.
Frequently Asked Questions

Written by
Edith
Writing about Claude and the Anthropic toolkit — models, Claude Code, pricing, features, and fixes, in clear, practical, hands-on guides tested by daily use.
View all posts →



