ADR-0009: Run, turn, and session model¶
- Status: Accepted
- Date: 2026-07-17
- Related: Sections 6.3, 6.4, 12, 16, 27
Context¶
The domain left several load-bearing questions implicit: what a run is relative to a conversational turn and a session; where a new run's prior conversation comes from (checkpoints are per-run); how an agent can ask the user a question mid-run; and whether a session may have concurrent runs (which would contend on the per-session event sequence).
Decision¶
- run == turn. Submitting a user message creates exactly one run; that run ends when the agent produces its final response, or fails, is cancelled, or times out. A session is a sequence of runs. Subagents are child runs, not turns.
- The session owns the authoritative event log and the per-session sequence. A run's checkpoint holds only that run's working conversation and is not the session's system of record.
- A new run seeds its conversation from a session-history projection built from events, plus the new user message, subject to context budget and compaction. Provider-opaque reasoning items never cross a run boundary.
- Add
WAITING_FOR_USER, entered by a deterministicconversation.ask_usercontrol tool (not by parsing model prose).POST /v1/runs/{id}/inputdelivers the answer and resumes the same run; this is distinct fromPOST /v1/sessions/{id}/messages, which starts a new turn/run. - Routing user text to a waiting run versus a new run is a deterministic API decision from run state, never a model decision.
- Default to at most one active (non-terminal) run per session, enforced by
a partial unique constraint. Allocate the per-session sequence inside the same
short transaction that appends an event;
UNIQUE(session_id, sequence)is the backstop.
Consequences¶
- The run stays the unit of scheduling, leasing, checkpointing, and recovery; the session stays the unit of memory and cross-device continuity.
- Provider switching between turns is safe by construction (only portable items carry forward).
- Adds an input endpoint, a control tool, and a database constraint.
- Parallel branches, if ever needed, are modeled as separate sessions or child runs, not concurrent same-sequence writers.
Alternatives considered¶
- run == whole session: rejected; makes leasing, budgeting, and recovery of a single response hard to reason about.
- Infer clarifying questions from assistant prose: rejected; nondeterministic and a prompt-injection surface.
- Allow concurrent runs per session by default: rejected; sequence contention and ambiguous ordering.