iterion

ADR-060 — Conversational single-agent bots: the chat loop pattern

Status: accepted (2026-07-07). Extends ADR-058 (minimal framing — lean on the agent) from code-writing campaign bots to interactive bots. Piloted by rewriting whats-next (Nexie) v1 (form state machine, 15 nodes / 21 edges / 4 bespoke human forms + hardcoded studio form resolvers) → v2 (chat loop, 5 nodes). First live session: run 019f3beb, 2026-07-07 — docs/bot-runs/whats-next.md.

Context

whats-next v1 modelled the operator dialogue as a state machine: every exchange was a typed human-node form (priorities radio, roadmap review checkboxes, dispatch pickers, an ask_continue radio of five preset actions

The 2026-07-07 dogfood run (019f3b6b) showed the failure squarely. The operator asked, in chat, “indique-moi les tickets les plus pertinents pour un quickwin”. The bot could only answer with a 13-item raw checkbox list (no analysis), forced the question into a preset radio’s detail field, burned a full state-machine cycle (~40 s) per utterance, alternated reply languages, and — because each triage_board invocation was a fresh LLM session — carried no conversational memory between turns. The operator abandoned the session.

The root cause mirrors ADR-058’s: the deficit was framing, not capability. A dialogue is the least decomposable flow there is — every node boundary inserted between two utterances destroys context, adds latency, and replaces language with forms. Meanwhile the engine already had every primitive a real conversation needs, each built for other purposes: ask_user pauses with same-session resume (claude --resume <id>; interaction depth resets on every human answer, so a conversation is unbounded), a budget that suspends entirely during human pauses (a session can idle for days at zero cost), the operator chatbox inbox drained into the running agent at every tool boundary, and the board MCP tools.

Decision

Design interactive/orchestrator bots as one conversational agent in a chat loop, with the engine as the interaction substrate rather than the dialogue script:

seed (compute) → nexie (agent) → gate (compute) ── close ──▶ done
                    ▲                 │ (default)
                    └── loop(N) ── chat (human, ONE free-text field)

Generic engine/studio work shipped with the pilot (benefits every bot): ask_user structured options across both backends, assistant_text narration events, ask_user pauses on agent nodes surfacing as chat turns, and the pending-input nav badge.

Consequences