Agentic Loop Lifecycle

Estimated time: 25 minutes

The agentic loop is the foundation of every Claude-powered agent. If you don't understand exactly how the loop terminates and how tool results flow back to the model, every other architecture decision becomes guesswork. This lesson covers the loop's mechanics, the stop_reason contract, and the anti-patterns that cause loops to fail in production.

The Loop in One Sentence

Send a request, inspect stop_reason, execute any requested tools, append the results to the conversation, and call again — until stop_reason returns end_turn. That's it. The model decides when it's done; your code never decides for it.

The Canonical Implementation

while (true) {
  const response = await claude.messages.create({ messages });
  if (response.stop_reason === 'end_turn') break;
  if (response.stop_reason === 'tool_use') {
    const results = await executeTools(response.content);
    messages.push({ role: 'assistant', content: response.content });
    messages.push({ role: 'user', content: results });
  }
}

Three things matter here. First, the loop continues only when stop_reason is tool_use. Second, the assistant's full content (including the tool_use blocks) gets pushed back into the conversation before tool results — order matters because the API rejects tool results without a preceding tool_use. Third, tool results must be appended as a user message, not as assistant.

Why Model-Driven Termination?

Claude is performing chain-of-thought reasoning across tool calls. The model knows when it has gathered enough information to answer. Your code parsing the assistant's text or counting iterations to decide termination injects guesses where Claude already has knowledge. Trust the stop_reason.

Anti-Patterns That Break Production Loops

  • Parsing assistant text for completion phrases. Looking for "I'm done" or "Final answer" in the model's text is unreliable — Claude doesn't always emit those phrases, and when it does, they may appear mid-reasoning before the actual conclusion.
  • Using iteration caps as the primary stop. An iteration cap is a defensive backstop, not a control mechanism. If your loop is hitting a 20-iteration cap, that's a signal that your tools are misdescribed or your task is malformed — fix the root cause, don't just lower the cap.
  • Forgetting to append tool results before the next call. The model's next response is determined by what's in messages. If you call create again without pushing the tool results, Claude will see its own request and assume nothing happened — typically leading to repeated calls of the same tool.

Skills to Develop

  1. Recognize the three valid stop_reason values: end_turn, tool_use, and (rarely) max_tokens. Handle each explicitly.
  2. Append the assistant's full response content (preserving order of text and tool_use blocks) before injecting tool results.
  3. Treat iteration caps as safety nets, not control flow. Log cap hits and investigate.
Exam tip: Questions about "how does Claude know it's done?" have one correct answer: the API returns stop_reason: 'end_turn'. Anything that involves your code interpreting Claude's text is wrong.