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:

  1. Event Fires: The SDK broadcasts that something is happening (e.g., Claude requested the Bash or Write tool).

  2. 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.

  3. 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 like Read or Glob.

  4. Callback Executes: Your custom function runs. It receives an event payload containing context like the tool_name, the tool_input (the arguments Claude generated), and the session_id.

  5. 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 simulated tool_result explaining 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 query limit=1000, but your hook silently forces it to limit=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 users table without a WHERE clause").

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.