Exit 2 Is the Only Exit Claude Hears
Updated: Oct 4
Pricing update, September 10, 2026: expert working sessions are $250 for 60 minutes. Build in a Day starts at $1,500; 30-Day Implementation starts at $6,000. Earlier package inclusions, credits, and hourly support terms below are historical. See current services and pricing for scope and terms.

There's a line at the bottom of my own guide to Claude that says I set things up "with guardrails so it fails loudly instead of quietly." That sentence has been live since August 17 and I've never once explained what it means. It reads like a promise. It's actually a description of a specific mechanism, and if you're paying somebody to run Claude against your business, the mechanism is the part worth knowing, because the default behavior is the opposite of loud.
So I went back through Anthropic's hooks reference this week to write the explanation I should have written in August, and what surprised me is that the quiet failure isn't an edge case you'd have to be unlucky to hit, it's what happens when the guardrail works exactly as written.
What a Hook Is, in 1 Sentence
A hook is a command Anthropic runs for you at a fixed point in the session, so the check doesn't depend on the model deciding to run it.
That distinction is the entire reason hooks matter to somebody who isn't writing the code. Anthropic's permissions documentation says it about as plainly as a vendor ever says anything:
Permission rules are enforced by Claude Code, not by the model. Instructions in your prompt or CLAUDE.md shape what Claude tries to do, but they don't change what Claude Code allows.
So a rule you typed into a prompt is a request, and Claude can miss it the same way anybody misses one line in a long document. Hooks get around that by not involving the model's judgment at all. Anthropic describes them as user-defined shell commands, HTTP endpoints, MCP tool calls, LLM prompts, or subagents that execute automatically at specific points in Claude Code's lifecycle, and "automatically" is doing all the work in that sentence.
They also travel, which matters more than it sounds like it should. Claude Code fires the same hook events wherever it runs: the terminal, IDE extensions, the Desktop app, and Claude Code on the web. Last week I wrote that a permission mode is a dial for how much Claude does without stopping, and that the careful one, Plan, doesn't even persist between sessions. A hook isn't a dial and it doesn't reset when somebody opens the work somewhere else.
33 Events, and 15 That Can Stop Anything
Here's the number nobody quotes. Anthropic's reference table lists 33 hook events, and only 15 of them can actually block what's about to happen. Checked September 1, 2026.
The 15 that can stop something are the ones worth building on:
PreToolUse: blocks the tool call before it runs, which is the one that matters most.
UserPromptSubmit: blocks prompt processing and erases the prompt.
ConfigChange: blocks a configuration change from taking effect.
TaskCompleted: prevents a task being marked complete.
PreCompact: blocks compaction.
The other 18 report and nothing more. PostToolUse and PostToolUseFailure are both in that group, and the docs are blunt about why: the tool already ran. SessionStart, Notification and PermissionDenied are in there too. That group is genuinely useful for telling you what happened, it just can't be the only place your rules live, because a system whose checks all sit there will report what went wrong with real accuracy once it has finished doing it.
Worth knowing if your build uses subagents: hooks from settings files, managed policy settings and plugins run inside subagents too, and the input carries the agent id and type, so the gate doesn't disappear when the work gets handed off.
Exit 0 Is the Quiet One
A hook signals a stop by exiting with code 2. Anthropic puts it in those words, that exit code 2 is the way a hook signals stop, don't do this. On PreToolUse, exit 2 blocks the tool call whether or not the hook prints JSON, and even a permission decision of "allow" can't override it. That's a genuine hard ceiling, and there aren't many of those anywhere in this stack.
The trouble is what happens on the other exit code. From the same page:
Stderr from a hook that exits 0 goes to the debug log only, never the transcript, and Claude never sees it.
Read that against the ordinary way a person writes a safety check. You write a script. It inspects what Claude is about to do. It finds the problem. It prints a warning and exits 0, because nothing crashed and the script did exactly its job. That warning goes to a debug log nobody opens, Claude never sees it, you never see it, and the action goes ahead. Anthropic writes this down plainly instead of leaving you to discover it in production, and it still means the guardrail you believe you have is a diary entry.
The correction is one character and it's on the same page: to surface a warning to Claude from a PostToolUse hook, exit 2 instead, and Claude sees the stderr even though the tool already ran. So when I'm looking at somebody's setup, the exit codes are the first thing I read, before any of the logic inside the script.
A Hook That Times Out Is Not a Gate
The second quiet failure is slower and I think it's the worse one. Command, HTTP and MCP tool hooks carry a default timeout of 600 seconds. Ten minutes. When a hook reaches it, Claude Code cancels the hook and discards its output, so on most events a timed-out hook renders no decision at all.
Anthropic states the consequence rather than leaving you to work it out:
A timed-out command, http, or mcp_tool hook doesn't block the tool call. The call continues through the normal permission flow, so don't count on a stalled hook to act as a gate.
One honest wrinkle, because two pages carry this story and they don't agree: an Agent SDK callback hook that exceeds its timeout does block the tool call. Which means the answer depends on which kind got built, and "we have a hook for that" doesn't tell you whether you're covered.
I care about this one because I've been on the wrong side of it. Rebuilding my own website with Claude, a finished About page was destroyed without a single error appearing anywhere. Every edit had verified as landed. Three removal calls ran while the editor's focus had quietly drifted to a different page, and they hit the wrong container. Then the automated check ran right afterward and came back clean, because an empty page has no defects left to find. Nothing crashed. Everything exited 0. That whole write-up, and the skill that came out of it, are a free download on the build page with no email.
The rule I've applied since is the same shape as exit 2: check the state before every single mutation instead of once per batch, and make the check block rather than report. That's what the line on my guide page actually means, and I should have written this in August instead of leaving it as a promise.
Sources
Checked September 1, 2026:
Hooks reference, Claude Code documentation, Anthropic
Permissions, Claude Code documentation, Anthropic
How to Use Claude, my own guide
Claude Code Has 5 Permission Modes Now, my post from August 28
If something is running against your business unattended, the question I'd start with is what it does when a check fails, not what it does when everything goes right. Consulting is $250 for a 60-minute expert working session with the hours estimated up front. Share a few details about your project.





Comments