CClaude Cert Prep
D127% of exam

CCA-F Domain 1 Study Guide: Agentic Architecture & Orchestration

The heaviest domain on the Claude Certified Architect – Foundations exam (27%). Master the agentic loop, stop_reason handling, structured handoffs, dynamic decomposition, and deterministic hook enforcement.

14 min read 6 objectives Reviewed July 25, 2026
On this page

Domain 1 carries the most weight on the Claude Certified Architect – Foundations (CCA-F) exam — 27% of your score — and it is where scenario questions get most demanding. The domain is not about writing prompts or wiring a single API call; it is about architecting the loop and the guardrails around it so that an autonomous agent behaves predictably, recovers gracefully, and never strands a user with an unfinished task.

Everything in this domain traces back to one mechanical fact: an agent is a loop driven by the model's `stop_reason` signal. The Anthropic Messages API is stateless — it returns a response and a reason it stopped, and your orchestration layer decides what happens next. Whether the loop continues executing tools, terminates cleanly, escalates to a human, or hangs is a property of the code you write around the model, not the model itself. The exam tests whether you understand that boundary precisely.

This guide works through all six Domain 1 objectives in order. For each, we cover the core concept, why it matters architecturally, a concrete agent scenario (a customer-support resolution agent recurs throughout), and the distractor an exam item is most likely to test. Ground yourself in the mechanics — stop_reason values, hook execution order, handoff payloads — and the scenario questions become much easier to reason about.

OBJ 01

Orchestration-Layer Safeguards: Every Session Resolves or Escalates

An agentic session can stop for many reasons, and only one of them means "the task is genuinely finished." The core architectural safeguard for Domain 1 is a terminal guarantee: no matter how the loop exits, the session must end in either a completed resolution or an explicit human escalation — never a silent hang.

Why it matters: the Messages API is stateless and the loop is yours. If your loop only handles the happy path (stop_reason: "tool_use" → run tools; stop_reason: "end_turn" → done) and the model instead stops with max_tokens, refusal, or pause_turn, a naive loop can break, spin, or return a half-finished answer with no owner. At scale, "the agent quietly gave up" is the failure mode that erodes user trust the fastest.

Consider a customer-support resolution agent with tools get_customer, lookup_order, process_refund, and escalate_to_human. It's mid-way through issuing a refund when the response comes back with stop_reason: "max_tokens". The orchestration layer must treat this as an incomplete state — resume with a higher token budget or continue the turn — not as a resolution. If it cannot make progress (repeated failures, a policy refusal, or an ambiguous state it can't safely act on), the safeguard is to route to `escalate_to_human` with the accumulated context rather than return nothing.

Practical mechanisms: a max-iteration cap (e.g. stop after N loop turns and escalate), a wall-clock or token budget, and a fallback branch that fires escalate_to_human whenever the loop exhausts its retries. The point is that termination is designed, not left to chance.

OBJ 02

Structured Handoff Packages: Preserving Context and Authorization State

When control transfers — from one agent step to the next, from an agent to a human operator, or from a primary agent to a subagent — the accumulated work must travel with it. A handoff package is the structured payload that carries findings, decisions, and authorization state across that boundary so the receiver doesn't have to reconstruct or re-derive anything.

