---
name: brainstorm
description: "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation."
---

# Brainstorming Ideas Into Designs

Audience: AI coding agents first.

Turn ideas into fully formed designs through dialogue. When enough context, write spec and proceed — no approval gates.

Route check first: user wants an autonomous run from a one-line request (no authored spec/plan) → `factory` skill instead; brainstorm→plan→run-plan is the authored-plan-doc route.

## Checklist

Create task per item, complete in order:

1. **Explore project context** — check files, docs, recent commits
2. **Ask clarifying questions** — one at a time until purpose/constraints/success criteria clear
3. **Propose viable approaches only (1-3)** — omit hacks/quick-fixes; trade-off table per approach; state recommended with reasoning; proceed unless user objects
4. **Write design doc** — auto when enough context; choose `PLAN_SLUG` (kebab key, reused by every artifact); save to `docs/specs/YYYY-MM-DD-<PLAN_SLUG>-design.md`
5. **Spec self-review** — Phase 1: completeness (placeholders, consistency, scope, ambiguity); Phase 2: architecture depth (deletion test, seam audit, depth scoring)
6. **Advisor review** — call advisor(); present questions to user if any; fix improvements/blockers silently
7. **Write compact-proof session file** — long runs only (gate below); skeleton (meta + sections 1–8 + anchors) written BEFORE invoking plan, so the durable file exists regardless of handoff
8. **Invoke plan skill → route to executor** — auto after advisor approves; immediately after plan saves its doc, populate section 9 from the wave/phase table, then route:
   - Serialize section 9 per the harness-native schema below (no `schema` key on the `meta` line). This is the only session-file format brainstorm writes.
   - **Multi-wave/multi-phase** (>1 wave/phase OR any wave has parallel tasks) → invoke `Skill("run-plan")` with the slug — it launches the harness engine directly, no handoff needed.
   - **Single-wave** → terminal; tell user: "Single-wave plan. Run `/run-plan <slug>` or `/ship` to execute."

## Process Flow

```dot
digraph brainstorm {
    "Explore project context" [shape=box];
    "Ask clarifying questions" [shape=box];
    "Enough context?" [shape=diamond];
    "Propose 2-3 approaches (state recommendation, proceed)" [shape=box];
    "Write design doc" [shape=box];
    "Spec self-review (fix inline)" [shape=box];
    "Call advisor()" [shape=box];
    "Advisor has questions for user?" [shape=diamond];
    "Present questions to user, update spec" [shape=box];
    "Fix improvements/blockers silently" [shape=box];
    "Invoke plan skill" [shape=doublecircle];

    "Explore project context" -> "Ask clarifying questions";
    "Ask clarifying questions" -> "Enough context?";
    "Enough context?" -> "Ask clarifying questions" [label="no"];
    "Enough context?" -> "Propose 2-3 approaches (state recommendation, proceed)" [label="yes"];
    "Propose 2-3 approaches (state recommendation, proceed)" -> "Write design doc";
    "Write design doc" -> "Spec self-review (fix inline)";
    "Spec self-review (fix inline)" -> "Call advisor()";
    "Call advisor()" -> "Advisor has questions for user?";
    "Advisor has questions for user?" -> "Present questions to user, update spec" [label="yes"];
    "Present questions to user, update spec" -> "Call advisor()";
    "Advisor has questions for user?" -> "Fix improvements/blockers silently" [label="no"];
    "Fix improvements/blockers silently" -> "Invoke plan skill";
}
```

**Terminal state: invoke plan → route to executor.** After advisor approval → invoke plan immediately. For long runs (gate below), write the compact-proof session file skeleton FIRST (plan auto-chains and does not return — a post-plan step would be orphaned), then invoke plan. After plan completes: multi-wave → `Skill("run-plan")` immediately; single-wave → tell user slug and stop. Do NOT invoke frontend-design, mcp-builder, or any other implementation skill.

## Understanding the Idea

