State Transitions
Complete transition table for the agent state machine defined in agent::state.
Transition Table
| From State | Event | To State | Side Effect |
|---|---|---|---|
Initializing | WorktreeReady | BuildingPrompt | None |
BuildingPrompt | PromptReady(prompt) | Spawning | StorePrompt(prompt) |
Spawning | SessionStarted(seq) | Running { session_seq: seq } | None (resets consecutive_errors to 0) |
Spawning | SessionExited(Error) | CoolingDown or Stopped | None or LogFatal (if threshold reached) |
Spawning | SessionExited(Timeout) | CoolingDown or Stopped | None or LogFatal (if threshold reached) |
Running | SessionExited(Success) | SessionComplete | None (resets consecutive_errors to 0) |
Running | SessionExited(Error) | CoolingDown or Stopped | None or LogFatal (if threshold reached) |
Running | SessionExited(Timeout) | CoolingDown or Stopped | None or LogFatal (if threshold reached) |
Running | UrgentMessage | Interrupting { session_seq } | CancelSession |
Interrupting | SessionExited(*) | BuildingPrompt | None (no error increment) |
Interrupting | GraceExceeded | BuildingPrompt | ForceStopSession |
SessionComplete | WorktreeReady | BuildingPrompt | IncrementSession (bumps session_seq) |
CoolingDown | BackoffElapsed | BuildingPrompt | None |
Global Transitions
These events are valid from any state:
| Event | To State | Side Effect |
|---|---|---|
OperatorStop | Stopped | CancelSession if currently Running or Interrupting; None otherwise |
FatalError(msg) | Stopped | LogFatal(msg) |
Error Counters
The state machine maintains two counters that affect transitions:
| Counter | Incremented On | Reset On | Fatal Threshold |
|---|---|---|---|
consecutive_errors | Any SessionExited(Error|Timeout) from Running or Spawning | SessionStarted or SessionExited(Success) | Default: 5 (max_consecutive_errors) |
total_errors | Any SessionExited(Error|Timeout) from Running or Spawning | Never | Default: 20 (max_total_errors) |
When a counter reaches its threshold, the state transitions to Stopped with LogFatal instead of CoolingDown.
Note: SessionExited(*) from Interrupting does not increment error counters — interrupts are intentional, not errors.
Backoff Formula
The CoolingDown duration uses exponential backoff:
duration_ms = min(2000 * 2^(n-1), 60000)
Where n = consecutive_errors after increment.
| n | Duration |
|---|---|
| 1 | 2,000 ms (2s) |
| 2 | 4,000 ms (4s) |
| 3 | 8,000 ms (8s) |
| 4 | 16,000 ms (16s) |
| 5 | 32,000 ms (32s) |
| 6+ | 60,000 ms (60s, cap) |
State Diagram
Initializing ──WorktreeReady──► BuildingPrompt ◄──BackoffElapsed── CoolingDown
│ ▲
│ PromptReady │
▼ │
Spawning ──Error/Timeout──────────────┤
│ │
│ SessionStarted │
▼ │
Running ──Error/Timeout───────────────┘
│ │
Success │ │ UrgentMessage
│ │ ▼
▼ │ Interrupting ──SessionExited──► BuildingPrompt
SessionComplete │ ──GraceExceeded──► BuildingPrompt
│ │
│ WorktreeReady
└──────────────────────────────────────────► BuildingPrompt
OperatorStop or FatalError from ANY state ──────► Stopped
ExitOutcome
The ExitOutcome enum describes how a backend session ended:
| Variant | Description |
|---|---|
Success | Session completed normally |
Error(String) | Session failed with an error message |
Timeout | Session exceeded its timeout |
Related
- Agent Lifecycle — Conceptual overview
- Error Types — Error enums used in transitions