The Interception Point

PreToolUse checks a tool call before it runs. PostToolUse adds context or changes the result Claude reads after success.

Pre  gates the call Post  shapes the result 15 slides
01Position

Where They Sit

PreToolUse runs before execution. Once a tool starts, success reaches PostToolUse and an execution error reaches PostToolUseFailure.

Claude selects a tool PreToolUse allow, deny, ask, defer or replace tool input Tool executes Bash · Edit · MCP… PostToolUse successful result annotate or replace for Claude PostToolUseFailure failed result observe or guide recovery success failure
A rejected call may never reach the tool. Invalid input can be rejected before either hook runs. A permission denial reaches PreToolUse, but does not fire PostToolUseFailure.
02Input shape

A Shared Base, Specific Payloads

Both hooks receive common session and tool-call metadata. PostToolUse additionally receives the successful tool_response.

ScopeFields and meaning
sharedtool_name, tool_input and tool_use_id identify and correlate the call
sharedsession_id, transcript_path, cwd and hook_event_name locate the event
sharedpermission_mode: default, auto, acceptEdits, dontAsk, bypassPermissions or plan
conditionalagent_id / agent_type identify subagent calls; agent type may also identify a configured session agent
Post onlytool_response contains the successful tool’s structured output
03PreToolUse

The Gate

Should this tool run, and with what input? Command, HTTP, MCP and SDK hooks answer through hookSpecificOutput.permissionDecision.

Hook runs permissionDecision allow ask defer deny approve within permission limits forces a user prompt pause non-interactive run; resume later blocked — reason sent to Claude
allow still respects deny rules, required user interaction and plan-mode restrictions. updatedInput replaces the whole input: include fields you want to keep. With no decision, normal permission checks apply. With defer, the replacement is ignored.
04PostToolUse

The Rewrite

The tool has already run. A hook can add a note, rewrite what Claude reads, or do follow-up work such as formatting a file. It does not roll back the original action.

Raw result tool_response PostToolUse hook additionalContext updatedToolOutput What Claude reads as the tool result
updatedToolOutput works for built-in and MCP tools. For a built-in tool, keep its expected fields and types: an invalid replacement is ignored. Example: redact Bash’s stdout while keeping the rest of its result. Use additionalContext to add a note.
05Exit codes

Command Hook Exit Codes

An exit code tells Claude Code how the hook finished. JSON can carry a decision too. For PreToolUse, exit 2 always blocks the call.

Exit codePreToolUsePostToolUse
0Read valid JSON. A JSON deny still blocks.Apply valid JSON notes or output changes.
2Block, even if JSON says allow. stderr explains why.Send stderr as feedback. The tool has already run.
otherUsually no decision. Valid JSON can still apply.*Usually an error notice. Valid JSON can still apply.*
Simple rule: exit 0 when returning a JSON decision. Exit 2 to block a PreToolUse call. *With onFailure: "block", an unexpected exit code counts as failure. Windows shell hooks without Git Bash also have stricter failure handling.
06Matchers

Scoping a Hook

The matcher string decides which tool calls reach the hook at all — and it's read two different ways depending on what's in it.

exact / list

Plain names

Only letters, digits, _ -, spaces, commas, pipes → matched literally.

"Bash" · "Edit|Write" · "Edit, Write"

regex

Anything else

A paren, bracket, *, ., ^ or $ → the whole string becomes a regex.

"mcp__memory__.*" · "^mcp__" · ".*"

An empty, omitted or * matcher catches every tool. Matchers inspect the tool name, not its arguments; use handler logic or an if rule to narrow by command, path or operation.
07settings.json

Config Anatomy

Inside the top-level hooks object, three conceptual levels connect an event to the handlers that run.

hooks top level PreToolUse / PostToolUse matcher group { matcher, hooks: […] } handler type: command… command timeout container → event → matcher group → one or more handlers Pre/Post support five handler types. Their replies and timeouts differ.
08Handler types

How a Handler Answers

The event says when to run. The handler type says what runs and how it replies. These defaults apply to PreToolUse and PostToolUse.

