L2: Hooks and Programmatic Enforcement
L2: Hooks and Programmatic Enforcement
Hooks and Programmatic Enforcement
Up to this point, we have controlled our agents primarily through Prompt Engineering —telling Claude what to do in plain English. However, prompts are probabilistic; an LLM might occasionally ignore a prompt if conflicting context pushes it off course.
When building production systems (especially those with read/write access to databases or file systems), you cannot rely on prompts alone for security or business logic. You need deterministic, hard-coded rules. In the Claude Agent SDK, this is achieved through Hooks.
1. What are Hooks?
Hooks are programmatic callback functions that intercept an agent's execution at specific points in its lifecycle (e.g., just before a tool is used, or right after a tool returns a result).
Think of them as middleware for your AI. Instead of hoping Claude follows the rule "Do not delete files," a hook allows your application code to physically intercept a file-deletion tool call, evaluate it, and block it before it executes.
2. The Hook Lifecycle
When you register hooks in the Claude Agent SDK, the execution follows a strict 5-step process:
Event Fires: The SDK broadcasts that something is happening (e.g., Claude requested the
BashorWritetool).SDK Collects Hooks: The SDK looks at your configuration (via Python/TypeScript dictionaries or settings files) to see if you have any hooks registered for that specific event.
Matchers Filter the Event: Hooks use "matchers" (regex patterns). If you set a matcher for
"Write|Edit", the hook will only trigger for those specific tools, ignoring others likeReadorGlob.Callback Executes: Your custom function runs. It receives an event payload containing context like the
tool_name, thetool_input(the arguments Claude generated), and thesession_id.Return a Decision: Your callback function must return a programmatic decision to the SDK, instructing it on how to proceed.
3. Key Hook Events
The Agent SDK exposes several hook events, but architects primarily focus on these:
PreToolUse: Fires after Claude generates the tool call JSON, but before your local system executes it. This is your primary security gate.PostToolUse: Fires after the tool executes, but before the result is sent back to Claude. This is used for redacting sensitive data (PII) from the tool's output so it doesn't enter the model's context window.Stop/ Execution Finished: Fires when the agentic loop terminates. Great for logging metrics, billing usage, or cleaning up temporary files.
4. Enforcement Decisions (The Action Output)
When a PreToolUse hook runs, your callback function must return one of the following decisions to enforce behavior:
allow: The tool call is approved and proceeds normally.block/deny: The tool call is rejected. The agent is immediately handed a simulatedtool_resultexplaining the rejection (e.g., "Error: Deleting production tables is blocked by policy"), forcing the agent to rethink its plan.ask: Pauses the agent completely and escalates to a human user in the terminal or UI, requiring explicit manual approval before proceeding.modify_input: You programmatically alter the tool arguments Claude provided. (e.g., Claude asked to querylimit=1000, but your hook silently forces it tolimit=50).inject_context: You allow the tool to run but inject a hidden system message alongside the result to steer the agent's next thought.
Architectural Note on Priority: If multiple hooks trigger simultaneously on the same event, the SDK enforces a strict priority: Deny takes priority over Ask, which takes priority over Allow. If even one hook returns deny, the action is blocked.
5. Prompts vs. Hooks (When to use which)
A common exam scenario will test your ability to choose between fixing an issue with a Prompt or fixing it with a Hook.
Use a Prompt when: The enforcement is stylistic, logical, or subjective (e.g., "Always write responses in a friendly tone" or "Think step-by-step before querying the database").
Use a Hook when: The enforcement is a strict business rule, a security boundary, or requires deterministic API validation (e.g., "Never allow a query that updates the
userstable without aWHEREclause").
By decoupling strict rules from the LLM's prompt and placing them in Hooks, you drastically reduce the complexity of the prompt, saving tokens and virtually eliminating the risk of a jailbreak or hallucinated tool execution.