Blueprint (Codex variant)
Turn a clean spec into a readable, implementation-ready plan: atomic vertical-slice tasks each with a Done when: shell proof, plain-language requirements, edge cases, ranked assumptions, and risks. The rigor lives in the proofs — not in ceremony.
This is the Codex CLI variant. Behaviourally identical to the Claude Code variant — only the user-interaction and cross-model-consensus invocations differ. Phase 7.6 is symmetric: this variant uses claude -p as the cross-model reviewer (the host is Codex, so Claude is "the other model"), optionally a diverse third model via OpenRouter, and codex exec as the same-family fresh-ctx self-assessor. Shared resources (roles/, scripts/, references/) come from the Claude variant tree via install-time symlinks.
Letter = spirit. If a rule blocks you from reaching the goal it was written for, the rule is wrong, not the goal. Don't look for a wording loophole — ask what the rule is protecting, and protect that.
Was
/clarify. Renamed to/blueprint(it's a planning tool).clarify/уточни спекуstill route here as aliases.
Usage
/blueprint <spec.md> [--consensus-rounds N]
--consensus-roundsdefaults to 3. Set it to 0 to skip the cross-model consensus loop (Phase 7.6) — only internal validation runs.- Third reviewer (optional, opt-in): if
OPENROUTER_API_KEYis set, Phase 7.6 adds one diverse frontier model via OpenRouter (defaultz-ai/glm-5.2, override withOPENROUTER_MODEL) as an independent finder alongsideclaude -p. No key → it stays Claude + Codex-self-assess, no error.
Weaknesses and when NOT to use
- Slow and thorough — overkill for hour-long tasks. Decomposition + Done-when proofs + edge cases + 3 consensus rounds (if claude CLI is available) take 10-15 minutes. For smaller tasks, write the plan by hand.
- Does not work on raw chat exports or unstructured notes. The input spec must already be sectioned with
##(after/cleanup). Otherwise — abort. - Not suited for product-style PRDs. This skill forces a
Done when:shell proof per task; for freeform product-management PRDs (success metrics, not shell proofs) it's the wrong tool. - Phase 7.6 needs at least one external reviewer. Best signal: the
claudeCLI on$PATH(npm@anthropic-ai/claude-code), invoked asclaude -pwithroles/codex-reviewer.md. Optionally a third model via OpenRouter (OPENROUTER_API_KEY). With neither — fallback to single-modelcodex execofroles/spec-validator.md(weaker). - Not for autonomous orchestration. The output has no
[P]markers, Stages, or dependency graphs — the execute pipeline was removed in v2.0. - Non-interactive mode (
codex execinvocation of/blueprintitself). The clarifying questions (step 2), Scope-cut audit (step 5), approval (step 9), and backup disposition (step 10) need user input via TUI. Fromcodex execwithout TTY, fail with an explicit error rather than auto-resolving. Must run fromcodexTUI.
How to do it wrong vs right
Task proof (Done when:)
❌ Wrong: Done when: the endpoint works.
- "Works" — who decides? No command. Boolean — no UNKNOWN.
✅ Right: Done when: \curl -sw '%{http_code}' :8080/api/users -o /dev/null` prints 200 in <200ms.`
- Concrete numbers, a runnable command. Tristate: PASS / FAIL / UNKNOWN.
Task scope
❌ Wrong: ### TASK-1: Implement authentication system — many files, mixed purposes, not one-command verifiable.
✅ Right: ### TASK-1: Create User model in src/models/user.py with email/password
- 1 file, one deliverable.
Done when: \python -c "from src.models.user import User; User(email='a@b',password='x')"` runs clean.`
Cross-model consensus disagreement
❌ Wrong: A reviewer returns "requirement X looks unusual, suggest removing it". I apply it — I remove it.
- The user added it on purpose. Removing it stomps their intent.
✅ Right: Issue type = NEEDS_USER (the reviewer flagged it, or the Codex self-assessor reclassified). Prompt the user with both views via numbered TUI list. The user decides.
Implicit scope reduction
❌ Wrong: Input mentions "batch user creation" and "admin role for DELETE". I tag them [later] and move on; "rate limiting" → Non-goals, without asking.
- The user wrote those on purpose. Tagging
[later]silently == deleting a user-stated requirement.
✅ Right: Step 5 has a hard-gate Scope-cut audit with numbered TUI prompts. Anything tagged [later], moved to Non-goals, or dropped from a task's coverage is surfaced before the plan is written. Per item: Keep deferred / Include in v1 / Drop entirely. Nothing quietly downgraded.
Writing style for the plan
The "challenge the task" and "assumptions & open questions" moves are borrowed from malakhov-dmitrii/fusion (MIT). Applies in step 2 (questioner) and steps 3-5.
Challenge the task before decomposing (multi-angle)
Before turning notes into tasks, spend one pass questioning the task itself: what if we don't build it (need met another way)? a much simpler version (80/20)? does the right shape depend on a future plan? which scenarios flip the answer (scale, single- vs multi-tenant, offline)? If a cheaper framing is plausible, surface it as a step-2 TUI question — don't silently commit to the literal reading.
Sharpen fuzzy language
When the input uses vague terms ("user", "account", "system", "data"), propose a precise canonical term and ask which the user means via TUI prompt. Push for precision until the next reader can't misread it.
❌ Fuzzy: "Users can manage their subscriptions" ✅ Sharp: "Subscription owners (Customer accounts) can cancel/resume their own subscriptions; admins can on behalf of any Customer."
Be opinionated about terminology
Pick ONE canonical term per concept and keep it through the whole plan. Map to a code type where one exists; note aliases in a brief "Terminology" preamble if the ambiguity is worth flagging.
Keep requirements tight and plain
Each requirement is one plain sentence, tagged [must] / [nice] / [later] — no RFC-2119 MUST/SHOULD/MAY shouting, no forced FR-NNN ids (add light R1/R2 ids only for big specs needing task↔requirement links). WHAT, not HOW. Details: references/contracts.md.
❌ Ceremonial: FR-001: The auth middleware MUST verify the signature, check expiration, return 401...
✅ Plain: - [must] Bad tokens (missing / expired / wrong signature) → 401.
Stress-test edge cases with concrete scenarios
Each edge case is a concrete input + expected output, written inline (Edge: ...).
❌ Abstract: "Edge case: empty request body."
✅ Concrete: Edge: POST /users with body {} (no email) → 400 {error:"email_required"}.
Cross-reference with code
If the codebase has paths/types matching spec terms, read them. If code says X and the spec says Y, surface the conflict in step 2 via TUI prompt.
❌ Stale: Spec says POST /users {email, name}; code already accepts {email, name, phone}. Plan written as-is.
✅ Reconciled: "Spec says POST {email, name}; code already accepts phone. Regression, or forgot phone?" — ask first.
Vertical slices, not horizontal layers
Each task cuts through ALL relevant layers end-to-end (schema → API → UI → tests). A finished slice is demoable on its own. Many thin slices over few thick ones.
❌ Horizontal: TASK-1 "all DB columns"; TASK-2 "all API"; … Nothing demoable until task 3. ✅ Vertical: TASK-1 "email on User: column + API + form + test"; TASK-2 "phone: same set."
Foundations first — don't start in mid-air, don't bury the scaffold
The first task leaves the project runnable/verifiable, so every later Done when: has something to run against. Greenfield → first task creates the minimal skeleton + smoke test; Done when: proves a fresh clone goes green (npm ci && npm test exits 0 with ≥1 passing test; uv run pytest -q collects+passes one). Brownfield → first task is a one-line baseline proof the build/test is green (make test exits 0); pins the starting state /verify-done re-checks first. No buried scaffold: the harness/fixtures/CI live in that task and are reused via **Leverage**: <foundation task> harness — never re-created as a side effect of a feature task. Order, don't graph: group by area, each area exactly once, prerequisites above dependents; the only sequencing is that order + an inline · after TASK-x in the checklist. No Stages, [P], or dependency graph.
Behavioural Done when:, not procedural
The proof describes what the system DOES (observable through its interface), not HOW.
❌ Procedural: Done when: middleware extracts the token, calls validateJWT(), returns 401.
✅ Behavioural: Done when: \curl -H 'Auth: ' :8080/me` → 401 {error:"token_expired"}.`
One place for what needs a human — ## Needs your attention
Everything that needs you goes in ONE block at the top of the tasks file — never scattered across both files and a dozen per-task Status: lines.
tasks.md → ## Needs your attention (omit the heading on a clean plan). Two kinds of line: blocking forks — ❓ NEEDS YOU with a light tag ([decision]/[question]/[unknown]), each ending in → blocks: TASK-n[, TASK-m] (or → blocks: all); HITL tasks — HITL: TASK-n — title (why), one per task carrying **Mode**: HITL.
reference.md → ## Assumptions — ranked non-blocking assumptions only (high/medium/low + basis). Blocking ❓ NEEDS YOU do NOT appear here. No item in both files.
# tasks.md
## Needs your attention
- ❓ NEEDS YOU [decision]: is DELETE admin-only? (input was ambiguous) → blocks: TASK-11
- HITL: TASK-3 — auth design call (pick session vs bearer before building)
# reference.md
## Assumptions
- Assume Postgres (high — matches src/db).
- Assume JWT, not sessions (medium — input didn't say).
tasks.md: checklist on top, full task blocks below
The tasks file holds the whole plan — checklist first, detail after — so it's scannable + trackable. The reference is the "why" only.
tasks.md→## Checklist— one line per task,- [ ] TASK-n — short title(bareTASK-n, never### TASK-n), grouped under**▸ AREA-n**(each group once, foundations-first), light flags· after TASK-x/· HITL/· ❓. At-a-glance map + checkbox tracker. No graph, no[P], no Stages.tasks.md→## Tasks— the full### TASK-nblocks below the checklist (**Files**,**Leverage**,Done when:proof, inlineEdge:), grouped by▸ AREA-nin the same order.Done when:lives here —/verify-done+ goal-prep read the proofs from these blocks.reference.md→ context only (Overview/Requirements/Assumptions/Risks/Non-goals) — NO task blocks.- One-to-one: every
## Checklistline ↔ exactly one### TASK-nblock below.
Keep the plan concise and DRY — lossless
State each fact ONCE, cross-reference instead of repeating. Tighten prose to facts (cut filler, restatement) but never drop a fact — every requirement, decision, assumption, risk, edge, and code-pointer survives somewhere. No cross-section duplication (a fact lives in exactly one of Overview/Requirements/Assumptions/Risks/Non-goals or a task's ### TASK-n block; the ## Checklist line is just a pointer + title). Structured facts → a table. Merge near-duplicate prose/risks. Lossless check: every distinct fact from the original notes is still findable.
Roles
Step 2 (questioner pattern) and the Phase 7.6 consensus loop — templates live in roles/ (shared with the Claude variant via install-time symlinks):
roles/questioner.md— format contract for clarifying questions in step 2 (anAskUserQuestionformat spec for the Claude variant — in Codex, render as numbered TUI prompts). Includes the multi-angle challenge.roles/codex-reviewer.md— full prompt for the cross-model reviewer. Same file used by both variants. In the Codex variant: passed toclaude -pas stdin, with<spec_path>substituted.roles/openrouter-reviewer.md— full prompt for the optional third reviewer (a diverse frontier model via OpenRouter). The spec content is appended to the prompt body (the model has no file access).roles/codex-self-assessor.md— Phase 7.6 self-assessor for the Codex variant (mirror ofclaude-self-assessor.md). Categorizes the union of reviewer findings as ACCEPT / REJECT_PETTY / NEEDS_USER. Run viacodex exec -fresh subprocess.roles/spec-validator.md— fallback used inside Phase 7.6 when NO external reviewer is available.
Substitutions:
| Variable | Source |
|---|---|
{spec_path} |
the tasks file after step 6 (write) — <spec-stem>/tasks.md or <spec>.md |
{round} |
round counter in Phase 7.6 (1, 2, 3) |
{original_baseline} |
pre-enrichment content for the coverage check: the untouched <spec>.md (directory mode) or git show pre-blueprint:<spec> |
{reviewer_prompt} |
roles/codex-reviewer.md, <spec_path> substituted, passed as stdin to claude -p |
Invocations (Codex variant):
- Cross-model reviewer =
claude -p(Claude is the "other model" since host is Codex):command -v claude >/dev/null 2>&1 || { echo "claude CLI not installed; using fallback"; FALLBACK=1; } PROMPT="$(sed "s|<spec_path>|$SPEC_PATH|g" roles/codex-reviewer.md)" OUTPUT="$(printf '%s' "$PROMPT" | claude -p -)" FINDINGS="$(printf '%s' "$OUTPUT" | python3 -c ' import sys, re, json text = sys.stdin.read() matches = re.findall(r"```json\s*\n(.*?)\n```", text, re.DOTALL) print(matches[-1] if matches else json.dumps({"summary":"approve","findings":[]})) ')" - OpenRouter third reviewer (optional): only if
OPENROUTER_API_KEYis set. The model has no file access — append the spec content to the prompt body. Same JSON schema; same extractor.OR_MODEL="${OPENROUTER_MODEL:-z-ai/glm-5.2}" # primary OR_FALLBACK="${OPENROUTER_FALLBACK:-moonshotai/kimi-k2.6}" # OpenRouter auto-routes to this if primary fails PROMPT="$(cat roles/openrouter-reviewer.md) SPEC FILE ($SPEC_PATH): $(cat "$SPEC_PATH")" # Reasoning reviewers (GLM/Kimi) on a long spec can take minutes — allow 300s # (120s/180s timed out: "response never arrived"). Timeout → non-200 → graceful degrade. resp="$(curl -sS --connect-timeout 20 --max-time 300 -w $'\n%{http_code}' \ https://openrouter.ai/api/v1/chat/completions \ -H "Authorization: Bearer $OPENROUTER_API_KEY" -H "Content-Type: application/json" \ -H "X-Title: blueprint consensus" \ -d "$(jq -nc --arg m "$OR_MODEL" --arg fb "$OR_FALLBACK" --arg c "$PROMPT" \ '{model:$m, models:[$m,$fb], messages:[{role:"user",content:$c}], temperature:0.2}')")" http="${resp##*$'\n'}"; body="${resp%$'\n'*}" [ "$http" = "200" ] && printf '%s' "$body" | jq -r '.choices[0].message.content' \ || echo "OpenRouter HTTP $http — dropping third reviewer this round" >&2 - Self-assessor =
codex exec -(same family as host, fresh ctx) over the union of reviewer findings:printf '%s\n\nSpec file: %s\n\nReviewer findings (union):\n%s' \ "$(cat roles/codex-self-assessor.md)" "$SPEC_PATH" "$ALL_FINDINGS" \ | codex exec - - Fallback validator (no external reviewer):
envsubst < roles/spec-validator.md | codex exec -
What the skill does (step by step)
Read and analyze the spec. Validate (markdown,
##headers, no[MISSING]markers), classify type (product / technical / small), scan the codebase if present, flag[NEEDS CLARIFICATION]items.Challenge + ask (hard gate). Run the multi-angle challenge (don't-build / simpler / future-dependent / scenarios). Then ask what's unclear — max 5 questions via numbered TUI prompts (
roles/questioner.md'sAskUserQuestionsemantic → numbered TUI list). If already clear and the framing is sound — skip.Decompose into atomic tasks. Format adapts to type —
references/task-format.md. Each task touches 1-3 files (a vertical slice) and has aDone when:line with a runnable shell proof. Foundations first — the first task leaves the project runnable/green (greenfield: skeleton + smoke test; brownfield: a baseline proof), the harness lives there and is reused, never buried later. Order so prerequisites precede dependents; each area appears exactly once. No[P], Stages,AC-N.N, orGiven/When/Then.Pin requirements & contracts. Plain sentences tagged
[must]/[nice]/[later](lightR1/R2ids only if needed). Skip if small/single-component. Details:references/contracts.md.Self-review checklist. Placeholder scan, internal consistency, ambiguity check, and a hard-gate Scope-cut audit (user-facing).
Hard-to-reverse decisions (no ceremony). If a task locks in a choice that's costly to undo with a real trade-off (DB schema, public API contract, auth/infra/messaging choice, security boundary, major dependency lock-in), record it in one line in the reference file's
## Risks— what was chosen + the trade-off. Genuine forks you shouldn't pick alone already go to the tasks file's## Needs your attentionas❓ NEEDS YOU(with→ blocks: TASK-n). Nodocs/adr/files, no numbering, no template.The Scope-cut audit (user-facing) scans for deferral signals:
- Requirements tagged
[later], or[must]/[nice]carrying(v2),(future),(deferred),(later),(stretch goal),(MVP only),(out of scope for now),(not for now). Non-goalsitems mapping back to input.- Input features/endpoints/edge cases with no backing task or silently dropped.
If any signal is found, surface a numbered TUI prompt per item with
Keep deferred (current)/Include in v1/Drop entirely/Drop (record in the plan). Apply decisions. ForDrop (record in the plan), note it in one line under the reference file's## Non-goals(what + why) — no separate files. Loop back to step 3/4 if scope changes require re-decomposition. NEVER write to disk while scope cuts are unconfirmed. Nothing found → gate silently passes.- Requirements tagged
Write the plan. Normally two files. When the plan is more than one file, put them in a flat directory
<spec-stem>/(e.g.auth-spec.md→auth-spec/) — no nested subdirs; a trivial spec that fits one file stays as<spec>.md. No.bak— in directory mode the original<spec>.mdis left untouched (it IS the backup); the gitpre-blueprintsnapshot covers both modes.<spec-stem>/tasks.md— the plan (checklist on top, blocks below). In order: a> Context (the "why"): see reference.mdpointer;## Needs your attention(only if it has content — blocking❓ NEEDS YOUeach with→ blocks: TASK-n, plus one line per HITL task);## Checklist— one- [ ] TASK-n — short titleline per task grouped by**▸ AREA-n**(each group once, foundations-first), light· after TASK-x/· HITL/· ❓flags (bareTASK-n, no###); then## Tasks— the full### TASK-nblocks (**Files**,**Leverage**,Done when:proof, inlineEdge:), grouped by▸ AREA-nin the same order. Downstream contract —/goal,/verify-done, goal-prep read THIS file's## Tasksproofs.<spec-stem>/reference.md— context only (the "why").## Overview, full## Requirements([must]/[nice]/[later]), Terminology,## Assumptions(ranked non-blocking only — blocking❓ NEEDS YOUlive in tasks.md, never here),## Risks(one line each),## Non-goals. NO task blocks. Keep it concise + DRY — lossless.- Self-sufficiency rule: to execute TASK-n, read its
### TASK-nblock in## Tasks; the## Checklisttells you what's left + order. Single-file fallback:<spec>.mdwith## Needs your attention(if any) +## Checklist+## Tasks+ context folded in. Downstream resolve<spec-stem>/tasks.md(or<spec>.md) and read### TASK-n+Done when:from its## Tasks. Template:references/task-format.md.
Mechanical validation.
python3 scripts/verify-spec.py <spec>. FAIL → fix and re-run. (Style warnings about old ceremony are non-blocking.)Cross-model consensus loop (Phase 7.6). External reviewer(s) find, Codex self-assesses, iterate until CONSENSUS or max rounds. Next section. Skippable with
--consensus-rounds 0.Approval gate. Summary report + numbered TUI prompt (Approve / Modify / Questions). After approval → step 10.
Done. Print a one-line summary +
"Plan written to <path>. /clear before continuing.". No.bakto dispose of — the original<spec>.mdstays as the backup (directory mode) and the gitpre-blueprintsnapshot is the rollback. Hand off to a builder — a human, orcodex exec/ the goal feature — and finish with/verify-done.
Phase 7.6 — Cross-model consensus loop (Codex variant — symmetric to Claude)
After steps 6-7 (write plan + verify-spec.py), the convergence loop runs. Each round, every available external reviewer finds independently; Codex (fresh codex exec -) triages the union. Reviewers:
- Claude —
claude -pwithroles/codex-reviewer.md(ifclaudeon$PATH). - OpenRouter third reviewer — a diverse frontier model (default
z-ai/glm-5.2) via the chat API (ifOPENROUTER_API_KEYset), withroles/openrouter-reviewer.md. - If neither → single-model fallback (
roles/spec-validator.mdviacodex exec -).
MAX_ROUNDS = consensus_rounds_flag (default 3, 0 disables)
round = 0
reviewer_prompt = sed "s|<spec_path>|$SPEC_PATH|g" roles/codex-reviewer.md
reviewers = []
if bash `command -v claude` nonempty: reviewers += ["claude"]
if env OPENROUTER_API_KEY set: reviewers += ["openrouter"]
if reviewers is empty:
log WARNING "no external reviewer (claude / OPENROUTER_API_KEY); single-model fallback"
result = bash: envsubst < roles/spec-validator.md | codex exec -
→ CONSENSUS or NEEDS_FIX (single round); goto Step 9
rounds = []
while round < MAX_ROUNDS:
round += 1
# 1. Each reviewer finds independently → union of findings JSON (same schema),
# tagged with its source. A reviewer erroring (no JSON, OpenRouter non-200)
# degrades to an empty approve for THIS round, logged — never aborts.
all_findings = []
for r in reviewers:
all_findings += run_reviewer(r) # claude -p | OpenRouter curl
# 2. Codex self-assessment over the UNION (fresh codex exec -)
assessment = bash:
printf '%s\n\nSpec file: %s\n\nReviewer findings (union):\n%s' \
"$(cat roles/codex-self-assessor.md)" "$SPEC_PATH" "$(json all_findings)" | codex exec -
# 3. Consensus = every reviewer "approve" AND assessment.verdict == AGREE_PASS
if all(f.summary == "approve" for f in all_findings) and assessment.verdict == AGREE_PASS:
→ CONSENSUS, exit loop
# 4. Process via categorization (dedupe identical findings from >1 reviewer —
# stronger signal, note it, apply once)
applied, rejected, needs_user = [], [], []
for each finding in dedupe(all_findings):
cat = assessment.categorization[finding.id]
if cat == ACCEPT: apply finding.recommendation to spec; applied.append(finding)
elif cat == REJECT_PETTY: rejected.append((finding, reason))
elif cat == NEEDS_USER: needs_user.append(finding)
print round summary: N applied, M rejected (reasons), K queued for user, per-reviewer counts
rounds.append({all_findings, assessment, applied, rejected, needs_user})
if needs_user not empty:
numbered TUI prompt per issue with reviewer views; apply user decisions
# 5. Oscillation detection
if round >= 3 and hash(dedupe(all_findings)) == rounds[-3].findings_hash:
→ ESCALATE: "the models are stuck — your call"; print full rounds[]; break
if round == MAX_ROUNDS and not CONSENSUS:
ESCALATE: "(A) approve as-is, (B) abort, (C) one more round"; print full rounds[]
Failure modes:
- No external reviewer (
claudenot on$PATHAND noOPENROUTER_API_KEY) → single-modelroles/spec-validator.mdviacodex exec -, continues with a warning. - OpenRouter unavailable (401 missing/invalid key, 402 no credits, 429 rate-limit, 5xx provider down) → drop the third reviewer that round, log the HTTP code, continue. Pin the exact model slug.
- A reviewer's response has no JSON block → extractor returns empty
approve(logged, no-op). Persistent → escalate. - Models gang up on user intent →
roles/codex-reviewer.md/roles/openrouter-reviewer.mdforbid proposing removal of unusual requirements;roles/codex-self-assessor.mdmirrors the rule. - Petty disagreements → reviewer prompts exclude style/formatting/word-choice; leaks → REJECT_PETTY.
- Oscillation → hash comparison between rounds N and N-2, escalation.
Output schema (defined identically by roles/codex-reviewer.md and roles/openrouter-reviewer.md):
{
"summary": "needs-attention | approve",
"findings": [
{ "file": "<spec.md path>", "line_start": <int>, "line_end": <int>,
"confidence": <0..1>, "recommendation": "<concrete change>" }
]
}
Outputs
<spec-stem>/tasks.md— the plan:## Needs your attention(if any) +## Checklist(- [ ] TASK-nper task) +## Tasks(the### TASK-nblocks withDone when:proofs — what/verify-done+ goal-prep read). (Trivial single-file spec →<spec>.md.)<spec-stem>/reference.md— context only (the "why"): overview / requirements /## Assumptions(ranked, non-blocking) / risks / non-goals. Concise + DRY, lossless. Folds into<spec>.mdfor a trivial single-file spec.- No
.bak— the original<spec>.mdis left untouched (directory mode); gitpre-blueprintsnapshot is the rollback.
Git: pre-blueprint: <name> (snapshot before) and blueprint: enrich <name> (after step 6).
Phase 7.6 internals (per-round findings, applied/rejected/escalated, per-reviewer counts) live in memory, printed at round boundaries — no critique files. On failure/oscillation, the full round-by-round summary is dumped before escalation.
Connections to other skills
- Input: typically after
/cleanup(sectioned markdown without[MISSING]). A manually written spec is fine if structurally valid. Optionally preceded by/extract-links. - Output (on disk): the plan directory
<spec-stem>/(tasks.md+reference.md), or<spec>.mdfor a trivial spec; the original<spec>.mdis left untouched (directory mode) as the backup — no.bak. Hard-to-reverse decisions are noted inline in## Risks, not in adocs/adr/tree. - Downstream builders:
codex exec/ the goal feature (autonomous) or manual implementation; finish with/verify-done. - Cross-model dependency: Phase 7.6 uses
claude -p(npm@anthropic-ai/claude-code) and/or a diverse OpenRouter model (OPENROUTER_API_KEY). Without either — fallback toroles/spec-validator.mdviacodex exec -.
Rules
Commonality
The plan is a shared artifact. Downstream work (the goal feature, a manual builder) makes decisions from it. A placeholder, a vague Done when:, or a contradictory requirement → the next step works from a holey map.
Prior commitment
In step 5 you committed to placeholder scan + consistency + ambiguity check + Scope-cut audit (user-facing gate). In step 7 — verify-spec.py. In step 8 — the consensus loop (or fallback). Skipping any withdraws the basis for the final verdict.
Authority (scope decisions belong to the user)
Tagging a requirement [later], moving a feature into Non-goals, or dropping an edge case — these are scope decisions, not spec hygiene. The user wrote the input on purpose; v1-vs-deferred is theirs. The Scope-cut audit is a hard user-facing gate precisely so the model never makes this call alone.
Social proof (cross-model rationale)
Phase 7.6 exists because single-model self-review is weaker. An independent reviewer (Claude via claude -p, plus an optional diverse third model from a different lab) catches issues the first biases past. A finding raised by more than one reviewer is a stronger signal. Skipping Phase 7.6 when a reviewer is available removes the only real basis to trust the plan beyond "Codex approved its own output".
Self-check before delivering the result
Would this plan pass review by a senior engineer who has to build the system from it? Concretely:
- Does every task have a concrete
Done when:shell proof (not "it works", not "manual check")? - No placeholders (
TBD,...,[NEEDS CLARIFICATION],<insert here>)? - Was the step 5 Scope-cut audit run, with every detected deferral (
[later],Non-goalsitems, dropped input features/edge cases) confirmed by the user via TUI prompt? No silent deferral. - Were hard-to-reverse decisions noted inline in
## Risks(one line each), notdocs/adr/files? - Is every task atomic — 1-3 files, single purpose, closeable by an independent worker without questions to the author?
- Foundations first: does the first task leave the project runnable/green (greenfield skeleton + smoke test, or brownfield baseline proof)? Is the harness in that task and reused — not buried later? Each area exactly once, prerequisites before dependents?
- One attention surface: are ALL blocking
❓ NEEDS YOUin tasks.md## Needs your attention(each→ blocks: TASK-n) plus the HITL tasks — with NONE duplicated in reference.md (which carries only the ranked non-blocking## Assumptions)? - Checklist ↔ blocks: is tasks.md's
## Checklistone- [ ] TASK-nline per task (bare ids, each area once), and does every checklist line have exactly one### TASK-nblock below in## Tasks(and vice-versa)? - Concise + DRY + lossless: no fact in two sections; per-task specifics only in their
### TASK-nblock; near-duplicate prose/risks merged — yet nothing lost? - Plan written as a flat
<spec-stem>/directory (tasks.mdchecklist +reference.mdbody) — or a single<spec>.mdif trivial; no nested subdirs? - Did Phase 7.6 pass (or was it explicitly skipped with reasoning)?
- Coverage: does every Overview item have at least one task? Does every task track back to Overview / a requirement?
If "no" on any item — redo, don't ship.