Quick Start
1
Simple Usage
Register a hook with Hook return values:
add_hook and any agent picks it up automatically:Noneor no return → AllowFalse→ Deny"reason"→ Deny with custom message
2
With HooksConfig
Attach a
HooksConfig to a specific agent for scoped hooks:Which Hook Point Should I Use?
Pick the lifecycle event that matches what you want to observe or block.How It Works
Available Hook Events
The events most agents will ever need are the agent / tool / LLM / error / session ones — start here.This is the core lifecycle subset. The SDK ships ~40 events in total — including plugin/system hooks (
on_init, on_shutdown), tool-result persistence (tool_result_persist), message-level bot hooks (before_message, after_message, message_received, message_sending, message_sent), gateway hooks (gateway_start, gateway_stop), compaction hooks (before_compaction, after_compaction), permission/config/auth hooks (on_permission_ask, on_config, on_auth), schedule hooks (schedule_add, schedule_remove, schedule_trigger), background-job hooks (job_completed), kanban task hooks, and Claude-Code-parity events (user_prompt_submit, notification, subagent_stop, setup).See Hook Events for the complete reference with input dataclasses and examples for each.on_retry is emitted once per retryable error, just before the back-off sleep. It runs whether the LLM call is agent.chat(...) (sync) or await agent.achat(...) (async). Sync-registered callbacks on the async path are run in a thread executor — they cannot block the event loop.
Two lookalike fields. Function-style hooks return
HookResult and set modified_input to rewrite the payload. Shell-command hooks parse into HookOutput and use modified_data for the same purpose. When you write a hook in Python, always use HookResult(decision="allow", modified_input={...}) — the internal Agent code reads .modified_input on hook results.Configuration Options
HooksConfig SDK Reference
Full parameter reference for HooksConfig
Common Patterns
Security Filtering
Audit Logging
Tool Matching with HookRegistry
Best Practices
Keep hooks lightweight
Keep hooks lightweight
Hooks run synchronously before/after each operation. Avoid network calls or heavy computation inside hook functions — use async queues for heavy processing.
Return None to allow, string to deny
Return None to allow, string to deny
The simplest hook contract: return nothing (or
None) to allow, return a string with a reason to block. This keeps hooks readable.Use add_hook for global rules, HooksConfig for per-agent rules
Use add_hook for global rules, HooksConfig for per-agent rules
add_hook registers hooks globally — all agents in the process obey them. Use HooksConfig when you need different rules per agent.Set _strict_hooks=True in tests
Set _strict_hooks=True in tests
By default, hook exceptions are logged as warnings and execution continues. Set
agent._strict_hooks = True in tests so hook failures surface immediately as errors.before_agent / after_agent cost nothing when unregistered
before_agent / after_agent cost nothing when unregistered
before_agent and after_agent cost nothing when no hook is registered — the runtime checks has_hooks() before building the input (including os.getcwd() and the tools list) on both sync (chat) and async (achat) paths. Register these hooks in production without a per-turn overhead concern.Related
Hook Events
Complete list of ~40 events with input dataclasses and examples
Guardrails
Validate agent output quality with automatic retry
Callbacks
Observe agent events for UI and logging purposes

