---
name: q00/interview
source: https://app.decimal.ai/s/q00-interview@4/SKILL.md
source_sha256: 760e9aa92198
---

# /ouroboros:interview

Socratic interview to crystallize vague requirements into clear specifications.


## Required Skill Capabilities

- `ask_user` — ask human-judgment questions through the active runtime's user-question surface.
- `inspect_code` — answer repo-local factual questions from exact local files before asking the user.
- `call_mcp` — use Ouroboros MCP tools for persistent interview state and seed generation.
- `run_lateral_review` — invoke lateral thinking subagents before milestone turns and direct-answer synthesis.
- `web_research` — fetch current external facts only when the interview genuinely depends on them.
- `run_shell` — run bounded local commands for version checks and repository inspection.
- `refine_answer` — confirm structured interpretations of free-text answers before forwarding them.
- `maintain_ledger` — keep ambiguity, gates, and unresolved decisions visible in the main session.
- `run_closure_gate` — audit readiness locally even when MCP reports `seed-ready`.
- `restate_goal` — restate the goal and require explicit approval before seed generation.

## Non-Skippable Gates

- Refine free-text answers that carry scope, constraints, or decisions.
- Maintain a visible ambiguity ledger in the main session.
- Treat MCP `seed-ready` as permission to audit closure, not as completion.
- Apply Seed Closer criteria before suggesting or running seed generation.
- Run the Restate gate before seed generation.
- Require explicit user approval before suggesting or running seed generation.

## Usage

```
ooo interview [topic]
/ouroboros:interview [topic]
```

**Trigger keywords:** "interview me", "clarify requirements"

## Instructions

When the user invokes this skill:

### Step 0: Version Check (runs before interview)

Before starting the interview, check if a newer version is available:

```bash
# Fetch latest release tag from GitHub (timeout 3s to avoid blocking)
curl -s --max-time 3 https://api.github.com/repos/Q00/ouroboros/releases/latest | grep -o '"tag_name": "[^"]*"' | head -1
```

Compare the result with the current version in the active runtime's local plugin metadata (for Claude installs this is `.claude-plugin/plugin.json`).
- If a newer version exists, ask the user through the active runtime's `ask_user` capability:
  ```json
  {
    "questions": [{
      "question": "Ouroboros <latest> is available (current: <local>). Update before starting?",
      "header": "Update",
      "options": [
        {"label": "Update now", "description": "Update plugin to latest version (restart required to apply)"},
        {"label": "Skip, start interview", "description": "Continue with current version"}
      ],
      "multiSelect": false
    }]
  }
  ```
  - If "Update now":
    - On Claude-plugin installs only:
      1. Run `claude plugin marketplace update ouroboros` via the active runtime's `run_shell` capability (refresh marketplace index). If this fails, tell the user "⚠️ Marketplace refresh failed, continuing…" and proceed.
      2. Run `claude plugin update ouroboros@ouroboros` via the active runtime's `run_shell` capability (update plugin/skills). If this fails, inform the user and stop — do NOT proceed to the package-manager step.
    - On non-Claude runtimes, skip Claude plugin commands and proceed directly to the package-manager step for `ouroboros-ai`; do not require Claude-only commands or tools.
    3. Detect the user's Python package manager and upgrade the MCP server:
       - Check which tool installed `ouroboros-ai` by running these in order:
         - `uv tool list 2>/dev/null | grep "^ouroboros-ai "` → if found, use `uv tool upgrade ouroboros-ai`
         - `pipx list 2>/dev/null | grep "^  ouroboros-ai "` → if found, use `pipx upgrade ouroboros-ai`
         - Otherwise, print: "Also upgrade the MCP server: `pip install --upgrade ouroboros-ai`" (do NOT run pip automatically)
    4. Tell the user: "Updated! Restart your session to apply, then run `ooo interview` again."
  - If "Skip": proceed immediately.
- If versions match, the check fails (network error, timeout, rate limit 403/429), or parsing fails/returns empty: **silently skip** and proceed.

Then choose the execution path:

### Step 0.5: Load MCP Tools (Required before Path A/B decision)

