๐ŸŽ“ Claude Architect KB CCAR-F ยท CCAR-P study guide

Domain 1 ยท Agentic Architecture & Orchestration (27%)

This is the heaviest domain, and the one that quietly decides pass or fail. What it's really checking is whether you can choose and justify an architecture โ€” not just recite the name of one.

๐Ÿ“– New here? The story of why this domain exists

You've already run an agent. Every time Claude Code fixed a bug for you โ€” grep, read, edit, retest โ€” you watched an agent loop execute. This domain is that loop, formalized: what starts it, what feeds it, and above all what stops it.

The problem it solves: a model that can act is a model that can act wrongly, expensively, and repeatedly. The first time a team ships an agent, it works in the demo. The second week, it refunds someone twice (no idempotency), spends $40 on one runaway task (no budget), and confidently emails a customer something untrue (no gate). None of that is the model's fault โ€” it's missing architecture.

The solution shape: keep the model as the decision-maker and wrap it in deterministic machinery โ€” the harness โ€” that executes tools, enforces limits, requires human sign-off where stakes are high, and logs everything. Then choose the lightest pattern that fits: a fixed pipeline (workflow) when you know the steps; a looping agent only when you genuinely can't predict the path.

So what for the exam: nearly every scenario question here reduces to two choices โ€” which pattern fits this task? and where does the deterministic leash go? Learn those two instincts and 27% of the exam becomes readable.

At a glance

Concept One-liner
Agent loop gather context โ†’ model decides โ†’ execute tools โ†’ append results โ†’ repeat until done
Workflow vs agent predefined code path with LLM steps vs model-directed looping โ€” prefer workflows when the path is known
Orchestratorโ€“workers a coordinator model plans and delegates to parallel specialized subagents
Evaluatorโ€“optimizer one model generates, another critiques in a loop until quality passes
Stop reason the Claude API's signal for why generation ended โ€” the harness branches on it
Human-in-the-loop deterministic approval gates for high-risk actions
Guardrails deterministic checks the model cannot talk its way past

The agentic loop โ€” the exam's core object

๐Ÿงญ Your seat at the table: the loop runs Claude's thinking, but everything it thinks with is your construction. Before any model call, you assembled the context (the messages array and its roles), chose the objective (the system prompt), curated what it can do (the tool catalog, from your tool registry), and set the rules (gates, budgets, guardrails). The exam calls this "architecture"; day to day, it's just being a good host to a brilliant guest.

flowchart TD
  S[Start: task + context] --> B[Build prompt: system + messages + tool definitions]
  B --> M[๐Ÿง  Claude call]
  M --> SR{stop_reason?}
  SR -->|tool_use| X[Harness executes the tool]
  X --> A[Append tool_result to messages]
  A --> G{Gates: budgets ยท guardrails ยท HITL}
  G -->|ok| B
  G -->|violation| E[Escalate / halt]
  SR -->|end_turn| R[Final response]
  SR -->|max_tokens| T[Truncated โ€” handle!]
  R --> V[Verify: evals, schema checks]

Every Anthropic doc keeps coming back to the same three phases: gather context โ†’ take action โ†’ verify results. Here's the part worth internalizing โ€” the model never actually does anything. It only requests actions, by emitting tool_use blocks; your deterministic harness is what runs them and hands back the tool_result blocks.

๐Ÿ” See it run โ€” a support agent handles "my order never arrived", turn by turn

Entry point: a customer message arrives via the support webhook: "My order #4531 never arrived. Can you send a replacement?" The harness looks up the customer record and starts a run.

[Start: task + context] โ†’ [Build prompt] โ€” the harness assembles:

JSON
{
  "system": "You are a support agent for Acme Store. Resolve delivery issues. Never promise refunds โ€” replacements only, per policy P-12.",
  "tools": [
    {
      "name": "get_order",
      "description": "Fetch one order by id. Read-only. Returns status, value, and replacement eligibility. Use when the customer references a specific order.",
      "input_schema": {
        "type": "object",
        "required": ["order_id"],
        "properties": { "order_id": { "type": "string" } },
        "additionalProperties": false
      }
    },
    {
      "name": "create_replacement",
      "description": "Ship a replacement for a lost or damaged order. SIDE EFFECT: creates a real shipment.",
      "input_schema": { "โ€ฆ": "same three-part shape as get_order โ€” elided here for brevity" }
    }
  ],
  "messages": [{ "role": "user", "content": "My order #4531 never arrived. Can you send a replacement?" }]
}

