CCAF logo

Domain 1 · Task 1.5

Agent SDK Hooks

Apply Agent SDK hooks for tool-call interception and data normalization.

Hooks are the Agent SDK's enforcement layer: callbacks that run your code at lifecycle events to transform results or block actions, deterministically, where prompts are only probabilistic. Two events carry most of the exam weight: PostToolUse intercepts tool *results* before the model sees them, and PreToolUse intercepts tool *calls* before they execute.

Key concept

A deterministic transform or a hard limit is always a hook, never a prompt. If a business rule requires guaranteed compliance, put it in a hook.

What you need to know

PostToolUse: normalize results before the model sees them

Different MCP tools return the same kind of data in different shapes — one gives Unix timestamps, another ISO 8601, another numeric status codes. A PostToolUse hook intercepts each tool result and normalizes the format before the model ever reasons over it, so the model never has to juggle mixed representations. Converting every tool's date field to ISO 8601 in a hook *guarantees* consistency; asking the model in the prompt to "always convert dates" works most of the time but not always.

python
@hook("PostToolUse")
def normalize_dates(tool_name, tool_output):
    # Coerce every tool's date field to ISO 8601 before the model sees it
    raw = tool_output.get("date")
    if raw is not None:
        tool_output["date"] = to_iso8601(raw)  # Unix, numeric, or ISO in -> ISO out
    return tool_output

PreToolUse: intercept and block policy-violating calls

A PreToolUse hook intercepts an outgoing tool *call* and can block it or redirect it. This is how you enforce compliance deterministically: block any process_refund where the amount exceeds $500 and redirect it to human escalation. Because the hook runs in code on every call, the limit is a hard guarantee — a prompt-based "never exceed $500" instruction is not.

Hooks for guarantees, prompts for preferences

The dividing line is exactly the master compass: hooks for deterministic guarantees, prompts for probabilistic compliance. Choose hooks whenever a business rule requires guaranteed compliance — hard money limits, mandatory format normalization, security or audit requirements. Reserve prompts for soft preferences and formatting where an occasional miss is tolerable.

Exam traps

The trapThe reality
Tell the model in the system prompt to always convert dates to a single format.That works most of the time, not always. A PostToolUse normalization hook guarantees every date is consistent before the model sees it.
A prompt instruction like "never issue a refund over $500" enforces the limit.Prompts are probabilistic. Use a PreToolUse interception hook to block refunds over $500 and redirect to escalation.
PreToolUse and PostToolUse are interchangeable ways to shape agent behaviour.PreToolUse intercepts the *call* (block/redirect); PostToolUse intercepts the *result* (transform/normalize). Pick by whether you're gating an action or reshaping data.
Normalizing heterogeneous MCP outputs is best done by asking the model to handle each format.Making the model reason over mixed formats is fragile. Normalize deterministically in a PostToolUse hook so the model sees one format.

Practice scenario

Real questions from the bank that test this topic — the correct answer is highlighted.

A code review agent runs in your CI pipeline. Compliance requires that the agent must never approve a PR that modifies files in /infrastructure/production/ without flagging it for human review — this is a hard regulatory requirement. The system prompt instructs Claude to flag such PRs, but quarterly audits found 1.2% of production-infrastructure PRs were approved automatically.

How do you achieve guaranteed compliance?

AAdd explicit examples to the system prompt showing the agent flagging /infrastructure/ production/ changes, and set temperature to 0
BUse a PreToolUse hook on the approve_pr tool that inspects the file list and blocks the call if any path matches /infrastructure/production/Correct
CAdd a separate critic agent that reviews the primary agent's decisions and overrides approvals on production-infrastructure changes
DConfigure the agent's allowed tools so approve_pr is unavailable when production- infrastructure paths are in scope, toggled by the coordinator

Why: "Hard regulatory requirement" rules out anything that leaves the decision to a model. That kills A (prompt-based, model still decides), C (a critic is just a second model with the same statistical failure mode), and D (the coordinator deciding "is production in scope?" is again model discretion). A PreToolUse hook (B) is deterministic code that fires every time, inspects the actual file list, and blocks the call if any production path is touched. Hooks are the layer for compliance guarantees — prompts and second models are not.

You want to implement two safety checks in Claude Code:

  1. Block any Edit/Write tool call targeting files in /secrets/ , regardless of model intent.
  2. Log every successful tool call (with file paths and results) to a centralized audit system.

What's the correct hook configuration?

AUse PreToolUse hooks for both (1) and (2) — both involve tool calls
BUse PreToolUse for (1) to block before execution, and PostToolUse for (2) to log after execution with actual resultsCorrect
CUse PostToolUse for both — pre-hooks add latency to every call
DUse Stop hooks for (1) and PreToolUse for (2)

Why: PreToolUse runs before the tool executes and can block the call — that's what you need for the /secrets/ guard. PostToolUse runs after the call succeeded and is the right place to log what actually happened, including outputs and side effects. Using PreToolUse for logging (A) misses post-execution data; using PostToolUse for blocking (C) is too late — the destructive action already happened. Stop hooks (D) fire on agent termination, not per tool call.

Build exercise

Normalize data and enforce a limit with hooks

~45 min
  1. 1
    Stand up two mock MCP tools that return dates in different formats — one Unix epoch, one ISO 8601 — plus a numeric status code.

    Why: Heterogeneous formats are exactly what a normalization hook is for.

  2. 2
    Add a PostToolUse hook that rewrites every date field to ISO 8601 before the result reaches the model.

    You should see: Downstream, the model only ever sees ISO 8601 dates regardless of which tool produced them.

  3. 3
    Add a PreToolUse hook that blocks any process_refund call with an amount over $500 and redirects it to a human-escalation path.

    Why: A hard money limit must be a deterministic gate, not a prompt request.

  4. 4
    Try a $750 refund and confirm the hook blocks it and routes to escalation.

    You should see: The call never executes; the agent is handed the escalation path instead.

  5. 5
    For contrast, add a prompt-only "never exceed $500" instruction with the hook removed, and show it occasionally lets a large refund through.

    Why: Demonstrates why guarantees belong in hooks, not prompts.

Sources

Drill Agentic Architecture & Orchestration

Practice only this domain’s questions, untimed, with instant explanations.