The Ouroboros MCP tools are often registered as **deferred tools** that must be explicitly loaded before use. **You MUST perform this step before deciding between Path A and Path B.**

1. Use the active runtime's tool-discovery capability to find and load the interview MCP tool:
   ```
   tool discovery query: "+ouroboros interview"
   ```
   This searches for tools with "ouroboros" in the name related to "interview".

2. The tool will typically be named `mcp__plugin_ouroboros_ouroboros__ouroboros_interview` (with a plugin prefix). After runtime tool discovery returns, the tool becomes callable.

3. If the tool is callable — already exposed, or loaded by discovery — proceed to **Path A**.
   An empty discovery result for an already-exposed tool is expected, not a failure.
   Proceed to **Path B** only if the tool is genuinely absent (no Ouroboros MCP server).

**IMPORTANT**: Do NOT skip this step. Do NOT assume MCP tools are unavailable just because they don't appear in your immediate tool list. They are almost always available as deferred tools that need to be loaded first.

**CRITICAL — deferred-schema guard (prevents "Invalid tool parameters"):**
This skill makes `ouroboros_*` MCP calls across multiple turns, and each turn runs
in a fresh tool context. A deferred tool's schema loaded on one turn is NOT
guaranteed to still be loaded on the next. If you call any `ouroboros_*` MCP tool
while its schema is not loaded in the **current** turn, the runtime rejects the
call with **"Invalid tool parameters"** before it ever reaches the server.
Therefore: **immediately before EVERY `ouroboros_*` MCP call in this skill, re-run
the tool-discovery load query for the specific MCP tool you are about to call**
(idempotent — a no-op when the schema is already loaded) so the correct schema is
guaranteed present for that call. Use `"+ouroboros interview"` before
`ouroboros_interview` and `"+ouroboros lateral"` before
`ouroboros_lateral_think`. If a load ever returns no matching tool (and the tool is not already callable — an empty load for an already-exposed tool is an expected no-op, not absence), switch to the
documented fallback / Path B instead of retrying the failing call.

### Path A: MCP Mode (Preferred)

If the `ouroboros_interview` MCP tool is available (loaded via runtime tool discovery above), use it for persistent, structured interviews.

**Architecture**: MCP is a pure question generator. You (the main session) are the answerer and router.

```
MCP (question generator) ←→ You (answerer + router) ←→ User (human judgment only)
```

**Role split**:
- **MCP**: Generates Socratic questions, manages interview state, scores ambiguity. Does NOT read code.
- **You (main session)**: Receives MCP questions, answers them by reading code through the active runtime's `inspect_code` capability, or routes to the user when human judgment is needed.
- **User**: Only answers questions that require human decisions (goals, acceptance criteria, business logic, preferences).

#### Interview Flow

1. **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.