(Every tool entry always carries the same three fields โ€” name, description, input_schema (a JSON Schema for the arguments). Where you see โ€ฆ in this guide it means "elided for brevity", never real syntax. Tool-definition craft โ€” why the description matters most โ€” is Domain 4's subject.)

Turn 1 โ€” [๐Ÿง  Claude call] returns (abridged):

JSON
{
  "stop_reason": "tool_use",
  "content": [
    {"type": "text", "text": "Let me look up that order first."},
    {"type": "tool_use", "id": "toolu_01A", "name": "get_order", "input": {"order_id": "4531"}}
  ]
}

Where did "id": "toolu_01A" come from? Not from you โ€” your tool list has no id field. The Claude API generates a fresh id for every tool_use block (the Claude API meaning Anthropic's Messages endpoint that carried this model call โ€” not the store's order system, and not the webhook that delivered the customer message). Its one job is correlation: the tool_result you send back echoes it as tool_use_id, so the Claude API knows which request each result answers (this matters when one response carries several tool requests). Definition vs. call, in one line: you name the tool; the Claude API names each use of it.

[stop_reason? โ†’ tool_use] โ€” the left branch. Note what did NOT happen: the model didn't query any database. It emitted a request as data.

[Harness executes the tool] โ€” validates order_id against the schema, queries the DB:

JSON
{"order_id": "4531", "status": "lost_in_transit", "value_cents": 8900, "replacement_eligible": true}

[Append tool_result to messages] โ€” the harness sends that back as a tool_result block with tool_use_id: "toolu_01A", then hits [Gates]: turn 1 of max 6 โœ“, no side effect yet โœ“ โ†’ ok branch โ†’ loops back to [Build prompt].

Turn 2 โ€” [๐Ÿง  Claude call] now sees the order data and returns:

JSON
{
  "stop_reason": "tool_use",
  "content": [{"type": "tool_use", "id": "toolu_02B", "name": "create_replacement",
               "input": {"order_id": "4531", "reason": "lost_in_transit"}}]
}

[Gates] โ€” this one has a side effect. The HITL rule says: replacements under $100 auto-approve, over $100 need a human. $89 โ†’ ok. (Had it been a $600 order, this is exactly where the violation โ†’ [Escalate / halt] branch fires: the run parks, a human gets the packet, and nothing has executed.) The harness runs the tool with idempotency key replace-4531 โ€” so a retry can never ship two boxes โ€” and gets back {"replacement_id": "R-7821", "eta_days": 3}.

Turn 3 โ€” [๐Ÿง  Claude call] returns:

JSON
{
  "stop_reason": "end_turn",
  "content": [{"type": "text", "text": "I'm sorry your order was lost in transit. I've created replacement R-7821 โ€” it should arrive within 3 days."}]
}

[stop_reason? โ†’ end_turn] โ†’ [Final response] โ†’ [Verify] โ€” deterministic checks before delivery: response contains a replacement id โœ“, contains no refund promise (policy P-12) โœ“ โ†’ send to customer. Run log: 3 turns, 2 tool calls, 1 gate check, terminal state resolved.

The third branch: had turn 3 come back with "stop_reason": "max_tokens" mid-sentence, the [Truncated โ€” handle!] node applies โ€” the harness must never deliver or parse it as complete; it raises the limit and continues, or fails loudly.

The messages array โ€” how the loop physically grows

The messages field puzzles everyone at first: why an array of objects? And when the loop runs, does the new stuff get prepended or appended โ€” and where does the tool result go?

Why an array: here's the thing that reframes everything โ€” the Claude API is stateless. It remembers no conversation between calls (the same fact sitting behind the tool registry: nothing lives on Anthropic's side). So if you want it to know what happened earlier, the entire conversation history has to ride along inside every request โ€” and messages is that history: an ordered array, oldest first, each element one turn carrying a role (user or assistant, alternating) and its content. The model doesn't "remember" turn 1. It re-reads it, every single call, because you re-sent it.

The growth rule: every new turn gets appended at the end โ€” never prepended. That's two appends per loop iteration, and here's the bit nobody tells you up front: the model's own response goes right back into the array too. Watch it grow across the support-agent run from above:

PYTHON
# โ”€โ”€ Call 1: one element
messages = [
  {"role": "user", "content": "My order #4531 never arrived. Can you send a replacement?"}
]
resp = client.messages.create(model=MODEL, system=SYSTEM, tools=TOOLS, messages=messages)
# โ†’ stop_reason "tool_use": wants get_order

