Socratic interview to crystallize vague requirements into clear specifications.
Compare the result with the current version in the active runtime's local plugin metadata (for Claude installs this is .claude-plugin/plugin.json).
-
Start a new interview:
Tool: ouroboros_interview
Arguments:
initial_context: <user's topic or idea>
cwd: <current working directory>
confused_terms: <optional explicit terms the user does not understand>
references: <optional [{reference_id, label, origin, url?, excerpt?}]>
Returns a session ID and the first question.
confused_terms and references are structured adapter context, not
requirements. They are queued on the start call and MUST NOT alter the first
question. On later turns, glossary help is limited to explicitly confused
terms and references are used only for contrast questions. Do not infer these
arguments from vocabulary density or fetch referenced URLs/files.
-
For each question from MCP, apply the routing paths below:
Parent-session question handoff:
If an MCP response includes meta.status="parent_question_required" or
meta.ask_user_directly=true, treat it as a normal interview continuation,
not as an MCP/provider/tool failure. Do not tell the user MCP failed, do
not expose reason_code, and do not retry the MCP question generator. Ask
exactly one natural Socratic clarification question yourself, using the same
routing judgement as any other interview turn. Save the exact user-facing
question text. When the user answers, call:
Tool: ouroboros_interview
Arguments:
session_id: <meta.session_id>
answer: <user answer>
last_question: <exact question you asked the user>
last_question is required on this path so MCP can persist the real
transcript even though the parent session generated the question.
Question-first advisory fanout:
If an MCP response includes meta.question_advisory_request, show the
interview question to the user first, then use the advisory request as a
parent-session assist layer. The advisory exists to help the human answer;
it must not hide, replace, or delay the question itself.
Run the advisory lanes through your runtime's native subagent mechanism when
one exists. For Claude Code this is the Task/Agent tool; for Codex, explicitly
start a native subagent workflow in natural language. Spawn one subagent per
lane, pass that lane's payload prompt, wait for all agents, then synthesize.
If the runtime has no parallel primitive, process payloads sequentially per
dispatch_mode="sequential" and the request's sequential_fallback
semantics. The standard lanes are:
code_context — inspect repo-local facts and reuse
meta.code_investigation_request when present.
web_context — browse/search only when current external facts genuinely
affect the answer.
ambiguity_contrarian — find hidden assumptions, vague terms, missing
decisions, and risky defaults.
answer_simplifier — turn the question into 2-3 easy choices or one
concise draft answer.
architecture_implications — check whether the answer changes ownership,
interfaces, rollout, or system shape.
Synthesize advisory results into a compact helper for the user: 2-3 answer
options, one recommended draft, or a short "I found these ambiguities" note.
Do not forward advisory output to ouroboros_interview until the user
approves, edits, or explicitly asks you to auto-confirm a safe answer.
When meta.question_advisory_subagents is present you MUST fan out: treat
each entry as a spawn-ready advisory payload with title, agent, prompt,
and context, and dispatch every payload through your host's native subagent
mechanism (Claude Code → one Task/Agent call per payload in one parallel
batch; Codex → explicitly spawn one Codex subagent per payload, wait for all
results, then synthesize; runtimes without a parallel primitive → process
payloads sequentially per dispatch_mode="sequential") instead of
reconstructing prompts from prose. This
is required regardless of dispatch mode: the payloads themselves are the
spawn signal.
Treat meta.question_advisory_host_action=spawn_subagents, when present, as
a reinforcing cue for host-driven runtimes such as Codex or Claude Code, not
as a prerequisite. The only time you skip spawning is when the host has no
subagent primitive at all (then use sequential_fallback).
Preserve the original question text while advisory children run.
Submitting fan-out results back (re-entry):
When the originating meta carries a fanout_id (e.g.
meta.question_advisory_fanout_id, or a fanout_id in a lateral persona
panel dispatch), after all advisory/persona subagents return, call
ouroboros_submit_fanout_results with:
fanout_id: the stamped id from that meta,
correlation_key: the stamped result_correlation_key
(context.lane_id, context.persona, or code_facts),
results: one { "key": <correlation value>, "content": <child output> }
per subagent, where key is that child's correlation value (its lane id,
persona, or code_facts).
A complete set returns the correlated synthesis to continue with; a partial
set returns status="partial" with missing_keys so you can resubmit the
remaining lanes. Sequential hosts submit after processing payloads
one-by-one — same tool, same contract. Continue the interview from the
returned synthesis; keep the user-facing question visible throughout.
Milestone lateral-review dispatch:
If an MCP response includes meta.lateral_review_recommended=true, treat it
as a required lightweight subagent review for that turn. The interview just
crossed an ambiguity milestone such as initial -> progress,
progress -> refined, or refined -> ready, which is exactly when hidden
assumptions tend to matter.
After showing the returned question to the user:
- Tell the user briefly that a few perspectives are checking the question.
- Call
ouroboros_lateral_think with meta.lateral_review_tool_args when
present. If only the legacy advisory fields are present, call it with
personas=["researcher","contrarian","simplifier"], a problem context
containing the current interview session/milestone/question, and a current
approach describing the next interview-routing decision.
- Fold only concrete, user-safe findings into the next answer or user
question. Do not present every subagent note as a report.
- If lateral tooling is unavailable, continue the interview and say the
review could not be run; do not restart the interview.
The MCP interview tool is still the question generator and source of
persistent state. Lateral review is a main-session assist layer: it helps the
user feel supported, but it does not by itself change requirements or mark the
interview complete.
Main-session direct-answer assistance:
Use lateral review frequently when the main session would otherwise answer
the MCP question directly or compress the user's free-text into a decision.
This is the supported "deep research style" experience for interviews: the
user should see that multiple perspectives are helping, while the final
prompt stays easy to answer.
Trigger a lightweight ouroboros_lateral_think call before continuing when
any of these are true:
- You are about to synthesize a product/UX/architecture answer from partial
user input.
- The question asks for tradeoffs, priorities, non-goals, risk, success
criteria, or rollout strategy.
- The factual code answer is lower confidence than an exact config/manifest
match.
- The user seems busy, uncertain, terse, or likely to benefit from selectable
options instead of another open-ended question.
Prefer personas=["researcher","contrarian","simplifier"] for this
assist. Add architect when the answer changes system shape or ownership.
Summarize the result as 2-3 concrete options or one recommended answer draft,
then let the user approve, tweak, or switch to auto.
PATH 1 — Code Answer (describe current state from codebase):
When the question asks about existing tech stack, frameworks, dependencies,
current patterns, architecture, or file structure:
- Use the active runtime's
inspect_code capability to find the factual answer
- Description, not prescription: "The project uses JWT" is fact.
"The new feature should also use JWT" is a DECISION — route to PATH 2.
- Evaluate confidence and choose sub-path:
PATH 1a — Auto-confirm (high-confidence factual, no user block):
When ALL of the following are true:
- The answer is found as an exact match in a manifest or config file
(e.g.,
pyproject.toml, package.json, Dockerfile, go.mod, .env.example)
- The answer is purely descriptive — it describes what exists, not what
the new feature should do
- There is no ambiguity — a single, clear answer (not multiple candidates)
Then:
- Send the answer to MCP immediately with
[from-code][auto-confirmed] prefix
- Display a brief notification to the user (do NOT block):
"ℹ️ Auto-confirmed: Python 3.12, FastAPI framework (pyproject.toml)"
- The user can correct at any time by saying "that's wrong" — re-send correction to MCP
- Increment the auto-confirm counter (see Dialectic Rhythm Guard below)
Examples of auto-confirmable facts:
- Programming language (from pyproject.toml, package.json, go.mod)
- Framework (from dependencies in manifest)
- Python/Node version (from config files)
- Package manager (from lock files present)
- CI/CD tool (from .github/workflows/, Jenkinsfile, etc.)
PATH 1b — Code Confirmation (medium/low confidence, user confirms):
When the codebase has relevant information but confidence is not high enough
for auto-confirm (inferred from patterns, multiple candidates, or no manifest match):
- Present findings to user as a confirmation question through the active runtime's
ask_user capability:
{
"questions": [{
"question": "MCP asks: What auth method does the project use?\n\nI found: JWT-based auth in src/auth/jwt.py\n\nIs this correct?",
"header": "Q<N> — Code Confirmation",
"options": [
{"label": "Yes, correct", "description": "Use this as the answer"},
{"label": "No, let me correct", "description": "I'll provide the right answer"}
],
"multiSelect": false
}]
}
- Prefix answer with
[from-code] when sending to MCP
- If the user picks "Yes, correct", send the concise factual answer with
[from-code] and do not apply the Refine gate. Increment the
auto-confirm counter (see Dialectic Rhythm Guard below).
- If the user picks "No, let me correct", immediately use the
ask_user capability to collect the corrected answer as free text:
{
"questions": [{
"question": "What should I send instead for this MCP question?\n\nMCP asks: What auth method does the project use?\n\nInclude any reasoning, constraints, or scope that should be preserved.",
"header": "Q<N> — Correction"
}]
}
- Route the correction text through the Refine gate before sending it to
MCP. Send the multi-section payload with
[from-user][refined] (the
human is now the source of the corrected answer).
- If the user supplies a correction directly without using the option, treat
that free text the same way: Refine first, then send with
[from-user][refined].
- Reset the Dialectic Rhythm Guard counter to 0 because the corrected
answer is direct user judgment, even though it was initiated from a code
or research confirmation path.
PATH 2 — Human Judgment (decisions only humans can make):
When the question asks about goals, vision, acceptance criteria, business logic,
preferences, tradeoffs, scope, or desired behavior for NEW features:
- Present question directly to user through the active runtime's
ask_user capability with suggested options
- Prefix answer with
[from-user] when sending to MCP
PATH 3 — Code + Judgment (facts exist but interpretation needed):
When code contains relevant facts BUT the question also requires judgment
(e.g., "I see a saga pattern in orders/. Should payments use the same?"):
- Use the active runtime's
inspect_code capability to read relevant code first
- Present BOTH the code findings AND the question to user
- If any part of the question requires judgment, route the ENTIRE question to user
- Prefix answer with
[from-user] (human made the decision)
PATH 4 — Research Interlude (external knowledge needed):
When the question asks about third-party APIs, pricing models, library
capabilities, version compatibility, security advisories, or industry
standards that are NOT answerable from the local codebase:
- Use the active runtime's
web_research capability to gather external information
- Present findings to user as a confirmation question through the active runtime's
ask_user capability
(same pattern as PATH 1, but with web sources instead of code):
{
"questions": [{
"question": "MCP asks: What rate limits does the Stripe API have?\n\nI found: Stripe allows 100 read ops/sec and 25 write ops/sec in live mode.\n\nIs this correct?",
"header": "Q<N> — Research Confirmation",
"options": [
{"label": "Yes, correct", "description": "Use this as the answer"},
{"label": "No, let me correct", "description": "I'll provide the right answer"}
],
"multiSelect": false
}]
}
- Prefix answer with
[from-research] when sending to MCP
- If the user picks "Yes, correct", send the concise factual answer with
[from-research] and do not apply the Refine gate. Increment the
auto-confirm counter (see Dialectic Rhythm Guard below).
- If the user picks "No, let me correct", immediately use the
ask_user capability to collect the corrected answer as free text:
{
"questions": [{
"question": "What should I send instead for this MCP question?\n\nMCP asks: What rate limits does the Stripe API have?\n\nInclude any source correction, reasoning, constraints, or scope that should be preserved.",
"header": "Q<N> — Research Correction"
}]
}
- Route the correction text through the Refine gate before sending it to
MCP. Send the multi-section payload with
[from-user][refined] (the
human is now the source of the corrected answer).
- If the user supplies a correction directly without using the option, treat
that free text the same way: Refine first, then send with
[from-user][refined].
- Reset the Dialectic Rhythm Guard counter to 0 because the corrected
answer is direct user judgment, even though it was initiated from a code
or research confirmation path.
- Facts, not decisions: "Stripe rate limit is 100 req/s" is research.
"We should use Stripe" is a DECISION — route to PATH 2.
When in doubt, use PATH 2. It's safer to ask the user than to guess.
-
Send the answer back to MCP:
When the user explicitly introduces a new reference or asks what a domain
term means, include the matching references or confused_terms argument on
that call. Do not put product decisions into glossary/reference fields; keep
those decisions in the user answer.
Payload format — preserve the user's reasoning, do NOT compress to one line.
MCP cannot read code, browse the web, or call tools. The text you send is
the only context MCP has when generating the next question. A one-line
answer collapses the user's reasoning, constraints, and scope decisions
into a label, which degrades both the next question's quality and the
ambiguity scoring. Send the user's full reasoning, structured.
Single-line answers are OK only for PATH 1a auto-confirmed facts,
PATH 1b / PATH 4 pre-built option confirmations where the factual
answer is already explicit, and short PATH 2 answers that have no reasoning
or constraints attached (e.g., "Yes" / "No" / "Python 3.12"). User
corrections, free-text reasoning, constraints, or scope decisions must be
sent as the multi-section payload below after the Refine gate.
Tool: ouroboros_interview
Arguments:
session_id: <session ID>
answer: |
[from-user][refined]
Decision: Stripe Billing.
Reasoning:
- Subscription is the core business model.
- Stripe bundles invoice/dunning/tax — avoids building those.
Constraints (user-stated):
- 30% Korean MAU, KRW required.
- Revenue recognition automation OUT OF SCOPE this quarter.
Out of scope (user-stated):
- Refund policy changes, tax-invoice issuance.
Codebase context (main session verified):
- src/billing/ does not exist yet.
- src/payments/toss_adapter.py is one-shot KRW only.
Short-answer cases (single-line OK):
"[from-code][auto-confirmed] Python 3.12, FastAPI (pyproject.toml)"
"[from-code] JWT-based auth in src/auth/jwt.py"
"[from-research] Stripe allows 100 read ops/sec and 25 write ops/sec in live mode"
"[from-user] Yes"
Append [refined] to an existing valid prefix ([from-code],
[from-user], or [from-research]) only when the answer has been through
the Refine gate (see Step 4). MCP records the answer, generates the next
question, and returns it.
-
Refine before forwarding (free-text answers only):
When the user gives a free-text answer that carries reasoning, constraints,
or scope decisions, do NOT forward it to MCP unmodified and do NOT compress
it to a label. Structure it into the multi-section payload above, then ask
the user a single ask_user capability to confirm nothing is lost:
{
"questions": [{
"question": "I structured your answer as follows before sending it to MCP:\n\n<multi-section payload>\n\nIs anything missing or misrepresented?",
"header": "Refine — preserve the structure of your answer",
"options": [
{"label": "Send as-is", "description": "The structure captures my answer faithfully"},
{"label": "Add to Constraints", "description": "I want to add a constraint I forgot"},
{"label": "Add to Out of scope", "description": "I want to mark something explicitly out of scope"},
{"label": "Add context", "description": "I want to add reasoning, code context, or research context"},
{"label": "Rewrite", "description": "Let me re-state the answer"}
],
"multiSelect": false
}]
}
The Refine gate replaces "compress to one line" with "preserve the user's
reasoning, surface anything missing." It is skipped for:
- PATH 1a auto-confirmed facts
- PATH 1b / PATH 4 confirmation answers where the user picked a pre-built
option (the structure is already explicit)
- Short PATH 2 answers (e.g., "Yes" / single proper noun) with no
reasoning attached
Exception — Restate corrections never skip Refine, regardless of length.
Any free-text follow-up collected by the Step 9 Restate gate
("Adjust wording" / "Missing scope") must go through Refine before being
forwarded to MCP. Even a short correction like
"Exclude retry scheduling from the seed." carries scope/boundary
information that MCP needs in structured form during the reopen call, so
the short-PATH-2 exemption above does NOT apply to Restate corrections.
A single-line Restate correction that bypasses Refine would forward
[from-user] instead of [from-user][refined] and would not trigger the
last_question reopen, leaving MCP on stale pre-correction state when
the seed is generated.
Refine-passed answers count as direct user judgment — they reset the
Dialectic Rhythm Guard counter to 0 (see below).
If the user picks "Add to Constraints", "Add to Out of scope", "Add context",
or "Rewrite", do not infer the missing text from the option label. Immediately
use the ask_user capability for one follow-up to collect the exact text:
{
"questions": [{
"question": "What text should I add or change before sending this to MCP?\n\nCurrent structured answer:\n\n<multi-section payload>",
"header": "Refine — Missing Text"
}]
}
Apply the follow-up text to the structured payload, then ask the Refine gate
once more. Do not send the payload to MCP while the user is still telling
you that required text is missing or the answer should be rewritten. If the
second Refine response again says "Add to Constraints", "Add to Out of
scope", "Add context", or "Rewrite", ask a targeted PATH 2 follow-up for the
exact missing text and withhold the MCP answer until the user either
supplies that text or explicitly accepts the structured payload. The
Add context option is handled identically to the other three on the
second pass — never infer omitted content from the option label, and prefer
stopping over forwarding a payload the user has identified as incomplete.
-
Mark the answer as Refine-passed:
Append [refined] to the prefix when sending the structured payload to
MCP (e.g., [from-user][refined]). MCP treats refined answers as
high-confidence ground truth for ambiguity scoring.
-
Keep a visible ambiguity ledger:
Track independent ambiguity tracks (scope, constraints, outputs, verification).
Do NOT let the interview collapse onto a single subtopic.
-
Repeat steps 2-6 until the user says "done" or MCP signals seed-ready.
-
Seed-ready Acceptance Guard (tri-panel fan-out):
When MCP signals seed-ready, do NOT relay completion blindly. Before
announcing completion or suggesting ooo seed, run the acceptance guard as a
3-lane fan-out instead of a single local check, so closure is pressure
-tested from three independent perspectives:
closer — apply the canonical Seed Closer criteria from
src/ouroboros/agents/seed-closer.md. This lane's verdict gates.
contrarian — challenge the interview's conclusions: hidden assumptions,
overloaded terms, decisions the interview skipped.
gap_hunter — hunt for missing requirements, unlisted constraints,
unhandled edge cases, and unverifiable acceptance criteria.
Spawn one subagent per lane through your runtime's native subagent mechanism
(Claude Code → one Task/Agent call per lane in one parallel batch; Codex →
one native Codex subagent per lane; runtimes with no parallel primitive →
process the lane payloads sequentially). Correlate results by
context.lane_id. Run the check from the main session's perspective,
including any code, research, or brownfield context MCP did not see.
Synthesis (deterministic): the closer verdict gates — if it is not
seed_ready, do not announce seed-ready. Additionally, any HIGH-severity
contrarian or gap_hunter finding blocks closure and its question is
appended to the blocking follow-ups. If closure is blocked, explicitly
override the MCP signal: "MCP says seed-ready, but I am not accepting it yet because <gap>." Explain the gap briefly and ask the single highest-impact
blocking follow-up question, routed through PATH 2 or PATH 3 as appropriate.
When no parallel primitive exists, running only the closer lane is the
backward-compatible single-pass fallback.
-
Restate gate (only after Seed-ready Acceptance Guard passes):
Once the Acceptance Guard passes, do not jump straight to ooo seed.
First restate the agreed goal as a single sentence and ask the user to
confirm it captures the decision. This is the one place where compression
to a single line is the goal — every other answer in the interview was
sent to MCP in full multi-section form (see Step 3), and now we collapse
the accumulated agreement into a one-line goal that another person could
read and arrive at the same outcome.
{
"questions": [{
"question": "Based on the answers we agreed on, here is a one-sentence restatement of the goal:\n\n goal: <one-sentence restatement>\n\nIf someone else read only this line, would they arrive at the same outcome you have in mind?",
"header": "Restate — one-line goal before seed",
"options": [
{"label": "Yes, generate seed", "description": "The line captures the goal; proceed to ooo seed"},
{"label": "Adjust wording", "description": "The intent is right but I want to change words"},
{"label": "Missing scope", "description": "A condition or boundary is missing from the line"}
],
"multiSelect": false
}]
}
Only after the user accepts the restated line do you suggest ooo seed.
If the user picks "Adjust wording", immediately use the ask_user capability
to collect the replacement wording:
{
"questions": [{
"question": "How should the one-sentence goal be worded instead?\n\nCurrent line:\n goal: <one-sentence restatement>",
"header": "Restate — Wording"
}]
}
If the user picks "Missing scope", immediately use the ask_user capability
to collect the missing condition or boundary:
{
"questions": [{
"question": "What scope, condition, or boundary is missing from the one-sentence goal?\n\nCurrent line:\n goal: <one-sentence restatement>",
"header": "Restate — Scope"
}]
}
Treat the follow-up text as a real interview correction, not a local-only
wording tweak. Route the follow-up text through the Refine gate before
forwarding it. The Step 4 short-PATH-2 skip rule does NOT apply here,
even if the correction is a single sentence — a bare reply like
"Exclude retry scheduling from the seed." still encodes a boundary
decision that must reach MCP as [from-user][refined] with the reopen
last_question; sending it as [from-user] would leave MCP on the stale
pre-correction state. Then build the same structured multi-section
payload from Step 3 using the canonical five-section schema —
- Decision: the corrected one-line goal verbatim.
- Reasoning: why the wording/scope changed (carry over the user's
correction text, do not paraphrase).
- Constraints (user-stated): any constraint introduced or tightened
by the correction.
- Out of scope (user-stated): anything the correction marks as
explicitly excluded.
- Codebase context (main session verified): the file paths, configs,
or facts the main session checked while preparing the restated goal, or
omit the section entirely if no code reference is involved.
Send that structured restate correction back to MCP with
[from-user][refined], preserving the corrected goal line and the user's
stated wording or missing scope. Because this is a post-seed-ready follow-up
that MCP did not generate, call ouroboros_interview with both the
structured answer and last_question set to the exact local Restate
follow-up prompt you asked (for example, the "How should the one-sentence
goal be worded instead?" or "What scope, condition, or boundary is missing?"
question). Without last_question, the handler must reject the reopen rather
than attach the correction to a stale MCP question. Then return to Step 7 so
MCP can update its interview state and the Seed-ready Acceptance Guard can
run again against the updated state. Do not proceed directly to ooo seed
from the stale pre-correction MCP state.
After MCP returns seed-ready again and the Acceptance Guard still passes, ask
the Restate gate once more with the corrected goal line. Do not loop more
than twice; if alignment is not reached, route back to PATH 2 with a targeted
question instead of forcing a goal line.
-
Prefer stopping over over-interviewing:
When the Restate gate passes, suggest ooo seed.
-
After completion, suggest the next step:
◆ Current state → next: ooo seed to crystallize these requirements into a specification
Track consecutive non-user answers (PATH 1a auto-confirms, PATH 1b code
confirmations, and PATH 4 research confirmations). If 3 consecutive questions
were answered without direct user judgment (PATH 1a, 1b, or PATH 4), the next
question MUST be routed to PATH 2 (directly to user), even if it appears
code- or research-answerable.
This preserves the Socratic dialectic rhythm — the interview is with the human,
not the codebase or external docs. Auto-confirmed answers especially need this
guard: if the AI answers too many questions on its own, the user loses awareness
of what the AI is assuming about their project.
Reset the counter whenever user answers directly (PATH 2 or PATH 3), or when a
PATH 1b / PATH 4 correction is routed through the Refine gate and sent as
[from-user][refined]. Only accepted code/research confirmations advance the
non-user streak.