2. **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.

   Read the stamped dispatch contract before running the lanes. With
   `dispatch_mode="host_driven"`, use the declared native parallel mechanism.
   With `dispatch_mode="host_decides"`, use native parallel fan-out when the
   current host exposes it and otherwise process the same payloads sequentially.
   With `dispatch_mode="sequential"`, process payloads in order. For Claude Code
   the parallel mechanism is Task/Agent; for Codex, explicitly start one native
   subagent per payload in a single fan-out turn. Wait for every result, then
   synthesize. 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.
   - `data_context` — take the measurements that inform the question.
     This lane takes the measurement; see "Data measurements" below.
   - `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 process every
   payload: treat each entry as spawn-ready advisory work with `title`, `agent`,
   `prompt`, and `context`, and pass its prompt unchanged. Obey
   `meta.question_advisory_host_action`: `spawn_subagents` means parallel support
   was declared; `dispatch_subagents_if_supported` means use native parallel
   dispatch when available and sequential fallback otherwise;
   `process_payloads_sequentially` means ordered processing is required. This is
   required regardless of mode—the payloads themselves are the work contract,
   while the host action selects the execution strategy. Never reconstruct
   prompts from prose. Preserve the original question text while 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:
   - `session_id`: the session the fan-out was issued under. Required whenever
     the producer ran with one — an omitted session is refused rather than
     waived, because this is what binds a submission to its owner. Contracted
     lanes assert no session of their own; this argument is the binding.
   - `fanout_id`: the stamped id from that meta,
   - `correlation_key`: the stamped `result_correlation_key`
     (`context.lane_id`, `context.persona`, or `code_facts`). Omitting it is
     refused the same way whenever the fan-out recorded one — send back what the
     meta stamped rather than leaving it out,
   - `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`).
   Every result must be either `{ "key": <lane>, "content": ... }` or exactly
   `{ "key": <lane>, "undispatched": true }` — the literal `true`, no `content`
   beside it, and never an entry carrying neither. One entry per lane: a lane
   reported twice is two statements about it, and nothing here picks between
   them by list position. Anything else comes back as
   `status="invalid_result_entry"` with `invalid_keys`, listing every bad entry
   at once so one resubmission fixes them all.

   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 explicit 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** — no submitted output is
   kept between calls, so each call is judged on what it carries. (The record
   stores only what was *asked*; retaining what children *answered* is durable
   result state, deferred with its sanitization duties to a later slice.)
   Sequential hosts submit after processing payloads one-by-one — same tool,
   same contract, so accumulate the outputs on your side and send the growing
   set. Continue the interview from the fetched synthesis; keep the
   user-facing question visible throughout.

   Only lanes marked `required: true` in the request block completion. A lane
   you ran that had nothing to say still submits its output — that is an answer.
   A lane you could **not spawn at all** (no capability for it, the child died,
   the user cancelled it) is submitted as
   `{ "key": <lane id>, "undispatched": true }`. Never invent output for a lane
   you did not run: a fabricated finding is worse than a missing one, and this
   is exactly why the declaration exists.

   **Data measurements**:
   The `data_context` lane discovers what data tools this host exposes, takes
   the measurement itself, and returns the aggregate it read.
   You do not confirm anything before it runs and you do not run anything after
   — it has already happened by the time you read the result. There is nothing
   to approve because the approval already exists: the user registered these
   tools, and registering one is the willingness to have it called. That is the
   standing every other advisory lane runs on, and this lane was the only one
   asked to hold a line in prose that its siblings did not.

   When its output carries measurements:
   - Show the numbers **beside** the question as material for the user's
     judgment. They are never the answer. The user answers in their own words
     on the ordinary `[from-user]` path; there is no `[from-data]` answer to
     forward. This is now the whole of the boundary: the lane carries real
     values, so the only thing standing between a measurement and the Seed is
     that you put it next to the question instead of into the answer.
   - 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 across
     measurements; you did not run the read and cannot know what would survive
     the arithmetic.
   - If the user has already answered the question by the time the measurement
     arrives, drop it. Do not re-open a decision the user has made, and do not
     present the numbers as a reason to reconsider — evidence informs a
     decision, it does not revisit one.

   When `data_needed` is false the lane looked and found nothing to measure.
   Every reason it can give is a statement about the lane, never about the
   user's infrastructure — a subagent sees what reached it, not what is
   connected, so it is not positioned to tell anyone a data path is missing.
   Read them accordingly:
   - `not_a_measurement` / `question_too_ambiguous_to_measure` — about the
     question. Nothing to relay beyond moving on.
   - `answer_would_not_be_an_aggregate` — about the shape of the answer.
   - `no_data_store_described` — nothing the lane was shown holds this answer.
     Worth mentioning only if you know the store exists and the lane was not
     told about it; otherwise it is ordinary.
   - `store_described_but_not_callable` — **this one is yours to handle, not
     the user's to hear.** A store exists and the child could not reach it. You
     see the environment and it does not: check whether the tool is available to
     you, take the read yourself, or re-dispatch the lane. Do not surface it as
     a missing data path. This constant exists because its predecessor was
     relayed to a user as a fact about their own infrastructure while the store
     in question sat described in the child's prompt.

   `no_evidence_reason` is one of a fixed set of constants, so say it in your
   own words rather than pasting the constant.

   What this lane can reach is not classified by anyone. The child names the
   tool it used; it cannot prove that tool was read-only, and MCP carries no
   cost or mutation metadata for you to check against. That risk is accepted
   knowingly and is the same one the sibling advisory lanes already run under.
   Do not manufacture a disclaimer about it: a warning attached to every
   measurement is one users learn to click through, and it would be
   describing a check nothing performed.

   **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:
     ```json
     {
       "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:
     ```json
     {
       "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):
     ```json
     {
       "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:
     ```json
     {
       "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.

3. **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.

4. **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:

   ```json
   {
     "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:
   ```json
   {
     "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.

5. **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.

6. **Keep a visible ambiguity ledger**:
   Track independent ambiguity tracks (scope, constraints, outputs, verification).
   Do NOT let the interview collapse onto a single subtopic.

7. **Repeat steps 2-6** until the user says "done" or MCP signals seed-ready.

8. **Seed-ready Acceptance Guard**:
   When MCP signals seed-ready, do NOT relay completion blindly. Before
   announcing completion or suggesting `ooo seed`, apply the canonical Seed
   Closer criteria from `src/ouroboros/agents/seed-closer.md` as the single
   source of truth for closure readiness. Run the check from the main session's
   perspective, including any code, research, or brownfield context MCP did not
   see.

   If any material decision remains unresolved, do not announce seed-ready.
   If the local challenge finds a material gap, 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 follow-up question,
   routed through PATH 2 or PATH 3 as appropriate.

9. **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.

   ```json
   {
     "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:
   ```json
   {
     "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:
   ```json
   {
     "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.

10. **Prefer stopping over over-interviewing**:
   When the Restate gate passes, suggest `ooo seed`.

11. After completion, suggest the next step:
   `📍 Next: ooo seed to crystallize these requirements into a specification`

#### Dialectic Rhythm Guard

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.

#### Retry on Failure

If MCP returns `is_error=true` with `meta.recoverable=true`:
1. Tell user: "Question generation encountered an issue. Retrying..."
2. Call `ouroboros_interview(session_id=...)` to resume (max 2 retries).
   State (including any recorded answers) is persisted before the error,
   so resuming will not lose progress.
3. If still failing: "MCP is having trouble. Switching to direct interview mode."
   Then switch to Path B and continue from where you left off.

**Special case — `meta.reason == "initial_context_too_large"`**: When the
response carries this `meta.reason` (with `meta.recoverable=true` and
`is_error=false` — the wire success/failure axis is intentionally **not**
flipped, to keep existing callers like the auto driver working), the text
body is a meta-directive asking *you* to re-send a shorter context — it is
**NOT** an interview question. Do not route it through the active runtime's `ask_user` capability.
Instead, produce a concise summary of the original `initial_context`
(≤ `meta.max_chars` characters; covers goal, constraints, success criteria)
and re-call `ouroboros_interview` with `session_id=<from meta>` and the
summary as `answer`. The next response will contain the real first question.

**Advantages of MCP mode**: State persists to disk, ambiguity scoring, direct `ooo seed` integration via session ID. Code-enriched confirmation questions reduce user burden — only human-judgment questions require user input.

### Path B: Plugin Fallback (No MCP Server)

If the MCP tool is NOT available, fall back to agent-based interview:

1. Read `src/ouroboros/agents/socratic-interviewer.md` and adopt that role
2. **Pre-scan the codebase**: Use the active runtime's `inspect_code` capability to check for config files (`pyproject.toml`, `package.json`, `go.mod`, etc.). If found, inspect key files and incorporate findings into your questions as confirmation-style ("I see X. Should I assume Y?") rather than open-ended discovery ("Do you have X?")
3. Ask clarifying questions based on the user's topic and codebase context
4. **Present each question using the active runtime's `ask_user` capability** with contextually relevant suggested answers (same format as Path A step 2)
5. Use the active runtime's `inspect_code` and `web_research` capabilities to explore further context if needed
6. Maintain the same ambiguity ledger and breadth-check behavior as in Path A:
   - Track multiple independent ambiguity threads
   - Revisit unresolved threads every few rounds
   - Do not let one detailed subtopic crowd out the rest of the original request
7. **Apply the Refine gate** (Path A Step 4) to free-text user answers before
   absorbing them into your running understanding. The structure preservation
   matters less here than in Path A (no MCP relay), but the "did I miss any
   reasoning, constraints, or scope?" check still surfaces gaps.
8. Prefer closure only after applying the Seed-ready Acceptance Guard above.
   Then **apply the Restate gate** (Path A Step 9): collapse the agreed answers
   into a one-sentence goal and confirm with the user before suggesting `ooo seed`.
   In fallback mode there is no MCP state to refresh, so if the user picks
   "Adjust wording" or "Missing scope", ask the same follow-up questions from
   Step 9, apply the correction directly to the local interview ledger and
   one-sentence goal, rerun the Seed-ready Acceptance Guard locally, and ask the
   Restate gate again with the corrected goal line. Do not try to "send it back
   to MCP" in Path B; the conversation context is the source of truth.
9. Continue until the user says "done"
10. Interview results live in conversation context (not persisted)
11. After completion, suggest the next step in `📍 Next:` format:
   `📍 Next: ooo seed to crystallize these requirements into a specification`

## Interviewer Behavior

**MCP (question generator)** is ONLY a questioner:
- Always generates a question targeting the biggest source of ambiguity
- Preserves breadth across independent ambiguity tracks
- NEVER writes code, edits files, or runs commands

**You (main session)** are a Socratic facilitator:
- Read `src/ouroboros/agents/socratic-interviewer.md` to understand the interview methodology
- You CAN use the active runtime's `inspect_code` capability to scan the codebase for answering MCP questions
- For high-confidence factual questions (PATH 1a), auto-confirm and notify the user
- For all other questions, present to user as confirmation or direct question
- You NEVER make decisions on behalf of the user — auto-confirm is for FACTS only
- You are the final gate on MCP seed-ready signals: apply the canonical Seed
  Closer criteria before suggesting `ooo seed`
- The Dialectic Rhythm Guard prevents over-automation: after 3 consecutive
  non-user answers, the next question MUST go directly to the user

## Example Session

```
User: ooo interview Add payment module to existing project

MCP Q1: "Is this a greenfield or brownfield project?"
→ PATH 1a: exact match in pyproject.toml + src/ directory
→ ℹ️ Auto-confirmed: Brownfield, Python 3.12 / FastAPI (pyproject.toml)
→ [from-code][auto-confirmed] sent to MCP (counter: 1)

MCP Q2: "What payment provider will you use?"
→ PATH 2: human decision — no code can answer this
→ User: "Stripe"
→ [from-user] sent to MCP (counter reset to 0)

MCP Q3: "What authentication method does the project use?"
→ PATH 1b: found src/auth/jwt.py but inferred (not manifest)
→ "I found JWT-based auth in src/auth/jwt.py. Is this correct?"
→ User: "Yes, correct"
→ [from-code] sent to MCP (counter: 1)

MCP Q4: "How should payment failures affect order state?"
→ PATH 2: design decision
→ User: "Saga pattern for rollback"
→ Refine gate structures the answer
→ User: "Add to Out of scope"
→ Follow-up asks for exact missing text
→ User: "Do not build automatic retry scheduling yet"
→ Refine gate runs once more, then [from-user][refined] sent to MCP (counter reset to 0)

MCP Q5: "What are the acceptance criteria for this feature?"
→ PATH 2: requires human judgment
→ User: "Successful Stripe charge, webhook handling, refund support"
→ Refine gate passes; [from-user][refined] sent to MCP

MCP signals seed-ready; Acceptance Guard passes
→ Restate: "Add Stripe payments with charges, webhooks, refunds, and failed-payment rollback."
→ User: "Missing scope"
→ Follow-up asks for exact missing scope
→ User: "Exclude retry scheduling from the seed."
→ Refine gate structures the restate correction
→ [from-user][refined] restate correction sent to MCP; return to Step 7/Seed-ready guard
→ MCP signals seed-ready again; Acceptance Guard still passes
→ Restate again: "Add Stripe payments with charges, webhooks, refunds, failed-payment rollback, and no retry scheduling."
→ User: "Yes, generate seed"

📍 Next: `ooo seed` to crystallize these requirements into a specification
```

## Next Steps

After interview completion, use `ooo seed` to generate the Seed specification.