Skip to main content

Tool Hook Events

Tool Events​

These events fire before a tool runs. They also fire when a permission prompt shows or auto mode denies a call. They are the main place to approve, change, or block a tool call. MCP tool names have the form mcp__<server>__<tool>.

PreToolUse​

Fires after Claude builds the tool input and before the tool runs. It does not fire for @ file mentions. Exit 2 blocks the call, and stderr is the reason. Handlers: all five types.

FieldStatusDirectionWhat it does
tool_name
Documented: An official docs page names this item.
InputThe tool name. Any tool except EndConversation.
tool_input
Documented: An official docs page names this item.
InputThe tool arguments. The shape depends on the tool (see below). File paths are absolute.
tool_use_id
Documented: An official docs page names this item.
InputThe tool call ID.
permissionDecision
Documented: An official docs page names this item.
Output, in hookSpecificOutputallow, deny, ask, or defer. allow skips the prompt but not deny or ask rules. Order of strength: deny, then defer, then ask, then allow. defer works only in -p with one tool call.
permissionDecisionReason
Documented: An official docs page names this item.
Output, in hookSpecificOutputThe reason text. For ask it shows in the prompt. For deny it goes to Claude. Otherwise it goes to the debug log.
updatedInput
Documented: An official docs page names this item.
Output, in hookSpecificOutputReplaces the whole tool input. Rules and background checks use the new input. Needed with allow for AskUserQuestion and ExitPlanMode. Claude Code ignores it with defer.
additionalContext
Documented: An official docs page names this item.
Output, in hookSpecificOutputText placed next to the tool result. Claude Code ignores it with defer.
permissionDisplay
Undocumented: Only the program shows this item. It can change without notice.
Output, in hookSpecificOutputWords for a permission card. For the desktop host only. An object with title (200 characters), description (2000), and displayName (64). Claude Code ignores it, with a debug line, if it cannot show the text.
Top-level decision and reason
Differs: The official docs and the program disagree. The row says how. Deprecated for this event. The program schema accepts the enum on all events.
Outputapprove maps to allow. block maps to deny. Use permissionDecision instead.
ask label
Documented: An official docs page names this item.
BehaviorThe prompt shows [settings], [plugin:<name>], or [skill]. An ask also forces a prompt in auto mode.

Tool Input Shapes​

The tool names link to Tools, which holds the status and the full parameters of each tool.

ToolStatusKeys in tool_input
Bash
Documented: An official docs page names this item.
command, description, timeout (milliseconds), run_in_background
PowerShell
Documented: An official docs page names this item.
Gated: Works only behind a flag or a server gate. CLAUDE_CODE_USE_POWERSHELL_TOOL
The same keys as Bash. Match with Bash|PowerShell.
Write
Documented: An official docs page names this item.
file_path, content
Edit
Documented: An official docs page names this item.
file_path, old_string, new_string, replace_all
Read
Documented: An official docs page names this item.
file_path, offset, limit
Glob
Documented: An official docs page names this item.
pattern, path
Grep
Documented: An official docs page names this item.
pattern, path, glob, output_mode, -i, multiline
WebFetch
Documented: An official docs page names this item.
Gated: Works only behind a flag or a server gate. CLAUDE_CODE_DISABLE_WEB_FETCH=1 turns it off
url, prompt, offset (2.1.290)
WebSearch
Documented: An official docs page names this item.
Gated: Works only behind a flag or a server gate. off for the gateway provider. Vertex depends on the model
query, allowed_domains, blocked_domains
Agent
Documented: An official docs page names this item.
prompt, description, subagent_type, model
AskUserQuestion
Documented: An official docs page names this item.
questions, and answers (set only through updatedInput)
ExitPlanMode
Documented: An official docs page names this item.
Gated: Works only behind a flag or a server gate. internal enable check
Claude Code adds plan and planFilePath. Claude Code accepts the old allowedPrompts key. It ignores the key.

The docs name Workflow as a tool you can match, but give no input shape for it.

PermissionRequest​

Fires when a permission prompt would show, or when Claude Code would deny a call that cannot prompt. This event does not honor exit 2. Deny with the decision object instead. We checked this in the interactive screen. The hook fires before the dialog opens. allow skips the dialog. deny returns message to the model. Claude Code ignores a top-level decision: "block". See Input and Output. There is no event for a sandbox network request. Handlers: command, http, mcp_tool, and prompt. Claude Code skips an agent hook.

