Skip to content

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:

Tell Claude not to do dangerous things.

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:

If tool_name == "Bash" and command contains "rm -rf":
    deny with reason

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 PostToolUse to 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:

After Write/Edit, run formatter or test suite.
Bad use:
After Bash("delete-prod-db"), decide whether deletion was allowed.

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 Stop hook is not the same as D1.1’s stop_reason.
stop_reason controls the API agentic loop. A Stop hook 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 1 is not the standard enforcement signal in Claude Code hooks. Use exit 2 or 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, inspect tool_input.file_path inside 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.