Skip to main content
Hooks are callback functions that run your code in response to agent events, like a tool being called, a session starting, or execution stopping. With hooks, you can:
  • Block dangerous operations before they execute, like destructive shell commands or unauthorized file access
  • Log and audit every tool call for compliance, debugging, or analytics
  • Transform inputs and outputs to sanitize data, inject credentials, or redirect file paths
  • Require human approval for sensitive actions like database writes or API calls
  • Track session lifecycle to manage state, clean up resources, or send notifications

How hooks work

1

An event fires

Something happens during agent execution and the SDK fires an event: a tool is about to be called (PreToolUse), a tool returned a result (PostToolUse), a subagent started or stopped, the agent is idle, or execution finished. See the full list of events.
2

The SDK collects registered hooks

The SDK checks for hooks registered for that event type. This includes callback hooks you pass in options.hooks and shell command hooks from settings files when the corresponding settingSources or setting_sources entry is enabled, which it is for default query() options.
3

Matchers filter which hooks run

If a hook has a matcher pattern (like "Write|Edit"), the SDK tests it against the event’s target (for example, the tool name). Hooks without a matcher run for every event of that type.
4

Callback functions execute

Each matching hook’s callback function receives input about what’s happening: the tool name, its arguments, the session ID, and other event-specific details.
5

Your callback returns a decision

After performing any operations (logging, API calls, validation), your callback returns an output object that tells the agent what to do: allow the operation, block it, modify the input, or inject context into the conversation.
The following example puts these steps together. It registers a PreToolUse hook (step 1) with a "Write|Edit" matcher (step 3) so the callback only fires for file-writing tools. When triggered, the callback receives the tool’s input (step 4), checks if the file path targets a .env file, and returns permissionDecision: "deny" to block the operation (step 5):
When you run either script, Claude attempts to create the .env file, the hook denies the tool call, and Claude’s final response explains that it can’t create .env files.

Available hooks

The SDK provides hooks for different stages of agent execution. Some hooks are available in both SDKs, while others are TypeScript-only.

Configure hooks

To configure a hook, pass it in the hooks field of your agent options (ClaudeAgentOptions in Python, the options object in TypeScript). This snippet assumes you have already defined a hook callback, like protect_env_files in Python or protectEnvFiles in TypeScript from the example above:
The hooks option is a dictionary in Python or an object in TypeScript, where:

Matchers

Use matchers to filter when your callbacks fire. The matcher field matches against a different value depending on the hook event type. For example, tool-based hooks match against the tool name, while Notification hooks match against the notification type. SDK matchers follow the same rules as matchers in settings files. That section documents the exact-string and regular-expression evaluation paths, their version requirements, and the matcher values for each event type. Use the matcher pattern to target specific tools whenever possible. A matcher with 'Bash' only runs for Bash commands, while omitting the pattern runs your callbacks for every occurrence of the event. Omit it on purpose to log every tool call your session makes.

Callback functions

Inputs

Every hook callback receives three arguments:
  • Input data: a typed object containing event details. Each hook type has its own input shape. For example, PreToolUseHookInput includes tool_name and tool_input, while NotificationHookInput includes message. See the full type definitions in the TypeScript and Python SDK references.
    • All hook inputs share session_id, cwd, and hook_event_name.
    • agent_id and agent_type are populated when the hook fires inside a subagent. In TypeScript, these are on the base hook input and available to all hook types. In Python, they are optional fields on PreToolUse, PostToolUse, PostToolUseFailure, and PermissionRequest, and required fields on SubagentStart and SubagentStop.
  • Tool use ID (str | None / string | undefined): correlates PreToolUse and PostToolUse events for the same tool call.
  • Context: in TypeScript, contains a signal property (AbortSignal) for cancellation. In Python, this argument is reserved for future use.

Outputs

