BrainyBeeBrainyBee
ExploreBlogStart Studying
HomeClaude Certified Architect - Foundations (CCAR-F)Domain 1 Project — build a support agent, then make it a team
Hands-on Lab932 words

Domain 1 Project — build a support agent, then make it a team

Claude Certified Architect - Foundations (CCAR-F) › Domain 1: Agentic Architecture & Orchestration

Domain 1 Project — build a support agent, then make it a team

One system, seven stages, 3 hours 0 minutes. You start with a single agent that can call two tools and finish with a coordinator delegating to subagents across resumable sessions. Every stage is one of Domain 1's seven task statements, so finishing the project is finishing the domain's practical half.

Domain 1 is 27% of the exam, the largest block, and nearly all of it reduces to one question: what is actually in control? You cannot answer that from reading. You answer it by writing the loop, watching it stop for the wrong reason, and fixing it.

The project at a glance

Domain
1 · Agentic Architecture & Orchestration (27%)
Stages
7, one per task statement
Difficulty
Intermediate
Total time
180 minutes
You need
Python 3.10+, the anthropic SDK, an API key
Based on
Exam guide Preparation Exercises 1 and 4

What you will be able to do

  • Write an agentic loop that terminates on stop_reason and explain why the other three termination strategies are wrong
  • Enforce a business rule in code and say when a prompt instruction is not enough
  • Build a coordinator that delegates to subagents and explain what each subagent does and does not inherit
  • Choose between a fixed pipeline and adaptive decomposition, and justify the choice from the task rather than from preference
  • Decide between resuming a session, forking it, and starting fresh with an injected summary

Build it in this order

The order is not the guide's. It is the order the system needs: enforcement has to have a loop to enforce, hooks intercept calls the loop is already making, and a coordinator is only worth having once there is decomposition to hand out.

Seven stages

  1. 1

    1.1 · The loop · 30 min

    BUILD — Two tools — lookup_order and a calculator — and a loop that calls the Messages API, branches on stop_reason, executes every tool_use block, and appends BOTH the assistant message and a user message carrying the tool results. WHY — Everything after this sits inside this loop, and it is the most reliably examined thing in the domain. Branching on stop_reason rather than on content is the difference between an agent that works and one that works on your test cases. YOU SHOULD SEE — History growing by exactly two messages per tool iteration, each tool_result carrying the tool_use_id of the call it answers, and the loop exiting only on stop_reason or the safety cap. TRAP — Appending the tool results but not the assistant message, or the reverse. Either one leaves the model reasoning from the same information twice, and the symptom is an agent that repeats a call rather than one that errors.

Stage 1 in full

Every other stage gives you the target and the trap. This one gets the code, because each later stage is a modification of it and a wrong loop invalidates everything built on top.

The four steps

Send the whole conversation. Read stop_reason. If it is tool_use, run the tools, append the results, and go again. If it is end_turn, you are done. The Messages API is stateless — everything the model knows on iteration four is something your loop put in the request.

stop_reason is the whole answer

When a Domain 1 question describes an agent that stops too early, runs forever, or repeats a call, the correct option almost always reads stop_reason and the distractors almost always do something else — count iterations, inspect text, or force a tool. Find the option that branches on stop_reason before you evaluate the others on their merits.

Beyond the two values the guide names

The exam guide keys tool_use and end_turn — the two a basic loop branches on, and the two you will be graded on. The live API returns four more, and a loop that assumes anything other than end_turn means tool_use will mishandle all of them:

stop_reasonWhat it means
end_turnFinished naturally. Stop.
tool_useWants one or more tools. Run them and continue.
max_tokensHit your max_tokens ceiling. The response is truncated.
stop_sequenceHit a stop sequence you supplied.
pause_turnPaused a long-running turn and can be resumed.
refusalDeclined on safety grounds, on an otherwise normal 200 response.

refusal arrives on a successful HTTP response, so a loop that only checks status codes treats it as ordinary output — and it is the only value that populates stop_details, which is null for every other one. The safe default is to treat anything other than end_turn as "not finished, find out why".

For the exam, know the two. For production, handle the six.

The three anti-patterns

Parsing natural language. Checking whether Claude said "I'm done". Ambiguous by construction — it may have finished the first file and be about to open the second.

An iteration cap as the primary stopping mechanism. It either cuts off work that needed twelve iterations or burns seven on a task that finished in three. A cap is a safety net; it is not a design.

Treating assistant text as completion. Claude routinely returns explanatory text alongside a tool_use block in the same response — "Let me look up your order" and the lookup arrive together. Text presence says nothing about whether the agent is finished.

The distractor that looks like a fix

An iteration cap is offered again and again as the remedy for an agent that stops EARLY. It cannot be. A cap bounds how long a loop runs; it does nothing about a loop exiting for the wrong reason. When a stem describes premature termination, the fix is always to read stop_reason correctly — and the cap in the option list is there to be rejected.

Multiple choice · Medium

An agent sometimes terminates early when Claude returns text alongside a tool call. The loop decides it is finished by checking whether the first content block has type text. Users report incomplete answers on complex queries. What should change?

Reference implementation

Work the stage first. This is what a finished stage 1 looks like, and the base every later stage modifies.

