C Claude Cert Prep All Claude Certifications

The Agentic Loop and stop_reason

How the model-tool-client loop actually terminates, and why stop_reason is the only signal you can trust to control it.

Agentic Architecture·Lesson 1 of 6·7 min

Every agentic system built on the Claude API runs the same underlying loop: the model receives the conversation so far, decides whether to call a tool, the client executes that tool and appends the result, and the whole thing repeats. There is no magic scheduler underneath this. The loop is just a while-loop in your own code, and the entire question of "when do we stop" comes down to one field on the API response: stop_reason.

On each turn, Claude returns a response with a stop_reason that tells you why generation stopped. The four values you need to know cold for the exam are:

The correct control-flow pattern is simple: after every API call, branch on stop_reason. If it's tool_use, execute the requested tools and loop again. If it's end_turn, exit. If it's max_tokens or stop_sequence, treat it as an error condition — log it, possibly retry with adjusted parameters, but do not silently continue as if the task finished normally.

Why not just read the text?

A tempting shortcut is to look at the assistant's text output and guess whether it "sounds done" — scanning for phrases like "Task complete" or "I have finished." This fails for several concrete reasons. Models phrase completion inconsistently across turns. A response can contain both prose and a tool call in the same turn, so text presence tells you nothing about whether more tool calls are coming. And relying on natural-language parsing couples your control flow to model phrasing, which changes across model versions and is not a contract Anthropic guarantees. stop_reason is a structured, documented field specifically designed to be machine-readable; text content is not.

Exam trap Expect a question describing a loop that checks whether the response contains a tool_use content block versus whether stop_reason equals tool_use, and asks which is correct. Both can look equivalent at first glance, but the robust pattern is branching on stop_reason directly — checking for a content block type is a weaker, indirect proxy and the exam will present a scenario where it diverges (e.g., a malformed or truncated response) from the stop_reason-based check.

Iteration caps are a safety net, not a control mechanism

Production agent loops should include a maximum iteration count. But its job is to prevent runaway cost and infinite loops when something goes wrong upstream — not to be the primary way you decide the task is done. If your loop's actual termination logic is "stop after N iterations regardless of stop_reason," you have built a timer, not an agent. The correct design uses stop_reason == "end_turn" as the primary exit condition and an iteration cap purely as a defensive ceiling that should, in a correctly functioning system, almost never be the thing that actually ends the loop.

Scenario: An agent is wired to call a search tool repeatedly. On iteration 40 of a 50-iteration cap, the model returns a response with no tool_use blocks and stop_reason of end_turn, but the assistant text happens to include the word "next" because it's summarizing next steps for the user. A text-scanning implementation misreads this as "more work to do" and keeps looping past a completed answer. The correct implementation exits immediately because stop_reason is end_turn, regardless of the words used in the response.

Try it

Using the Claude API directly (not the SDK's agent loop helpers), write a bare tool-use loop for a single tool of your choice. Log the stop_reason on every turn. Then deliberately set max_tokens low enough that a tool call gets truncated, and observe what stop_reason comes back and how your loop should react to it versus how it reacts if you naively assume any non-empty response means success.

Interactive
What should the client do next?
Orchestration Patterns: Chaining, Routing, Parallelization →