- Check project state first (files, docs, recent commits)
- Assess scope before detailed questions: multiple independent subsystems → flag and decompose first
- Too large for one spec → decompose into sub-projects, brainstorm first sub-project. Each gets own spec → plan → implementation cycle
- Use `AskUserQuestion` for ALL clarifying questions — one per call, always include options. Focus on: purpose, constraints, success criteria

## Exploring Approaches

Only present approaches worth building. Omit hacks, quick fixes, clearly inferior options. Don't pad to reach a count.

Per approach, evaluate:
- **Robustness** — handles failures, edge cases, unexpected load?
- **Long-term maintainability** — easy to change/extend/reason about in 2 years?
- **Scalability** — holds under 10x data/users?
- **Performance** — latency, throughput, resource usage?
- **Reversibility** — one-way door (schema migration, protocol change, vendor lock-in) or two-way door? Prefer reversible when uncertain. One-way doors require stronger justification.
- **SEO/GEO** — crawlability, structured data, rendering strategy? *(skip if not web-facing)*
- **Infra cost** — compute, storage, egress, vendor lock-in? *(skip if negligible)*

Format per approach:
```
### Approach N: [Name]
[One-line description]

| Dimension | Assessment |
|-----------|------------|
| Robustness | ... |
| Long-term | ... |
| Scalability | ... |
| Performance | ... |
| Reversibility | two-way door / one-way door — [what locks you in or frees you] |
| Infra cost | ... |  ← only if relevant

**Weakness:** [one honest trade-off]
```

End with:
```
**Recommended: Approach N** — [2-3 sentences why it wins on dimensions that matter most]
```

Proceed with recommended unless user objects. YAGNI: no approach includes unneeded scope.

## Writing the Spec

- When enough context → write spec. Do not ask permission.
- **Choose `PLAN_SLUG` now** — short kebab-case key derived from the topic (e.g. `auth-rework`). It is the primary key for every artifact this run and the string the user types into `[[run-plan]]`. One slug, reused verbatim across spec, session file, and plan. Pass it to the plan skill so the plan doc shares the stem.
- Save spec to `docs/specs/YYYY-MM-DD-<PLAN_SLUG>-design.md`
- Cover: architecture, components, data flow, error handling, testing
- Scale sections to complexity
- Units: one clear purpose, well-defined interfaces, independently testable — can someone understand a unit without reading its internals? Can internals change without breaking consumers? If not, boundaries need work.
- In existing codebases: explore structure first, follow patterns. Include targeted improvements where existing code has problems affecting this work. No unrelated refactoring.

### Contract-level spec, NOT a code dump

**A spec pins DECISIONS and SEAMS in prose; it NEVER pastes implementation bodies.** Highest-altitude doc in the chain — leans MORE to prose than the plan does. The implementer writes the body for free by reading the repo; a body written into the spec is paid-for work the plan re-states, the implementer re-derives, and advisor + code-reviewer re-read — quadruple cost plus context rot. Same body-bloat economics `[[plan]]` applies per task, applied here at design level.

Pin in prose: architecture, component responsibilities, data flow, error-handling strategy, test strategy — and each **seam**: interface signature, type / data shape, route / schema, required literal string.

**PERMIT (keep — seams + design, not bodies):**
- interface / type signatures, function shapes (the contract, not the logic)
- data shapes, schema / route / IO shapes, JSON examples
- a required literal string / format, verbatim
- diagrams (dot / mermaid / ascii)
- illustrative snippet for a non-obvious algorithm core / tricky seam — keep ONLY the shape callers must match, any length; never the surrounding body

**NEVER paste:**
- full component / function / class body — describe behavior in bullets + pin its signature
- full stylesheet, full markup block, full config file — name the tokens / structure, link the pattern file
- any fenced block whose lines are implementation logic the implementer re-derives for free

**NEVER write the spec as a before/after code diff of the existing file.** Modifying existing code → describe the change as a CONTRACT (what the seam becomes + behavior delta), NOT a patch. Section headings like `## CSS changes`, `## HTML changes`, `## JS changes`, or `Current: <code> / Required: <code>` pairs are the tell — they pull the whole file in as a diff and balloon the spec. Instead: name the file + the responsibility that changes, pin the new seam, state the behavior delta in prose. The implementer produces the actual diff by reading the repo.

