AnthropicClaude Certified Architect – Foundations2026-101.1 Design and implement agentic loops for autonomous task execution
Separate completion signals from execution safeguards
Completed by the knowledge check
Learning objective
Avoid termination anti-patterns: parsing natural-language completion, checking for assistant text, or using an iteration cap as the primary stop condition.
Core idea
A reliable loop needs two separate rules: how it recognizes a completed assistant turn, and how it prevents uncontrolled execution. The Messages API supplies stop_reason for the first. Your application supplies resource limits and a distinct outcome when those limits interrupt work.
Natural-language wording and the presence of assistant text do not replace the protocol. “Done” can appear before a requested tool has run. Text can explain a next step while the same response requests tools. A counter can tell you that a budget is exhausted, but cannot tell you that the user’s goal was met.
The exam objective rejects arbitrary iteration caps as the primary completion mechanism. It does not reject limits themselves. Anthropic’s engineering guidance includes maximum iterations as a control, and the Agent SDK exposes turn and spend limits. The architectural error is reporting that safeguard as successful completion.
How it works
Do not parse a completion phrase
A text-based implementation looks for phrases such as “task complete,” “finished,” or “no further action needed.” That rule depends on presentation rather than the API state. An explanation can quote a user’s message, describe a completed subtask, or announce an intended action without completing it.
For an application-owned Messages API loop, use the response’s stop_reason to route execution. A tool_use response goes through tool resolution; an end_turn response ends the assistant turn. See 1.1.1 for the complete state handling. Inspecting the answer’s meaning belongs to result validation after the control decision, not to a string match that decides whether tools should execute.
Adding a system instruction to always end with a special phrase does not turn that phrase into a protocol guarantee. You have created another output requirement to validate. If you need a prescribed delimiter, the Messages API has stop_sequences and reports stop_reason: "stop_sequence" plus the matching stop_sequence; that still needs its own acceptance rule rather than silently masquerading as end_turn.
Do not stop when assistant text appears
A tool-use response can contain a text block and one or more tool_use blocks. The text might say, “I’ll inspect the failing test first.” Stopping because the response has text skips the very operation the response asks your executor to perform.
Streaming makes this mistake more tempting. A user interface can display an explanation before the complete response arrives. That display event is not an execution-state boundary. In the Messages API stream, stop_reason starts as null in message_start and is supplied in message_delta. Use the completed response-state information, not the first printable content, to decide whether the loop continues.
The inverse assumption is also unsafe: lack of text does not always mean the loop must keep running. Anthropic documents empty responses with end_turn, particularly after tool results. Treat that as an ended turn with a missing or inadequate business answer. Anthropic identifies text added immediately after tool_result blocks as a common cause; send result-only user messages to avoid that pattern. If an empty turn still occurs and further output is needed, continue with a new user message rather than resending the empty completed response.
Keep a progress channel distinct from the job’s terminal outcome. You can show text to a user while work remains pending, but the application should not mark the job successful merely because something readable appeared.
Keep the cap as an interruption rule
For an application-owned loop, define a maximum number of tool rounds, a deadline, or a spend policy in application code as appropriate to the workload. The acceptance rule for your business goal belongs in application code.
When a safeguard prevents another request, stop scheduling work and record an incomplete outcome with the reason. Preserve the evidence of what ran and what remains unresolved. A loop that stops after five rounds regardless of state can terminate before a necessary operation, or continue making unnecessary requests after an earlier end_turn. The number five is an application example, not an Anthropic default or recommendation.
In the Agent SDK, the Python options max_turns and max_budget_usd correspond to TypeScript maxTurns and maxBudgetUsd. The turn limit counts tool-use round trips, not individual tool calls or text chunks. Both limits default to no limit. Reaching either limit interrupts execution rather than establishing successful completion; see 1.1.5 for the result subtype identifiers.
The spend threshold uses a client-side estimate and can be exceeded; leave operational headroom rather than promising an exact billing ceiling. See 1.1.5 for choosing the owner of SDK-managed execution and its result handling. The important point here is that explicit error subtypes preserve the difference between a finished task and a forced stop.
Key distinctions and trade-offs
Protocol signal versus semantic evidence: stop_reason determines the response transition. The answer and observed tool results help establish whether the business requirement was met. A persuasive sentence cannot replace either.
Primary termination versus safeguard: Primary turn termination follows the protocol. A safeguard stops execution when continuing would exceed policy. Both can end the process; they produce different outcomes and must remain distinguishable in logs and user-facing status.
Bounded execution versus guaranteed completion: Limits bound exposure to long-running work. They cannot guarantee that a task finishes inside the bound. Smaller limits can increase incomplete outcomes; larger limits can increase cost and opportunities for repeated mistakes. Choose them from workload evidence and report exhaustion honestly.
Interruption versus permission to retry: Automatically restarting every capped run with a fresh budget defeats the cap. A continuation or retry needs an explicit recovery policy that accounts for work already performed, especially when tools modify state.
Architecture / decision scenario
A code-generation service asks an agent to fix a failing test. An assistant response says, “The cause is clear; I’ll inspect the implementation,” then includes a tool_use request. A phrase matcher mistakes “clear” or “fixed” in an explanation for completion; a text-presence check stops even earlier. Both prevent the inspection from running.
The correct Messages API implementation routes the completed response by stop_reason, resolves the tool call, and continues with the result. Progress text can appear in the interface while the job remains active. If a later response has end_turn, the loop ends and the application evaluates the patch and test evidence before claiming a successful fix.
Now suppose repeated test failures consume the allowed tool rounds. The application records incomplete work, the failed test evidence, and the exhausted budget. It does not relabel the last explanation as a finished patch. In an Agent SDK implementation, the limit-error subtypes described in 1.1.5 identify that boundary, and the host handles it as an interrupted job.
An empty end_turn response takes a different path: the turn ended, but the expected summary is missing. The host can deliberately request a summary with a new user message if policy allows. That recovery is driven by a validation failure, not by an assumption that every text-free response means tools are still running.
Common exam traps
- Matching “done” in an explanation to stop execution.
- Stopping because the first content block is text, as if a text block excluded tool calls in the same response.
- Forcing
tool_choice: {"type": "any"}so a turn can never end in text alone. Claude must then call a tool in every response, which removes the naturalend_turnexit; the loop runs until a safeguard such as the cap stops it. - Treating the first streamed text as the final answer.
- Rejecting all iteration limits because the objective rejects caps as primary termination.
- Counting multiple tool calls in one SDK round as multiple capped turns.
- Marking an exhausted budget as success.
- Restarting capped jobs indefinitely with fresh limits.
What to remember
Use protocol fields for turn control, validation for business acceptance, and resource limits for containment. Text describes work; it does not certify completion. A cap is a useful reason to stop, provided the outcome records that work stopped before normal completion.
Knowledge check
A code-generation agent often stops before running the tests it planned. Logs show the loop ends whenever a response contains a text block, and many responses say “I’ll run the failing test first” before a tool_use block. Which change fixes the stopping logic?
stop_reason: "tool_use" and end the turn on "end_turn"tool_use blocks together; only stop_reason says whether the turn ended or tools are waiting. A completion phrase swaps one presentation signal for another, a prompt cannot guarantee the shape of the output, and a cap changes how long the loop may run, not what it stops on.A team ends its support loop after exactly five model calls, whatever the responses contain. Simple refunds finish within that, but billing disputes that need more lookups are cut off, and the cut-off runs are logged as completed. What is the best redesign?
stop_reason , and keep a limit that records an incomplete outcomeTo stop an agent from “quitting early”, a team sets tool_choice: {"type": "any"} on every request, on a model that supports it. Now every run continues until the iteration cap ends it. What explains this?
end_turnany requires a tool call in every response, which removes the natural end_turn exit and leaves the safeguard as the only way out. The fix is to return to auto and let stop_reason end the turn.An Agent SDK job fixing a failing test stops because its configured tool-use-round limit is exhausted. The last assistant message says “The fix is applied.” How should the host record the job?
maxTurns budgetReferences
- Anthropic, Stop reasons and fallback
- Anthropic, Handle tool calls
- Anthropic, Define tools
- Anthropic, Agent loop
- Anthropic, Building effective agents