A ready-to-run example is available here!
Overview
Hooks let you observe and customize key lifecycle moments in the SDK without forking core code. Typical uses include:- Logging and analytics
- Emitting custom metrics
- Auditing or compliance
- Tracing and debugging
Hook Types
Exit Codes
Command hooks (shell scripts) signal their result through their exit code. Prompt-based hooks and agent-based hooks return a JSON decision instead. The SDK matches the Claude Code hook contract:0— success. The operation proceeds.stdoutis parsed as JSON for structured output (decision,reason,additionalContext,continue).2— block. The operation is denied. ForPreToolUseandUserPromptSubmitthis rejects the action; forStopit prevents the agent from finishing and the conversation continues.stderr/reasonis surfaced as feedback.- Any other non-zero exit code — non-blocking error.
successis set toFalseand the error is logged viaHookExecutionEvent, but the operation still proceeds.
Key Concepts
- Registration points: subscribe to events or attach pre/post hooks around LLM calls and tool execution
- Isolation: hooks run outside the agent loop logic, avoiding core modifications
- Composition: enable or disable hooks per environment (local vs. prod)
Execution Modes
Hook definitions support three execution modes:
Use the least powerful mode that can make the decision. Command hooks are the
most deterministic. Prompt hooks add model judgment with one completion. Agent
hooks add an agent loop and tools when the event payload is not enough.
Ready-to-run Example
This example is available on GitHub: examples/01_standalone_sdk/33_hooks
examples/01_standalone_sdk/33_hooks/main.py
The model name should follow the LiteLLM convention:
provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o).
The LLM_API_KEY should be the API key for your chosen provider.Hook Scripts
The example uses external hook scripts in thehook_scripts/ directory:
block_dangerous.sh - PreToolUse hook
block_dangerous.sh - PreToolUse hook
log_tools.sh - PostToolUse hook
log_tools.sh - PostToolUse hook
inject_git_context.sh - UserPromptSubmit hook
inject_git_context.sh - UserPromptSubmit hook
require_summary.sh - Stop hook
require_summary.sh - Stop hook
Prompt-based Hooks
Settype="prompt" to evaluate a hook event with one LLM completion. Prompt
hooks are useful when a decision needs semantic judgment but all required
context is already present in the HookEvent payload. For example, a
PreToolUse policy can evaluate the intent of a terminal command without
starting a tool-using sub-agent.
HookDefinition:
name— identifies the hook in logs, events, and its stableprompt-hook:<name>metrics bucket.prompt— the trusted policy used to evaluate each matching event.timeout— the timeout applied to the copied hook LLM.
decision="allow" and
success=False. This lets consumers distinguish an execution failure from a
deliberate allow verdict.
This example is available on GitHub: examples/01_standalone_sdk/57_prompt_hooks
examples/01_standalone_sdk/57_prompt_hooks/main.py
The model name should follow the LiteLLM convention:
provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o).
The LLM_API_KEY should be the API key for your chosen provider.Agent-based Hooks
Besides shell scripts, a hook can delegate its decision to an LLM-driven sub-agent by settingtype="agent". The sub-agent receives the lifecycle event
as JSON, reasons about it semantically, and replies with a decision payload:
PreToolUse reviewer that recognises awk '{print}' /etc/passwd as reading a
sensitive file even though no obvious keyword (cat, /etc/shadow) appears.
Key fields on an agent HookDefinition:
name— a label for the hook; identifies it in logs, events, and itsagent-hook:<name>metrics bucket.system_prompt— the policy the reviewer agent follows.tools— optional tools the reviewer may use (e.g.["file_editor"]to inspect the workspace before deciding).timeout/max_iterations— bound how long the reviewer runs.
agent-hook:<name> usage
bucket that is merged back into the parent conversation’s metrics. If no LLM is
available or the reviewer fails to produce a valid decision, the hook falls
open (allows) so it never blocks the agent on an internal error.
This example is available on GitHub: examples/01_standalone_sdk/51_agent_hooks
examples/01_standalone_sdk/51_agent_hooks/main.py
The model name should follow the LiteLLM convention:
provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o).
The LLM_API_KEY should be the API key for your chosen provider.Next Steps
- See also: Metrics and Observability
- Architecture: Events

