Skip to content
Domain 1Task 1.1

Agentic Loops

Learn this interactively

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.

  1. 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.

  2. Inspect the stop_reason field 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.
  3. If stop_reason is "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.

  4. If stop_reason is "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

Exam Trap

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.

Exam Trap

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.

Exam Trap

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.

Exam Trap

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 Exercise

Build a Multi-Tool Agent Loop

Difficulty
45 minutes

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
  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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