Architecturally this matters because context lives in the message history, and a boundary crossing often means a new context (a human's dashboard, a fresh subagent conversation, a different model). Anything not explicitly packaged is lost. The most dangerous thing to lose is authorization state — the fact that a human already approved a $500 refund, or that identity verification already passed. Re-deriving that is at best wasteful and at worst a security hole (the receiver silently re-grants or, worse, skips a check).

A good handoff package for the support agent escalating a refund dispute includes: the resolved customer identity, the specific order in question, what the agent already tried, the current pending action, and — critically — the authorization already obtained. For example:

json
{
  "handoff_type": "escalation",
  "reason": "refund exceeds agent auto-approval limit",
  "customer": { "id": "cus_8842", "verified": true },
  "order": { "id": "ord_5521", "status": "delivered_damaged" },
  "findings": [
    "Customer provided photos; damage confirmed against policy",
    "Duplicate charge ruled out via lookup_order"
  ],
  "pending_action": { "tool": "process_refund", "amount_usd": 640.00 },
  "authorization": {
    "identity_verified": true,
    "refund_approved_by": null,
    "requires_human_approval": true
  }
}
A structured escalation handoff package

Note how the package makes the gap explicit: identity is verified, but refund approval is still null and requires_human_approval is true. The human operator picks up exactly where the agent stopped, with no re-verification and no ambiguity about what still needs sign-off.

OBJ 03

Session Resumption: Restoring State Without Repeating Work

Long-running agents get interrupted — a process restarts, a user steps away, a rate limit pauses a run. Session resumption is the technique of restoring an agent to its prior state accurately, so it continues from where it left off instead of restarting from scratch. Two ideas dominate this objective: targeted re-analysis and context injection.

Because the Messages API is stateless, resumption means reconstructing the working context. The naive approach — replay the entire history and re-run every tool — is slow, expensive, and can cause harmful re-execution (imagine re-calling process_refund on resume). The architect's approach is surgical: inject the accumulated findings as context, and re-analyze only what has actually changed since the interruption.

Concrete example: a code-review agent was analyzing a 40-file pull request when it was interrupted. On resume, it doesn't re-read all 40 files. It injects its prior findings (which files it cleared, which had issues) into the new context, then performs targeted re-analysis of only the files whose contents changed since it last looked. For the support agent, resumption means injecting the verified-customer and pending-refund state rather than re-verifying identity and re-querying every order.

  • Context injection — feed prior findings, decisions, and authorization state into the restored session as input so the agent starts "knowing" what it already established.
  • Targeted re-analysis — re-examine only the inputs that changed (changed files, updated order status), not the entire prior workload.
  • Idempotency awareness — never blindly replay side-effecting tools on resume; a completed process_refund must not fire twice.
OBJ 04

Dynamic Task Decomposition: Subtasks That Adapt to Discovery

Complex work must be broken into subtasks — but when and how you decompose is the architectural decision. Dynamic decomposition generates and revises subtasks as new information surfaces, rather than committing to a fixed, pre-planned sequence that runs regardless of what the agent discovers along the way.

This matters because real tasks are contingent. A static plan ("step 1, step 2, step 3, always") is brittle: if step 1 reveals the problem is different than assumed, steps 2 and 3 are now wrong but still execute. Claude's agentic loop is naturally suited to dynamic decomposition — the model reasons over each tool result and chooses the next action, so the plan evolves with the evidence.

Support-agent example: the agent is asked to "resolve this billing complaint." It doesn't run a canned refund script. It calls get_customer, then lookup_order — and discovers the charge was a legitimate subscription renewal, not an error. A static plan would have refunded anyway. Dynamic decomposition lets the agent pivot: the newly discovered fact changes the remaining subtasks from "issue refund" to "explain the renewal and offer to cancel future billing."

  • Fixed sequence (fragile): plan all steps up front, execute in order, ignore intermediate findings.
  • Dynamic decomposition (robust): decide the next subtask from the result of the last one; add, drop, or reorder subtasks as discovery warrants.
  • Where it lives: the agentic loop is the engine — each tool_use result feeds back into the model, which generates the next step rather than following a frozen script.
OBJ 05

PreToolUse and PostToolUse Hooks: Deterministic Enforcement Outside Model Discretion

Some rules must always hold — they cannot be left to the model's judgment. Hooks are the mechanism for deterministic enforcement: shell commands the harness runs at defined points in the loop, outside model discretion. A PreToolUse hook runs before a tool executes and can block or allow it; a PostToolUse hook runs after a tool completes and can inspect the result and feed structured feedback back to the agent.

The architectural principle: policy that must never be violated does not belong in the prompt. A prompt instruction like "never write to the production database" is a strong suggestion the model usually follows — but "usually" is not a guarantee. A PreToolUse hook that inspects the pending tool call and denies it is a deterministic barrier that fires 100% of the time, regardless of how the model was prompted or jailbroken.

For the support agent, a PreToolUse hook on process_refund can enforce the hard rule "refunds over $500 require human approval" by denying the call and returning a reason the agent sees:

json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Refunds over $500 require human approval. Route to escalate_to_human."
  }
}
A PreToolUse hook denying a policy-violating tool call