Decide BEFORE you type each fenced block: would it show HOW it works (a body)? Emit the signature + behavior prose instead — never type the body. Would it show the SHAPE callers must match (a seam)? Emit it. Classify at the keystroke; a body costs zero tokens because it is never drafted.

**Emit seams from the FIRST keystroke — do NOT draft a body then strip it.** As you write each component, reach for the signature + behavior bullets, never the implementation. Drafting full code then deleting it still burns the tokens and rots context; the win is in never writing it.

Before/after — same component:

```ts
// DO NOT — full body pasted into spec (implementer re-derives this for free):
function PreviewPane({ theme }: Props) {
  const [scale, setScale] = useState(1);
  useEffect(() => { /* 40 more lines of resize logic */ }, []);
  return <div style={{ /* 30 lines of inline style */ }}>…</div>;
}
```

```
// DO — seam + behavior:
PreviewPane({ theme: ThemeTokens }): JSX
  - renders live preview of `theme`; debounced 150ms on token change
  - fits parent via ResizeObserver; min-scale 0.5
  - styling: design tokens only (var(--*)), no inline literals — see src/components/Pane.tsx pattern
```

## Spec Self-Review

Two phases. Run both before calling advisor.

### Phase 1: Completeness

1. **Placeholder scan:** "TBD", "TODO", incomplete sections, vague requirements? Fix them.
2. **Internal consistency:** Sections contradict each other? Architecture match features?
3. **Scope check:** Focused enough for one plan, or needs decomposition?
4. **Ambiguity check:** Requirement interpretable two ways? Pick one, make it explicit.

Fix inline. (No body-bloat scan here — bodies are prevented at generation time by "Contract-level spec, NOT a code dump"; there is nothing to strip after the fact.)

### Phase 2: Architecture Depth

**Size gate:** fewer than 3 distinct proposed modules → skip (trivial spec).

Per module, apply:

**Deletion test** — delete module entirely → complexity scatters to callers? Yes → earns its boundary. No → collapse into caller.

**Single-adapter test** — seam has exactly one plausible implementation? YAGNI: collapse until second adapter needed.

**Seam audit** — boundary hides non-trivial complexity behind stable interface, or purely organizational? Decorative seams → collapse. Classic failure: hexagonal/ports-adapters/CQRS on a service whose primary function is data movement.

**Depth score per module:**
- *Shallow:* interface mirrors internal representation. No hiding.
- *Medium:* hides some implementation detail; interface survives one refactor.
- *Deep:* callers can't tell how it works; internals replaceable entirely.

Spec should have mostly medium/deep. All-shallow = over-decomposed.

**Revision candidates:** flagged modules (failed deletion, single-adapter, decorative, all-shallow). Present collapse/merge via `AskUserQuestion`. Update for accepted. For rejections, record reason.

**Append to spec:** `## Architecture Decisions` section — accepted collapses + rejected candidates with one-line reason each.

## Advisor Review Gate

After self-review, call advisor():

- **Advisor has questions** → present to user, update spec, call advisor() again
- **Advisor has only improvements/blockers** → fix inline, no user involvement
- **Spec passes** → invoke plan immediately, no user confirmation

**Only escalate to user when advisor has genuine questions that can't be resolved from context. Everything else: fix silently and proceed.**

## Session File (long runs only)