# โ”€โ”€ Append #1: the assistant's response โ€” VERBATIM, tool_use block and all
messages.append({"role": "assistant", "content": resp.content})

# โ”€โ”€ Append #2: your tool result โ€” inside a USER-role message
messages.append({"role": "user", "content": [
  {"type": "tool_result", "tool_use_id": "toolu_01A",
   "content": '{"status": "lost_in_transit", "value_cents": 8900}'}
]})

# โ”€โ”€ Call 2: the SAME array, now 3 elements, resent IN FULL
resp = client.messages.create(model=MODEL, system=SYSTEM, tools=TOOLS, messages=messages)
# โ†’ another tool_use โ†’ two more appends โ†’ Call 3 sends 5 elements โ†’ end_turn

So here's how the array looks across the three calls of the walkthrough:

Call The array (roles, oldest โ†’ newest) Elements
1 user (the complaint) 1
2 user ยท assistant (tool_use: get_order) ยท user (tool_result) 3
3 user ยท assistant (tool_use: create_replacement) ยท user (tool_result) ยท โ€ฆ 5

Three details that quietly make or break a real harness:

And now you can see why context management even exists: a 40-turn conversation means a 40-turn array resent on every single call, growing without any natural ceiling. The messages array is the context-window budget Domain 5 spends its time managing โ€” compaction swaps old elements out for a summary, but that append-at-the-end rule never changes underneath it.

๐Ÿงฎ Fundamentals: the Claude call explained in the loop โ€” what bounds the response, and the context math

Three natural worries, in order: what stops the model from returning a huge response? Is the response restricted to a schema? And if everything gets appended, don't we run out of context? Three different leashes answer them โ€” each bounds a different thing:

Leash Bounds Who enforces it
max_tokens the output of one call โ€” a hard ceiling you set per request the Claude API โ€” the model physically stops there
input_schema the tool arguments inside a tool_use block steers generation; your harness validates (Domain 3 has the guarantee ladder)
the context window the total: input + reserved output the Claude API โ€” an over-long request is rejected

1 โ€” The response cannot be huge, because you capped it. max_tokens is a mandatory request field: the model generates at most that many output tokens, full stop. If it genuinely needed more, generation cuts off and stop_reason: max_tokens tells you so โ€” that's the "Truncated โ€” handle!" branch, not a silent overflow. And there's a second, natural bound in agent loops: a tool_use turn isn't prose โ€” it's a name plus JSON arguments, typically 50โ€“300 tokens. The support-agent walkthrough's actual sizes: turn 1's response โ‰ˆ 90 tokens, turn 2's โ‰ˆ 60, and only turn 3's customer-facing text reaches โ‰ˆ 120.

2 โ€” The whole response is NOT schema-restricted โ€” only tool arguments are. input_schema shapes what goes inside a tool_use block's input; the model's free-text content is bounded only by max_tokens and the prompt. When you need the entire output to obey a schema, that's the Domain 3 move: force a tool whose schema IS your output shape.

3 โ€” The context math, per call. Everything must fit the window (200K tokens standard) โ€” and max_tokens reserves its allowance from that same window before generation starts:

TEXT
input (system 2.1K + tools 3.4K + messages array) + max_tokens (4K reserved) โ‰ค 200K

The walkthrough's three calls, honestly accounted:

Call system + tools messages array max_tokens Total demand
1 5.5K 0.1K 4K ~9.6K
2 5.5K* 0.3K 4K ~9.8K
3 5.5K* 0.5K 4K ~10K

* The starred 5.5K still occupies the window every call โ€” but bills at ~10% price thanks to prompt caching: the Claude API keeps a server-side copy of the processed prefix for a few minutes, so a byte-identical resend skips reprocessing. (This doesn't contradict statelessness โ€” the Claude API remembers no conversation; it briefly caches the computation of a prefix you resend anyway. Cache lives at the Claude API, not in your harness's memory.)

Nowhere near trouble โ€” a short run never is. The thing that actually eats context in real loops isn't the model's responses โ€” it's the tool results you append: one naive "return the whole tool-backend payload" tool can add 20K tokens in a single append, dwarfing every model turn combined. That's why Domain 5's first commandments are trim tool results and compact old turns.

4 โ€” And when the budget IS exceeded? Two different failures, two different fixes: output side โ€” generation hits max_tokens โ†’ stop_reason tells you โ†’ raise the cap or continue; input side โ€” the array has grown past the window โ†’ the Claude API rejects the request with an error before any generation โ†’ compact/summarize the history (Domain 5) and retry. Different symptoms, never confuse them: one is a truncated response, the other is no response at all.

