The Agent Loop
A turn is everything that happens from your prompt to the final answer. Inside a turn, the model asks for tools, Claude Code runs them, and the model reads the results. This repeats until the model answers without a tool call. This page walks through each stage and shows where you can step in.
At a Glance
| Question | Answer |
|---|---|
| Can you use it? | ✅ Yes. Every prompt starts a turn. |
| Can you change it? | ✅ Yes, at fixed points. Use hooks, mod events, permission rules, and a few env vars. |
| Can you turn it on or off? | Each hook and rule has its own switch. The loop itself always runs. |
| Where does it live? | Inside the program. Hook settings are in settings. files. |
| Status | Documented Undocumented |
The Turn at a Glance
The Stages
Sources: Hooks Reference: Hook Lifecycle and Mods Reference for the events. Source: the program for the rest.
| Stage | Status | What happens | Where you can act |
|---|---|---|---|
| 1. Input | Documented | Claude Code reads your text. A message you type during a turn joins at a safe point. | User hook, prompt. mod event |
| 2. Command expansion | Documented | A slash command or skill name turns into a prompt. | User hook |
| 3. Context pickup | Documented | Claude Code adds nested memory, @ mentions, and file-change notes. | Instructions hook, prompt. and prompt. mod events |
| 4. Message prep | Undocumented | Large tool results become references. Claude Code looks up the facts of the model. | Pre and Post hooks |
| 5. Auto compaction | Documented | Claude Code compacts the conversation if it is over the threshold. See Context and Compaction. | Pre and Post hooks |
| 6. Attachments | Undocumented | Claude Code adds reminders and notes about the mode. | prompt. mod event |
| 7. Request build | Documented | Claude Code builds the system, tools, and messages parts. See Request and Cache. | prompt., prompt., and tool. mod events |
| 8. Stream | Documented | Claude Code sends the request and reads the events, with retries and fallbacks. See Models. | Message hook |
| 9. Tools | Documented | Each tool call passes the permission check and then runs. | Tool hooks (next section) |
| 10. Next round | Undocumented | The tool results join the messages, and the loop starts again at stage 3. | Post hook |
| 11. Stop | Documented | With no tool call, the Stop hooks run. A hook that blocks sends its reason back to the model. | Stop and Stop hooks |
The mod events turn.start, turn.step, and turn.complete wrap the whole turn.
See the Mod API pages in Extend.
The Tool Stage
Sources: Hooks Reference and Environment Variables.
| Step | Status | What happens |
|---|---|---|
| Permission check | Documented | Your rules and the permission mode decide to allow, ask, or deny. See Permission Flow in this section. |
Pre hook | Documented | The hook can block or change the call. |
Permission hook | Documented | The hook runs when a decision is needed. |
| Run | Documented | Read-only tools and subagents run in parallel, up to CLAUDE_ (default 10). Other tools run one after another. |
Post and Post hooks | Documented | They run after each call. |
Post hook | Documented | It runs after a batch of parallel calls and before the next model call. It can stop the loop. |
Recovery Inside the Loop
The loop does not fail on every error. It tries to fix the problem and go on.
| Case | Status | What Claude Code does |
|---|---|---|
The output stops at max_ | Undocumented | It adds a nudge message and asks again, a limited number of times. |
| The response is cut off | Undocumented | It does the same. |
A tool_ block has no valid call | Undocumented | It drops the reply and asks once more. Then it ends with a message that the tool call could not be parsed. |
| The model sends only thinking | Undocumented | It sends one nudge. |
| A safety refusal | Documented | It runs again on the fallback model of that category. See Models. |
| The context is too long | Documented | It lowers max_ or compacts. |
| Autocompact refills 3 times in a row | Documented | It ends the turn with an error that starts Autocompact is thrashing. See Troubleshooting in the official docs. |
A Stop hook blocks | Documented | It feeds the reason back. After CLAUDE_ blocks in a row (default 8), it ends the turn. |
-- is reached | Documented | It ends the run. See the CLI Reference in the official docs. |
How a Turn Ends
The loop returns a reason, and Claude Code records it in telemetry.
The chat does not show it.
A result message of the Agent SDK and of --output-format stream-json carries it as terminal_reason.
All reasons are Undocumented, because only the Agent SDK pages name some of them.
reason | Meaning |
|---|---|
completed | The turn ended in the normal way. |
max_ | The turn limit was reached. |
aborted_, aborted_ | You stopped the turn (for example with Esc) while the model streamed or tools ran. |
hook_, stop_ | A hook stopped the turn. |
tool_ | A hook deferred a tool call. |
tool_ | A deferred tool call could not be resumed. |
background_ | The turn moved to a background session. |
blocking_ | The context hit the blocked level. See Context and Compaction. |
rapid_ | Autocompact refilled the context too fast. |
model_, api_, image_ | The API or an image failed. |
malformed_ | The model sent two bad tool calls in a row. |
prompt_ | The prompt did not fit the context window. |
budget_ | The budget for the run was used up. |
structured_ | The model did not give valid structured output after the allowed retries. |
turn_ | Claude Code failed to set up the turn. |
What You Can Change
| Goal | How |
|---|---|
| Check or edit every prompt before it runs | A User hook. |
| Block or rewrite a tool call | A Pre hook or a permission rule. |
| Force the model to keep working | A Stop hook that blocks. Mind CLAUDE_. |
| Limit tool parallelism | Set CLAUDE_. |
| Limit the number of turns | Use -- in print mode. |
| Rewrite a part of the system prompt | A mod listening to prompt. or prompt.. See The System Prompt. |
| Change the compaction point | See Context and Compaction. |
Example
This hook in .claude/settings.json runs a script before every Bash call.
If the script exits with code 2, the call is blocked and the reason goes back to the model.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": ".claude/hooks/check-bash.sh" }]
}
]
}
}
Related Pages
- Architecture
- Request and Cache
- Context and Compaction
- Hooks, Tools, Subagents, and Mod API pages in Extend and Reference.