1.3 Constructing Claude Agents: SDK, Custom Loops, and Hooks
1.3.1 Three Ways to Build the Loop
Once you've decided a task needs an agent, you still have to build the loop itself, and there are now three legitimate ways to do it. This is not a beginner-vs-expert distinction -- it's a spectrum of how much of the agent's runtime you're willing to own, and the correct choice is whichever point on that spectrum the requirement actually demands.
| Approach | What it gives you | Choose it when |
|---|---|---|
| Custom agent loop | You write the loop yourself over the Messages API: send messages, receive tool_use, execute tools, feed back tool_result, repeat until stop_reason is end_turn | Full control over dispatch, logging, and stopping conditions is required |
| Claude Agent SDK | A programmable agent loop, built-in tools, session management, subagents, and hooks -- Anthropic handles the gather-context, act, verify cycle for you, running inside your own process | Managed loop mechanics and Anthropic-maintained tooling are sufficient for the requirement |
| Claude Managed Agents (public beta) | Anthropic runs the loop AND the execution sandbox for you, off in Anthropic's own infrastructure; you define the agent once and refer to it by ID | The task runs long, you'd rather not build or secure a sandbox yourself, and the workload has no Zero Data Retention or HIPAA BAA requirement |
Three points on the same spectrum -- how much of the agent's runtime you own decreases from top to bottom. The tool-use loop underneath is identical in all three; what changes is who runs each iteration.
The one idea to hold onto
Three wiring paths, one underlying loop: a custom loop (you own everything), the Agent SDK (Anthropic's loop mechanics running in your process), and Claude Managed Agents (Anthropic runs the loop and the sandbox server-side). Pick based on how much infrastructure you want to own and what your compliance constraints allow -- not by which sounds most sophisticated.
1.3.2 The Claude Agent SDK
The Claude Agent SDK is Anthropic's own framework for the agent loop: it provides the loop mechanics, a set of built-in tools, session management across turns, first-class support for subagents (Lesson 1.2's pattern, ready-made), and hooks (this lesson's next topic). It handles the underlying gather-context, act, verify cycle so you don't have to reimplement that harness by hand every time you build an agent.
# Illustrative shape of building an agent with the Claude Agent SDK
from claude_agent_sdk import ClaudeAgentOptions, query
options = ClaudeAgentOptions(
system_prompt="You triage support tickets and draft replies.",
allowed_tools=["read_tickets", "draft_reply"],
hooks={"PreToolUse": [block_destructive_actions]}, # see 1.3.5
)
async for message in query(prompt="Handle ticket #4821", options=options):
# the SDK runs the gather-context -> act -> verify loop internally;
# your code just consumes the resulting messages/events
handle(message)Because the SDK is Anthropic-maintained, it also tends to track new capabilities -- new built-in tools, new hook events -- without you having to hand-build support for them. The cost of that convenience is exactly what you'd expect from any managed layer: you're working within the shapes it exposes.
1.3.3 The Custom Agent Loop Over the Messages API
The alternative is to write the loop yourself directly over the Messages API. The cycle is simple to state and easy to get subtly wrong in practice: send messages to the model, receive tool_use blocks when it wants to act, execute those tools in your own code, feed the results back as tool_result blocks, and repeat the whole cycle until the model's stop_reason comes back as end_turn rather than tool_use.
# A minimal custom agent loop over the Messages API
messages = [{"role": "user", "content": user_input}]
while True:
response = client.messages.create(
model="claude-sonnet-4-6", max_tokens=2048,
tools=tool_definitions, messages=messages,
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
break # model is done -- end_turn (or another terminal reason)
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input) # your dispatch logic
tool_results.append({
"type": "tool_result", "tool_use_id": block.id, "content": result,
})
messages.append({"role": "user", "content": tool_results})This buys you exactly the control the SDK doesn't expose: your own dispatch logic (route tool calls however you want), your own logging (capture whatever detail your observability stack needs), and your own stopping conditions (a custom budget, a custom max-steps rule, a custom success check) -- at the cost of maintaining the harness yourself.
1.3.4 Claude Managed Agents: The Third Wiring Path
A raw loop or the Agent SDK still leaves every pass through the cycle in your own code: issue the request, parse the tool-use blocks, run the tools, append the results. Claude Managed Agents, currently in public beta, hands that whole division of labor to Anthropic instead -- the loop and the sandbox both run on Anthropic's infrastructure. Your application registers the agent once (model, system prompt, tools, MCP servers, skills), keeps a reference to that registration by ID, pushes user events into an active session, and reads the results back as a server-sent event stream. None of the loop's actual iteration happens inside your process.
| Category | What you stop owning | What you take on instead |
|---|---|---|
| Execution & infrastructure | Running the loop, hosting the execution sandbox, retrying inside it, and the whole tool-execution runtime -- Anthropic handles every bit of this server-side | A versioned resource that defines the agent, plus a thin application layer for pushing events in and reading the streamed results back out |
| Session duration & state | Keeping a long session alive -- a session can sit open for minutes or hours with nothing in your own process holding it there | State that lives entirely server-side: Anthropic stores it and governs it under its own data-handling policies |
| Sandbox lifecycle | Standing the sandbox up and tearing it back down around tool calls | Being limited to whatever tools and execution model the managed sandbox happens to expose, rather than controlling your own runtime |
Every row is a trade: something you used to build and maintain becomes something you instead configure and depend on.
Managed Agents makes the most sense for a particular shape of workload: work that runs long enough that holding a loop open in your own process for minutes or hours stops being practical; work where you'd otherwise have to stand up and secure your own tool-execution sandbox, which Managed Agents simply takes off your hands; or cases where you'd rather register the agent as an API resource once and skip owning the loop, the sandbox, and the execution runtime entirely.
1.3.4 -- Exam Trap
Because Managed Agents sessions live statefully on Anthropic's servers, they don't currently qualify for a Zero Data Retention agreement or a HIPAA BAA. A workload handling PHI, or bound by a ZDR commitment, can't take this path regardless of how well it would otherwise fit the job -- send it to the Agent SDK or a self-built loop on an approved configuration instead. The next note works through the broader set of regulated-data constraints this same rule belongs to.
A typical path is to build against the Agent SDK on your own machine first -- fast iteration, full visibility into every step of the loop -- and only move to Managed Agents once behavior is proven and nothing regulatory stands in the way. The agent's underlying design carries over, but not as a code export: you re-express it. The Agent SDK holds the agent in code and filesystem settings; Managed Agents holds the same agent as a versioned API resource that a session pulls up by ID.
1.3.5 Deployment Models: Hosted vs. Self-Hosted
Independent of which loop you build, you also choose where it runs. Anthropic-hosted (managed) deployment means Anthropic runs the agent infrastructure for you -- less operational burden, but also less control over the environment the agent executes in. Self-hosted (in-process) deployment means you run the loop and its tools inside your own environment -- maximum control over data flow, networking, and least-privilege boundaries, at the cost of operating that infrastructure yourself.
| Model | Character | Trades off |
|---|---|---|
| Anthropic-hosted / managed | Anthropic runs the agent infrastructure | Less operational burden, in exchange for less control over the execution environment |
| Self-hosted (in-process) | You run the loop and tools in your own environment | Maximum control over data flow, networking, and least privilege, in exchange for operating it yourself |
Neither deployment model has a universal winner -- the choice trades operational burden against control over data residency, networking, and least privilege.
1.3.4 -- Exam Trap
Exam trap: assuming "managed/hosted" always wins because it's less work. Self-hosting gives tighter control over data residency and least privilege -- a legitimate, sometimes required, reason to run the loop yourself, especially under strict data-sensitivity constraints.
1.3.6 Regulated-Data Deployment Constraints
When the data an agent will handle carries a regulatory or contractual string attached -- attorney-client privilege, HIPAA, GDPR, or FedRAMP -- that string settles which endpoint your code calls, which credential type it carries, and where its logs end up, ahead of any prompt, tool, or memory decision. You rarely pick the delivery surface itself, but you're the one writing the code that targets a specific endpoint, attaches the credential, sets the region, and ships the logs -- and unpicking a wrong choice there after the agent is wired costs far more than getting it right up front.
| Constraint | What it rules out | What survives review |
|---|---|---|
| Attorney-client privilege | A consumer Claude.ai session with no end-to-end audit trail the firm can point to, regardless of how carefully the prompt is worded | Calls from a first-party application the firm operates, with SSO identity and traffic routed through a vetted gateway. Anthropic doesn't retain prompt/response/tool-call content by default for direct API traffic, so the firm's own application has to write that record if compliance requires it |
| HIPAA (PHI) | Routing PHI to any endpoint or path that a signed Business Associate Agreement doesn't name for that exact configuration | A configuration the BAA actually names: a HIPAA-enabled org on the direct API, or a route through the partner's existing HIPAA-eligible AWS Bedrock or GCP Vertex account. Console, Workbench, beta features, and consumer plans all fall outside BAA coverage |
| GDPR / EU data residency | A code path where the processing region floats rather than being fixed, or that could get served from a jurisdiction the customer never approved | Bedrock or Vertex with the region locked in the client config -- Anthropic's own direct API has no EU residency option as of this writing |
| FedRAMP / government | Anything served from a cloud environment not authorized for the impact level in question, including a dev/test setup that quietly points at the commercial endpoint while production points elsewhere | Exactly three routes clear this bar: Claude for Government (C4G, FedRAMP High through Palantir's federal cloud), Claude on Amazon Bedrock GovCloud (FedRAMP High plus DoD IL4/5), and Claude on Vertex AI Assured Workloads (FedRAMP authorized) |
In every row, the constraint is a hard gate on the delivery route itself -- not something a well-written prompt or a clever tool design can work around.
1.3.6 -- Exam Trap
Exam trap: 'Claude Enterprise on AWS Marketplace is FedRAMP authorized.' False -- it is explicitly NOT FedRAMP authorized. The three authorized government routes are Claude for Government (C4G), Claude via Amazon Bedrock GovCloud, and Claude via Vertex AI Assured Workloads. A question that offers AWS Marketplace as a FedRAMP answer is a distractor.
Notice how this connects back to the previous note: Managed Agents' ZDR/BAA ineligibility is one instance of this same governing principle -- a storage or data-handling property of the delivery route rules out an otherwise-attractive wiring path before any other design consideration gets a vote. Get the constraint named at the start of the build, before any choice about the agent's loop, tools, or wiring path.
1.3.7 Hooks: Deterministic Guardrails in the Loop
Hooks are ordinary code callbacks that fire at fixed points in the agent loop -- PreToolUse fires before a tool executes, PostToolUse fires after. Because a hook is just code, not a model generating text, it behaves deterministically: it can block a dangerous call, validate the arguments, redact sensitive output, or require human approval, and it does this regardless of whatever the model itself "decided" was appropriate.
# PreToolUse hook: deny a destructive tool call outright, every time.
# Runs BEFORE delete_database_row executes -- the model's own reasoning
# about whether deletion is appropriate never gets a vote here.
TOOL_NAME=$(jq -r '.tool_name' < /dev/stdin)
if [ "$TOOL_NAME" = "delete_database_row" ]; then
jq -n '{hookSpecificOutput:{hookEventName:"PreToolUse",
permissionDecision:"deny",
permissionDecisionReason:"Row deletion requires a human-approved change ticket; the agent cannot self-authorize this action."}}'
else
exit 0 # no decision here -- let normal permission flow continue
fiThat last point is the crux of why hooks matter: a system-prompt instruction like "never delete a row without confirmation" is probabilistic. The model generally complies, but a prompt cannot guarantee compliance in every case, especially under adversarial or unusual input. A PreToolUse hook that inspects the proposed call and denies it outright doesn't depend on the model choosing to comply -- it enforces the boundary before the action ever executes.
1.3.5 -- Key Concept
A prompt is probabilistic; a hook is deterministic. Destructive or high-stakes tool calls belong in a PreToolUse (or PostToolUse) hook, not solely in prompt text -- this is the correct place for guardrails, and the exam treats it as a hard rule, not a best practice among several options.
1.3.8 Human-in-the-Loop (HITL) Insertion Points
Hooks give you a deterministic mechanism for gating a tool call. This note answers a different question: where in the loop should that gate actually go? Weigh two things per step: how much damage a wrong, unsupervised call at that step could do, and how hard that damage would be to undo afterward. Steps that score high on both get a gate.
| Insertion point | What triggers the check | Risk level it addresses |
|---|---|---|
| Before a destructive tool call | The agent is one step from running a write, delete, or outbound send | High -- these actions are hard or impossible to walk back once executed |
| After a planning step | The agent has produced a multi-step plan and is about to start on it | Medium -- a flawed plan reaches the wrong outcome even when every step in it runs cleanly |
| On unexpected output | A tool result comes back with an error flag, an empty payload, or an out-of-range value | Variable -- surfaces failures a plain retry would never fix |
These three gates are not interchangeable, and picking only one is a common design gap -- each catches a different failure class.
A gate before a destructive call catches a bad action. A gate after planning catches a bad plan before any action executes at all -- and a plan can be wrong even when every individual step in it would succeed if run in isolation. A gate on unexpected output catches a third failure class entirely: the agent's own tool didn't fail loudly, it returned something quietly wrong that a blind retry would never fix.
1.3.8 -- Key Concept
Passing a tool's own local validation is not the same as being safe to commit. A file-editing agent that corrects an out-of-range parameter, writes it, and re-runs validate_config can pass validation cleanly -- and still break a downstream system the validator was never designed to check. The gap is between 'proposed change ready' and 'write committed,' and only a HITL checkpoint before the destructive write closes it.
- •Before a destructive tool call -- always gate; the action can't be undone if it's wrong.
- •After a planning step -- gate when the plan's correctness matters more than any single step's correctness.
- •On unexpected output -- gate situationally, when an error flag, empty result, or out-of-bounds value signals something retry logic alone won't fix.
- •Design the insertion point in when scoping the tool surface -- not after the first incident exposes the gap.
1.3.9 Put It Together: Exam Traps for Task Statement 1.3
Task Statement 1.3 questions tend to hand you a construction decision -- SDK or custom loop, hosted or self-hosted, prompt or hook -- and test whether you pick based on the stated requirement rather than a general impression of which option is "more advanced" or "safer by default."
- •Putting a safety rule only in the system prompt and calling it a guardrail. ✗ Any answer that relies on prompt wording alone for a destructive or high-stakes action. ✓ The answer that places the rule in a PreToolUse or PostToolUse hook.
- •Assuming managed/hosted deployment always wins because it's less operational work. ✗ Defaulting to hosted regardless of data-sensitivity constraints. ✓ The answer anchored to the actual control requirement -- self-hosting when data residency or least privilege demands it.
- •Treating the Agent SDK and a custom loop as a skill ladder rather than a tradeoff. ✗ Assuming a custom loop is always "better engineering." ✓ The answer that matches the tool to whether managed mechanics are sufficient or full dispatch/logging control is actually required.
Where this shows up on the exam
1.3 questions often bury the real requirement in a phrase like "must be auditable," "must run in our own VPC," or "must block this action every time." Match that phrase to the SDK-vs-custom, hosted-vs-self-hosted, or prompt-vs-hook decision it's actually pointing at.
Key Takeaways
- ✓The Claude Agent SDK provides a managed loop, built-in tools, sessions, subagents, and hooks -- use it when managed mechanics are sufficient for the requirement.
- ✓A custom loop cycles tool_use, tool execution, and tool_result, repeating until stop_reason is end_turn -- use it when full control over dispatch, logging, or stopping conditions is required.
- ✓Anthropic-hosted deployment lowers operational burden; self-hosted deployment maximizes control over data flow, networking, and least privilege -- neither wins universally.
- ✓Hooks (PreToolUse, PostToolUse) are ordinary code callbacks that fire at fixed points in the loop and behave deterministically -- they can block, validate, redact, or require approval regardless of the model's own decision.
- ✓A prompt-only safety rule is probabilistic; a hook enforces the same boundary structurally and reliably -- destructive or high-stakes tool calls belong in a hook, not in prompt text alone.
- ✓Every construction decision in this lesson -- SDK vs. custom, hosted vs. self-hosted, prompt vs. hook -- is a requirement-driven tradeoff, not a hierarchy with one side always winning.
- ✓Claude Managed Agents (public beta) is a third wiring path: Anthropic runs the loop AND the execution sandbox server-side; your app registers the agent's configuration a single time (model, system prompt, tools, MCP servers, skills), then addresses it by that ID afterward, streaming events back over SSE.
- ✓Managed Agent sessions are stateful and stored server-side, which is exactly why they are NOT currently eligible for Zero Data Retention (ZDR) or a HIPAA Business Associate Agreement (BAA) -- PHI or ZDR workloads must use the Agent SDK or a raw loop instead.
- ✓Regulated-data constraints (attorney-client privilege, HIPAA, GDPR, FedRAMP) decide the endpoint, credentials, and log destination before any design choice about the agent's loop or tools -- and Claude Enterprise on AWS Marketplace is explicitly NOT FedRAMP authorized.
- ✓Human-in-the-loop checkpoints belong at three insertion points -- before a destructive tool call (high risk), after a planning step (medium risk), and on unexpected output (variable risk) -- chosen by asking what the worst outcome is if that step runs unchecked.
Check Your Understanding
Test what you learned in this lesson.
Q1.Where should a rule that blocks a destructive shell command be enforced?
Q2.A team needs an agent with fully custom logging and a bespoke stopping condition not offered by any managed framework. Which approach fits?
Q3.A design must keep all agent execution and data flow inside the company's own VPC due to a strict data-residency requirement. Which deployment model fits, and why isn't the alternative simply better by default?
Q4.What is the correct relationship between the Claude Agent SDK and a custom agent loop?
Q5.Why does a PostToolUse hook provide a guarantee that a system-prompt instruction cannot?
Q6.A team wants Anthropic to run both the agent loop and the tool-execution sandbox, defining the agent once and referring to it by ID from their application. Which wiring path fits, and what does it rule out for a PHI workload?
Q7.A government contractor needs a FedRAMP High authorized delivery route for Claude. Which of the following is NOT a valid authorized route?
Q8.An agent generates a multi-step plan and then begins executing it. Why does a HITL checkpoint placed only before destructive tool calls fail to fully cover this scenario?
Practice This Lesson