In Claude Code's hook system, a PreToolUse hook signals its decision either by exit code (a non-zero blocking exit feeds stderr back to the model) or, for precise control, by emitting JSON with hookSpecificOutput.permissionDecision set to allow, deny, or ask, plus a permissionDecisionReason. (The older top-level decision/reason shape is deprecated for PreToolUse — use hookSpecificOutput.) PostToolUse runs after execution: it can't un-run the tool, but it can validate the output — for example, run a linter or a schema check on a file the agent just wrote — and block/return feedback so the agent corrects course.

PreToolUsePostToolUse
WhenBefore the tool runsAfter the tool completes
Can prevent execution?Yes — deny blocks the callNo — the tool already ran
Typical usePolicy gates, permission checks, input guardsValidation, linting, formatting, result feedback
Enforcement natureDeterministic, outside model discretionDeterministic post-check with feedback to the agent
OBJ 06

The Agentic Loop: How stop_reason Drives Continue-vs-Terminate

The engine underneath everything in Domain 1 is the agentic loop, and it is driven by the stop_reason field on each Messages API response. After every model turn, the orchestration layer reads stop_reason and decides: execute the requested tools and loop again, or terminate and return the final answer.

The two central signals: stop_reason: "tool_use" means the model wants to call one or more tools — the harness executes them, appends the results as a new user message, and calls the API again to continue. stop_reason: "end_turn" means the model finished naturally — the loop terminates and returns the response. A minimal loop is literally "while the model asks for tools, run them and continue."

python
messages = [{"role": "user", "content": user_query}]

while True:
    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=16000,
        tools=tools,
        messages=messages,
    )

    if response.stop_reason == "end_turn":
        break  # model is done — return the final response

    if response.stop_reason == "pause_turn":
        # server-side tool loop paused — resend to resume
        messages.append({"role": "assistant", "content": response.content})
        continue

    if response.stop_reason == "tool_use":
        messages.append({"role": "assistant", "content": response.content})
        tool_results = [run_tool(b) for b in response.content if b.type == "tool_use"]
        messages.append({"role": "user", "content": tool_results})
        continue

    # max_tokens, refusal, stop_sequence — handle explicitly, never fall through
    handle_termination(response.stop_reason)
    break
The core agentic loop, driven by stop_reason

A complete design accounts for every value stop_reason can take. The Messages API can return: end_turn, tool_use, max_tokens, stop_sequence, pause_turn, and refusal. pause_turn appears in long-running server-side tool flows (e.g. web search hitting an iteration limit) — you resume by resending the conversation, without adding a "continue" message. max_tokens means the response was cut off at the output cap — resume or raise the limit. refusal means the model declined for safety reasons. This is exactly where Objective 6 connects back to Objective 1: the loop's stop_reason handling is how you deliver the terminal guarantee that every session resolves or escalates.

stop_reasonMeaningLoop action
tool_useModel wants to call toolsExecute tools, append results, continue
end_turnModel finished naturallyTerminate, return final response
max_tokensHit the output token capResume / raise max_tokens — not a resolution
pause_turnServer-tool loop pausedResend conversation to resume automatically
refusalDeclined for safetyTerminate gracefully; escalate if needed
stop_sequenceHit a custom stop sequenceTerminate per your logic

