Route each question through the PATHs below. First check the response:
meta.status="parent_question_required" or meta.ask_user_directly=true: a normal turn, not a failure. Follow the response text: ask one Socratic question yourself, never mention MCP, provider failures, or reason_code, and send the user's answer with last_question set to the exact question you asked.
meta.question_advisory_request: run the question-first advisory fan-out below.
meta.lateral_review_required=true: run the milestone lateral-review dispatch below.
- Errors and
meta.reason == "initial_context_too_large": see Retry on failure.
Question-first advisory fan-out: show the interview question first. The advisory helps the human answer; it never hides, replaces, or delays the question, which stays visible while lanes run.
When meta.question_advisory_subagents is present you MUST process every
payload: each entry (title, agent, prompt, context) is spawn-ready work, and its prompt passes unchanged. Never reconstruct prompts from prose. Obey meta.question_advisory_host_action: spawn_subagents means parallel support was declared; dispatch_subagents_if_supported means native parallel dispatch when available and sequential processing otherwise; process_payloads_sequentially requires ordered processing. The stamped dispatch_mode (host_driven, dispatch_mode="host_decides", sequential) says the same. The payloads are the work contract, while the host action selects the execution strategy. For parallel dispatch, start one child per payload through the active runtime's orchestrate_subagents capability in a single fan-out turn. Wait for every result, then synthesize.
Lanes: code_context (repo-local facts; reuses meta.code_investigation_request), web_context (only when current external facts affect the answer), data_context (takes measurements; see Data measurements), ambiguity_contrarian (hidden assumptions, vague terms, missing decisions, risky defaults), answer_simplifier (2-3 easy choices or one concise draft), architecture_implications (ownership, interfaces, rollout, system shape). Synthesize a compact helper: 2-3 answer options, one recommended draft, or a short ambiguity note. Do not forward advisory output to ouroboros_interview until the user approves, edits, or explicitly asks you to auto-confirm a safe answer.
Submitting fan-out results (re-entry): when the meta carries a fanout_id (meta.question_advisory_fanout_id, or a lateral persona panel's), call ouroboros_submit_fanout_results after all children return, with:
session_id: the session the fan-out was issued under; refused if omitted when the producer had one.
fanout_id: the stamped id.
correlation_key: the stamped result_correlation_key (context.lane_id, context.persona, or code_facts); refused if omitted when the fan-out recorded one.
results: one entry per lane, either { "key": <correlation value>, "content": <child output> } or exactly { "key": <lane>, "undispatched": true } (the literal true, no content). A lane that ran and found nothing still submits its output. A lane you could not spawn at all (no capability, the child died, the user cancelled) is undispatched. Never invent output for a lane you did not run. Bad entries come back together as status="invalid_result_entry" with invalid_keys.
A complete set returns a bounded artifact envelope. Call ouroboros_fetch_artifact with its contract_id, then continue from the correlated synthesis in the fetched body; this MCP fetch is required even when the host has no shell. A partial set returns status="partial" with missing_required_keys: retry with every lane you hold, not only the missing ones, because no submitted output is kept between calls. Sequential hosts accumulate outputs and send the growing set. Only lanes marked required: true block completion. Continue the interview from the fetched synthesis.
Data measurements: the data_context lane discovers the host's data tools, takes the measurement itself, and returns the aggregate it read. Nothing is confirmed before it runs and nothing is run after it; the user registering a tool is the consent to have it called. When its output carries measurements:
- Show the numbers beside the question as material for the user's
judgment, never as the answer. The user answers on the ordinary
[from-user] path; there is no [from-data] answer to forward.
- Carry the aggregate as the lane reported it, with its
metric and the
decision it informs. Do not re-derive, re-scale, or combine numbers.
- If the user has already answered the question by the time the measurement
arrives, drop it. Do not re-open the decision with it: evidence informs a
decision, it does not revisit one.
When data_needed is false, the reason describes the lane, never the user's infrastructure; say it in your own words rather than pasting the constant. not_a_measurement, question_too_ambiguous_to_measure, answer_would_not_be_an_aggregate: move on. no_data_store_described: mention it only if you know a store exists and the lane was not told about it. store_described_but_not_callable: yours to handle, not the user's to hear; check whether the tool is available to you, take the read yourself, or re-dispatch the lane. Do not attach read-only or cost disclaimers to measurements; nothing performs that check.
Milestone lateral-review dispatch: meta.lateral_review_required=true (older responses carry only meta.lateral_review_recommended=true) means the interview crossed an ambiguity milestone (initial -> progress, progress -> refined, refined -> ready). The server raises it at most once per milestone per session. Treat it as a required lightweight subagent review for that turn, and run it silently: after showing the question, call ouroboros_lateral_think with meta.lateral_review_tool_args and dispatch its persona payloads in the same fan-out turn as the advisory lanes. Do not announce it. Its personas are only those the advisory lanes do not already run, so fold its findings into the same helper (the options or the recommended draft), never a separate block, and mention it only when a finding changes the recommended answer or the next question. If only legacy advisory fields are present, use personas=["researcher","contrarian","simplifier"], a problem context with the session, milestone, and question, and a current approach describing the next interview-routing decision. If lateral tooling is unavailable, continue the interview and say the review could not be run. Lateral review never changes requirements or marks the interview complete by itself.
Main-session direct-answer assistance: when you would otherwise answer the MCP question yourself or compress the user's free text into a decision, the advisory lanes are your lateral review: ambiguity_contrarian and answer_simplifier run the contrarian and simplifier personas on every question, and architecture_implications runs the architect. Build 2-3 concrete options or one recommended draft from their output, then let the user approve, tweak, or switch to auto. Do not call ouroboros_lateral_think again for a question that carried advisory lanes. Only when the response carried none (for example a meta.ask_user_directly=true turn where you write the question yourself) and you are about to synthesize a product, UX, or architecture answer from partial input, call it at most once for that question with one persona: contrarian for tradeoffs, priorities, non-goals, risk, or success criteria; architect when the answer changes system shape or ownership; simplifier when the user seems busy or terse. The same silence rule applies.
PATH 1: Code Answer (current state: stack, frameworks, dependencies, patterns, architecture, file layout). Use inspect_code. Description, not prescription: "the project uses JWT" is a fact; "the new feature should use JWT" is a decision, so PATH 2.
- PATH 1a: Auto-confirm only when ALL hold: the answer is an exact match in a manifest or config file (
pyproject.toml, package.json, go.mod, Dockerfile, .env.example, lock files, CI config), purely descriptive, and unambiguous (one candidate). Send [from-code][auto-confirmed] at once, show a non-blocking note (ℹ️ Auto-confirmed: Python 3.12, FastAPI framework (pyproject.toml)), and resend a correction if the user later says it is wrong.
- PATH 1b: Code Confirmation otherwise (inferred from patterns, several candidates, no manifest match): use the confirmation pattern with
[from-code].
PATH 2: Human Judgment (goals, vision, acceptance criteria, business logic, preferences, tradeoffs, scope, behavior of new features): ask through ask_user with suggested options; prefix [from-user].
PATH 3: Code + Judgment (facts exist but need interpretation, e.g. "I see a saga pattern in orders/. Should payments use the same?"): read the code first, show the findings with the question, and route the entire question to the user; prefix [from-user].
PATH 4: Research Interlude (third-party APIs, pricing, library capabilities, version compatibility, security advisories, standards the codebase cannot answer): use web_research, then the confirmation pattern with [from-research]. Facts, not decisions: "Stripe's rate limit is 100 req/s" is research; "we should use Stripe" is PATH 2.
When in doubt, use PATH 2.
Confirmation pattern (PATH 1b, PATH 4): ask through ask_user: "MCP asks: <question>. I found: <finding and its source>. Is this correct?" with options Yes, correct and No, let me correct.
Yes, correct: send the concise fact with the path's prefix; no Refine gate.
No, let me correct, or a correction typed directly: collect the corrected answer as free text (ask for any reasoning, constraints, or scope to keep), run the Refine gate, and send it as [from-user][refined].