Agent SDK Hooks
Prompts ==guide== behavior; Hooks, Permissions, Callbacks, and Application logic ==enforce== behavior.
1. What this topic is testing
The exam will likely test whether you know where to enforce rules in an agentic system.
A weak answer says:
A strong answer says:
Use hooks, permission rules, approval callbacks, validators, and deterministic application logic to block, modify, approve, or audit actions at runtime.
Anthropic’s Agent SDK docs describe hooks as callback functions that run on agent events such as tool calls, session start, subagent start/stop, compaction, or execution stop; hooks can block dangerous operations, log/audit tool calls, transform inputs or outputs, require approval, and manage lifecycle state. (Claude Code)
2. Core mental model
Hook = lifecycle interception point
A hook is code that runs automatically at a specific point in the agent lifecycle.
Example:
Claude wants to run:
Bash("rm -rf /tmp/build")
PreToolUse hook fires first.
Hook inspects command.
Hook returns deny.
Tool does not execute.
Claude receives the denial reason.
The important exam point:
Hooks run outside the model’s free-form reasoning. They are programmatic control points.
Claude can propose an action, but the hook can block or modify it before execution.
3. Hooks vs prompts
| Requirement | Is Prompt enough? | Better enforcement |
|---|---|---|
| Preferred writing style | Yes | System prompt / instructions |
| “Be careful with files” | No | PreToolUse hook or permission rule |
Block writes to .env |
No | PreToolUse hook or deny rule |
| Log all tool calls | No | PostToolUse hook |
| Require human approval for deploy | No | canUseTool, ask rule, approval workflow |
| Run tests after edits | No | PostToolUse hook |
| Prevent completion until tests pass | No | Stop hook |
| Prevent subagent from finishing early | No | SubagentStop hook |
| Enforce regulated workflow | No | Application logic + hooks + approval gates |
Exam point:
If violation has real consequences, do not rely only on prompting.
4. Where hooks fit in the permission flow
When Claude requests a tool, the SDK evaluates permissions in a specific order: hooks run first, then deny rules, ask rules, permission mode, allow rules, and finally the canUseTool callback if unresolved. A hook can deny a call outright, but a hook returning allow does not skip later deny or ask rules. (Claude)
High-yield implications:
| Situation | Correct interpretation |
|---|---|
Hook returns allow, but deny rule matches |
Tool is still denied |
Deny rule matches in bypassPermissions |
Tool is still blocked |
allowed_tools lists Read only, but mode is bypassPermissions |
Other tools can still run unless denied |
dontAsk mode and unapproved tool |
Denied, not prompted |
plan mode and file edit |
Prompts through approval callback; edits are not auto-approved |
The exam will likely test precedence. Do not assume one allow setting overrides all other controls.
5. Programmatic enforcement layers
Think of enforcement as a stack.
| Layer | Best for | Example |
|---|---|---|
| System prompt | Behavioural guidance | “Prefer minimal changes.” |
| Allowed tools | Pre-approve safe tools | Auto-allow Read, Glob, Grep |
| Deny rules | Static hard blocks | Block Bash(rm *) |
| PreToolUse hook | Dynamic runtime validation before execution | Block writes outside /src |
| PostToolUse hook | Audit or react after execution | Run linter after file edit |
| Stop hook | Prevent premature completion | Continue until tests pass |
| Subagent hooks | Track or constrain subagents | Log subagent output or block early stop |
| canUseTool callback | Human approval or UI-mediated decisions | Ask user before deploy |
| Application logic | Business-critical deterministic rules | Refund > $500 requires manager approval |
Use the lowest reliable enforcement layer. For example, “never delete production data” should be enforced in code or permission policy, not just in a model instruction.
6. Must-know hook events
Anthropic’s hooks reference divides events across the session lifecycle, per-turn lifecycle, and tool-call lifecycle. Common exam-relevant events include UserPromptSubmit, PreToolUse, PermissionRequest, PostToolUse, PostToolUseFailure, PostToolBatch, SubagentStart, SubagentStop, Stop, PreCompact, and SessionEnd. (Claude Code)
High-yield subset
| Hook event | Fires when | Exam use case |
|---|---|---|
UserPromptSubmit |
Before Claude processes user prompt | Reject prompt containing forbidden data or inject context |
PreToolUse |
Before a tool executes | Block, allow, ask, defer, or modify tool input |
PermissionRequest |
Permission dialog would appear | External approval notification |
PostToolUse |
After successful tool execution | Logging, audit, post-edit checks |
PostToolUseFailure |
After failed tool execution | Error logging, recovery signal |
PostToolBatch |
After a batch of parallel tool calls | Inject conventions before next model turn |
Stop |
Claude is about to stop | Check completion criteria; prevent stopping |
SubagentStart |
Subagent starts | Track spawning |
SubagentStop |
Subagent finishes | Validate subagent completion |
PreCompact |
Before compaction | Archive transcript before summarization |
Notification |
Status notification | Send Slack/PagerDuty update |
Exam shortcut:
Before execution → PreToolUse
After execution → PostToolUse
Before finishing → Stop
Before subagent finishes → SubagentStop
Before prompt enters model → UserPromptSubmit
Before compaction → PreCompact
6.1. PreToolUse: the enforcement workhorse
Use PreToolUse when you must decide before a tool runs.
Best for: - blocking destructive shell commands - preventing writes to protected files - validating API request parameters - enforcing path restrictions - requiring approval for sensitive tools - sanitizing or redirecting tool inputs - controlling MCP tool calls.
Example policy:
Anthropic’s hook docs show a PreToolUse hook that blocks writes to .env files by returning permissionDecision: "deny" with a reason. (Claude Code)
Exam trap:
Do not use
PostToolUseto block dangerous execution. By then, the tool already ran.
6.2. PostToolUse: audit and reaction, not prevention
Use PostToolUse after the tool succeeds.
Best for: - logging tool use - recording audit trails - running lint/test checks after edits - sending webhook notifications - adding context after a tool result - detecting tool output anomalies
But PostToolUse cannot prevent the original action because it has already happened. Claude Code’s hook reference explicitly distinguishes events that can block from those that cannot; PostToolUse cannot block the action and can only show feedback after the fact. (Claude Code)
Good use:
Bad use:6.3. Stop hook: completion enforcement
A Stop hook runs when Claude is about to finish. Use it to enforce completion criteria.
Good cases: - tests must pass before Claude stops - required checklist must be complete - output must include required sections - all requested files must be updated - no unresolved TODOs remain
Anthropic’s hooks reference gives an example of a multi-criteria Stop hook that checks whether all user-requested tasks are complete, whether errors need addressing, and whether follow-up work is needed; if not OK, Claude continues working. (Claude Code)
Exam trap:
A
Stophook is not the same as D1.1’sstop_reason.
stop_reasoncontrols the API agentic loop. AStophook can intercept Claude Code / Agent SDK lifecycle completion and enforce additional criteria.
6.4. SubagentStart and SubagentStop
From D1.2, subagents are isolated workers and all coordination should flow through the coordinator. For D1.5, hooks let you observe or enforce subagent lifecycle behavior.
Use subagent hooks for: - logging spawned subagents - tracking parallel work - preventing premature subagent completion - validating subagent output - auditing subagent tool usage
Anthropic’s Agent SDK hook docs list SubagentStart and SubagentStop and show a SubagentStop example that logs subagent completion, transcript path, and tool-use ID. (Claude Code)
Important trap:
Subagents do not automatically inherit every permission assumption safely. Be careful with broad permission modes.
Anthropic’s permission docs warn that when a parent uses bypassPermissions, acceptEdits, or auto, subagents inherit that mode and it cannot be overridden per subagent; in particular, inherited bypassPermissions can give subagents full autonomous system access. (Claude)
Hook decisions
For SDK callback hooks, a PreToolUse hook can return:
| Decision | Meaning |
|---|---|
allow |
Approve the operation |
deny |
Block the operation |
ask |
Escalate to user approval |
defer |
End query so it can be resumed later |
updatedInput |
Modify tool input before execution |
permissionDecisionReason |
Tell Claude why a tool was denied |
additionalContext |
Add context after a tool result |
updatedToolOutput |
Replace tool output before Claude sees it |
Anthropic documents these fields under hook outputs and notes that updatedToolOutput replaces tool output before Claude sees it, while additionalContext can append information to tool results. It also states that when multiple hook or permission results apply, the priority is deny > defer > ask > allow. (Claude Code)
Exam implication:
If any matching hook denies, the operation is blocked even if another hook allows.
Command hook exit codes
For Claude Code command hooks, exit codes matter.
| Exit code / output | Meaning |
|---|---|
0 with no JSON |
No decision; normal flow continues |
0 with valid JSON |
Structured control decision |
2 |
Blocking error for blockable events |
| Other non-zero | Usually non-blocking error |
The hooks reference says exit 2 is the “stop, don’t do this” signal for blockable events such as PreToolUse, PermissionRequest, UserPromptSubmit, Stop, SubagentStop, and PreCompact; it also says PostToolUse cannot block because the tool already ran. (Claude Code)
Exam trap:
Exit code
1is not the standard enforcement signal in Claude Code hooks. Useexit 2or structured JSON for blocking.
Matchers and filters
Hooks can use matchers to decide when they fire.
Examples:
| Matcher | Meaning |
|---|---|
Bash |
Exact match for Bash tool |
Write|Edit |
|
* or omitted |
Match all events of that type |
^mcp__ |
Regex for all MCP tools |
mcp__memory__.* |
All tools from the memory MCP server |
Anthropic’s docs explain that simple matcher strings are exact matches, pipe-separated values represent alternatives, and strings with regex characters are evaluated as regex; MCP tools follow the mcp__<server>__<tool> naming pattern. (Claude Code)
Important trap:
Tool-based matchers filter by tool name, not file path or command argument.
To filter by path, inspecttool_input.file_pathinside the hook callback. (Claude Code)
Permissions: allow, deny, ask, and modes
Hooks are only one enforcement mechanism. Permission rules and modes are equally exam-relevant.
Allow and deny rules
| Rule | Meaning |
|---|---|
allowed_tools=["Read", "Grep"] |
Auto-approve these tools |
disallowed_tools=["Bash"] |
Remove Bash tool from Claude’s available tools |
disallowed_tools=["Bash(rm *)"] |
Keep Bash available, but block matching rm calls |
disallowed_tools=["*"] |
Remove every tool |
Anthropic’s permission docs distinguish allow rules from deny rules: allow rules pre-approve matching tools, while deny rules can remove a whole tool or block scoped patterns; scoped deny rules still apply even in bypassPermissions. (Claude)
Permission modes
| Mode | Exam meaning |
|---|---|
default |
Standard permission behaviour |
dontAsk |
Deny anything not pre-approved |
acceptEdits |
Auto-accept file edits/filesystem operations in scope |
bypassPermissions |
Auto-approve tools unless denied/asked by earlier controls; dangerous |
plan |
Explore and plan; file edits are not auto-approved |
auto |
TypeScript-only model-classified approvals, where available |
Use dontAsk for headless locked-down agents. Use plan when Claude should inspect and propose but not modify files. Use bypassPermissions only in isolated controlled environments, because it grants broad system access unless deny/ask/hooks stop it. (Claude)
6.5. canUseTool: human approval and user input
Use canUseTool when your application needs to surface tool approval requests or clarifying questions to the user. Anthropic’s docs say Claude may need input when it wants permission for a tool or when it asks a clarifying question through AskUserQuestion; both trigger canUseTool, which pauses execution until the callback returns. (Claude Code)
Good use cases: - user approval before deletion - user approval before deployment - user selects which database/environment to use - user confirms an irreversible action - UI-mediated “allow / deny / modify” decision
Anthropic documents that a callback can allow, deny, approve with changes, remember a permission update, reject with guidance, or redirect Claude through application logic. (Claude Code)
Exam distinction:
| Need | Use |
|---|---|
Automatically block every .env write |
Hook or deny rule |
| Ask user whether to allow a specific file delete | canUseTool |
| Ask user which output format they want | AskUserQuestion via canUseTool |
| Send Slack message when approval is needed | PermissionRequest or notification hook |
6.6. Async hooks
Async hooks are useful for side effects that should not block Claude.
Examples: - logging - sending metrics - starting background tests - notifying Slack - firing analytics
But async hooks cannot block, modify, or inject context into the current operation because Claude continues immediately. Anthropic’s docs explicitly state that async hook decisions such as permissionDecision and continue have no effect after the triggering action has proceeded. (Claude Code)
Exam trap:
Do not use an async hook for a mandatory security check.
Use synchronous PreToolUse or permission rules for enforcement.
7. Hook types
Claude Code hooks can be implemented as command hooks, HTTP hooks, MCP tool hooks, prompt hooks, or agent hooks. Command hooks run shell commands; HTTP hooks call endpoints; MCP tool hooks call connected MCP tools; prompt hooks use an LLM for single-turn evaluation; agent hooks spawn a subagent to verify conditions. (Claude Code)
Exam guidance:
| Hook type | Best use |
|---|---|
| Command | Deterministic local scripts, validation, linting |
| HTTP | Centralized policy service or audit endpoint |
| MCP tool | Use connected MCP capability as validator |
| Prompt | Soft judgement / rubric check |
| Agent | Richer verification requiring file inspection |
| Async command | Logging or long-running side effect |
Anthropic marks agent hooks as experimental and says production workflows should prefer command hooks. (Claude Code)
8. Security best practices
Hooks can be powerful and dangerous. Command hooks run with the user’s system permissions, so hook scripts must be reviewed and tested. Anthropic’s hooks reference recommends validating and sanitizing inputs, quoting shell variables, blocking path traversal, using absolute paths, and skipping sensitive files like .env, .git, and keys. (Claude Code)
Exam traps:
- Do not pass raw tool input into shell commands without quoting
- Do not trust hook input blindly
- Do not assume hooks run in a sandbox unless your environment enforces one
- Do not use a prompt hook as a hard security boundary
- Do not let bypassPermissions run outside a controlled environment
- Do not assume allowed_tools constrains bypassPermissions
9. Exam decision table
| Scenario wording | Best answer |
|---|---|
| “Block dangerous command before execution” | PreToolUse hook or deny rule |
| “Log every file change” | PostToolUse hook |
| “Prevent Claude from stopping before tests pass” | Stop hook |
| “Validate subagent output before accepting it” | SubagentStop hook |
| “Ask user before deleting files” | canUseTool callback / ask rule |
| “Headless agent with only Read/Grep allowed” | allowed_tools + dontAsk |
| “Claude should plan but not edit” | plan mode |
| “Need auto-approve file edits in isolated repo” | acceptEdits |
| “Need full speed in isolated sandbox but still block rm” | bypassPermissions + deny rules/hooks |
| “Need security policy to apply to all developers” | Managed policy settings / project hooks |
| “Need external approval service” | HTTP hook or canUseTool integration |
| “Need non-blocking analytics” | Async hook |
10. Common exam anti-patterns
| Anti-pattern | Why wrong |
|---|---|
| “Just tell Claude not to do X” | Prompt is not enforcement |
Use PostToolUse to block deletion |
Too late; deletion already happened |
| Use async hook for mandatory approval | Async cannot block |
Use allowed_tools with bypassPermissions as a restriction |
allowed_tools does not constrain bypass mode |
Assume hook allow overrides deny rules |
Deny/ask rules are still evaluated |
| Use direct shell interpolation of tool input | Injection/path traversal risk |
| Use broad matcher with no filtering | Hook fires too often or blocks unrelated tools |
| Filter file paths in matcher | Tool matchers filter tool names, not path arguments |
Let subagents inherit bypassPermissions casually |
Subagents may get full system access |
| Use prompt/agent hook for deterministic security | Prefer command hook, deny rule, or app logic |
Scenario-Based Questions
Q1. Prompt vs enforcement
A developer writes in the system prompt: “Never edit .env files.” Claude later attempts to edit .env. What is the best fix?
A. Make the prompt more emotional
B. Add a PreToolUse hook or deny rule that blocks .env edits
C. Use PostToolUse to complain after the edit
D. Increase model size
Answer
B. Sensitive file protection should be enforced before tool execution.
Q2. Blocking dangerous Bash before execution
Claude attempts Bash("rm -rf /tmp/build"). The organization wants this blocked before execution. Which hook is best?
A. PreToolUse
B. PostToolUse
C. SessionEnd
D. Notification
Answer
A. PreToolUse fires before the tool call and can block it.
Q3. Too late to block
A team uses PostToolUse to prevent production deletes. What is wrong?
A. PostToolUse cannot see tool results
B. PostToolUse runs after the action already happened
C. PostToolUse only works for subagents
D. PostToolUse disables permissions
Answer
B. Prevention must happen before execution; PostToolUse is for audit and reaction, not blocking.
Q4. Stop criteria
Claude edits code and says it is done, but tests have not run. What hook can enforce “do not finish until tests pass”?
A. Stop
B. SessionStart
C. Notification
D. CwdChanged
Answer
A. Stop can prevent completion and continue the work.
Q5. Subagent premature completion
A subagent returns before completing all assigned research. Which hook best validates whether it may finish?
A. SubagentStop
B. PreCompact
C. PostToolUseFailure
D. SessionEnd
Answer
A. SubagentStop is used around subagent completion to validate output.
Q6. Human approval
A coding agent wants to deploy to production. Company policy requires a human approval dialog. What should you use?
A. canUseTool or ask rule
B. A stronger system prompt only
C. PostToolUse after deployment
D. Async logging hook only
Answer
A. Human-in-the-loop approval belongs in canUseTool or ask/approval flow.
Q7. Hook precedence
One matching hook returns allow, while another matching hook returns deny. What happens?
A. The operation runs because allow is positive
B. The operation is blocked because deny wins
C. The latest hook wins
D. Claude chooses
Answer
B. Deny has higher priority than allow.
Q8. Permission rules vs hooks
A hook returns allow, but a deny rule also matches. What is the correct result?
A. The tool runs because hooks run first
B. The tool is denied because later deny rules still apply
C. The user is always prompted
D. The hook is ignored
Answer
B. Hook allow does not skip deny or ask rules.
Q9. bypassPermissions trap
An engineer sets allowed_tools=["Read"] and permission_mode="bypassPermissions" expecting only Read to run. What is wrong?
A. allowed_tools does not constrain bypassPermissions
B. Read cannot be allowed
C. bypassPermissions disables Claude
D. Hooks cannot run in bypass mode
Answer
A. In bypass mode, unlisted tools can still be approved unless deny rules/hooks block them.
Q10. Locked-down headless agent
A headless agent should only use Read, Glob, and Grep. Everything else should be denied without prompting. What is best?
A. allowed_tools=["Read", "Glob", "Grep"] with dontAsk
B. bypassPermissions
C. Prompt: “Only read files”
D. acceptEdits
Answer
A. dontAsk denies anything not pre-approved.
Q11. Planning without edits
A reviewer wants Claude to inspect a repo and propose changes, but not edit files. Which mode fits?
A. plan
B. acceptEdits
C. bypassPermissions
D. auto
Answer
A. Plan mode is for exploration and planning without auto-approved edits.
Q12. Auto-accept edits
A developer works in an isolated throwaway branch and wants faster iteration with automatic file edits. Which mode may fit?
A. acceptEdits
B. dontAsk
C. plan
D. SessionEnd
Answer
A. acceptEdits auto-approves file edits and filesystem operations in scope.
Q13. Async hook misuse
A security team configures an async hook to approve or deny every Bash command. Why is this wrong?
A. Async hooks cannot block or control the current operation
B. Async hooks cannot run shell commands
C. Async hooks only run on SessionStart
D. Async hooks disable Claude
Answer
A. Async hooks are for side effects, not enforcement; use synchronous PreToolUse or permission rules.
Q14. Command hook exit code
A command hook must block a dangerous tool call using exit codes. Which exit code should it use?
A. 0
B. 1
C. 2
D. 255
Answer
C. Exit code 2 is the blocking signal for blockable events; exit 1 is not the enforcement signal.
Q15. MCP matcher
You want to match every tool from an MCP server named memory. Which matcher is correct?
A. mcp__memory
B. mcp__memory__.*
C. memory.*
D. mcp_memory_all
Answer
B. MCP tools use mcp__<server>__<tool> naming; use .* after the server prefix.
Q16. File path filtering
A hook should run only for .ts files. The developer tries to put *.ts in a tool matcher. What is the issue?
A. Tool matchers filter tool names, not file paths
B. Hooks cannot inspect file paths
C. .ts files cannot be edited
D. The hook should use SessionEnd
Answer
A. Filter file path inside the callback using tool_input.file_path.