Curriculum › Agents and Workflows · 14.7% of the exam

Agent construction with Claude

What you'll be able to do

  • Choose between the Agent SDK and a custom loop on real criteria
  • Weigh managed deployment against self-hosting
  • Use hooks where a prompt instruction cannot reach
  • Identify the request-execute gap as the control point

What you’ll be able to do

  • Choose between the Agent SDK and a custom loop on real criteria
  • Weigh managed deployment against self-hosting
  • Use hooks where a prompt instruction cannot reach
  • Identify the request-execute gap as the control point

What you need to know

Agent SDK or hand-rolled loop

The Agent SDK gives you the loop, built-in tools, and context management out of the box. A custom harness is justified when you need control the SDK doesn't expose — an unusual orchestration shape, bespoke state handling, integration with an existing framework.

The tested instinct is that "we'll write our own loop" is not a neutral default. It's a decision with an ongoing maintenance cost, and it needs a reason beyond preference.

The request-execute gap

Worth understanding precisely, because several exam answers live here. The model requests a tool call. Your code decides whether to execute it. Those are two separate moments with a gap between them.

That gap is the control point for everything supervisory: approval prompts, permission checks, argument validation, rate limiting, audit logging, and hooks. It's a property of the architecture, not a latency defect to engineer away.

Hooks: the guarantee a prompt cannot give

A system prompt is a request. Under enough pressure — a long conversation, a persuasive injected instruction, an unusual edge case — the model can deviate from it. That's not a flaw to prompt harder against; it's the nature of the mechanism.

Hooks are deterministic code running at fixed points in the loop. They are configured in settings.json — user, project, local, or enterprise-managed — and matched to tool names. They enforce a rule regardless of what the model decides, because the model isn't the one deciding.

before — a request the model can be argued out of
system_prompt += "Never run destructive shell commands."
after — a PreToolUse hook in .claude/settings.json
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": ".claude/block-destructive.sh" } ] } ] } }

The handler receives the event as JSON on stdin — tool_name, tool_input, session context — and decides:

block-destructive.sh — the decision is code, not wording
#!/usr/bin/env bash cmd=$(jq -r '.tool_input.command' <&0) if [[ "$cmd" =~ rm[[:space:]]+-rf ]]; then echo "Destructive command blocked by policy" >&2 exit 2 # exit 2 blocks the tool call fi exit 0

When a question asks for a rule that holds "no matter what the model decides," it is asking for a hook. Every prompt-wording option in that question is a distractor.

Managed versus self-hosted

A straight trade, and the scenario always tells you which side it's on:

  • Managed — faster to ship, less operational burden, less control. Right when speed matters and the team lacks ops capacity.
  • Self-hosted — full control over runtime and environment, at the cost of running it. Right when a compliance boundary, network constraint, or customisation need makes control non-negotiable.

Look for the deciding phrase: "we need this in our VPC" or "we have the ops capacity" points one way; "ship quickly with a small team" points the other.

Key concept

The model requests, your code executes — that gap is where approval, validation, and hooks live. A hook enforces what a prompt can only request. Managed versus self-hosted is a control-for-burden trade the scenario decides for you.

Practice scenario

ScenarioYour team wants a guarantee that an agent will never delete a production record, and someone suggests putting it in capital letters at the top of the system prompt.
Work it through, then open this

Capital letters don’t change the mechanism: a prompt is a request the model can be argued out of, and a long conversation or an injected instruction is enough pressure. This needs a hook at the request-execute gap — code that denies the call by name regardless of what the model concluded.

Build exercise — Put a hook in front of a destructive action

Intermediate · 25 min

What you’ll learn

  • Where the request-execute gap sits in your own loop
  • Why a prompt instruction can’t give the same guarantee
  • How to test that a block actually blocks
  1. Take an agent you can run and list every tool it can call. Mark the ones where a single bad call is unrecoverable — an external send, a delete, a write to a system of record.

    • Why: Hooks are for unbounded or irreversible actions, not for every call. Marking them first stops you hooking everything and reducing the agent to a pipeline.
    • You should see: Usually one or two tools out of a handful, not the whole list.
  2. Write a system prompt instruction telling it never to call one of those tools, then deliberately construct a prompt that talks it into doing so anyway.

    • Why: You need to see a prompt instruction fail before the hook argument lands. It’s the difference between believing it and knowing it.
    • You should see: With enough context pressure, the model attempts the call. If you can’t break it in five minutes, try a longer conversation — drift does the work for you.
  3. Replace the instruction with a hook at the pre-execution point that denies that tool by name, and re-run the same adversarial prompt.

    • Why: The hook decides in code, so the model’s conclusion is irrelevant.
    • You should see: The model still requests the call; the call never executes. That gap between request and execution is the whole lesson.

Exam traps

Using a system prompt instruction as a hard guarantee

A prompt is a request the model can deviate from. Anything that must hold regardless needs a hook.

Writing a custom agent loop with no reason beyond preference

It carries ongoing maintenance cost. The SDK is the default you move away from with a justification.

Treating the request-execute gap as latency to remove

It is the control point for approval, validation, and audit. Collapsing it removes your supervision surface.

Self-hosting when the scenario emphasises shipping speed and thin ops

That is the profile managed deployment exists for. Control has a running cost someone has to pay.

Sources

Quick check

An orchestrator delegates three independent research subtasks to three subagents instead of running them in one long conversation. What's the main benefit?