Stop reasons โ€” memorize this table

Where does this list come from? stop_reason is a field the Claude API sets on every response โ€” a closed, standard set defined by Anthropic, and that's the whole point. Your harness never invents these values and can't add to them; it plays the other side of the contract: read the value and branch on it. (The webhook that delivered the task and the tool backends the harness calls don't get a say in this field.)

stop_reason Meaning Correct harness behavior
end_turn Model finished its turn Deliver/parse the response
tool_use Model wants a tool executed Run tool(s), append tool_result, call again
max_tokens Output hit the token limit Treat as incomplete โ€” raise limit, continue, or fail loudly; never parse as complete
stop_sequence A custom stop string matched Handle per your protocol
refusal / safety stop Model declined Do not auto-retry the same prompt in a loop

๐Ÿชค Trap: a question shows JSON parsing failures "sometimes." The hidden cause is often max_tokens truncation being parsed as if complete. The architect answer: check stop_reason before parsing, and set max_tokens generously for structured output.

Workflows vs agents โ€” Anthropic's decision rule

From Anthropic's engineering guide Building Effective Agents (the most-quoted source in this domain):

The rule the exam keeps rewarding: reach for the simplest thing that works โ€” workflows for well-defined tasks, and agents only for the open-ended problems where you genuinely can't hardcode the path in advance. Any time a scenario hands you a known, repeatable sequence, a workflow pattern beats "give it tools and let it figure it out."

The five workflow patterns (parallelization comes in two flavors)

Anthropic's Building Effective Agents names five patterns โ€” the two Parallelization rows below are the two flavors of one pattern (sectioning and voting), which is why five categories fill six rows. Count patterns as five; memorize both flavors.

Pattern Shape Use when
Prompt chaining output of call A feeds call B (with optional programmatic checks between) task decomposes into fixed sequential subtasks
Routing classifier directs input to a specialized downstream prompt/model distinct input categories need distinct handling
Parallelization โ€” sectioning (flavor 1 of 2) independent subtasks fan out concurrently subtasks don't depend on each other
Parallelization โ€” voting (flavor 2 of 2) same task run N times, results aggregated confidence via diverse attempts
Orchestratorโ€“workers central model decomposes dynamically, delegates, synthesizes subtasks can't be predicted upfront
Evaluatorโ€“optimizer generator + critic loop clear evaluation criteria; iteration adds value
flowchart LR
  subgraph Orchestrator-workers
    O[Coordinator: plans + decomposes] --> W1[Worker: search]
    O --> W2[Worker: analyze]
    O --> W3[Worker: code]
    W1 --> SYN[Synthesize]
    W2 --> SYN
    W3 --> SYN
  end
๐Ÿ” See it run โ€” "compare our three competitors' pricing" with orchestratorโ€“workers

Entry point: a PM asks the research agent: "Compare Acme, Bolt, and Corel's pricing pages and summarize how we should position."

[Coordinator: plans + decomposes] โ€” the coordinator model fetches nothing itself. It emits a plan as data: three independent research subtasks, one per competitor. The harness spawns three workers, each with its own clean context window holding only the shared research instructions + its one assigned competitor.

[Worker: search] ร—3, in parallel โ€” each worker runs its own mini agent-loop (fetch page โ†’ extract tiers โ†’ normalize). Worker 2's fetched pricing page alone is ~12,000 tokens of HTML โ€” and that's the whole point: those 12K tokens live and die inside worker 2's window. What returns to the coordinator is a compressed summary:

JSON
{"competitor": "Bolt", "model": "per-seat", "tiers": [{"name": "Pro", "usd_mo": 29}],
 "notable": "free tier removed in June; annual-only enterprise"}

~150 tokens each โ€” a ~99% compression before anything touches the coordinator's context. Who owns this shape? The harness owner defines and validates the worker-result schema (these fields โ€” competitor, model, tiers, usd_mo, notable); each worker emits one object conforming to it; the coordinator consumes the validated objects in its next prompt, and the run trace stores them.

[Synthesize] โ€” the coordinator reasons over three 150-token summaries (not three 12K-token pages) and writes the positioning memo.

Why not one agent? A single loop doing all three would be carrying ~36K tokens of page dumps in one window by step 3, degrading every later decision. The fan-out costs more total tokens, but each decision happens in a small, relevant context โ€” that's the trade the exam wants you to articulate. And workers never talk to each other: hub-and-spoke, coordination through the coordinator only.

Multi-agent design judgments (scenario 3 territory)

Model portability โ€” the "what if we swap models?" question

Companies ask this early: "if we build on one vendor's SDK, are we locked in?" The industry's answer has three layers, and knowing which layer solves which problem is the architect skill:

Layer What it solves The tools
A gateway in front of models credentials, quotas, failover, audit, and config-level swapping โ€” your harness speaks one interface; the gateway routes to providers enterprise LLM gateways (self-built or LiteLLM-style proxies); cloud catalogs (Amazon Bedrock, Vertex AI) serving many models behind one auth surface
Ports-and-adapters in your harness keeps the loop, gates, tools, and state PROVIDER-NEUTRAL; a thin adapter per provider translates message/tool formats ~200 lines you own โ€” the deterministic 80% of your agent never changes when the model does
Orchestration frameworks buy the abstraction + ecosystem instead of building it LangGraph (stateful agent graphs), and friends โ€” note LangSmith is observability/evals, not orchestration; you can use it with ANY harness

The trade nobody puts on the landing page: abstraction has a tax. A lowest-common-denominator model interface forfeits provider-native strengths โ€” prompt caching semantics, native structured outputs, extended thinking โ€” and frameworks lag new provider features. Anthropic's own guidance in Building Effective Agents is to use frameworks judiciously and keep the calling layer simple enough to understand. The Claude Agent SDK sits at the opposite pole: maximum harness quality, Claude-shaped by design (it does run against Bedrock/Vertex-served Claude โ€” cloud portability without model portability).

What the adapter actually translates โ€” the dialect problem. Every major provider converged on the same concepts: a model id, an ordered conversation, optional tool definitions, a token budget. That convergence is why gateways and adapters are feasible at all. But the dialects differ exactly where a hand-rolled integration breaks:

Concept The Claude API Typical other dialects
System instruction top-level system field, NOT a message a system/developer role inside messages, or a separate instruction field
Roles user / assistant only some add a dedicated tool role; one major provider says model instead of assistant
Tool definitions input_schema (JSON Schema) function.parameters, functionDeclarations โ€” same schema idea, different wrapping
Tool results tool_result block inside a user message, matched by id a tool-role message, or a functionResponse part
"Why did it stop?" stop_reason: end_turn ยท tool_use ยท max_tokensโ€ฆ finish_reason: stop ยท tool_calls ยท lengthโ€ฆ โ€” same idea, different names
Output budget max_tokens required usually optional with defaults

Same music, different notation โ€” an adapter is ~200 lines because it's transposing these six rows, not reinventing anything.

And the Agent SDK doesn't take this input shape at all โ€” by design. You don't hand it messages + tools; you hand it a prompt and options (allowed tools, max turns, system additions, MCP servers), and it owns building and growing the messages array internally. That's the abstraction level shift in one sentence: the Claude API's input is a conversation you manage; the Agent SDK's input is an intent plus a policy.

And the truth that makes this whole table honest: model-agnostic is NOT prompt-agnostic. Swapping frontier models is never a config flip in practice โ€” prompts are tuned to a model's behaviors, tool-selection patterns differ, guardrail phrasings land differently. The gateway makes a swap possible; only your eval suite (golden set + negative controls, run side-by-side) makes it safe. Teams that "swapped in an afternoon" had evals; teams that swapped by config discovered their refund agent's tone and tool habits changed in production.

๐ŸŽฏ Exam lens: portability questions reward the layered answer โ€” deterministic controls in the harness (they survive any swap), tools behind MCP (capability investments outlive model choices), model access behind a gateway, and an eval gate on every model change. "Rewrite on the other vendor's SDK" and "the framework handles it" are both trap answers.

Harness controls โ€” what makes an agent production-grade

Control Mechanism
Budgets max turns / max tokens / max cost / wall-clock time (real elapsed seconds) โ€” exceeded โ‡’ terminal state, not silent continuation
Guardrails deterministic validation of model output (schemas, allowlists, arithmetic bounds) โ€” unpromptable
HITL gates high-risk tools require human approval before execution; silence โ‰  approval
Idempotency retried actions must not double-execute (idempotency keys, effects ledgers โ€” a durable record of side effects already performed, checked before any retry)
Audit trail every decision, tool call, and gate verdict logged and replayable
Checkpointing long-running agents persist state so restarts resume, not restart

Where these controls physically live โ€” the container, the queue, the approval UI โ€” is the Deployment & Operations page's subject.

๐ŸŽฏ Exam lens: when a scenario asks "how do you prevent the agent from X," the correct answer is almost always a deterministic harness control, not "add instructions to the prompt." Prompts steer; harnesses enforce.

The harness as real files โ€” annotated, clickable

๐Ÿ’ก Budgets, gates and ledgers stop being vocabulary when you see them as config and code. Cookbook chips are public; the local chips open the tracecraft harness that runs on this machine.

JSONC
// usecase config โ€” BUDGETS: hard ceilings whose breach is a TERMINAL state, not a warning
{
  "budgets": { "max_model_calls": 6, "max_tool_calls": 8, "max_turns": 3 },
  "confidence_floor": 0.75            // below this, the classify gate routes to review
}
PYTHON
# a GATE โ€” plain arithmetic the model cannot talk its way past
def action_allowed(category, action, cfg):
    allowed = cfg["actions"].get(category, [])
    if action not in allowed:                       # allowlist: absence IS the policy
        return False, f"{action} not allowed for {category}"
    return True, None
JSONC
// EFFECTS LEDGER entry โ€” a retry replays the RECORD, never the side effect
{
  "idempotency_key": "refund:A-1042:2026-08-30",   // same key โ†’ same outcome, no double refund
  "effect": "refund_issued", "amount_cents": 2500,
  "status": "applied", "at": "2026-08-30T17:12:03Z"
}

Specimens in the wild: cookbook:patterns/agents/basic_workflows.ipynb โ€” the workflow patterns ยท cookbook:patterns/agents/orchestrator_workers.ipynb ยท cookbook:patterns/agents/evaluator_optimizer.ipynb ยท cookbook:tool_use/memory_demo/demo_helpers.py โ€” a real loop with tool dispatch.

Escalation design (scenario 1 territory)

A support agent needs to escalate the moment any of these shows up: confidence drops below a floor, the category falls outside its charter, a tool dependency goes down, the user flat-out asks for a human, or a gate blocks the action it wanted to take. Treat escalation as a first-class terminal path โ€” ticket + context handoff + an honest message to the user โ€” not some afterthought exception. And design the handoff packet (conversation summary, evidence gathered, actions attempted) as part of the architecture from the start, not bolted on later.

Evaluation of agents (bleeds into Domain 5)

Drill-down: choosing an architecture โ€” a worked decision tree
  1. Is the task path known and repeatable? โ†’ Workflow (chain/route/parallelize). Done.
  2. Open-ended but single-focus (one context can hold it)? โ†’ Single agent loop with a tight tool set.
  3. Requires breadth (research many independent threads) or context exceeds one window? โ†’ Orchestratorโ€“workers.
  4. Quality-critical output with objective criteria? โ†’ add evaluatorโ€“optimizer on the output stage.
  5. Any step with real-world side effects (money, access, data mutation)? โ†’ add HITL gate + idempotency regardless of pattern.
Drill-down: cost & latency levers in agentic systems
  • Model tiering per role: cheap/fast model for classification & routing; a frontier model (the most capable, most expensive tier) for reasoning; different family for judging.
  • Prompt caching for the static prefix (system prompt + tool definitions) โ€” the single biggest cost lever in loops, since every iteration resends the prefix.
  • Parallel tool execution when independent; batch API for offline/eval workloads.
  • Bound loops: max-turn ceilings prevent runaway spend; log per-run token/cost telemetry.

Sessions, forking, and spawning โ€” the mechanics the exam names

The Task tool โ€” how subagents are actually born

Subagents are spawned through the Task tool โ€” and the exam tests the plumbing precisely:

๐Ÿชค Trap: "the coordinator should share its memory with subagents" โ€” it can't. Context passing is explicit, by prompt, every time. Questions that assume automatic context inheritance are describing the wrong system.

Session management โ€” --resume, fork_session, and when to start fresh

๐ŸŽฏ "Two testing strategies from one shared analysis" โ†’ fork_session. "Continue yesterday's migration" โ†’ --resume + a note about what changed. "Tool results are three days old" โ†’ fresh session + summary injection.

Practice this domain

๐ŸŽฏ Done with Domain 1? Prove it: Agentic Architecture (Q1โ€“Q8) โ€” commit to an answer before revealing. Locally, your picks are captured with timestamps and scored per section, so weak spots surface on the practice page's comfort tiles.