Key takeaways

  • 01The agentic loop is your orchestration code reading stop_reason; the stateless Messages API only returns a response and a reason it stopped.
  • 02tool_use continues the loop (run tools, append results, resend); end_turn terminates it. Handle max_tokens, pause_turn, and refusal explicitly.
  • 03Design a terminal guarantee: every session must end resolved or escalated to a human with context — never a silent hang.
  • 04Handoff packages must preserve findings AND authorization state, so the next step or human doesn't re-verify or skip a required approval.
  • 05Resume by injecting prior state and re-analyzing only what changed — never blindly replay history and re-run side-effecting tools.
  • 06Dynamic decomposition adapts subtasks to discoveries; fixed sequences execute obsolete steps after new information invalidates them.
  • 07PreToolUse hooks deny/allow before a tool runs; PostToolUse validates after. Hooks enforce hard rules deterministically, outside model discretion.

Common mistakes

Building a loop that only handles tool_use and end_turn, letting max_tokens/refusal/pause_turn fall through as dead ends.

Branch on every stop_reason value; map non-terminal stops to resume-or-escalate so the session always resolves or hands off to a human.

Enforcing a non-negotiable business rule (spending limits, no prod writes, PII redaction) with a strongly-worded system prompt.

Prompts guide probabilistically. Put hard constraints in a PreToolUse hook that deterministically denies the tool call regardless of how the model was prompted.

Handing off to a human or next step by copying the transcript but omitting authorization state.

Package authorization explicitly (identity_verified, approved_by, requires_human_approval) so the receiver neither re-runs nor skips required checks.

Resuming an interrupted session by replaying the full history and re-invoking every tool.

Inject accumulated findings as context and re-analyze only changed inputs; guard side-effecting tools (e.g. process_refund) against duplicate execution.

Hard-coding a fixed subtask sequence that runs regardless of intermediate findings.

Let the agentic loop decompose dynamically — choose the next subtask from the last tool result so the plan adapts when discovery changes the situation.

Frequently asked

What exactly is the difference between `stop_reason: "tool_use"` and `"end_turn"`?

tool_use means the model has requested one or more tool calls — your harness executes them, appends the results as a user message, and resends to continue the loop. end_turn means the model finished its response naturally, so the loop terminates and you return the final answer. The orchestration layer, not the model, acts on these signals.

How is a hook different from a tool the model can call?

A tool is invoked at the model's discretion — the model decides whether and when to call it. A hook is run by the harness at a fixed point (PreToolUse before a call, PostToolUse after), deterministically and outside the model's control. Use tools for capability; use hooks to enforce rules that must always hold.

Can a PostToolUse hook stop a tool from running?

No. PostToolUse runs after the tool has already executed, so it cannot prevent the action — it can only inspect the result and feed feedback back to the agent (e.g. flag a lint failure so the agent fixes it). To block an action before it happens, use a PreToolUse hook, which can return a deny permission decision.

What is `pause_turn` and how do I handle it?

pause_turn appears in long-running server-side tool flows (like web search) when the server-side sampling loop reaches its iteration limit. You resume by resending the conversation — including the assistant's response — without adding a manual "continue" message; the server detects the trailing server-tool activity and picks up where it left off.

Why does Domain 1 emphasize that a session must "resolve or escalate"?

Because the loop can exit for reasons that don't mean success — a token cutoff, a refusal, an unrecoverable tool error. Without a designed terminal guarantee, those exits leave the user with an empty or half-finished result and no owner. Routing unresolved cases to a human (with a structured handoff) closes that gap.

Independent, unofficial study material. Not affiliated with, endorsed by, or authorized by Anthropic. Every example is original and written to teach the public exam objectives — no real exam questions are reproduced. Technical details reflect Claude, the Anthropic API, Claude Code, and MCP as of July 25, 2026; always confirm specifics against current official documentation.

Test yourself

Turn what you just read into answers you can check.

Take the mock exam

Keep studying

All guides

These guides are free and never paywalled. Keep Claude Cert Prep free ♥