ADR-0006 Architecture decision record
The agent picks from a Machine-defined, schema-backed menu; it does not drive the workflow
The control plane is Menu tool calls (ADR-0002), but which events an Agent may emit is scoped to the current Machine state and defined by the Machine, not an open set the Agent invents. The menu derives from the invoking state's transitions (ADR-0015 — the consumer authors no tool lists), is read by the Harness through the pod's Custodian (ADR-0013), and the Agent chooses one (controlled agency); the Machine owns the transition table. The Agent never steers the workflow — it answers within a frame the Machine set — and because its only control-plane peer is the Custodian (which holds a credential it cannot read), that frame is enforced, not advertised. Menus only change at turn boundaries, and the Harness re-reads the Menu per Submission (ADR-0013/0027), so no list_changed push channel is needed.
There is no jr2-blessed event vocabulary: every menu entry is a workflow-defined event (ADR-0011).
Encode flat
A named event schema must compile to a flat tagged object (an enum discriminator + each option's params as optionals
- a validation
check), never a top-leveloneOf/anyOf. Measured (PoC #5b): a strict variant (→oneOf/consttool schema) is unsatisfiable for Qwen3-Coder — it serializes the tool args as a JSON string and validation fails on every retry. A flat object is satisfied first try. A conditional contract ("notesrequired iffrequest_changes") is enforced by jr2 after the pick, not by the tool schema.
A pick declares its input, never its answer
A def states what the Agent supplies (input) and nothing about what comes back. Every pick is ack: delivered and answered on the same call. A pick that moves the workflow to work inside the Agent's state is answered when that work is done (ADR-0024), and the answer is the Machine's: the last reply since the pick, or what its answer action sets (ADR-0067). So a def has no output schema and no deferred semantics; defineEvent refuses both. poll stays reserved (ADR-0013).
One path: every conversation lives on the agent wire
The wire has exactly one conversation surface (ADR-0027): POST /agents/:name/:id, resumable by (name, iid) + offset. There is no separate "workflow run" surface, and nothing on the wire forces a structured result out of a turn — the menu is the only structured channel. Consequences:
- All continuing, multi-turn work lives on the agent path, driven by
agentRun(ADR-0016). - A turn that settles without a valid pick is re-prompted by jr2 — the budgeted no-signal nudge inside
agentRun(ADR-0016). The workflow sees one terminalagent.faulton exhaustion. - Self-contained, single-shot decisions (an LLM-judge / classifier / "given this diff + this rubric, return a verdict") are one-turn conversations whose menu is the verdict — the same path, not a second mechanism.
Residual
Unsolicited mid-turn steering remains the hard case (ADR-0002): the menu only opens when the Agent reaches a checkpoint or a turn boundary. Evidence for the findings above: poc/actor/POC-5B-FINDINGS.md, poc/actor/POC-5C-FINDINGS.md (poc/ is gitignored; conclusions live here).