Your callback returns an object with two categories of fields:
  • Top-level fields are accepted on every event: systemMessage shows a message to the user, and continue (continue_ in Python) determines whether the agent keeps running after this hook. Some events discard them or deliver them elsewhere. Each event’s section on the hooks page says where they land.
  • hookSpecificOutput controls the current operation. The fields you set inside depend on the hook event type:
    • For PreToolUse hooks, this is where you set permissionDecision ("allow", "deny", "ask", or "defer"), permissionDecisionReason, and updatedInput. If you return "defer", the query ends so you can resume it later.
    • For PostToolUse hooks, you can set additionalContext to append information to the tool result. To replace the tool’s output before Claude sees it, set updatedToolOutput, which works for any tool in both SDKs. The older updatedMCPToolOutput field replaces MCP tool output only and is deprecated.
    • In the TypeScript SDK, a PostToolUse callback can also return classifierContext, a short note about the tool call’s result for the auto mode permission classifier. Because your callback runs in your application’s own process, the classifier may weigh a user statement you relay in the note as user intent. The field requires TypeScript Agent SDK v0.3.236 or later. Annotate a result for the auto mode classifier covers the length cap, the synchronous-only rule, and what not to put in the note.
Return {} to allow the operation without changes. SDK callback hooks use the same JSON output format as Claude Code shell command hooks, which documents every field and event-specific option. For the SDK type definitions, see the TypeScript and Python SDK references.
When multiple hooks or permission rules apply, deny takes priority over defer, which takes priority over ask, which takes priority over allow. If any hook returns deny, the operation is blocked regardless of other hooks.

Asynchronous output

By default, the agent waits for your hook to return before proceeding. If your hook performs a side effect, such as logging or sending a webhook, and doesn’t need to influence the agent’s behavior, you can return an async output instead. This tells the agent to continue immediately without waiting for the hook to finish. In this snippet, send_to_logging_service in Python and sendToLoggingService in TypeScript stand in for any logging function you define:
Async outputs can’t block, modify, or inject context into the operation since the agent has already moved on. Use them only for side effects like logging, metrics, or notifications.

Examples

Several examples in this section show only the callback function. To run one, register the callback under the matching event in the hooks field of your options, as shown in Configure hooks.

Modify tool input

This example intercepts Write tool calls and rewrites the file_path argument to prepend /sandbox, redirecting all file writes to a sandboxed directory. The callback returns updatedInput with the modified path and permissionDecision: 'allow' to auto-approve the rewritten operation:
Pair updatedInput with permissionDecision: 'allow' to auto-approve the modified input, or permissionDecision: 'ask' to show it to the user. If you omit permissionDecision, the modified input still applies and flows through the normal permission evaluation. With 'defer', updatedInput is ignored. Always return a new object rather than mutating the original tool_input.
To confirm the redirect, set the prefix to a path you can write to, such as ./sandbox or /tmp/sandbox (macOS doesn’t allow creating a root-level /sandbox directory), then ask the agent to write a file: the Write tool’s result in the message stream names the path with your sandbox prefix rather than the one Claude requested.

Add context and block a tool

This example blocks writes to the /etc directory and explains why to both the model and the user:
  • permissionDecision: 'deny' stops the tool call.
  • permissionDecisionReason tells the model why, so it avoids retrying.
  • systemMessage shows the user what happened.

Auto-approve specific tools

By default, the agent may prompt for permission before using certain tools. This example auto-approves read-only filesystem tools (Read, Glob, Grep) by returning permissionDecision: 'allow', letting them run without user confirmation while leaving all other tools subject to normal permission checks:

Register multiple hooks

When an event fires, all matching hooks run in parallel. For permission decisions, the most restrictive result applies: a single deny blocks the tool call regardless of what the other hooks return. Because completion order is non-deterministic, write each hook to act independently rather than relying on another hook having run first. The example below registers three independent checks for every tool call:

Filter with multi-tool matchers

Use multi-tool matchers to share one callback across related tools. This example registers three matchers with different scopes:
  • A pipe-separated exact list (Write|Edit|NotebookEdit) triggers file_security_hook only for file modification tools.
  • A regex (^mcp__) triggers mcp_audit_hook for any MCP tool whose name starts with mcp__.
  • An omitted matcher triggers global_logger for every tool call regardless of name.

Track subagent activity

Use SubagentStop hooks to monitor when subagents finish their work. See the full input type in the