FieldStatusDirectionWhat it does
tool_name, tool_input
Documented: An official docs page names this item.
InputThe same as in PreToolUse. There is no tool_use_id.
permission_suggestions
Documented: An official docs page names this item.
InputUpdates that Claude Code suggests. The same shape as updatedPermissions. A dialog may show other options.
decision.behavior
Documented: An official docs page names this item.
Output, in hookSpecificOutputallow or deny. Deny and ask rules still apply.
decision.updatedInput
Documented: An official docs page names this item.
OutputNew tool input. allow only. Checked again against deny and ask rules.
decision.updatedPermissions
Documented: An official docs page names this item.
OutputPermission updates to apply. allow only.
decision.message
Documented: An official docs page names this item.
OutputThe reason for the denial. deny only. Goes to Claude.
decision.interrupt
Documented: An official docs page names this item.
OutputStops Claude. deny only.

Permission Update Entries​

updatedPermissions and permission_suggestions use these entries.

EntryStatusWhat it doesFields
addRules, replaceRules, removeRules
Documented: An official docs page names this item.
Change permission rules.rules (each {toolName, ruleContent?}), behavior (allow, deny, ask), destination
setMode
Documented: An official docs page names this item.
Change the permission mode.mode: default, auto, acceptEdits, dontAsk, bypassPermissions, plan. bypassPermissions works only if bypass was on when Claude Code started.
addDirectories, removeDirectories
Documented: An official docs page names this item.
Change working directories.directories
destination
Differs: The official docs and the program disagree. The row says how. The docs list four values. The program type also includes cliArg.
Where Claude Code keeps the change.session, localSettings, projectSettings, userSettings

PermissionDenied​

Fires only when auto mode denies a call, including a denial with no classifier verdict. It does not fire for manual denials, PreToolUse blocks, or deny rules. Claude Code ignores the exit code and stderr. We checked this in the interactive screen. An auto mode denial fired it. A manual "No" did not. With no classifier verdict (the classifier failed), retry: true changed nothing in the model's input. With a verdict (a stub answered the classifier with a block and the reason [Data Exfiltration]), the denial stood. The tool did not run. The model's next request got the extra text The PermissionDenied hook indicated you may retry this tool call. after the denied tool result. Without retry that text was absent. systemMessage was not shown. This event accepts all five handler types. Claude Code drops output from prompt and agent.

FieldStatusDirectionWhat it does
tool_name, tool_input, tool_use_id, mcp_server
Documented: An official docs page names this item.
InputAs in PreToolUse.
reason
Documented: An official docs page names this item.
InputWhy auto mode denied. A rule name in brackets, such as [Data Exfiltration].
retry
Documented: An official docs page names this item.
Output, in hookSpecificOutputtrue tells the model it may retry. The denial stands. Ignored for denials with no verdict.

Tool Result Events​

These events fire after a tool runs. PostToolUse and PostToolUseFailure match on tool name. PostToolBatch has no matcher. All three accept the five handler types.

PostToolUse​

Fires after a tool call succeeds. Exit 2 shows stderr to Claude but does not undo the tool. It does not see writes made by Bash or by outside processes. Use FileChanged for those.

FieldStatusDirectionWhat it does
tool_name, tool_input, tool_use_id, mcp_server
Documented: An official docs page names this item.
InputAs in PreToolUse.
tool_response
Documented: An official docs page names this item.
InputThe structured tool output. The shape depends on the tool.
duration_ms
Documented: An official docs page names this item.
InputRun time in milliseconds. Excludes permission prompts and PreToolUse hooks. Optional.
decision, reason
Documented: An official docs page names this item.
Outputblock adds the reason next to the result. Claude still sees the original output.
additionalContext
Documented: An official docs page names this item.
Output, in hookSpecificOutputText next to the result. Claude Code does not deliver it for async hooks.
updatedToolOutput
Documented: An official docs page names this item.
Output, in hookSpecificOutputReplaces what Claude sees. Must match the tool output shape. For built-in tools, Claude Code ignores a bad shape. The tool already ran.
updatedMCPToolOutput
Documented: An official docs page names this item.
Output, in hookSpecificOutputThe same, for MCP tools only. Prefer updatedToolOutput.
classifierContext
Documented: An official docs page names this item.
Output, in hookSpecificOutputA note for the auto mode classifier. Needs 2.1.236. At most 2,000 characters for one call. Dropped for async hooks and read-only calls. Treated as unverified context.
tool_response.bashEditDiff
Documented: An official docs page names this item.
InputFiles that a Bash run changed. Needs 2.1.269, a public beta, and the setting bashEditDiffEnabled. Keys: changedFiles (200), files (5), moreFiles, unavailable, skipped, shared.
tool_response of Agent
Documented: An official docs page names this item.
Inputstatus (completed or async_launched), agentId, content, resolvedModel, modelsUsed, totalTokens, totalDurationMs, totalToolUseCount, usage, and outputFile when the agent starts in the background.
tool_response of ExitPlanMode
Documented: An official docs page names this item.
Inputplan and filePath.
SubagentHandback tool
Documented: An official docs page names this item.
MatcherThe tool that carries a subagent report in auto mode. Match it to read tool_input.message. Needs 2.1.271.

