Transform unstructured brain dumps into implementation artifacts through a conversational interview that builds shared understanding before writing anything. HTML is for interactive decision-making (visualizations, comparisons, the contract); Markdown is for reference documents (specs, PRDs).
-
Name the project yourself and say so — the interview just produced the evidence for every gate, so the name is inferable; kebab-case it into the slug. State it in one line (Calling this "{name}" → docs/ideation/{slug}/) rather than asking. The user corrects it in passing if it's wrong, and a rename here costs one git mv before anything references the slug. Ask only when the brain dump genuinely covers two separable projects and the split decides what gets built.
-
Create ./docs/ideation/{slug}/. (Resumed project: the slug and directory already exist. Reuse both, don't re-name the project, and let the generator's lineage rules handle the re-render: a Draft is replaced in place, an Approved contract is snapshotted to contract-{date}.html with the supersedes link set.)
-
Write contract-data.json there. The schema is the types in ${CLAUDE_PLUGIN_ROOT}/scripts/contract-gen.ts — read them when unsure; the generator also validates at render time and rejects a malformed file naming the exact criterion, before writing anything. Minimal shape:
{
"projectName": "Human-Readable Name",
"slug": "kebab-case-name",
"date": "YYYY-MM-DD",
"status": "Draft",
"gates": {
"dimensions": [
{ "key": "problem", "label": "Problem Clarity", "status": "ready", "evidence": "One sentence citing the artifact" }
]
},
"problem": ["paragraph"],
"goals": ["Measurable goal"],
"successCriteria": [
{ "criterion": "Pass/fail criterion", "check": { "cmd": "npx vitest run src/auth", "expect": "exits 0" } },
{ "criterion": "Judgment-only criterion", "check": { "judgment": "who looks at what" } }
],
"scope": {
"mvp": [{ "item": "Core feature", "reason": "Why it's MVP" }],
"outOfScope": [{ "item": "Excluded item", "reason": "Why excluded" }]
},
"decisions": [{ "decision": "What was chosen", "rejected": "The alternative", "reason": "Why it lost" }],
"openQuestions": [{ "id": "idp-token-ttl", "question": "What TTL does the identity provider allow?", "gate": "criteria", "type": "research" }],
"execution": {
"strategy": "Sequential",
"phases": [{ "title": "Phase name", "risk": "low", "blocking": true, "specPath": "docs/ideation/slug/spec-phase-1.md", "notes": "What this phase covers" }]
}
}
Semantics no schema can express: the five gate dimensions are exactly the rubric's gates with their canonical keys/labels (${CLAUDE_PLUGIN_ROOT}/references/confidence-rubric.md) — a real file carries all five, each with one-sentence evidence; proceed only when all 5 are ready, recording not-ready gates only on an early-stopped interview. Write openQuestions only when the interview left a gate open on work it couldn't do itself: one entry per question the engine wrote, each gate matching a dimensions key, and blockedBy carrying the ids of other entries, omitted entirely when the question is takeable now. A resumed interview drops the entries it closed and rewrites that gate's evidence to cite what closed them. An open question never marks a gate ready; it is the reason the gate is open. check is a union: {cmd, expect} whenever a command can verify the criterion — scripts/verify.mjs executes every cmd at acceptance time — or {judgment} naming who looks at what (rendered with a visible "judgment call" tag, printed but never counted by verify; the success-criteria critic challenges any judgment where a command is plausible). Never author the legacy plain-string check form. Record each decisions entry at the moment the user rejects an alternative, not reconstructed later; rejected is optional when no concrete alternative was on the table. scope.full/stretch/future and supersedes are optional; phase fields also allow kind: "gate" (human checkpoint) and prereqs (phase titles). Two top-level fields belong to the express finish and are written only when step 7's routing chooses it: approvalMode ("express") and branch (isolation branch autopilot re-asserts). status stays "Draft" here — run commands appear when Phase 5 flips it to "Approved".
-
Fan out the plan critics (before rendering — fixing a blocker is a one-line JSON edit at this stage, not a regenerate loop). Issue all four Agent calls in one message so they run concurrently: subagent_type: ideation:plan-critic, prompt = per-invocation inputs only (contract-data.json path, project directory, and the lens — one of scope-creep, over-engineering, hidden-dependency, success-criteria); workflow/format/read-only tools come from the registered definition and are platform-enforced. Agent names differ by harness — see ${CLAUDE_PLUGIN_ROOT}/references/harness-compat.md § 2: in pi, issue one dispatch call with four tasks, each carrying the lens in its task, the body of ${CLAUDE_PLUGIN_ROOT}/agents/plan-critic.md as systemPrompt, and the default read-only tools. Same agent, same prompt, same lens.
Act on findings: each blocker → revise contract-data.json to resolve it (re-tier a scope item, add a phase prereq, rewrite a criterion); if a blocker exposes a genuine unknown rather than a fixable defect, return to the interview loop for that gate. Each notable → fold in if clearly right, else carry to the digest with a one-line dismissal. nit → digest mention only. Every critic-blocker fix that changes the plan also appends a decisions entry recording what changed and what the pre-fix approach was — otherwise critic-driven revisions evaporate after the transient digest.
Failure tolerance: a failed critic or an unregistered ideation:plan-critic (older Claude Code) → warn, proceed without that lens, note the gap in the digest. Critics amplify quality; never block the contract on a critic failure. Run-once rule: critics run exactly once per contract — re-run only if a revision changes goals or scope fundamentally, not for wording. The "Needs changes" approval loop does not re-trigger them.
-
Run the generator (it handles lineage — an existing Approved contract.html is renamed to contract-{date}.html with the supersedes link set; a Draft is replaced in place, so interview revisions and the Draft→Approved flip don't accumulate snapshots):
node ${CLAUDE_PLUGIN_ROOT}/scripts/contract-gen.ts \
--input ./docs/ideation/{slug}/contract-data.json \
--output ./docs/ideation/{slug}/contract.html
(Plain node works on Node ≥ 22.18 via type stripping; npx --yes tsx remains a fallback on older Node — but npx is denied in unattended runs, so prefer node.) After the Generated … line the generator prints {N} criteria ({M} cmd, {K} judgment) — capture it; the routing steps below read this count instead of eyeballing the criteria. The generator is the only renderer for contract.html. There is no fallback template — never hand-write the contract HTML or "render it from a template" if the generator can't run. If the command is denied by permissions (common when the plugin root is outside the current repo — the classifier flags an out-of-repo script as untrusted code), do not work around the denial and do not hand-render — the denial message may say you "may attempt other tools to accomplish this goal"; for this step that does not apply, since any other tool means hand-authoring the contract. Instead show the user the exact command and ask them to run it themselves by typing ! node … in the prompt, then continue once contract.html exists. Run the generator and open as separate Bash calls — never chained with && — so a denial of one is visible and doesn't silently skip the other.
-
Open it: open ./docs/ideation/{slug}/contract.html (macOS) or xdg-open (Linux).
-
Present the Critic digest and a contract summary, then ask for approval and routing in one call. Only ask once contract.html was actually generated and opened — never ask the user to approve a contract they haven't seen. Present in the terminal, in order:
- Critic digest — one line per lens:
found N (B blockers folded in, M notables, dismissed X — reasons); note any skipped lens; if all four returned SOUND, say so.
- Summary block — counts, not tables: quote the generator's printed
{N} criteria ({M} cmd, {K} judgment) line; then the top checks (up to 3) verbatim; then scope tier counts ({a} MVP · {b} Full · {c} Stretch · {d} out of scope). Do not render the full criteria table in the terminal — the opened contract shows every criterion with its check; point the user at it for the detail.
- Routing recommendation — derived from the interview's evidence, with the reason named in the option description. Recommend the express finish when all 5 gates went ready without an early stop AND the generator's count has
cmd > judgment; anything else, recommend full review and say why in one line, citing the count (e.g. "9 criteria (3 cmd, 6 judgment) — unattended verification can't certify them", or "the interview ended early with Scope not-ready"). The user always chooses.
Then ONE AskUserQuestion call carrying two independent questions (when the routing answer was pre-committed by the /ideation:express alias, ask the Express finish path's run-mode question in its place, keeping the one consolidated confirmation):
Question 1: "Which scope tier should we target?"
Options:
- "Full (Recommended)" - Build MVP + Full tiers
- "MVP" - Ship the minimum viable version first
- "Stretch" - Include MVP + Full + Stretch tiers
Question 2: "Approve the contract — and how should we finish?"
Options:
- "Approve — express finish" - One-pass finish: specs generate with no further approval questions and execute immediately on an isolation branch. {reason, when recommended}
- "Approve — full review" - Interactive review continues: spec approval, then the handoff menu. {reason, when recommended}
- "Needs changes" - Some parts need revision before approving
Early-stopped interview: when the user ended the interview with not-ready gates, omit the express-finish option entirely — don't merely de-recommend it. The full path records not-ready gates for a human to weigh during review; an express finish would implement a known-unresolved gate headlessly. A contract carrying openQuestions is omitted the same way — an open question exists only where a gate is open. Say what that gate now holds (the open questions naming what would close it, plus what each one waits on) and how to pick it up: point ideation at docs/ideation/{slug}/ and the interview resumes on the open questions alone. Open questions are contract-level state read at review; they do not travel into specs.
The approved tier determines what goes into specs; items outside it move to "Future Considerations". If "Needs changes": revise (fundamental misunderstanding → back to the interview loop; otherwise edit contract-data.json, re-run the generator, re-open) and re-ask both questions, iterating until approved. Do not proceed until explicitly approved. On "Approve — full review", continue to Phase 4. On "Approve — express finish", follow the Express finish path below.