Chapter 3: The Agent Loop

The agent loop is the heartbeat of a coding agent. It's the cycle of: receive input → call the LLM → execute tools → feed results back → repeat until done. Both agents implement this loop, but with very different execution models.

Codex: Turn-Based State Machine

Codex structures execution as discrete turns, each encapsulated in a TurnContext:

User Input
    ↓
TurnContext Creation (model, config, sandbox policy, permissions)
    ↓
Build Prompt (base instructions + history + tool schemas)
    ↓
Stream Model Response (SSE or WebSocket)
    ↓
Parse Tool Calls from Response
    ↓
For Each Tool Call:
    ├── Check Approval (Guardian system)
    ├── Apply Sandbox Policy
    ├── Execute in Sandbox
    └── Collect Result
    ↓
Append Results to History
    ↓
Emit Events to UI
    ↓
Next Turn (if model wants to continue)

Key Types

Code Location

Concurrency

Codex uses Tokio for async I/O. All tool executions are non-blocking. The ToolOrchestrator manages parallel tool execution with approval request queuing.

Claude Code: Generator-Based Streaming Loop

Claude Code uses an async generator pattern — the query() function yields events as they happen, with no hard turn boundaries:

User Input
    ↓
Assemble System Prompt (cached sections + dynamic context)
    ↓
Normalize Messages for API
    ↓
Stream from Claude API
    ↓
Process stop_reason:
    ├── "tool_use" → Extract tool blocks
    │   ├── Check permissions (canUseTool)
    │   ├── Execute tools (parallel for reads, serial for writes)
    │   ├── Append tool results
    │   └── Loop back to API call
    │
    ├── "end_turn" → Return text response, done
    │
    ├── "max_tokens" → Auto-compact context, continue
    │
    └── "stop_sequence" → Process stop hooks

Key Types

Code Location

Concurrency

Tools are partitioned into concurrent and serial batches:

Key Differences

Aspect Codex (Turn-Based) Claude Code (Generator)
Boundary Explicit TurnContext per iteration Fluid — no hard boundary between tool batches
State Immutable per-turn config Mutable AppState updated continuously
Streaming Events emitted at turn boundaries Events yielded continuously via generator
Recovery Turn can be retried or rolled back Auto-compaction on context overflow, fallback model on overload
Cancellation Cancellation tokens per turn Generator can be aborted at any yield point

Why It Matters

The turn-based model is easier to reason about — each turn is a clean unit with defined inputs and outputs. Codex does stream text and reasoning deltas to the UI during a turn, and spawns tool futures during streaming (not waiting for the response to complete). However, tool results are only processed after all futures are drained at stream end, making the turn boundary the synchronization point.

The generator model is more flexible — it can yield events as they happen, handle mid-stream context compaction, and naturally pause at permission prompts. Claude Code's StreamingToolExecutor can yield completed tool results while other tools are still running, making the flow more fine-grained. But the control flow is harder to follow (main.tsx alone is ~785KB).

Deep Dive

For a detailed trace of the actual execution mechanics — streaming event processing, tool dispatch timing, error recovery cascades, and continuation logic — see Agentic Execution: Deep Dive.

Auto-Continuation

Both agents handle the case where the model wants to keep going:

Context Overflow

When the conversation grows too large for the model's context window:

See Chapter 9: Context Management for details.