PostToolUseFailure​

Fires when a started tool fails, or an MCP tool returns an error. It does not fire for unknown tools, schema errors, or permission denials. Exit 2 shows stderr to Claude.

FieldStatusDirectionWhat it does
tool_name, tool_input, tool_use_id, mcp_server
Documented: An official docs page names this item.
InputAs in PostToolUse.
error
Documented: An official docs page names this item.
InputWhat went wrong. The same text as the tool result. Bash and PowerShell errors start with Exit code N.
is_interrupt
Documented: An official docs page names this item.
Inputtrue for an abort. Canceling a running tool does not fire this hook.
duration_ms
Documented: An official docs page names this item.
InputRun time in milliseconds. Optional.
additionalContext
Documented: An official docs page names this item.
Output, in hookSpecificOutputText next to the error. A top-level decision: "block" also works.

PostToolBatch​

Fires once after all tool calls of a batch resolve, before the next model request. Exit 2, decision: "block", or continue: false stops the loop.

FieldStatusDirectionWhat it does
tool_calls
Documented: An official docs page names this item.
InputOne entry per call, with tool_name, tool_input, tool_use_id, and tool_response.
tool_calls[].tool_response
Documented: An official docs page names this item.
InputWhat the model gets in the tool_result. A serialized string or content blocks. It is not the PostToolUse object.
additionalContext
Documented: An official docs page names this item.
Output, in hookSpecificOutputContext for the next request. Claude Code sends it once.

PostToolUse tool_response Shapes​

We logged the stdin of a PostToolUse command hook in -p on 2.1.305, with one scripted call per tool. This is the tool_response you can read, and the shape updatedToolOutput replaces.

ToolStatustool_response
Bash
Documented: An official docs page names this item.
stdout, stderr, interrupted, isImage, and noOutputExpected.
Read (text)
Undocumented: Only the program shows this item. It can change without notice.
type (text) and file with filePath, content, numLines, startLine, and totalLines.
Write (new file)
Undocumented: Only the program shows this item. It can change without notice.
type (create), filePath, content, structuredPatch (empty), originalFile (null), and userModified.
Edit
Undocumented: Only the program shows this item. It can change without notice.
filePath, oldString, newString, originalFile, structuredPatch (items with oldStart, oldLines, newStart, newLines, lines), userModified, replaceAll, and contentNotInModelContext. The last key shows only when the file had a partial Read (with offset and limit) or no Read. tool_input also has replace_all.
ToolSearch
Undocumented: Only the program shows this item. It can change without notice.
matches (tool names), query, and total_deferred_tools. tool_input also has max_results.
Agent
Undocumented: Only the program shows this item. It can change without notice.
First the async start: isAsync, status (async_launched), agentId, description, resolvedModel, prompt, outputFile, canReadOutputFile, and canContinueAgent. Then, for a finished subagent: status (completed), prompt, agentId, agentType, content (text blocks), resolvedModel, totalDurationMs, totalTokens, totalToolUseCount, usage, canContinueAgent, harnessNoteCount, harnessTailCount, and harnessSectionHash.
ListAgents
Undocumented: Only the program shows this item. It can change without notice.
listing (text), sections, and notes.
CronCreate
Undocumented: Only the program shows this item. It can change without notice.
id, humanSchedule, recurring, durable, and nextFireAt.
CronList
Undocumented: Only the program shows this item. It can change without notice.
jobs.

A second probe ran the same hook in the interactive screen (2.1.305, acceptEdits, one scripted call per tool). It confirmed the shapes of Bash, Read, Write, and Edit above, with one difference: the Edit result after a Read had no contentNotInModelContext key. It also confirmed that an MCP tool's tool_response is the array of content blocks the server returned ([{"type":"text","text":"echo:OK"}]), and that the hook input has mcp_server. Every PostToolUse input had hook_event_name, tool_name, tool_input, tool_response, tool_use_id, and duration_ms. On 2.1.305 an Edit of a file that was never read was not an error, in acceptEdits and in the default mode. The file changed, PostToolUse fired, and no PostToolUseFailure fired. That tool_response had contentNotInModelContext: true, which the Edit after a Read did not have. The interactive probe did not run Glob, Grep, NotebookEdit, WebFetch, or WebSearch (this build's tool list there had no Glob or Grep), and did not test whether updatedToolOutput accepts these shapes. See Interactive Probes.