What You Need to Know
On its own, Claude answers one request with one response. To act, such as finding an order, it needs tools: functions in your code that you describe to Claude in the request. Claude does not run a tool you define. When Claude needs a tool, its response asks for the call. Your code then runs the function and returns the result to Claude. An agent is Claude, its tools and the code that continues this exchange.
That code is the agentic loop: the core execution cycle of every Claude-based agent. It is deterministic control flow, defined in code. It is not a prompt trick, a retry loop or a chatbot turn. Until Claude has finished, your code sends a request, runs any tools that Claude requests, and sends the results to Claude. The stop_reason field in each response says whether to run the loop again. The other Domain 1 lessons, on orchestration, subagents, hooks and sessions, all depend on this loop.
This lesson uses one made-up example throughout: a glazier who runs an agent that answers customer messages. When a customer asks for their fitting date, the agent must find the order and check the fitting diary before it replies. An agent with a broken loop stops halfway through a task like this in production.
The Agentic Loop Lifecycle
The loop has four steps, repeated until Claude has finished.
-
Send a request to Claude via the Messages API. It includes the conversation history: system prompt, prior messages, and any tool results from the previous iteration.
-
Inspect the
stop_reasonfield in the response. It is the authoritative signal for what happens next. Two of its values matter for agentic loops:"tool_use": Claude wants to call one or more tools. The loop continues."end_turn": Claude has finished its work. The loop terminates.
-
If
stop_reasonis"tool_use", execute the requested tool(s) and append the tool results to the conversation history as a new message. Then send the updated conversation to Claude. -
If
stop_reasonis"end_turn", the agent has finished. Present the final response to the user.
The glazier's agent gets "tool_use" for the order lookup and again for the diary check, then "end_turn" with the reply.
Step 3 is where loops fail. Your code must append the tool results to the conversation history. Otherwise the model never sees what the tool returned, so it has nothing new to reason about on the next iteration. The glazier's order details would never reach Claude.
Key Concept
The stop_reason field is the only reliable signal to control the loop. It is deterministic and unambiguous. Never make any of these your primary stopping mechanism: parsing natural language, checking text content, or arbitrary iteration caps.
Model-Driven Decision-Making
In an agentic loop, Claude uses the current context to decide which tool to call. This is model-driven decision-making: the model reads the task, compares the available tools and picks one. In a pre-configured decision tree or fixed tool sequence, the developer hard-codes which tool runs at which point.
Model-driven approaches are flexible. Claude adapts to situations that the developer never planned for. It handles edge cases. It also uses tools one after another in orders that nobody planned. A glazier's customer might ask about a cracked pane and a late fitting in one message.
The exception is business logic that demands deterministic compliance, such as financial operations, security checks and regulatory requirements. For that logic, programmatic enforcement overrides that flexibility. So the glazier's refund rules are in code. Task Statement 1.4 covers this.
The Three Anti-Patterns
Three anti-patterns recur when code decides to stop the loop.
Anti-Pattern 1: Parsing natural language signals. The code checks whether Claude said "I'm done" or "task complete". Natural language is ambiguous. Claude might say "I've finished analysing the first file" while intending to continue with more files. stop_reason exists to remove that ambiguity.
Anti-Pattern 2: Arbitrary iteration caps as the primary stopping mechanism. The code stops after a fixed count, such as 10 loops. If a task needs 12 iterations, the cap stops useful work early. If it finishes in 3, the cap runs unnecessary iterations. The model uses stop_reason to signal that it has finished, so use that field. A cap is acceptable as a safeguard against runaway agents (agents that do not stop), never as the primary control.
Anti-Pattern 3: Checking for assistant text content as a completion indicator. The code uses response.content[0].type == "text" to decide that the loop is finished. Claude can return text together with tool_use blocks. For example, it can return "I'll now search for the customer's order history" followed by a tool call. Text in the response does not tell you whether the agent is finished.
Practical Example: The Premature Termination Bug
The glazier's agent works for simple queries but sometimes stops mid-task on complex ones. Its code checks if response.content[0].type == "text" to decide whether the agent has finished. Claude returns "Let me look up your order" together with a tool_use block for lookup_order. The code sees text in position [0] and concludes that the agent is finished. Then the code returns the incomplete response.
The fix is to check stop_reason instead of the content type: continue on "tool_use", terminate on "end_turn". This check works whatever content types the response holds.
In the exam
If you understand this lifecycle correctly, most of Domain 1 becomes clear. The right answer continues on "tool_use", terminates on "end_turn", and rejects all three anti-patterns. The exam favours model-driven tool selection because it is flexible, except where deterministic compliance requires programmatic enforcement.
Common Wrong Answer
The exam frequently presents iteration caps as a fix for premature termination. Reject these answers. Caps address runaway loops, not premature exits. The fix is always to check stop_reason correctly.
Current state: beyond the two exam values
The exam guide (v1.0) tests tool_use and end_turn, the two values that a basic loop branches on. Current state (checked 6 October 2026): the Messages API also returns pause_turn, max_tokens, stop_sequence, refusal and model_context_window_exceeded. A production loop must handle these values. pause_turn means continue a long-running server-tool turn. refusal means Claude declined to respond. A refusal is a normal HTTP 200 response, not an error. model_context_window_exceeded means the response filled the model's context window. Handle it like max_tokens truncation. Treat any value other than end_turn as "not finished, check why" rather than assuming tool_use. Source: the Messages API stop-reason docs.
Exam Traps
Using response.content[0].type == 'text' to determine loop completion
Claude can return text alongside tool_use blocks in the same response. Text presence does not indicate completion. The stop_reason field is the authoritative signal.
Setting arbitrary iteration caps (e.g., 'stop after 10 loops') as the primary stopping mechanism
Iteration caps either cut off useful work or run unnecessary iterations. They are acceptable as a safeguard, not as the primary loop control. Use stop_reason instead.
Parsing natural language phrases like 'I'm done' or 'task complete' to decide loop termination
Natural language is ambiguous and unreliable. The stop_reason field provides a deterministic, unambiguous signal for loop control.
Leaving tool results out of the conversation history, or replacing the history with a summary, to cut token spend
The Messages API keeps no server-side memory of the turn, so a dropped result leaves the model nothing new to reason about. Append each tool result to the history and send the full conversation. For large results, shrink what the tool returns.
Practice Scenario
A customer support agent built by a developer sometimes exits too early. Its loop decides it is finished whenever response.content[0].type == 'text', so it stops even while Claude still has tools to call. What is wrong, and what is the fix?
Build Exercise
Build a Multi-Tool Agent Loop
What you'll learn
- How the agentic loop lifecycle works with the Messages API
- Why stop_reason is the authoritative signal for loop control
- How to handle tool_use and end_turn stop_reason values correctly
- How to append tool results to conversation history for multi-turn execution
- When safety iteration caps are appropriate versus inappropriate as stopping mechanisms
- Set up a Claude API client with two tools: a calculator tool (accepts expression, returns result) and a web search stub (accepts query, returns mock results)
Why: Multi-tool setups expose model-driven decision-making — Claude must select the right tool based on context, which is core to agentic architecture.
You should see: Two tool definitions registered with proper JSON Schema input_schema, each with name, description, and parameters.
- Implement the agentic loop that sends requests to Claude and inspects stop_reason after each response
Why: The agentic loop is the core execution pattern — the exam tests whether you use stop_reason (deterministic) versus content-type checks or natural language parsing (unreliable).
You should see: A while loop that calls client.messages.create() and checks response.stop_reason after each iteration.
- Handle the tool_use stop_reason by executing the requested tool, creating a tool result message, and appending it to conversation history
Why: This is the critical step in the loop — the exam specifically tests whether you correctly extract tool calls, execute them, and return results in the right message format.
You should see: When Claude requests a tool, your code extracts the tool_use block, runs the corresponding function, and appends both the assistant response and a user message with tool_result to the conversation.
- Handle the end_turn stop_reason by extracting and returning the final response
Why: end_turn is Claude signal that it has completed the task — extracting the final text response correctly ends the loop and returns the result to the user.
You should see: When stop_reason is end_turn, your loop exits and returns the text content from the final response.
- Test with a prompt that requires multiple sequential tool calls (e.g., search for a value then calculate something with it) and verify the loop continues correctly through all iterations
Why: Sequential tool calls test the full loop lifecycle — the agent must complete one tool call, receive the result, reason about it, and decide to call another tool before finally returning.
You should see: At least two tool call iterations before end_turn. The agent searches first, uses the search result in a calculation, then returns the combined answer.
- Add a safety iteration cap of 20 as a maximum bound (not the primary stopping mechanism) and log a warning if it triggers
Why: The exam distinguishes safety caps (acceptable as a fallback) from using caps as the primary stopping mechanism (an anti-pattern). Your cap should never trigger in normal operation.
You should see: A MAX_ITERATIONS constant, a counter that increments each loop, and a warning log if the cap is hit. Normal queries should terminate via stop_reason well before reaching 20.
Sources
- Claude Agent SDK Overview — Anthropic
- Messages API Reference — Anthropic
- Tool use overview — Anthropic, who runs a tool you define
- Building with Claude API (Skilljar) — Anthropic
- CCAR-F Exam Guide v1.0: Task Statement 1.1 — Anthropic