| name | create-spec |
| disable-model-invocation | true |
| description | Interview the user to produce a feature spec, then run multi-model generator and spec review gate |
| argument-hint | [--mode <name>] [--max-rounds <N>] <feature description> |
Host-Neutral Execution
Before running any Bash snippet in this skill, run the shared Cerberus resolver below. It lazily builds and executes bin/cerberus from the configured plugin root.
set +u
if [ -n "${CODEX_THREAD_ID:-}" ] || [ -n "${PLUGIN_ROOT:-}" ]; then
host=codex
elif [ -n "${CLAUDE_SESSION_ID}" ] || [ -n "${CLAUDE_PLUGIN_ROOT}" ] || [ -n "${CLAUDE_SKILL_DIR}" ]; then
host=claude
else
host="${CERBERUS_HOST:-}"
if [ "$host" = claude-code ]; then
host=claude
fi
fi
root="${CERBERUS_ROOT:-}"
if [ -z "$root" ] && [ "$host" = codex ]; then
root="${PLUGIN_ROOT:-}"
fi
if [ -z "$root" ] && [ "$host" = codex ] && [ -n "${CODEX_THREAD_ID:-}" ]; then
cache_home="${HOME:-}"
[ -n "$cache_home" ] || cache_home="${USERPROFILE:-}"
if [ -n "$cache_home" ]; then
cache_file="$cache_home/.codex/cerberus/sessions/$CODEX_THREAD_ID/plugin-root"
if [ -r "$cache_file" ]; then
IFS= read -r root < "$cache_file" || true
fi
fi
fi
if [ -z "$root" ] && [ "$host" != codex ]; then
root="${CLAUDE_PLUGIN_ROOT}"
[ -n "$root" ] || root="${PLUGIN_ROOT:-}"
fi
if [ -z "$root" ] && [ "$host" != codex ]; then
skill_dir="${CLAUDE_SKILL_DIR}"
if [ -n "$skill_dir" ]; then
root="$(cd "$skill_dir/../.." && pwd)"
fi
fi
[ -n "$root" ] || { echo "cerberus: plugin root not set; set CERBERUS_ROOT and retry" >&2; exit 127; }
bin="$root/bin/cerberus"
export CERBERUS_ROOT="$root"
claude_session="${CLAUDE_SESSION_ID}"
if [ "$host" = claude ]; then
export CERBERUS_HOST=claude
elif [ "$host" = codex ]; then
export CERBERUS_HOST=codex
fi
if [ "$host" = codex ] && [ -n "${CODEX_THREAD_ID:-}" ]; then
export CERBERUS_HOST=codex CERBERUS_SESSION_ID="$CODEX_THREAD_ID"
elif [ "$host" = claude ] && [ -n "$claude_session" ]; then
export CERBERUS_HOST=claude CERBERUS_SESSION_ID="${CERBERUS_SESSION_ID:-$claude_session}"
fi
command -v make >/dev/null 2>&1 || { echo "cerberus: make not found on PATH; install make and retry." >&2; exit 127; }
if ! make -q -C "$root" build >/dev/null 2>&1; then
command -v go >/dev/null 2>&1 || { echo "cerberus: Go >= 1.22 not found on PATH; install Go and retry." >&2; exit 127; }
echo "cerberus: building... (this happens once after clone or upgrade)" >&2
start=$(date +%s)
make -C "$root" build >&2 || exit $?
end=$(date +%s)
echo "cerberus: build complete in $((end-start))s" >&2
fi
exec "$bin" "$@"
Use bin/cerberus through the configured plugin root when invoking Cerberus commands below.
Create Spec (Interview + Multi-Model Generator)
Transform a vague feature idea into a complete, reviewable specification by combining codebase research, a targeted interview, multi-model generation, and a spec review gate.
Spec Tiers (Progressive Disclosure)
Specs scale with complexity. Start minimal and expand as signals emerge.
| Tier | Use Case | What's Required |
|---|
| S | Bug fix, tiny tweak | Problem, change summary, scope boundary, UX impact, 2-5 acceptance bullets, validation method, open questions |
| M | Small feature, single flow | S + Goal, success criteria, non-goals, primary flow, key states, 3-7 requirements with MUST + verification examples, basic instrumentation |
| L | Multi-flow, high-risk project | M + Constraints, alternate flows, full Given/When/Then, edge cases per requirement, detailed instrumentation, launch checklist |
Canonical field mapping:
- S only: Change summary, Scope boundary, UX impact (yes/no), Acceptance bullets, Validation after release
- M adds: Goal, Success criteria, Non-goals, Primary flow, Key states, Requirements (R1/R2 with MUST + examples), Instrumentation (light)
- L adds: Constraints, Alternate flows, Edge cases per requirement, Full GWT verification, Launch checklist
Complexity Signals (auto-detect tier)
Score these signals during the interview. Suggest tier upgrade if score exceeds threshold.
| Signal | Points |
|---|
| New user-facing flow or screen | +2 |
| Changes to data model / schema | +2 |
| Involves auth, security, payments, compliance | +2 |
| Impacts multiple user flows or personas | +2 |
| Integrates with external or multiple internal services | +1 |
| Needs new analytics or A/B experiment | +1 |
| Requires feature flags or data migration | +1 |
| Multiple teams or owners involved | +1 |
Score → Tier: 0-1 = S, 2-4 = M, 5+ = L
If detected tier differs from apparent scope, confirm with user:
"This looks like it touches multiple flows and data models. Should we expand to a fuller spec? (yes/no)"
Tier Disagreement Handling
If user declines an upgrade:
- Respect their choice, but record the override in Open Questions: "Tier kept at [S/M] despite complexity signals suggesting [M/L]. Signals: [list]. Risk: [potential gaps]."
- For S specs with score ≥2, still ask about backwards compatibility and basic error handling even if not filling full M template.
If user requests a downgrade:
- Confirm explicitly: "Downgrading to [tier] means we won't cover [list of omitted sections]. OK to proceed?"
- If confirmed, record in Open Questions: "Tier downgraded to [S/M] per user request. Omitted: [sections]."
Reviewers and tier overrides:
- Reviewers should respect the stated tier and not fail for missing higher-tier sections.
- If a reviewer believes the tier is dangerously low, they should flag it as a P1 recommendation to upgrade, not a spec failure.
Mode Behavior
Modes only select a model panel from config.yaml. Mode names do not alter interview depth, tier, priority scope, or refinement policy, so custom modes behave exactly like built-in modes.
Interview depth follows the selected spec tier and the user's stop signals. Override: --max-rounds <N> sets the review round cap explicitly, overriding defaults.max_rounds. Accepts any integer >= 0; 0 runs the initial review once and disables refinement respawns.
Input
The user provides a brief feature description inline, e.g.:
- "add user authentication"
- "batch export functionality"
- "undo/redo for the editor"
Argument Handling
Before Phase 1, parse command arguments:
- Set
MODE only when an explicit --mode <name> flag is present; otherwise leave it unset so config.yaml can supply defaults.mode.
- Remove
--mode <name> and --max-rounds <N> from the feature description before writing the spec.
- Preserve an explicit
--max-rounds <N> separately as MAX_ROUNDS for the review gate.
Workflow
Phase 1: Codebase Research
Before asking any questions, understand the existing codebase:
- Identify relevant areas (search for related files, modules, routes, or services)
- Note existing conventions (naming, patterns, testing, error handling)
- Find integration points and constraints
- Capture key files you will reference in the spec
Document findings internally—these inform the skeleton and your questions.
Phase 1a: Integration Constraints & Expectations (CRITICAL)
Goal: Identify codebase-aware constraints on WHAT to build, not HOW to build it.
This phase prevents specs that imply new infrastructure when stakeholders/architecture require extending existing systems. The spec captures constraints and expectations; the plan makes detailed integration decisions.
-
Identify existing mechanisms relevant to this feature:
- Config systems, plugin architectures, registry patterns
- Existing abstractions that handle similar concerns
- Hook points, event systems, middleware chains
-
Document integration expectations as constraints:
- "Must plug into existing [X] system" (if architecturally required)
- "Must not introduce a new [Y]" (if ownership/consistency requires it)
- "Should follow established pattern from [similar feature]"
-
Capture in spec (Constraints, Non-goals, or Open Questions):
- Constraints (L-tier): Hard integration requirements (e.g., "Must reuse existing auth pipeline")
- Non-goals: Explicit exclusions (e.g., "Not building a new config system")
- Open Questions: Suspected needs for new infrastructure, flagged as risks for plan to evaluate (e.g., "Open: Can existing event system handle required throughput?")
Important: The spec should avoid binding to specific modules/file paths unless they are product-level constraints. Detailed extend-vs-new decisions belong in the plan.
Phase 1b: Draft Spec Skeleton
Create a skeleton based on your research. Start with Tier S fields; expand as complexity signals emerge.
IMPORTANT: When you finish Phase 1b:
- Write the skeleton spec to a file (e.g.,
docs/YYYY-MM-DD-FEATURE-spec.md) — this becomes the canonical doc
- The skeleton MUST contain
[TBD] placeholders — fill them only after user answers in Phase 2
- Present the skeleton and your first batch of interview questions via
AskUserQuestion
PHASE 2 GATE: After sending Interview Batch 1, end your turn immediately. Do not proceed to Phase 3+ until the user answers or issues a stop signal. This gate is mandatory.
# [Feature Name]
**Tier:** S / M / L (auto-detected, confirm with user)
**Owner:** [TBD or pre-fill from research]
**Target ship:** [TBD]
**Links:** [Figma, ticket, related docs]
## 1. Outcome & Scope
**Problem / context** *(S/M/L)*
[TBD: What's broken/missing today? Who is impacted?]
**Change summary** *(S only — omit for M/L)*
[TBD: What are we changing and why?]
**Goal** *(M/L)*
[TBD: "Enable <user> to <do X> so that <benefit>."]
**Success criteria** *(M/L)*
- [TBD: Metric + threshold + timeframe]
**Non-goals** *(M/L)*
- [TBD or inferred from research]
**Constraints** *(L only)*
- Compatibility: [TBD: Any existing clients/integrations affected?]
- [Other constraints: performance, security, environment]
**Scope boundary** *(S only — omit for M/L)*
[TBD: "Only affects X; does not change Y/Z."]
## 2. User Experience & Flows
**UX impact** *(S only)*
- User-visible? (yes/no): [TBD]
- If yes: [TBD: "When user does A, they now see B instead of C."]
**Primary flow** *(M/L)*
1. [TBD]
2. [TBD]
3. [TBD]
**Key states** *(M/L)*
- Empty state: [TBD]
- Loading state: [TBD]
- Success state: [TBD]
- Error state(s): [TBD]
**Alternate flows** *(L only)*
- [TBD: What if user cancels? Lacks permission? Partial completion?]
## 3. Requirements + Verification
*(Tier S: Use simple acceptance bullets)*
*(Tier M/L: Use numbered requirements with MUST statements)*
**Acceptance criteria** *(S)*
- [TBD: When user does X in situation Y, Z happens]
- [TBD: Also verify these still work: ...]
**R1 — [Short name]** *(M/L)*
- **Requirement:** The system MUST [TBD]
- **Verification:** *(M: example or single GWT; L: full GWT)*
- Given [TBD], When [TBD], Then [TBD]
- **Edge cases:** *(L only)* [TBD]
**R2 — [Short name]** *(M/L)*
- **Requirement:** The system MUST [TBD]
- **Verification:**
- Given [TBD], When [TBD], Then [TBD]
- **Edge cases:** *(L only)* [TBD]
## 4. Instrumentation & Release Checks
**Validation after release** *(S)*
- How to confirm this worked: [TBD: "Try scenario X in env Y"]
- Known risks / blast radius: [TBD]
**Instrumentation** *(M/L)*
- Events to track: [TBD: feature entry, completion, failure reasons]
**Launch checklist** *(L only)*
- [ ] All MUST requirements verifiable
- [ ] Key error states covered
- [ ] Metrics available to confirm success criteria
- [ ] Rollback condition defined
**Decisions made** *(S/M/L)*
- [Record "you decide" / "whatever's standard" resolutions here]
**Open questions** *(S/M/L)*
- [List unknowns from research]
Skeleton rules:
- Start with Tier S fields; add M/L fields as complexity signals accumulate
- Pre-fill anything you can confidently infer from research
- Mark unknowns explicitly as
[TBD] or [TBD: hint about what's needed]
- When outputting final spec, omit sections marked for other tiers
Phase 2: Prioritized BFS Interview
Load the interview engine: Read ${CLAUDE_PLUGIN_ROOT}/prompts/interview-engine.md for the full mechanism. Key principles below.
IMPORTANT: Use the AskUserQuestion tool for ALL interview questions. Put coverage + numbered questions + off-ramp in a single tool call. Plain text questions are not interactive.
Core Mechanism: Prioritized Breadth-First Search
Ask questions in order of priority (P0-P3) and depth (L0-L3), with breadth across topics before depth in any single topic.
| Priority | What | Examples |
|---|
| P0 | Blockers / correctness | Scope boundaries, acceptance criteria, backwards compatibility |
| P1 | Major design | Primary flow, testing strategy, success criteria |
| P2 | Edge cases | Alternate flows, failure modes, observability |
| P3 | Polish | Ergonomics, minor UX improvements |
| Depth | Scope | Examples |
|---|
| L0 | Vision / outcome | What problem? Who? Definition of done? |
| L1 | Behavior / approach | Primary flow, key states, acceptance criteria shape |
| L2 | Decomposition | Requirement breakdown, GWT examples, test layers |
| L3 | Implementation details | Exact event schemas, precise error codes, rollout mechanics |
Anti-deep-dive rule: Don't ask L2 for Topic A until all P0 topics have L1 coverage.
Stop Signals (MUST HONOR IMMEDIATELY)
| Signal Type | Trigger Phrases | Action |
|---|
| Global stop | "enough detail", "that's enough", "stop here", "we're good", "ship it" | End interview, remaining TBDs → Open Questions |
| Depth cap | "keep it high-level", "stop at L1", "no deep dive", "details later" | Set max_depth, continue within cap |
| Priority cap | "skip P2/P3", "just blockers", "P0/P1 only" | Set max_priority, lower items → Open Questions |
| Per-topic stop | "enough about testing", "park observability", "skip auth" | Mark topic capped, continue others |
| Per-question skip | "skip this one", "next question" | Mark TBD as Open Question, no follow-ups |
| Delegation | "you decide", "whatever's standard" | Pick safe default, record in Decisions |
| Uncertainty | "I don't know" | Offer 2-3 options; if declined → Open Question |
Batch Presentation Format
Present questions with context and an explicit off-ramp:
**Interview Batch [N]** (Priority: P0, Depth: L0)
Current coverage: [P0 in progress at L0]
Questions (answer any, skip any):
1. [Topic: Scope] What's explicitly out of scope?
- Options: [A] Exclude X and Y, [B] Exclude only X, [C] You decide
2. [Topic: Requirements] What MUST the system guarantee?
- Evidence: Similar features use [pattern] — should we follow that?
3. [Topic: Verification] How will we validate this works?
- Options: [A] Manual QA, [B] E2E tests, [C] Both
---
Reply using `1: <answer> 2: <answer>` format (skip numbers to leave as Open Questions).
Or say "enough detail" to stop, "keep it high-level" to cap depth.
After Each Batch
- Update skeleton immediately — fill TBDs or mark as Open Questions
- Check for stop signals in the response
- Ask one meta-question: "Continue to L{k+1}, stop here, or drill deeper on a specific topic?"
Progressive Coverage by Tier
Tier S (P0/L0-L1):
- Problem/context, change summary, scope boundary
- UX impact, acceptance bullets, validation method
Tier M (add P1/L1-L2):
- Goal, success criteria, non-goals
- Primary flow, key states
- Requirements with MUST + examples
Tier L (add P2/L2-L3):
- Constraints, alternate flows
- Edge cases per requirement
- Full GWT, instrumentation, launch checklist
Tier upgrade prompt: When complexity signals accumulate:
"This touches [signals]. Want to expand to Tier M/L for [additional coverage]?"
Handling Responses
| User says... | You should... |
|---|
| "You decide" | Pick safe default, record in Decisions, stop deeper |
| "I don't know" | Offer 2-3 options with tradeoffs |
| "Whatever's standard" | Use codebase conventions, record decision |
| "Skip this" | Record as Non-Goal or Open Question |
| Stop signal | End interview or cap depth immediately |
Phase 3: Build Spec Context
Create a compact context block for generators:
- Current spec file (with TBDs filled from interview, remaining gaps marked)
- Feature summary (1-2 paragraphs)
- Codebase findings (key files, patterns, constraints)
- User answers (structured bullets, mapped to spec sections)
- Decisions made + rationale
- Remaining open questions
Context Checklist by Tier:
Tier S:
Tier M (add to S):
Tier L (add to M):
Phase 4: Run Multi-Model Generators
Create, populate, and remember a temporary prompt file for concatenating the base prompt with your context:
CRITICAL: Tool/Bash calls do not share exported variables. Do not create PROMPT_TMP in one Bash call and then use $PROMPT_TMP in a later Bash call unless you explicitly re-export the printed literal path in that same later call. Prefer the single Bash block below, which keeps creation and population in one shell process.
CRITICAL: The command MUST start with an executable, NOT a bare variable assignment. Variable assignments trigger permission prompts.
env bash -lc 'set -euo pipefail
PROMPT_TMP="$(mktemp "${TMPDIR:-/tmp}/create-spec-prompt-XXXXXX")"
test -f "$PROMPT_TMP"
set +u
if [ -n "${CODEX_THREAD_ID:-}" ] || [ -n "${PLUGIN_ROOT:-}" ]; then host=codex; elif [ -n "${CLAUDE_SESSION_ID}" ] || [ -n "${CLAUDE_PLUGIN_ROOT}" ] || [ -n "${CLAUDE_SKILL_DIR}" ]; then host=claude; else host="${CERBERUS_HOST:-}"; if [ "$host" = claude-code ]; then host=claude; fi; fi; root="${CERBERUS_ROOT:-}"; if [ -z "$root" ] && [ "$host" = codex ]; then root="${PLUGIN_ROOT:-}"; fi; if [ -z "$root" ] && [ "$host" = codex ] && [ -n "${CODEX_THREAD_ID:-}" ]; then cache_home="${HOME:-}"; [ -n "$cache_home" ] || cache_home="${USERPROFILE:-}"; if [ -n "$cache_home" ]; then cache_file="$cache_home/.codex/cerberus/sessions/$CODEX_THREAD_ID/plugin-root"; if [ -r "$cache_file" ]; then IFS= read -r root < "$cache_file" || true; fi; fi; fi; if [ -z "$root" ] && [ "$host" != codex ]; then root="${CLAUDE_PLUGIN_ROOT}"; [ -n "$root" ] || root="${PLUGIN_ROOT:-}"; fi; if [ -z "$root" ] && [ "$host" != codex ]; then skill_dir="${CLAUDE_SKILL_DIR}"; if [ -n "$skill_dir" ]; then root="$(cd "$skill_dir/../.." && pwd)"; fi; fi; [ -n "$root" ] || { echo "cerberus: plugin root not set; set CERBERUS_ROOT and retry" >&2; exit 127; }
cat "$root/prompts/generators/create-spec.md" > "$PROMPT_TMP"
cat >> "$PROMPT_TMP" <<'"'"'EOF'"'"'
## Context
EOF
printf "PROMPT_TMP=%s\n" "$PROMPT_TMP"'
This creates a unique temp file like /tmp/create-spec-prompt-abc123. Do not use a top-level PROMPT_TMP=$(mktemp ...) assignment, and do not add a suffix like .md; BSD/macOS mktemp only replaces trailing X characters.
Record the printed PROMPT_TMP=... value. In subsequent Bash calls, substitute the actual printed path (for example /tmp/create-spec-prompt-abc123) or start that same call with export PROMPT_TMP='/tmp/create-spec-prompt-abc123' && .... Never assume $PROMPT_TMP still exists from an earlier tool call.
Now append the Phase 3 context (skeleton + findings + answers) to the actual prompt file path printed above. Substitute the printed path in this same Bash call:
: "${PROMPT_TMP:=<paste the printed /tmp/create-spec-prompt-... path here>}" && export PROMPT_TMP && cat >> "$PROMPT_TMP" <<'EOF'
[Paste Phase 3 context here]
EOF
Spawn generators with the mode flag. The cerberus generate subcommand resolves the selected panel from config.yaml and manages provider execution internally.
CRITICAL: The command MUST start with an executable, NOT a variable assignment. Variable assignments trigger permission prompts.
: "${PROMPT_TMP:=<paste the printed /tmp/create-spec-prompt-... path here>}" && export PROMPT_TMP && export OUTPUT_PARENT="${REVIEW_DIR:-${TMPDIR:-/tmp}}" && mkdir -p "$OUTPUT_PARENT" && export OUTPUT_DIR="$(mktemp -d "$OUTPUT_PARENT/create-spec-drafts-XXXXXX")" && test -d "$OUTPUT_DIR" && printf 'OUTPUT_DIR=%s\n' "$OUTPUT_DIR" && MODE_ARGS=() && if [ -n "${MODE:-}" ]; then MODE_ARGS=(--mode "$MODE"); fi && set +u; if [ -n "${CODEX_THREAD_ID:-}" ] || [ -n "${PLUGIN_ROOT:-}" ]; then host=codex; elif [ -n "${CLAUDE_SESSION_ID}" ] || [ -n "${CLAUDE_PLUGIN_ROOT}" ] || [ -n "${CLAUDE_SKILL_DIR}" ]; then host=claude; else host="${CERBERUS_HOST:-}"; if [ "$host" = claude-code ]; then host=claude; fi; fi; root="${CERBERUS_ROOT:-}"; if [ -z "$root" ] && [ "$host" = codex ]; then root="${PLUGIN_ROOT:-}"; fi; if [ -z "$root" ] && [ "$host" = codex ] && [ -n "${CODEX_THREAD_ID:-}" ]; then cache_home="${HOME:-}"; [ -n "$cache_home" ] || cache_home="${USERPROFILE:-}"; if [ -n "$cache_home" ]; then cache_file="$cache_home/.codex/cerberus/sessions/$CODEX_THREAD_ID/plugin-root"; if [ -r "$cache_file" ]; then IFS= read -r root < "$cache_file" || true; fi; fi; fi; if [ -z "$root" ] && [ "$host" != codex ]; then root="${CLAUDE_PLUGIN_ROOT}"; [ -n "$root" ] || root="${PLUGIN_ROOT:-}"; fi; if [ -z "$root" ] && [ "$host" != codex ]; then skill_dir="${CLAUDE_SKILL_DIR}"; if [ -n "$skill_dir" ]; then root="$(cd "$skill_dir/../.." && pwd)"; fi; fi; [ -n "$root" ] || { echo "cerberus: plugin root not set; set CERBERUS_ROOT and retry" >&2; exit 127; }; bin="$root/bin/cerberus"; export CERBERUS_ROOT="$root"; claude_session="${CLAUDE_SESSION_ID}"; if [ "$host" = claude ]; then export CERBERUS_HOST=claude; elif [ "$host" = codex ]; then export CERBERUS_HOST=codex; fi; if [ "$host" = codex ] && [ -n "${CODEX_THREAD_ID:-}" ]; then export CERBERUS_HOST=codex CERBERUS_SESSION_ID="$CODEX_THREAD_ID"; elif [ "$host" = claude ] && [ -n "$claude_session" ]; then export CERBERUS_HOST=claude CERBERUS_SESSION_ID="${CERBERUS_SESSION_ID:-$claude_session}"; fi; command -v make >/dev/null 2>&1 || { echo "cerberus: make not found on PATH; install make and retry." >&2; exit 127; }; if ! make -q -C "$root" build >/dev/null 2>&1; then command -v go >/dev/null 2>&1 || { echo "cerberus: Go >= 1.22 not found on PATH; install Go and retry." >&2; exit 127; }; echo "cerberus: building... (this happens once after clone or upgrade)" >&2; start=$(date +%s); make -C "$root" build >&2 || exit $?; end=$(date +%s); echo "cerberus: build complete in $((end-start))s" >&2; fi; "$bin" generate "$OUTPUT_DIR" --type create-spec "${MODE_ARGS[@]}" --prompt-file "$PROMPT_TMP"
Record the printed OUTPUT_DIR=... value, then read the draft.md paths cerberus generate prints to stdout — one line per drafter that succeeded. The panel comes from the selected mode in config.yaml (falling back to claude + codex + gemini), so the set of directories is dynamic: each drafter writes to $OUTPUT_DIR/<label>/draft.md, where <label> is the provider name, with additional same-provider instances suffixed (for example codex and codex-2). Use exactly the paths printed; do not assume a fixed list. Do not pass literal $OUTPUT_DIR/... paths to a subagent unless you have replaced $OUTPUT_DIR with the actual printed directory.
IMPORTANT: The tool result contains only file paths, not the full draft content. This preserves your context window.
Phase 5: Synthesize Drafts (SUBAGENT REQUIRED)
You MUST use a subagent (Task tool) to synthesize drafts. This preserves your main context for the review gate phase.
Use the Task tool with a prompt like:
Synthesize the following generator drafts into the spec file.
Draft files to read:
[Paste the actual draft.md paths printed by `cerberus generate` — one per successful drafter. The panel is whatever the selected `config.yaml` mode resolves to; the example shape below may differ from your run.]
- /actual/output/dir/claude/draft.md
- /actual/output/dir/codex/draft.md
- /actual/output/dir/codex-2/draft.md
Spec file to update: docs/YYYY-MM-DD-FEATURE-spec.md
Tier: [S/M/L]
Synthesis rules:
1. Use the existing spec file as canonical structure — don't invent new sections
2. Identify common conclusions across drafts for each section
3. Resolve conflicts by checking the codebase and user answers
4. Fill remaining [TBD] placeholders with synthesized content or mark as Open Questions
5. Include only sections required for the tier (see tier requirements below)
6. Tier-specific verification:
- Tier S: Simple acceptance bullets, no formal requirements
- Tier M: Requirements with MUST + verification examples (GWT optional)
- Tier L: Requirements with MUST + full Given/When/Then + edge cases per requirement
7. Include alternatives considered and risk analysis when the selected tier or feature complexity requires them
Update the spec file in place with the synthesized content.
Return a summary of key decisions made during synthesis.
The subagent will:
- Read each draft file
- Read the existing spec file
- Synthesize drafts into the spec
- Update the spec file in place
- Return a summary to you
Delegate draft reading to the subagent — reading drafts yourself would consume your context. The subagent reads drafts, synthesizes, and returns a summary.
Phase 6: Verify Spec
The subagent updated the spec file in Phase 5. Confirm the [TBD] placeholders have been filled.
Phase 7: Review Gate with Prioritized BFS Refinement
Spawn external reviewers on the spec file. Forward --max-rounds only when the user supplied an explicit command-level override:
- If
--max-rounds <N> was passed to this command, forward that N.
- Otherwise omit the flag so
config.yaml and the CLI defaults remain authoritative for built-in and custom modes.
set +u; if [ -n "${CODEX_THREAD_ID:-}" ] || [ -n "${PLUGIN_ROOT:-}" ]; then host=codex; elif [ -n "${CLAUDE_SESSION_ID}" ] || [ -n "${CLAUDE_PLUGIN_ROOT}" ] || [ -n "${CLAUDE_SKILL_DIR}" ]; then host=claude; else host="${CERBERUS_HOST:-}"; if [ "$host" = claude-code ]; then host=claude; fi; fi; root="${CERBERUS_ROOT:-}"; if [ -z "$root" ] && [ "$host" = codex ]; then root="${PLUGIN_ROOT:-}"; fi; if [ -z "$root" ] && [ "$host" = codex ] && [ -n "${CODEX_THREAD_ID:-}" ]; then cache_home="${HOME:-}"; [ -n "$cache_home" ] || cache_home="${USERPROFILE:-}"; if [ -n "$cache_home" ]; then cache_file="$cache_home/.codex/cerberus/sessions/$CODEX_THREAD_ID/plugin-root"; if [ -r "$cache_file" ]; then IFS= read -r root < "$cache_file" || true; fi; fi; fi; if [ -z "$root" ] && [ "$host" != codex ]; then root="${CLAUDE_PLUGIN_ROOT}"; [ -n "$root" ] || root="${PLUGIN_ROOT:-}"; fi; if [ -z "$root" ] && [ "$host" != codex ]; then skill_dir="${CLAUDE_SKILL_DIR}"; if [ -n "$skill_dir" ]; then root="$(cd "$skill_dir/../.." && pwd)"; fi; fi; [ -n "$root" ] || { echo "cerberus: plugin root not set; set CERBERUS_ROOT and retry" >&2; exit 127; }; bin="$root/bin/cerberus"; export CERBERUS_ROOT="$root"; claude_session="${CLAUDE_SESSION_ID}"; if [ "$host" = claude ]; then export CERBERUS_HOST=claude; elif [ "$host" = codex ]; then export CERBERUS_HOST=codex; fi; if [ "$host" = codex ] && [ -n "${CODEX_THREAD_ID:-}" ]; then export CERBERUS_HOST=codex CERBERUS_SESSION_ID="$CODEX_THREAD_ID"; elif [ "$host" = claude ] && [ -n "$claude_session" ]; then export CERBERUS_HOST=claude CERBERUS_SESSION_ID="${CERBERUS_SESSION_ID:-$claude_session}"; fi; command -v make >/dev/null 2>&1 || { echo "cerberus: make not found on PATH; install make and retry." >&2; exit 127; }; if ! make -q -C "$root" build >/dev/null 2>&1; then command -v go >/dev/null 2>&1 || { echo "cerberus: Go >= 1.22 not found on PATH; install Go and retry." >&2; exit 127; }; echo "cerberus: building... (this happens once after clone or upgrade)" >&2; start=$(date +%s); make -C "$root" build >&2 || exit $?; end=$(date +%s); echo "cerberus: build complete in $((end-start))s" >&2; fi; MODE_ARGS=(); if [ -n "${MODE:-}" ]; then MODE_ARGS=(--mode "$MODE"); fi; ROUND_ARGS=(); if [ -n "${MAX_ROUNDS:-}" ]; then ROUND_ARGS=(--max-rounds "$MAX_ROUNDS"); fi; "$bin" spawn-spec-review "${MODE_ARGS[@]}" "${ROUND_ARGS[@]}" docs/YYYY-MM-DD-FEATURE-spec.md
CRITICAL: After running the spawn command, STOP IMMEDIATELY. Do NOT poll, sleep, wait, or run any further commands. The Stop hook will automatically wait for reviewers and present their findings when you stop. Any attempt to manually check reviewer status will fail.
IMPORTANT: Use the AskUserQuestion tool for ALL clarifying questions during review. Put findings + options in a single tool call. Plain text questions are not interactive.
Prioritized BFS for Review Findings
Treat reviewer findings as a queue, just like interview questions. Process them in priority-first, breadth-first order:
- Group findings by priority — P0 across all sections, then P1, then P2, etc.
- Address breadth before depth — Surface all P0s before deep-diving into any; within a priority, ask L0 clarification questions first, then apply deeper rewrites (L1/L2)
- Ask user to resolve ambiguous ones — Don't silently fix substantive issues
Priority definitions:
- P0: Blocking/incorrect — spec is fundamentally unclear or contradictory
- P1: Major clarity issues — will cause implementation failures
- P2: Should clarify before implementation
- P3: Nits and minor improvements
Batch Presentation Format for Findings
**Review Findings Batch [N]** (Priority: P0)
Reviewers found 2 P0 issues and 3 P1 issues. Let's address P0s first:
1. [Section: Scope] Unclear what happens when user cancels mid-flow
- Options: [A] Rollback to last save, [B] Discard changes, [C] You decide
2. [Section: Requirements] R2 has no verification method
- Options: [A] Add unit test, [B] Add E2E test, [C] Manual validation
---
Reply "enough detail" to stop drilling into fixes, or "skip P2/P3" to focus only on blockers.
Stop Signals for Review
| Signal | Action |
|---|
| "enough detail" / "that's good" | Stop asking about remaining issues, mark as Open Questions |
| "skip P2/P3" / "just fix blockers" | Only address P0/P1, leave rest as future improvements |
| "you decide" | Pick safe fix, record in Decisions Made |
Refinement Rules
DO:
- Present all findings of current priority before asking about any
- Offer 2-3 concrete options for resolving each ambiguous finding
- Record decisions in Decisions Made section
- After applying fixes, summarize changes in 2-3 bullets
Always ask for user input on:
- Substantive issues (scope, behavior, design) — present options before fixing
- Ambiguous issues — offer 2-3 concrete choices
- All findings at current priority level — address breadth before depth
OK to silently fix: Typos, formatting, and purely mechanical issues.
Round limits
Use the gate's resolved round cap from explicit --max-rounds <N> or config.yaml/CLI defaults. Process findings in priority order regardless of mode name. If the cap is reached, record unresolved findings as Open Questions or future improvements. --max-rounds 0 runs the initial review once, records its unresolved findings, and performs no refinement respawn.
Done
When the spec passes review, summarize the final spec and offer to proceed with implementation.