HandlerHow it repliesDefault wait
command / http / mcp_toolYour code returns hook JSON. Command hooks also use exit codes.600 seconds
promptA model returns { "ok": true }, or false with a reason.30 seconds
agentAn agent checks files or tools, then returns ok and a reason. Experimental.60 seconds
SDK callbackYour application function returns hook JSON directly.600 seconds
For a prompt hook, ok: false normally ends the turn. Set continueOnBlock: true to let Claude read the reason and continue. Agent hooks already continue this way. A PreToolUse rejection still prevents that tool call.
09Configuration

Config File or Callback

A settings hook starts a program. An SDK callback runs in your application. Here, both respond after a file edit. Define the formatter before using either example.

settings.json (Node.js required)
{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "node",
        "args": [
          "${CLAUDE_PROJECT_DIR}/format.mjs"]
      }]
    }]
  }
}
Agent SDK (Python)
from claude_agent_sdk import (
  ClaudeAgentOptions, HookMatcher
)

options = ClaudeAgentOptions(
  hooks={
    "PostToolUse": [HookMatcher(
      matcher="Edit|Write",
      hooks=[format_file]  # async callback
    )]
  }
)
Node runs format.mjs on Windows, macOS and Linux. With args, no shell is needed. The script reads JSON from stdin. The SDK passes it to your callback. Both read tool_input.file_path.
10Concurrency

When Hooks Collide

Matching hooks can run in parallel. Their declaration order does not control their execution order. Prompt and agent hooks have concurrency limits, so some may wait.

hook A → allow hook B → ask hook C → deny deny wins precedence: deny > defer > ask > allow independent hooks; no ordering contract
Use one hook to rewrite a given input or output. Other hooks can check or log it. If check B needs check A’s result, put both steps in one handler.
11Boundaries

Security & Limits

What hooks can enforce — and what they can't get around.

runs as you

Full user permissions

A command hook runs with your operating-system access, outside the tool sandbox. Validate its input and give it only the credentials it needs.

deny always wins

Even in bypassPermissions

A PreToolUse deny blocks the call in every permission mode. allow can't override a settings‑level deny rule.

can't undo

No automatic rollback

Changing a result does not reverse a file write or network request. Earlier telemetry may also contain the original output.

failure semantics

SDK callback timeout

A timed-out PreToolUse callback blocks that call. A timed-out PostToolUse callback keeps the tool result. Claude can continue in both cases.

If a policy check fails, should the tool run? Command and HTTP hooks usually let it proceed on failure. Set onFailure: "block" on a synchronous PreToolUse handler to stop it on errors or timeouts. Requires Claude Code 2.1.295+.
12Examples

Four Patterns

Choose the hook based on what you need to prevent, change or record.

PreToolUse

Secrets gate

Inspect tool_input and deny a forbidden file access. A Bash text check is only one guard: other tools or indirect commands need protection too.

PostToolUse

Auto‑format

Matcher Edit|Write runs a wrapper that reads tool_input.file_path, then formats the touched file.

PostToolUse

Clearer output

Rewrite a result with updatedToolOutput while keeping that tool’s schema. Add a common summary with additionalContext.

Lifecycle

Tool activity log

Record attempts in PreToolUse and execution outcomes in the Post hooks. Record denials in your guard too. Early validation failures need separate logging.

13Recap

Before and After a Tool Call

PreToolUse decides whether it happens PostToolUse shapes what Claude receives after success

Before execution, check whether the call should run. After success, add context or adjust its result. Use PostToolUseFailure for execution errors.

14Reference

Sources and Version Notes

Reviewed 27 October 2026 against Claude Code 2.1.312 release notes and current Anthropic documentation. Older installations may behave differently.

Read moreWhat it explains
Hooks referenceEvents, permissions, exit codes and output schemas
Hooks guidePractical examples, handler types and timeout defaults
Agent SDK hooks / Python APICallback setup, return values and timeout behavior
Claude Code changelogonFailure: "block" requires 2.1.295+. Prompt and agent concurrency limits can change.
SDK compatibility noteupdatedMCPToolOutput is deprecated. Use updatedToolOutput.
Before a demo, check claude --version and python -m pip show claude-agent-sdk. The snippets show configuration patterns. Supply your formatter and test it with the versions you use.
01 / 15
background
use ← → or click the edges to navigate