| title | description | category | tags | last_updated | difficulty | estimated_time | author | status | audience | prerequisites | related_docs | |||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Claude Code Hooks — Input & Output Schemas |
Authoritative reference for the JSON input/output schemas for all Claude Code hook events, including blocking behaviors and exit codes |
reference |
|
2025-01-18 |
advanced |
30 minutes |
Claude Code Team |
published |
|
|
|
A precise, implementation‑ready reference for the JSON input each hook receives on
stdinand the output a hook may emit onstdoutto steer Claude Code's behavior.
Scope:PreToolUse,PostToolUse,Notification,UserPromptSubmit,Stop,SubagentStop,PreCompact,SessionStart.
- Quick Map of Hook Events
- Common Input Envelope
- Common Output Contract
- Event-Specific Schemas
- Exit-Code-2 Behavior Matrix
- Matchers and MCP Tool Names
- Practical Tips
- Sources
- PreToolUse — before a tool call executes (approval/gating).
- PostToolUse — after a tool completes successfully (validate/feedback).
- Notification — on system notifications (permission wait, idle input).
- UserPromptSubmit — when a user submits a prompt (pre‑processing).
- Stop — when the main agent finishes its reply (not user interrupt).
- SubagentStop — when a subagent (via
Task) finishes its reply. - PreCompact — right before conversation compaction.
- SessionStart — when a session starts or resumes.
Matchers: Only
PreToolUseandPostToolUseusematcherpatterns for tools. Other events ignorematcher. MCP tools are namedmcp__<server>__<tool>(e.g.mcp__filesystem__read_file).
Each hook receives a base envelope plus event‑specific fields:
Hooks can signal decisions via exit codes and/or structured JSON on stdout.
- 0 → success.
stdoutis visible in transcript mode (Ctrl‑R).
Special cases: forUserPromptSubmitandSessionStart,stdoutis added to context. - 2 → blocking.
stderris routed according to the event (matrix below). - Other → non‑blocking error;
stderris shown to the user; execution continues.
{
"type": "object",
"properties": {
"continue": { "type": "boolean", "description": "If false, halt after hooks run (overrides decisions)" },
"stopReason": { "type": "string" },
"suppressOutput": { "type": "boolean", "description": "Hide this hook's stdout in transcript mode" }
},
"additionalProperties": true
}Precedence: If "continue": false, Claude stops after hooks run — this overrides any "decision": "block" you might also set.
When: After Claude prepares tool params before executing a tool. Good for policy checks and approvals.
Additional Input fields:
{
"tool_name": { "type": "string" },
"tool_input": { "type": "object" } // tool‑specific shape
}Output (two styles):
A) Preferred (hookSpecificOutput):
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow" | "deny" | "ask",
"permissionDecisionReason": "string"
}
}B) Legacy (still supported):
{
"decision": "approve" | "block",
"reason": "string"
}Semantics:
"allow"— bypasses permission UI (reason shown to user, not Claude)."deny"— blocks call (reason shown to Claude)."ask"— shows permission UI (reason shown to user).
Exit code 2: blocks the tool call; stderr is sent to Claude.
When: Immediately after a tool completes successfully. Good for validating results and giving automated feedback.
Additional Input fields:
{
"tool_name": { "type": "string" },
"tool_input": { "type": "object" },
"tool_response": { "type": "object" }
}Output:
{
"decision": "block" | null,
"reason": "string"
}"block"— automatically prompts Claude withreasonabout the tool’s result.- Omitted/
null— accept result;reasonignored.
Exit code 2: tool already ran; stderr shown to Claude.
When: On system notifications (e.g., permission request; input idle ≥ 60s).
Additional Input fields:
{ "message": { "type": "string" } }Output: Only common JSON fields apply (no event‑specific decisions).
Exit code 2: N/A; stderr shown to the user only.
When: As soon as the user submits a prompt, before Claude processes it.
Additional Input fields:
{ "prompt": { "type": "string" } }Output options:
{
"decision": "block" | null,
"reason": "string", // shown to user; not added to context
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "string" // appended to context if not blocked
}
}"block"— prevents processing; prompt is erased from context.- Alternative: print plain text to
stdoutwith exit code 0 — it will be injected into context.
Exit code 2: blocks prompt; stderr shown to the user only.
When: Main agent finishes naturally (not user interrupt).
Additional Input fields:
{ "stop_hook_active": { "type": "boolean" } } // true if a previous Stop hook already kept Claude runningOutput:
{
"decision": "block" | null, // prevent stopping
"reason": "string" // REQUIRED if decision = "block"
}"block"— prevents stopping;reasoninstructs Claude on what to do next."continue": falsein common fields halts everything and overridesdecision.
Exit code 2: blocks stoppage; stderr shown to Claude.
When: A subagent (via Task tool) finishes.
Input / Output: Same structure and semantics as Stop.
Exit code 2: blocks subagent stoppage; stderr shown to the subagent.
When: Right before conversation compaction (manual /compact or automatic).
Additional Input fields:
{
"trigger": { "enum": ["manual","auto"] },
"custom_instructions": { "type": "string" } // empty when auto
}Output: Only common JSON fields apply.
Exit code 2: N/A; stderr shown to the user only.
When: On new session start or resume.
Additional Input fields:
{ "source": { "enum": ["startup","resume","clear"] } }Output (context injection):
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "string"
}
}Also supported: printing plain text to stdout with exit code 0 — added to context.
Exit code 2: N/A; stderr shown to the user only.
Documentation note: Anthropic’s page includes a reminder that mentions only
UserPromptSubmitfor stdout‑to‑context on code 0, while the bullet list states it applies to bothUserPromptSubmitandSessionStart. The bullet list is the authoritative statement; many teams rely onSessionStartstdout to inject bootstrapping context.
| Event | Effect of exit code 2 |
|---|---|
| PreToolUse | Blocks the tool call; stderr → Claude |
| PostToolUse | Tool already ran; stderr → Claude |
| Notification | N/A; stderr → user only |
| UserPromptSubmit | Blocks prompt; prompt erased; stderr → user only |
| Stop | Blocks stoppage; stderr → Claude |
| SubagentStop | Blocks stoppage; stderr → Claude (subagent) |
| PreCompact | N/A; stderr → user only |
| SessionStart | N/A; stderr → user only |
PreToolUse/PostToolUsesupportmatcherpatterns targeting tools: exact string, regex (Edit|Write), or wildcard*(also""or omitted).- MCP tools appear as
mcp__<server>__<tool>and can be matched similarly (e.g.,mcp__filesystem__read_file).
- Prefer
hookSpecificOutputfor new setups (permissionDecisiononPreToolUse,additionalContextonUserPromptSubmit/SessionStart). - Use
"continue": falsesparingly; it halts processing and takes precedence over any"decision"fields. - For
UserPromptSubmit/SessionStart, decide between stdout injection (quick text) and JSONadditionalContext(explicit). - Keep hook scripts idempotent and time‑bounded; default timeout is 60s (configurable).
-
Anthropic — Hooks reference (event list, input/output, decisions, exit‑code semantics).
https://docs.anthropic.com/en/docs/claude-code/hooks -
Anthropic — Get started with Claude Code hooks (setup & examples).
https://docs.anthropic.com/en/docs/claude-code/hooks-guide
{ "type": "object", "properties": { "session_id": { "type": "string" }, "transcript_path": { "type": "string" }, // path to session .jsonl "cwd": { "type": "string" }, // current working directory "hook_event_name": { "type": "string" } // one of the 8 events }, "required": ["session_id","transcript_path","cwd","hook_event_name"], "additionalProperties": true }