A long run WILL compact and lose goal/intent/standing-instructions/progress. Defeat that: emit one durable JSONL the executing agent (and `bin/runplan`'s launcher) re-reads to re-inject session context after every compaction. This is the **proactive** twin of `[[fix-rot]]` — fix-rot reconstructs lost context reactively; this file prevents the loss. Same record vocabulary, so fix-rot can repair this file instead of forking a format.

### Gate — write it ONLY when

`≥2 waves` OR the run is expected to compact at least once. Single obvious approach, single pass → SKIP. Do not stage a trivial task; it buries the answer under ceremony.

### File

- Path: `docs/plans/YYYY-MM-DD-<PLAN_SLUG>.jsonl` (in `docs/plans/`, next to the plan doc — NOT in `docs/specs/`). Specs are source-of-truth and may be edited in place; a fresh plan + session file is spawned per change, so the session file is plan-scoped.
- Shares the `YYYY-MM-DD-<PLAN_SLUG>` stem with the plan doc. `<PLAN_SLUG>` is the key the user passes to `[[run-plan]]`.
- **One JSON record per line. NEVER pretty-print.**
- Anchor records **point** to spec/plan; do NOT copy their prose in here.
- The harness engine's own append-only journal at `runstate/<slug>.jsonl` is the SOLE progress ground truth once a run starts — this file is authored (intent + task graph), then read, never rewritten by the engine. A task line is not touched again after authoring; there is no inline task-status field to maintain.

### Schema

Line 1 is `meta` — no `schema` key (single engine, so there is nothing left to discriminate).

```jsonl
{"type":"meta","slug":"<PLAN_SLUG>","base_branch":"<branch the plan builds ON — see rule below>","gate0_mode":"strict","preset":"<preset for the run launch — see rule below>"}
{"type":"goal","text":"<session goal>"}
{"type":"methodology","text":"<how user wants work done — standing approach>"}
{"type":"intent","text":"<the underlying WHY>"}
{"type":"direction","verbatim":"<explicit standing rule, quoted EXACTLY — never paraphrase>"}
{"type":"deferred","text":"<consciously postponed>","reason":"<why parked>"}
{"type":"checkpoint","text":"<...>"}
{"type":"gated","id":"g1","category":"irreversible|fork|input|policy|architecture","needs":"…","why":"…","blast_radius":"…","options":["proceed","abort"],"default":null,"status":"OPEN|RESOLVED","answer":null,"resolved_by":null,"source":"author|scan","binds_meta":null}
{"type":"anchor","path":"docs/specs/YYYY-MM-DD-<PLAN_SLUG>-design.md","what":"spec"}
{"type":"anchor","path":"docs/plans/YYYY-MM-DD-<PLAN_SLUG>.md","what":"plan"}
{"type":"task","id":"t<N>","wave":<N>,"seat":"coder","tier":"medium","desc":"<see rule below>","requires_decision":null}
{"type":"session_memory","note":"<fact worth keeping for THIS session only — NOT MEMORY.md-worthy (cross-session-redundant)>"}
```

**`gated` lifecycle fields (absent ⇒ treated OPEN):**
- `id` — stable key; `task.requires_decision` refs it
- `category` — open enum; baseline: `irreversible|fork|input|policy|architecture`
- `blast_radius` — MANDATORY when `category:"irreversible"`
- `options` — closed choice list shown at pre-flight. **Go/no-go decision MUST use exactly `["proceed","abort"]`** — `"abort"` is the ONLY value the engine treats as stop (every other answer PROCEEDS); a non-`abort` stop word (`skip`/`no`/`cancel`) is rejected at load. There is NO skip-this-task-but-continue — that is a plan-time graph concern (re-plan), not a gate answer. A `category:"fork"` gated is the sole exception: its options are the branch values (all proceed-semantics, injected as the task's input).
- `status` — `OPEN|RESOLVED`; absent ⇒ `OPEN`
- `answer` — chosen option, written at pre-flight; null while OPEN
- `resolved_by` — audit trail (`"user"`)
- `source` — `"author"` (planner) | `"scan"` (backstop)
- `binds_meta` — OPTIONAL; names a `meta` field this decision resolves into (run-level, no task link); absent ⇒ per-task

**`task.requires_decision`** — OPTIONAL string; the `gated.id` this task is gated on. `deps` is task→task only — user-decision blocking uses `requires_decision`, not `deps`.

**Unified "needs a human" model — three mechanisms, no new record type:**
- `deps` — task→task (agent unblocks when dep completes)
- `requires_decision` — per-task human decision (links a `gated` record)
- `gated.binds_meta` — run-level decision → meta field (no task link needed)

Planner authors `gated` records + `requires_decision` links at plan time — see [[plan]] (decision-enumeration pass).

**When to write:** skeleton (meta + goal/methodology/intent/direction/deferred/checkpoint/gated/anchor) BEFORE invoking plan. Plan auto-chains into execution and never returns control, so a post-plan write would be orphaned and the file would never exist.

- Fill goal/methodology/intent/direction/deferred/checkpoint/gated/anchor from brainstorming, before invoking plan. `checkpoint` only if user explicitly asked. `gated` only when a REAL user decision is pending (test below).
- `task` records (full list, all waves): plan owns wave analysis. Immediately after plan saves its doc — before plan proceeds to execution — populate the `task` records from the plan doc's wave table.
- `session_memory`: in-session scratch the agent appends during the run — important to remember now, redundant cross-session. Keep out of `MEMORY.md`.
- `meta.slug` = `<PLAN_SLUG>` (resume key).
- `meta.gate0_mode` — read directly by the harness engine (`plan.meta.gate0_mode`, defaults `"strict"` if absent).
- `meta.preset` — read by the v2 engine directly from this meta line (`runplan --preset <name>` can override per launch); brainstorm asks once (or reuses the project's already-established default).
- task `id`: `"t<N>"`, `N` = the plan doc's Task number. Stable, collision-free within one plan.
- task `wave`: copied directly from the plan doc's Wave Plan table — the SAME topological-sort output `plan` already produces; no re-analysis.
- task `seat`: always `"coder"`. One task record = one unit of work; `reviewer`/`fixer` seats are resolved automatically per-task at RUN time by `runTask`/`resolveOptionalSeat`, never authored per-task.
- task `tier`: preset seat-tier key, closed enum `low`/`medium`/`high` (`spec/presets.schema.json`, `lib/resolve-seat.sh`) — picks CODER's model/wrapper. Default `"medium"`. NOT a risk field — never write `"regular"`/`"critical"`, engine has no such tiers. Risk-based review escalation is separate: keyed off `riskLevel` from diff, only adds REVIEWER seat, never touches `task.tier`.
- task `desc`: **a pointer, not a body** — DRY with the plan `.md`, same doctrine as spec-writing (Contract-level spec). Exact required shape: `"Read docs/plans/<slug>.md Task <N> (<Component Name>) for the full contract. <one-line behavior summary>. Acceptance: <verbatim acceptance command from the plan doc>. Commit only: <exact Files list paths>."` This keeps the JSONL from duplicating contract prose the plan `.md` already owns, while staying self-sufficient for `buildTaskPrompt` (no other file gets auto-read by the harness engine).
- task `requires_decision`: `null` unless the decision-enumeration pass linked a `gated` record to this task.
- **`meta.base_branch` = the branch the plan builds ON — MANDATORY whenever the plan amends/extends existing code (any task that says "amend/extend/add-to <existing module>").** It MUST be the branch that ALREADY contains that code — normally the remote default (`origin/main`) or a program integration branch where the prerequisite work landed, NOT a stale local `main` and NOT the current feature checkout. The executor cuts its integration branch from this; a wrong/missing base makes the implementer rebuild the dependency from scratch → a huge bogus diff that review can't cover. Determine it by checking where the amended module actually exists (`git ls-tree -r <ref> <path>`), not by assuming. Greenfield plan with no prerequisite code → set the remote default branch anyway (never leave it to a guess).

**Surface the slug to the user.** The user executes or resumes by typing `/run-plan <PLAN_SLUG>` — they cannot if they never learned it. After writing the session file, the brainstorm output MUST state it plainly, e.g.:

> Session slug: `auth-rework` — execute or resume anytime with `/run-plan auth-rework`.

### Refresh protocol (keeps intent alive through compaction)

Event-anchored, NOT timed (agents have no timer). At a wave boundary or after a compaction system-reminder, **native Read** the durable header (every goal/methodology/intent/direction record) back into context. MUST be native Read — an exec call defeats the purpose by keeping bytes out of the thread.

Re-read AND re-write when drift is found: reading re-injects intent; rewriting the header keeps it accurate (correct drift, fold in new standing directions) so the header re-entering context is current, not stale.

### End-of-session report

Brief: what was done, what's blocked, what's deferred, what's canceled. **No "next action to do"** — if a next action is known, do it, don't announce it.

### Escalate to user only for real decisions

Before any `AskUserQuestion`: is this genuinely the user's call (irreversible, preference-bound, or outside your authority), or can advisor() or a sensible default resolve it? Prefer advisor / default. Fire `gated` + `AskUserQuestion` only for a true user decision.

## Visual Mockups

If user asks: for UI wireframes, layout comparisons, visual design choices → invoke `creating-mockups` skill.

## Key Principles

- Use `AskUserQuestion` for ALL questions — NEVER plain text
- One question per call
- YAGNI ruthlessly
- Auto-proceed when ready — no permission needed to write spec or invoke plan
- Approaches: only viable options, always recommend one, always explain why

## Learned Rules

### spec-pastes-impl-body-not-seam | fired:1 | 2026-06-25
Wizard appearance spec was 69% code — 168-line full stylesheet, 61-line JS component, 41-line markup block pasted as implementation bodies. Plan re-stated, implementer re-derived, advisor + code-reviewer re-read the same code: quadruple cost + context rot. Spec's job is decisions + seams, not bodies.
Prevent: as you draft each component, write its behavior in bullets + signature / data shape only — never type the body in the first place. Paste a body ONLY when ≤ ~10 lines AND it is a non-obvious algorithm core or a required literal. Full stylesheet / component / markup / config → name structure + tokens, link the pattern file. (Phase-1 backstop catches leaks; it is not the control.)

### ae-query-date-predicate-copy-existing | fired:1 | 2026-05-29
Spec hand-wrote AE date range as `toDateTime('YYYY-MM-DD 24:00:00')` — invalid literal. Advisor caught it. Correct predicate: `toDate(timestamp) = '${day}'` (mirrors `buildShareAeQuery`).
Prevent: when speccing any new AE query that reuses an existing dataset, read all existing `buildXxxAeQuery` functions first. Copy the exact date predicate from there — never invent one from memory.

### defineapi-no-query-field | fired:1 | 2026-05-29
Spec used `query: QuerySchema` inside a `defineApi()` call. `defineApi` has no `query` field — GET params require manual `url.searchParams.get(...)`. Advisor caught it.
Prevent: before speccing any admin API handler, read `src/server/api/define-api.ts` to confirm supported options. Supported: `body`, `auth`, `scope`, `services`, `rateLimit`. No `query`. Manual `url.searchParams` for GET params (pattern: `pages/api/admin/share/stats.ts`).

### analytics-denominator-population-mismatch | fired:1 | 2026-05-29
Spec passed `totalClicks` (from `kpis` — counts links *created* in window) as denominator for country % in AudienceTab. Country data from `share_audience_daily` counts *clicks* in window — different population. Final reviewer caught it; required prop removal + denominator fix.
Prevent: when a UI component shows percentages from two different DB/AE sources, explicitly call out their population definitions in the spec. If populations differ, the denominator must come from the same source as the numerator. Never default to a KPI-level total for a breakdown that queries a separate aggregate table.

### zustand-modal-trigger-shell-audit | fired:1 | 2026-06-05
Spec's call-site audit for `triggerAuth()` listed BuyButton callers but stopped at component level. Two `AppShell`-wrapped shells (`DealDetail`, `PageOrganizedClub`) lacked `<AuthGateModal />` in `pageOverlays` — advisor caught mid-execution, required 2 extra files.
Prevent: when spec introduces a Zustand-triggered modal (`triggerAuth`, `openX`, etc.), the Files Changed section must enumerate EVERY shell that renders any caller, verified by reading the shell file (grep for `AppShell\|PublicAppShell\|BaseLayout`). Spec claiming "N file changes" is wrong until all shells are checked.