python
import ast import operator import anthropic client = anthropic.Anthropic() MODEL = "claude-opus-5" MAX_ITERATIONS = 20 TOOLS = [ { "name": "lookup_order", "description": "Look up an order by id. Returns status, total and placed_at.", "input_schema": { "type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"], }, }, { "name": "calculator", "description": "Evaluate an arithmetic expression and return the result.", "input_schema": { "type": "object", "properties": {"expression": {"type": "string"}}, "required": ["expression"], }, }, ] # A whitelist evaluator, not eval(). A tool is an execution surface the model # chooses to invoke, so its blast radius is a design decision — this one can add, # subtract, multiply and divide numbers, and can do nothing else. _OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul, ast.Div: operator.truediv} def calculate(expression): def walk(node): if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)): return node.value if isinstance(node, ast.BinOp) and type(node.op) in _OPS: return _OPS[type(node.op)](walk(node.left), walk(node.right)) if isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub): return -walk(node.operand) raise ValueError("unsupported expression") return walk(ast.parse(expression, mode="eval").body) def run_tool(name, tool_input): if name == "lookup_order": return "status=delivered total=129.99 placed_at=2026-08-02" if name == "calculator": try: return str(calculate(tool_input["expression"])) except ValueError as error: return f"Error: {error}" return "Unknown tool" def run_agent(prompt): messages = [{"role": "user", "content": prompt}] for _ in range(MAX_ITERATIONS): response = client.messages.create( model=MODEL, max_tokens=16000, tools=TOOLS, messages=messages ) # Anything other than end_turn is "not finished, find out why". if response.stop_reason == "end_turn": return next(b.text for b in response.content if b.type == "text") if response.stop_reason == "refusal": return f"Declined: {response.stop_details.category}" if response.stop_reason != "tool_use": return f"Stopped early: {response.stop_reason}" # The assistant turn goes back verbatim — the tool_use blocks in it are # what each tool_result below refers to. messages.append({"role": "assistant", "content": response.content}) # Every result in ONE user message. Splitting them teaches the model to # stop calling tools in parallel. results = [ { "type": "tool_result", "tool_use_id": block.id, "content": run_tool(block.name, block.input), } for block in response.content if block.type == "tool_use" ] messages.append({"role": "user", "content": results}) print("WARNING: safety cap reached — the loop should have ended on stop_reason") return "Terminated by safety cap" if __name__ == "__main__": print(run_agent("Look up order A-4417 and tell me what a 20% refund would be."))

Three details worth reading twice. The refusal branch reads stop_details, which is populated for that value alone. The loop is a for over the cap rather than a while True with a counter, so the cap is structurally a bound — exactly what the anti-pattern says it should be. And the calculator walks a whitelisted syntax tree rather than calling eval: a tool is an execution surface the model decides to invoke, and a lab that ships eval teaches the opposite of what Domain 2 is about.

Prove stage 1 before moving on

  • Break the append on purpose: stop adding the tool_result message and re-run. The agent should call the same tool again — the repeated-call symptom seen from the inside.
  • Log stop_reason every iteration. A two-tool prompt should print tool_use, tool_use, end_turn.
  • Confirm the safety cap never trips on a normal query. If it does, the loop is not terminating on stop_reason and stage 1 is not finished.

When not to write this loop

Having written one by hand, know that the SDK ships a tool runner that drives this cycle for you, with per-turn hooks for approval gates and error interception. Production code should usually reach for it. The exam asks about the loop's mechanics, so build it once yourself — then let the SDK own it.

Where the depth lives

This page is for building. The reading is elsewhere, and repeating it here would put the same claims in three places to drift apart:

  • The Domain 1 roadmap — what the domain is about, the order to learn it in, and where it catches people
  • Seven flashcard decks, 48 cards — one card per published objective
  • 66 Domain 1 questions — judgement under exam conditions, inside the six production scenarios

Nobody has run this yet

The code here was written against the documented Messages API and checked value by value against the reference — but no stage has been executed end to end against a live API key. If something does not behave as described, trust what your terminal says over what this page does, and please report it. The row carries a needs_human_run_through stamp so this page can be found again once someone has worked it through.

Sources

  • CCAR-F Exam Guide v1.0, section 6 — Domain 1's seven task statements, which are this project's seven stages.
  • CCAR-F Exam Guide v1.0, section 8 — Preparation Exercise 1 ("Build a Multi-Tool Agent with Escalation Logic") and Exercise 4 ("Design and Debug a Multi-Agent Research Pipeline"). This project merges them: exercise 1 is the loop-and-enforcement half, exercise 4 the coordinator half.
  • Anthropic Messages API reference — the stop_reason set, stop_details, the tool_result message shape, and the parallel-tool-use rule.

What is quoted, and what is argued

The task statements and the exercise skeletons are the exam guide's. The API behaviour is documented behaviour, checked against the Messages API reference rather than restated from memory. The stage ordering, the traps and the teaching are this hive's reading of that material — useful preparation, not an official statement about what the exam contains.

All Claude Certified Architect - Foundations (CCAR-F) Study Resources

Related Notes

  • Domain 1: Agentic Architecture & Orchestration169 words
  • CCAR-F: how the exam is dealt194 words
  • Scenario 1: Customer Support Resolution Agent225 words
  • Scenario 2: Code Generation with Claude Code185 words
  • Scenario 3: Multi-Agent Research System199 words
  • Scenario 4: Developer Productivity with Claude197 words
  • Scenario 5: Claude Code for Continuous Integration168 words
  • Scenario 6: Structured Data Extraction185 words
  • Domain 2: Tool Design & MCP Integration157 words
  • Domain 3: Claude Code Configuration & Workflows150 words
  • Domain 4: Prompt Engineering & Structured Output150 words
  • Domain 5: Context Management & Reliability165 words

Ready to study Claude Certified Architect - Foundations (CCAR-F)?

Practice tests, flashcards, and all study notes — free, no sign-up.

Start Studying

Ready to study Claude Certified Architect - Foundations (CCAR-F)?

Practice tests, flashcards, and all study notes — free, no sign-up needed.

Start Studying — Free
Claude Certified Architect - Foundations (CCAR-F) ResourcesExplore All HivesBlogHome

© 2026 BrainyBee. Free AI-powered exam prep.