diff --git a/boss/SKILL.md b/boss/SKILL.md index 7852283..1744697 100644 --- a/boss/SKILL.md +++ b/boss/SKILL.md @@ -56,7 +56,9 @@ re-enters by typing `/boss` again. NO AUTONOMOUS DISPATCH OUTSIDE A `/boss` SESSION. DONE-STATE = QUEUE EMPTY, NOT SUB-GOAL COMPLETE. BOUNCE-BACK ONLY ON THE FOUR NAMED TRIGGERS. -A NEW CYCLE NEVER STARTS AUTONOMOUSLY — IT IS A BOUNCE-BACK. +A NEW CYCLE'S DESIGN RUNS AUTONOMOUSLY VIA THE `brainstorm` SWARM — IT DECIDES + THE CONVERGENT (CITED-GROUND) FORKS AND BOUNCES ONLY A DIVERGENT DIRECTION + FORK OR A GREENFIELD DESIGN BELOW THE SWARM'S GROUNDING FLOOR. ``` Universal rules (only-orchestrator-commits, main-is-sacrosanct, @@ -144,10 +146,12 @@ route(task): autonomously, as a bug issue already is. - **Forces a genuine design choice → `brainstorm`.** Writing the work down would force a choice between two or three plausible designs with - real trade-offs. Discovery must resolve it first. Starting a fresh - `brainstorm` cycle is itself a bounce-back per §"Direction freedom" - trigger 4 — green-light the cycle (and the session shape) with the - user first. + real trade-offs. Discovery must resolve it first — and `brainstorm` now + **dispatches autonomously**: its synthetic-user swarm decides the forks it + can settle on a cited shared ground (recorded on the reference issue) and + bounces only a genuine divergent direction fork, or a greenfield design + below its grounding floor, per §"Direction freedom" trigger 4. A fresh + `brainstorm` is no longer a blanket pre-dispatch bounce. - **A type/signature edit at a definition site, propagating mechanically → `compiler-driven`.** The positive trigger is *syntactic and observable*: a carrier/newtype narrowing, a constructor or field @@ -187,13 +191,17 @@ whose handling is a new code path with new observable output — is which side a change falls on, that doubt is itself the signal it carries behaviour: route up to tdd/spec, not down to compiler-driven. -The asymmetry in autonomy — `debug`, `compiler-driven`, `tdd`, and -`specify` all dispatch autonomously, while a fresh `brainstorm` cycle -bounces back — is **not** a ranking of the paths. It is a consequence of -context budget: the four are bounded (no open Q&A; `compiler-driven` and -`debug` self-settle on a run), whereas a fresh `brainstorm` is -high-context discovery the orchestrator cannot compact on its own (see -trigger 4). `specify` dispatched in `/boss` signs through its own Step-6 +Every entry path now dispatches autonomously — `debug`, `compiler-driven`, +`tdd`, `specify`, and `brainstorm` — and what differs is only *what each +bounces on*, not whether it runs. The old asymmetry (a fresh `brainstorm` +bouncing before it starts) rested on context budget: a serial-interview +`brainstorm` was high-context discovery the orchestrator could not compact on +its own. The swarm retires that rationale — it IS the compaction: the +orchestrator gets back a triaged populated space, not a 10-round interview +transcript, so `brainstorm` decides the forks the swarm settles on a cited +ground and bounces only a divergent direction fork (or a greenfield design +below its grounding floor — see trigger 4). `specify` dispatched in `/boss` +signs through its own Step-6 gate — the Step-5 `grounding-check` `PASS`, an independent agent's verdict against currently-green tests, not the orchestrator's confidence; the run then continues to `planner` without pausing. A no-override @@ -220,8 +228,10 @@ All entry paths are always available — none is profile-gated. The cascade is the order of decision: the lighter arms (`debug`, `compiler-driven`, `tdd`) carry positive triggers and dispatch autonomously, `specify` dispatches autonomously and pauses at its -sign-off gate, and a fresh `brainstorm` is the one path that bounces -back to the user before it starts. +sign-off gate, and `brainstorm` dispatches its swarm autonomously — +deciding the forks it can settle on a cited ground and bouncing only a +divergent direction fork (or a greenfield design below its grounding +floor). If the working tree is mid-flight (uncommitted changes left over from a previous session): inspect first, then resume the right @@ -373,24 +383,28 @@ Bounce back to the user only when: project's direction (a fundamental design flaw, an external dependency failure, a discovered invariant violation). - The user has explicitly asked for a checkpoint. -- **The next item on the queue is a new cycle** — i.e. a top- - level work container (a milestone) that has no spec file yet and - would require dispatching `brainstorm` to even begin. - Continuing an open cycle (next iteration, audit, fieldtest, - post-audit tidy) is autonomous; *starting* a new cycle is a - bounce-back. +- **The `brainstorm` swarm surfaces a divergent direction fork.** A new + cycle's design runs autonomously through the `brainstorm` swarm, which + decides the forks it can settle on a cited shared ground and records them on + the reference issue. What bounces is the residue: a fork the swarm splits on, + or agrees on with no citable ground (ungrounded-consensus), or one the + orchestrator's own Step-2 enumeration held open — a genuine **direction + fork** only the user's preference can settle. A greenfield design *below the + swarm's grounding floor* (no ledger to cite against) likewise bounces, + because the swarm cannot run honestly and the work needs a human interview. + Continuing an open cycle and *starting* a new one are now both autonomous up + to this residue. **Why this is different from the other three triggers.** - Cross-cycle work is high-context work. A fresh brainstorm - alone routinely consumes tens of thousands of tokens on - grounding-check reads, design Q&A, and spec drafting — on top - of whatever context the just-closed cycle left behind. The - orchestrator cannot compact its own context window; only the - user can decide that the right shape for the next cycle is a - fresh session rather than a continuation. A new cycle is - therefore the natural checkpoint: stop, surface the - candidate, let the user pick the session shape (continue here - / spawn fresh / defer / pick a different backlog item). + This is the design-judgement checkpoint the swarm cannot discharge. The + swarm compacts the discovery — the orchestrator gets back a triaged + populated space, not a high-context interview transcript — so the old "a + fresh brainstorm is too high-context to run autonomously" rationale is + retired (the swarm IS the compaction). What stays genuinely the user's is + the direction fork itself: a choice no source settles, where a guessed + default is the reactive-overreach the discipline forbids. Surface it as a + vetoable problem-state notify naming, in the user's terms, the design choice + that needs them; the convergent decisions ride along on the reference issue. A summary of what shipped is fine and welcome — but in autonomous mode, follow it with the next dispatch, not a @@ -416,8 +430,9 @@ narrow one for spec auto-sign: freedom" — design fork the orchestrator cannot resolve, an unexpected invariant violation, an external dependency failure, the user has explicitly asked for a checkpoint, or - the next backlog item is a new cycle (no spec yet) and - starting it would force a fresh `brainstorm`. + the `brainstorm` swarm surfaced a divergent direction fork + (or a greenfield design below its grounding floor) that needs + the user's call. 3. **Auto-sign.** The orchestrator signed a spec in the user's place and is @@ -667,13 +682,13 @@ the user wants it — there is no autonomous filing to govern. | "Top of the backlog has two equally good options, I'll just pick one" | If both are substantive and the choice is non-obvious, that's a real fork — bounce back. The cost of a wrong pick (working-tree discard) is higher than the cost of one short ping to the user. | | "User said 'until X then notify', X just completed, notify now" | Check whether X was actually the last actionable thing. If hitting X leaves an open cycle with obvious follow-up, the user's intent was "wake me when there's nothing else to do" — continue. | | "Notify can name the iteration code — user will figure out what it means" | No. The notify text is for the user-as-reader who did not watch the orchestrator work. Iteration codes, crate names, function identifiers, type names — all internal, all banned. | -| "The previous cycle closed cleanly and the next backlog item is obvious — just dispatch `brainstorm` and keep going" | No. Starting a new cycle is itself a bounce-back. A fresh `brainstorm` is high-context work, and the orchestrator cannot compact its own context — only the user can decide whether the next cycle wants a fresh session or a continuation of this one. The "obviousness" of the candidate is irrelevant; the *cross-cycle hop* is the checkpoint, not the topic choice. | -| "It's the same broad area as the cycle I just closed, that's not really a new cycle" | If there is no spec file for it yet and it would route through `brainstorm` to get one, it IS a new cycle for this rule's purposes. The rule keys on "needs a fresh spec", not on subjective continuity. | +| "The previous cycle closed cleanly and the next backlog item is obvious — just dispatch `brainstorm` and keep going" | Dispatching `brainstorm` IS now the autonomous move — its swarm decides the forks it can settle on a cited ground and records them. What you may not do is auto-decide a *divergent direction fork* the swarm could not ground; that bounces. Dispatch the swarm, decide the convergent forks, bounce only the residue. | +| "The swarm all converged, so I can auto-decide the whole design and move on" | Only forks converged on a *cited shared ground* are decided. Same-model stances agreeing with no citable ground is ungrounded-consensus — a direction fork that bounces, not a decision. Auto-deciding bare agreement is the false-convergence trap that ships the user's once-per-project fork past them. | | "Feature work, so route it to `brainstorm` — that's the safe default" | The entry paths are an ordered cascade, none the default. Routing a settled design to `brainstorm` re-litigates decided choices; routing a test-specifiable item there wastes the test path; routing a behaviour-preserving type-edit there is the heavy-path gravity well this whole reflection exists to break. Walk the cascade and take the first matching positive trigger. The only tilt toward `brainstorm` is a genuinely unresolved fork — and that is a fork, not a default. | | "It's just a mechanical rename across N files — run the full implement loop on it" | That is the `compiler-driven` arm's job, not the heavy loop. Route it there; the type checker enumerates the sites, and the done-signal (clean build AND suite green unchanged) is the gate. Funnelling a behaviour-preserving edit through the full per-task loop is the disproportionality the cascade was added to fix. | | "The compiler-driven edit built clean — that's the done-signal, commit" | Clean build is only half. The done-signal is clean build **AND suite green unchanged**. A behaviour change can build clean; the unchanged-green suite is what catches it. No suite run, no commit — and if the suite isn't green-unchanged, bounce to `debug`. | | "It's a bug but the fix is a one-line type edit — route it `compiler-driven`" | No. An observed bug is first in the cascade → `debug`, RED-first, regardless of how mechanical the fix looks. The bug-gate sits before the type-edit arm precisely so a regression cannot launder itself around RED-first. | -| "The issue is exhaustive but it's a new cycle, so bounce to the user before `specify`" | `specify` direct-entry is bounded and autonomously dispatchable — it is NOT the high-context `brainstorm` cycle that trigger 4 reserves for the user. Dispatch it; it will pause at its own user-review gate for sign-off. The pre-dispatch bounce is for an *open* design that needs discovery, not for a settled one that needs only production. | +| "The issue is exhaustive but it's a new cycle, so bounce to the user before `specify`" | `specify` direct-entry is bounded and autonomously dispatchable — a settled design needs production, not discovery; don't route it through `brainstorm` at all. And even an *open* design no longer blanket-bounces: its swarm runs autonomously and bounces only a divergent direction fork. The bounce is for an unresolved *direction*, never for "it's new". | | "`tdd` is the secondary skill, `brainstorm` is the real entry" | All entry paths are always available. The choice among them is the cascade, walked per item — not a habit of treating `brainstorm` as primary and the lighter arms as exceptions. The lighter arms exist to be reached; reaching past them by elimination is the failure the verification axis was added to prevent. | | "This spec is clearly good — I'll sign it on my judgement" | Your judgement is not the signature; the Step-5 `grounding-check` `PASS` is. Run grounding and sign on the PASS. A no-override grounding `BLOCK` routes to the human — never signed over on confidence. (The old unanimous `spec-skeptic` panel is retired; do not re-introduce it as a gate.) | | "There's an open fork — I'll bounce to `brainstorm` to be safe" | If you can *derive* an answer (sources, code, consistency, risk), decide it boldly and record it in the reference issue. Only a *pure-preference* fork bounces. Bouncing a derivable fork is exactly the timidity the bold stance retired; unsure if your leaning is bias, pull one ad-hoc `spec-skeptic` lens, then decide. | @@ -692,7 +707,7 @@ the user wants it — there is no autonomous filing to govern. - About to autonomously dispatch in a session where the user did NOT type `/boss`. - About to send a notify that names a crate, an iteration code, or an agent. - About to bounce back at every iteration boundary "just to be safe" — that's reactive deference, not direction freedom. -- About to dispatch `brainstorm` on a backlog issue that does not yet have a spec file, without first bouncing back to the user. New cycles never start autonomously. +- About to *auto-decide* a divergent direction fork the `brainstorm` swarm could not ground (or could only agree on with no citable ground) instead of bouncing it — or, conversely, bouncing the whole fresh `brainstorm` "to be safe" instead of running its swarm autonomously and bouncing only the divergent residue. - About to route feature work to `brainstorm` without walking the Entry-path cascade — defaulting to it because it "feels safer" than the lighter arms, rather than taking the first matching positive trigger. Routing a *settled* design, a *test-specifiable* item, or a *behaviour-preserving type-edit* to `brainstorm` is as much a failure as skipping discovery on an open one. - About to route an observed bug to the `compiler-driven` arm because "the fix is mechanical" — a regression is `debug`, RED-first; the bug-gate is first in the cascade for exactly this reason. - About to route a behaviour-encoding change to `compiler-driven` because it "looks mechanical" — apply the straddle rule: if the change encodes new behaviour it is `tdd` / `spec-driven`, and doubt means it carries behaviour. diff --git a/brainstorm/SKILL.md b/brainstorm/SKILL.md index 183a5d9..67d55f9 100644 --- a/brainstorm/SKILL.md +++ b/brainstorm/SKILL.md @@ -1,45 +1,55 @@ --- name: brainstorm -description: Use when a new cycle is starting and the design is NOT yet settled — gathers requirements, explores 2-3 approaches with trade-offs, presents a sectioned design with user approval, then hands the ratified design to the specify skill to produce the spec. The optional discovery front-end; when the design is already settled in the sources, skip to specify directly. Applies even when the user says they have a clear vision. +description: Use when a new cycle is starting and the design is NOT yet settled — enumerates the load-bearing design forks, populates them with a parallel swarm of grounded synthetic-user stances instead of a serial interview, triages the result (forks the swarm settles on a cited ground are decided; forks it splits on are the user's call), then hands the ratified design to specify. The optional discovery front-end; when the design is already settled in the sources, skip to specify directly. Applies even when the user says they have a clear vision. --- -# brainstorm — cycle spec generator +# brainstorm — cycle discovery front-end > **Violating the letter of these rules is violating the spirit.** ## Overview -Discovery is where the orchestrator does the *deciding* work — -surfacing requirements, exploring approaches, and ratifying a design -with the user. It is the front-end that resolves a genuine design fork -before any spec is written. Skipping it when the design is genuinely -open means shipping the user's intuition unfiltered, which is exactly -the reactive-deference failure mode the orchestrator discipline exists +Discovery is where the orchestrator does the *deciding* work — surfacing the +load-bearing forks a new cycle forces, resolving the ones it can ground an +answer for, and putting the rest to the user. It is the front-end that +settles a genuine design fork before any spec is written. Skipping it when the +design is genuinely open means shipping the user's intuition unfiltered, which +is exactly the reactive-deference failure the orchestrator discipline exists to prevent. +What `brainstorm` no longer does is run a **serial interview** — one question +per message, a per-section ratification gate — to get there. That ceremony +spent ~10 blocking round-trips per cycle to catch a divergence from the +orchestrator's recommendation that, across a whole project, materialises about +once. Instead `brainstorm` **populates the design space in parallel**: it +enumerates the forks, dispatches a swarm of grounded, genuinely-opposed +synthetic-user stances to answer them, and triages the result. Where the +stances converge on a *cited* common ground the fork was derivable — it is +decided, and the user only vetoes. Where they genuinely split, no source +settles it — it is a **direction fork**, and that is the user's call. Direction +is never delegated downstream; it is set here, by the user, on exactly the +forks that turn out to be theirs. + `brainstorm` does not write the spec. Its terminal state is handing the -ratified design to `specify` (the spec-production core), which applies -the acceptance criterion, writes the spec under `docs/specs`, runs -the gates, and takes user sign-off. When the design is *already* -settled in the sources, `brainstorm` is skipped entirely and the work -enters through `specify` directly. +ratified design to `specify` (the spec-production core), which applies the +acceptance criterion, writes the spec under `docs/specs`, runs the gates, and +takes sign-off. When the design is *already* settled in the sources, +`brainstorm` is skipped entirely and the work enters through `specify`. ## When to Use / Skipping Triggers: -- A new cycle is starting (e.g. user proposes a new feature - area, a new subsystem, or a major refactor of an existing - one). -- A cycle-scope spec is missing for an existing line of - work and one is needed retroactively. +- A new cycle is starting (a new feature area, a new subsystem, or a major + refactor of an existing one) whose design is genuinely open. +- A cycle-scope spec is missing for an existing line of work and one is needed + retroactively, and the design behind it was never settled. **Skip `brainstorm` (enter through the named alternative) for:** -- A design already settled in the sources — an exhaustive issue, a - long in-context discussion, settled design docs. Use `specify` - directly: discovery would only re-litigate decisions the sources - already made. +- A design already settled in the sources — an exhaustive issue, a long + in-context discussion, settled design docs. Use `specify` directly: + discovery would only re-litigate decisions the sources already made. - A test-specifiable feature — use `tdd` directly. - A bug-fix iteration — use `debug` directly. - A tidy iteration — use `audit` directly. @@ -47,156 +57,294 @@ Triggers: **Do not skip `brainstorm`** when the design is genuinely open: -- A user request framed as "I have a clear vision, just plan it" whose - vision still hides an unresolved fork. +- A request framed as "I have a clear vision, just plan it" whose vision still + hides an unresolved fork. - A cycle where a load-bearing decision is not yet made. The discriminator is the design line: if the sources resolve every -load-bearing decision, the work belongs to `specify`; if writing the -spec would force you to *pick* one, discovery is what resolves it, and -that is `brainstorm`. +load-bearing decision, the work belongs to `specify`; if writing the spec +would force you to *pick* one, discovery is what resolves it, and that is +`brainstorm`. + +## The Iron Law + +``` +ENUMERATE EVERY LOAD-BEARING DESIGN FORK BEFORE POPULATING ANYTHING — THIS + ENUMERATION IS ALSO THE ORCHESTRATOR'S OWN INDEPENDENT SIGNAL, USED LATER TO + CROSS-CHECK THE SWARM. +A FORK THE SWARM SETTLES ON A *CITED SHARED GROUND* WAS DERIVABLE -> PRESENT IT + DECIDED (USER VETOES), AND RECORD THE GROUND. A FORK THE SWARM SPLITS ON, OR + AGREES ON WITH *NO CITABLE GROUND* (UNGROUNDED-CONSENSUS), IS A DIRECTION + FORK -> THE USER'S CALL. THE LINE IS GROUNDED-DERIVABILITY VS PREFERENCE, + NOT SMALL VS LARGE, AND NOT BARE AGREEMENT. +A FORK THE ORCHESTRATOR'S OWN ENUMERATION FLAGGED OPEN BUT THE SWARM CLOSED IS + SURFACED TO THE USER ANYWAY — THE SWARM NEVER ERASES A FORK THE ORCHESTRATOR + INDEPENDENTLY HELD OPEN. +THE DECIDING WORK IS NEVER SKIPPED. A DESIGN PRESENTED WITHOUT THE FORK + ENUMERATION + SWARM + TRIAGE DONE IS THE RUBBER-STAMP BETRAYAL, NOT DISCOVERY. +DESIGN DIRECTION IS SET HERE BY THE USER — NEVER DELEGATED TO THE SWARM, NEVER + TO `specify`. +``` + +Every clause is non-negotiable. The swarm is *evidence*, not an oracle: it +populates the space and exposes where stances split, but the convergent-vs- +direction verdict is the orchestrator's derivability judgement (the same one +`specify` Step 1.5 applies), and bare agreement among same-model stances is +never that judgement — only agreement on a citable ground is. ## The Process ### Step 1 — Explore project context -Before asking any clarifying questions: +Before enumerating anything: -- `git log -5 --format=full` for the full bodies of the most - recent iter / audit commits — current state of the project. -- If the project has a design ledger (its CLAUDE.md project facts name - it), walk to the relevant contracts for the invariants the new cycle - might touch. -- When reading any file under the project's design models, if it has - them, or the ledger's "model" rows, note its `status` / - `validated-against` frontmatter if present: `status: - aspirational` means its code is a target, not verified fact. - Track which content you may lift from such a source — it is - flagged for lift-time validation when `specify` writes the spec. +- `git log -5 --format=full` for the full bodies of the most recent iter / + audit commits — current state of the project. +- If the project has a design ledger (its CLAUDE.md project facts name it), + walk to the relevant contracts for the invariants the new cycle might touch. +- When reading any file under the project's design models, note its `status` / + `validated-against` frontmatter if present: `status: aspirational` means its + code is a target, not verified fact. Track which content is flagged for + lift-time validation when `specify` writes the spec. - `git log --oneline -20` for the chronological scan. -- Identify scope: is this one cycle, or does it need to be - decomposed into sub-cycles first? If multi-subsystem, - decompose. +- Identify scope: is this one cycle, or does it need to be decomposed into + sub-cycles first? If multi-subsystem, decompose. -### Step 2 — Ask clarifying questions, one at a time +### Step 2 — Enumerate the load-bearing forks -Multiple-choice when possible (easier to answer). One -question per message — no batching. Focus on: +List the **load-bearing design forks** the cycle forces — the choices that, +decided differently, would change what ships — exactly as the clarifying +questions you would otherwise have put to the user. Cover at least: - **Purpose:** what problem does this solve? -- **Constraints:** what semantic / performance / - compatibility invariants must hold? +- **Constraints:** what semantic / performance / compatibility invariants must + hold? - **Success criteria:** how do we know it shipped? - **Scope:** what is OUT of scope? -### Step 3 — Propose 2-3 approaches with trade-offs +For each fork, privately note whether *you* think it is derivable or genuinely +open. This enumeration is the swarm's input **and** your own independent +signal: a fork you flagged open that the swarm later closes is surfaced to the +user anyway (the Iron Law cross-check). Do not interview the user here — no +serial questions. -Lead with your recommended option and explain why. Each -approach gets: +### Step 2.5 — Fire-check (skip the swarm when it would be ceremony) -- core idea (1-2 sentences) -- **concrete code first, prose second.** The *primary* - artefact is the actual program or invocation that should - work under this approach — written in the project's - canonical authoring or consumer form. Show it. The - implementation shape (changed struct / signature / match- - arm, before → after) is *secondary supporting* detail — - "also useful, not the point" — include it but never let it - stand in for the concrete user-facing code. "The approach - extends the struct with a field" is not an approach; the - user-facing program it makes work (or correctly reject) is. -- substantive trade-offs (semantic fit, schema impact, - performance, composability) -- effort observation (NOT effort as rationale — see the - project's CLAUDE.md on design rationale ≠ implementation - effort) +The swarm is justified only when there are **multiple non-trivial forks whose +derivability is genuinely uncertain** *and* there is enough checked-in ground +to answer them honestly. Skip it, and resolve inline, when: -Wait for user choice before proceeding. +- **Too few forks.** Zero or one real fork — answer it directly (a single + derivable fork is decided and noted; a single open one is one question to + the user). Spinning up a swarm for one fork is more machinery than the + ceremony it replaced. +- **Grounding floor not met.** No design ledger, a thin or absent glossary, an + under-specified audience — a greenfield or new-territory project. With + nothing to cite, every synthetic stance confabulates and "convergence" is + 100% hallucination wearing a quorum. Below this floor the swarm is NOT + dispatched; fall back to a direct human interview (and under `/boss`, that is + a bounce-back — see § Under `/boss`). -### Step 4 — Present design in sections +Record the skip reason in the cycle's notes / the run's reference issue. The +swarm is an optimization for context-rich mature projects, not an +unconditional default. -Scale each section to its complexity (a few sentences if -straightforward, up to 200-300 words if nuanced). Cover: +### Step 3 — Populate the space with the synthetic-user swarm -- Architecture -- Components -- Data flow -- Error handling -- Testing strategy +Dispatch the read-only `agents/synthetic-user.md` agent **in parallel, one per +stance, in a single turn** — the same ad-hoc fan-out brainstorm already uses +for `plan-recon` and `specify` uses for `spec-skeptic`. No Workflow wrapper: a +one-shot stateless fan-out has no re-loop, no ordering, and no in-code verdict +to enforce, so it is a direct dispatch, not an `implement-loop`-style script. -The design you present here is conceptual — the architecture, -components, data flow, error handling, and testing strategy the cycle -commits to. The concrete user-facing code and the before → after -implementation shapes are produced downstream, when `specify` -materialises this ratified design into the spec (and applies the -acceptance criterion against that worked code). Your job here is to get -the *design decision* right and ratified, not to write the artefact. +The roster is **fixed convention** (no per-project config knob; only the +*grounding* — the project's declared audience / ledger / glossary, reached via +standing reading — varies): -Ask after each section whether it looks right. Be ready to -revisit earlier sections if a later one surfaces a -contradiction. +- **minimalist** — convention over config, the smallest change that ships. +- **power-user / composability** — capability, extension, what it unlocks. +- **maintainer / future-self** — invariants, drift cost, long-term carry. +- **skeptic** — does this need to exist at all (the feature-acceptance + criterion incarnate). +- **off-ledger wildcard** — advocates the direction the project does *not* + imply. Inherently ungrounded by design, so it can only ever surface a fork, + never close one; it exists to keep the swarm from collapsing into + status-quo unanimity. -### Step 5 — Hand off to `specify` +Each stance answers the whole `fork_set` with a **mandatory per-answer source +citation or an honest `ungrounded:true`** (the agent's Iron Law). The swarm +ONLY answers the forks; it never authors approaches. -The terminal state of `brainstorm` is invoking `specify`. NO spec file -is written here; NO other skill is invoked; NO direct jump to `planner` -or `implement`. +### Step 4 — Triage and present the populated space + +This is the **one user stop** in interactive mode. Cluster the stances' +answers per fork and apply the derivability test — the same one `specify` +Step 1.5 uses, measured here against the swarm: + +- **Converged on a cited shared ground → DECIDED.** Present it as decided with + the ground shown; the user only vetoes. Record the ground. +- **Split, or converged with no citable ground (ungrounded-consensus) → + DIRECTION FORK.** The user's call. Surface the conflicting positions (and + the wildcard's off-ledger alternative where it raised one) as the things to + weigh. Bare agreement among same-model stances is *not* a decision — demote + it. +- **Cross-check.** Any fork your own Step-2 enumeration flagged open that the + swarm closed is surfaced anyway, never auto-decided. + +Then **author the 2-3 approaches** yourself — the orchestrator's job, never the +swarm's. They crystallise out of the populated space: the converged axes are +fixed; each genuine direction fork's conflicting answers *is* an approach the +user weighs. Lead with your recommended option and why; for each: + +- **concrete code first, prose second.** The primary artefact is the actual + program or invocation that should work under this approach, in the project's + canonical authoring or consumer form. The implementation shape (changed + struct / signature / match-arm, before → after) is secondary supporting + detail, never a substitute for the user-facing code. +- substantive trade-offs (semantic fit, schema impact, performance, + composability). +- effort observation (NOT effort as rationale — see the project's CLAUDE.md on + design rationale ≠ implementation effort). + +Present the conceptual design alongside — Architecture, Components, Data flow, +Error handling, Testing strategy — each scaled to complexity. This design is +conceptual: the concrete user-facing code and the before → after shapes are +materialised downstream when `specify` writes the spec and applies the +acceptance criterion. Your job here is to get the *design decision* right and +ratified, not to write the artefact. + +If the populated space shows **every** candidate approach is bad, that is the +"problem is mis-framed" signal — STOP and escalate to the user, do not ratify a +known-bad shape. Three unsatisfying approaches mean the problem is wrong, not +that one must be picked. + +### Step 5 — Deepen the forks the user opens + +Deepening is **free chat** with the orchestrator by default — the user's +native mode, and the one place they have chosen to engage. A direction fork is +by definition one the swarm could not ground, so re-running the swarm on it +asks the machinery that already failed to converge to try again; do not make a +second swarm round the default. It is an **optional** tool the orchestrator MAY +reach for, scoped to one fork, only to populate *in-direction* sub-options once +the user has tilted toward a direction, or to rescue a fork that turns out to +be mis-framed — `spec-skeptic`-style, a tool reached for, not a gate. + +**Capture the resolution.** Whatever the chat settles is folded into the +ratified design narrative handed to `specify`, and minuted on the run's +reference issue (the `specify` Step-1.5 reconciliation-comment / `boss` +decision-log discipline). The free-chat deliberation that used to evaporate now +lands in the pipeline. + +### Step 6 — Hand off to `specify` + +The terminal state of `brainstorm` is invoking `specify`. NO spec file is +written here; NO other skill is invoked; NO direct jump to `planner` or +`implement`. Hand off carries the **ratified design narrative**, in-context (same orchestrator context — no intermediate artefact): - the approach chosen and why -- the constraints and invariants surfaced in Q&A +- the constraints and invariants surfaced in the swarm + deepening - the design sections the user ratified (Step 4) +- the **decided forks with their cited grounds**, and the **resolved direction + forks with the user's choice** — so `specify`'s chain-entry (Step 1.5, + "re-ground lightly … rather than re-deriving it") reads them as already + settled instead of re-litigating them - the iteration scope ("the first iteration covers section X+Y") -`specify` reads this narrative as its source, applies the -acceptance criterion, writes the spec, runs the parse and -grounding-check gates, takes user sign-off, and hands off to `planner`. -The production gates live there, not here. +`specify` reads this narrative as its source, applies the acceptance criterion, +writes the spec, runs the parse and grounding-check gates, takes sign-off, and +hands off to `planner`. The production gates live there, not here. + +## Under `/boss` (autonomous) + +When the user is away, the swarm runs **autonomously** — the discovery is now +bounded and context-compacting (the orchestrator gets back a triaged populated +space, not a 10-round interview transcript), so a fresh `brainstorm` is no +longer a mandatory pre-dispatch bounce. The autonomous contract mirrors +`specify`'s bold-decide stance: + +- **Decide the convergent forks.** A fork the swarm settles on a cited shared + ground is decided autonomously and **recorded on the run's reference issue** + with the ground (the `boss` § Direction-freedom decision-log discipline) — + exactly as `specify` Step 1.5 records a derived fork. +- **Bounce only the divergent direction forks.** A genuine direction fork (split, + or ungrounded-consensus, or one the Step-2 cross-check held open) is the + user's call; there is no user present, so it routes to a **problem-state + bounce** — a vetoable notify naming, in the user's terms, the design choice + that needs them. The convergent decisions ride along; only the genuine forks + stop the loop. +- **Grounding floor → bounce.** If Step 2.5's grounding floor is not met + (greenfield, no ledger), the swarm cannot run honestly and the work needs a + human interview — that remains a bounce-back, on grounding grounds, not on + the retired "fresh brainstorm is too high-context" rationale. + +See `../boss/SKILL.md` § Direction freedom (trigger 4) and the Entry-path +reflection for how this folds `brainstorm` into the autonomous cascade. ## Handoff Contract | Direction | Carrier | |-----------|---------| | user → `brainstorm` | new cycle request with a genuinely open design | -| `brainstorm` → `specify` (Step 5) | ratified design narrative (approach, constraints, ratified sections, iteration scope) — in-context; no spec file written | +| `brainstorm` → `synthetic-user` swarm (Step 3) | `fork_set` + one `stance` per dispatch + grounding pointers; read-only, parallel, no Workflow | +| `brainstorm` → user / reference issue (Step 4 / `/boss`) | the triaged populated space: decided forks + cited grounds, direction forks surfaced for the user's call | +| `brainstorm` → `specify` (Step 6) | ratified design narrative (approach, constraints, ratified sections, decided forks + grounds, resolved direction choices, iteration scope) — in-context; no spec file written | ## Common Rationalisations | Excuse | Reality | |--------|---------| -| "User says 'clear vision, just plan it' — skip the spec" | "Clear vision" is a starting point, not a spec. The user's intuition hasn't priced in semantic commitments the project carries. Write the spec; frame it as "load-bearing decisions this idea forces on us". | -| "Cycle is small, two iterations, no spec needed" | Iteration count isn't the metric — feature surface is. A two-iter feature touching design-ledger invariants needs a spec; a CLI flag does not. Assess what the feature changes in invariants. | -| "Three approaches in, none feel right, ship the least bad" | Three unsatisfying approaches usually means the problem is mis-framed. Stop, capture the three approaches and what fails about each in the spec's design notes (or escalate to the user), sleep on it. End-of-day pressure is the worst signal to resolve a design fork. | -| "User is busy, present my own design without Q&A" | Reactive deference disguised as decisiveness. The Q&A surfaces constraints the user hasn't articulated; skipping it means shipping the user's defaults, not their intent. | -| "Spec exists from previous cycle, append to it" | The previous cycle's spec was retired at its close (see `../docs/conventions.md` § Lifecycle) — there is nothing to append to. New cycle = new spec file; the architect reads one cycle's spec at a time, and mixing scopes makes drift review unreadable. | -| "Approaches A, B, C are all bad — proceed with A" | This is exactly the moment to surface "the problem is mis-framed" rather than ratify a known-bad shape into the design ledger. Escalate to the user. | +| "User says 'clear vision, just plan it' — skip the discovery" | "Clear vision" is a starting point, not a settled design. Enumerate the forks; the swarm will show which the vision actually resolves and which it papers over. The ones it papers over are the user's to settle. | +| "Present my own derived design without the swarm — I already know the answer" | Deriving one answer alone and presenting it polished is the single-guess rubber-stamp. The swarm's diversity is what surfaces the constraint you did not think to derive; the cross-check is what stops your own prior from erasing a fork. Run the swarm (above the fire-check floor) or you are shipping unfiltered intuition with extra steps. | +| "The swarm all agreed, so the fork is decided" | Only if they agreed on a *cited shared ground*. Same-model stances agree by shared prior all the time — that is ungrounded-consensus, and it is a direction fork for the user, not a decided one. Bare agreement is the false-convergence trap, not a verdict. | +| "There's a direction fork left — re-run the swarm on it to be thorough" | A direction fork is the one the swarm could not ground; re-swarming asks the same non-oracle the same unanswerable question at higher resolution, and the extra detail only makes the guess more persuasive. Deepen it in free chat with the user; a scoped re-swarm is optional and only for in-direction sub-options after the user has tilted. | +| "Three approaches in, none feel right — ship the least bad" | Three unsatisfying approaches usually means the problem is mis-framed. Stop, capture what fails about each, escalate to the user. End-of-day pressure is the worst signal to resolve a design fork. | +| "Spec exists from previous cycle, append to it" | The previous cycle's spec was retired at its close (see `../docs/conventions.md` § Lifecycle) — there is nothing to append to. New cycle = new spec file; mixing scopes makes drift review unreadable. | +| "Let the swarm author the approaches — it has the stances already" | The swarm answers forks; the orchestrator authors approaches. A finished design from the swarm delegates design DIRECTION to a fan-out — the same downstream-delegation sin the reform exists to prevent, just relocated from `specify` to the agents. | ## Red Flags — STOP -- "Skip the spec" thoughts (any flavour) -- "One paragraph is enough" -- "User said it's clear, who am I to push back" -- "The 2-3 approaches all suck, just pick one" -- Inventing a design rationale that's actually about effort, - not semantics +- "Skip the discovery" thoughts (any flavour) on a genuinely open design. +- Presenting a design without having enumerated the forks, run the swarm + (above the fire-check floor), and triaged it. +- Treating bare swarm agreement as a decision — an ungrounded-consensus + silently auto-decided instead of surfaced as the user's call. +- A fork your own Step-2 enumeration held open, quietly closed by the swarm and + not surfaced (the cross-check skipped). +- Letting the swarm author the 2-3 approaches, or delegating any design + *direction* to it. +- Re-running the swarm on a direction fork as the default deepening path + instead of free chat with the user. +- Running the swarm below the grounding floor (greenfield, no ledger) and + trusting its confabulated convergence. +- "The 2-3 approaches all suck, just pick one" — that is the mis-framed-problem + escalation, not a forced pick. +- Inventing a design rationale that's actually about effort, not semantics. ## Cross-references -- **Output target:** `../specify/SKILL.md` — the only valid next - skill. `brainstorm` hands the ratified design to `specify`, which - produces the spec and gates `planner`. There is no direct - `brainstorm → planner` edge any more. -- **Alternative entry path / bounce-back source:** `../tdd/SKILL.md` — - a test-specifiable feature enters through `tdd` instead of here; - `tdd` bounces back the moment the behaviour stops being - test-specifiable. `../specify/SKILL.md` likewise bounces back here - when the sources do not resolve a design fork. -- **Ad-hoc dispatch.** The orchestrator MAY ad-hoc dispatch - `../planner/agents/plan-recon.md` during Step 1 when the cycle - enters code territory not recently read; ad-hoc, not part of the - standard process. +- **Agent dispatched:** `agents/synthetic-user.md` — the read-only synthetic + design-stance respondent, dispatched as a parallel swarm in Step 3. A + `spec-skeptic` sibling: a fixed read-only lens family that returns a finding, + never a verdict. +- **Output target:** `../specify/SKILL.md` — the only valid next skill. + `brainstorm` hands the ratified design to `specify`, which produces the spec + and gates `planner`. There is no direct `brainstorm → planner` edge. +- **Shared derivability test:** `../specify/SKILL.md` Step 1.5 — the + derivable-vs-pure-preference line `brainstorm` measures against the swarm is + the same one `specify` applies to the sources; defined there, referenced here, + so the two cannot drift. +- **Alternative entry path / bounce-back source:** `../tdd/SKILL.md` — a + test-specifiable feature enters through `tdd` instead; `tdd` bounces back the + moment the behaviour stops being test-specifiable. `../specify/SKILL.md` + likewise bounces back here when the sources do not resolve a design fork. +- **Autonomous behaviour:** `../boss/SKILL.md` § Direction freedom (trigger 4) + and the Entry-path reflection — how the autonomous swarm-brainstorm decides + convergent forks and bounces only divergent ones. +- **Ad-hoc dispatch.** The orchestrator MAY also ad-hoc dispatch + `../planner/agents/plan-recon.md` during Step 1 when the cycle enters code + territory not recently read; ad-hoc, not part of the standard process. - **Project feature-acceptance criterion:** declared in the project's - `CLAUDE.md` — applied prospectively by `specify` (its Step 2), not - here. + `CLAUDE.md` — applied prospectively by `specify` (its Step 2), not here. diff --git a/brainstorm/agents/synthetic-user.md b/brainstorm/agents/synthetic-user.md new file mode 100644 index 0000000..c822f67 --- /dev/null +++ b/brainstorm/agents/synthetic-user.md @@ -0,0 +1,134 @@ +--- +name: synthetic-user +description: Read-only synthetic design-stance respondent for the brainstorm swarm. Answers the orchestrator's enumerated design forks from ONE fixed adversarial stance, grounded in the project's audience / design ledger / glossary, with a mandatory source citation per answer. Does NOT decide and does NOT author approaches; the convergence vs divergence of many stances is the orchestrator's fork-triage evidence. +tools: Read, Glob, Grep, Bash +--- + +> Violating the letter of these rules is violating the spirit. + +## What this role is for + +This role exists to stop two opposite failures of brainstorm discovery at +once. The first is the **serial interview**: marching the user through one +question at a time about forks the orchestrator could have derived — the +wall-clock tax the swarm replaces. The second is **the single-guess +rubber-stamp**: the orchestrator deriving one answer alone and presenting it +as settled, which the user waves through without the constraints a real +interview would have surfaced. A swarm of grounded, genuinely-opposed stances +answers the forks in parallel so that *where the stances converge on a cited +ground the fork was derivable, and where they diverge it is the user's call*. + +But the swarm has its own failure mode, and it is the one you must fight: +**false convergence**. Every stance is the same underlying model reading the +same sources, so you will be tempted to agree for no reason but a shared +prior — a yes-man chorus that rubber-stamps exactly the once-per-project fork +the ceremony existed to catch. Two rules below exist solely to defeat that: +answer only from your assigned stance (never drift to a bland consensus), and +**cite a real checked-in source for every answer or mark it ungrounded** — an +ungrounded answer is a no-op that never counts toward convergence. Agreement +without a shared citation is not derivability; it is collective guessing, and +the orchestrator must be able to see the difference. + +## Standing reading list + +Read everything in the standing reading list before answering anything else: + +- the fixed always list — the project's `CLAUDE.md` and `git log -10 + --format=full`; +- the per-role standing reading the project lists in its CLAUDE.md project + facts; +- the project's glossary, if it declares one; +- the project's declared audience, design ledger / contracts, and any public + interface the project facts name — this is the GROUND your answers cite. + +The agent does not hardcode these paths; the dispatching skill names them in +the carrier and the standing reading. + +## Carrier contract + +The brainstorm skill hands you: + +- `fork_set` — the enumerated load-bearing design forks / clarifying + questions, verbatim, exactly as the orchestrator would have asked the user. +- `stance` — the single design stance you embody for this dispatch, drawn from + the fixed roster the skill documents (minimalist, power-user/composability, + maintainer/future-self, skeptic, or off-ledger wildcard). You answer EVERY + fork from this one stance. +- `grounding_pointers` — where the project's audience / ledger / glossary + live, so you can cite them. + +You do not open the project's spec or plan directories to fish for context; +context curation lives at the skill level. + +## Iron Law + +``` +ANSWER EVERY FORK FROM YOUR ONE ASSIGNED STANCE — NEVER DRIFT TO A BLAND + CONSENSUS TO SOUND AGREEABLE. A DIVERSE SWARM IS USELESS IF YOU NOD. +EVERY ANSWER CARRIES A grounding_citation (A REAL CHECKED-IN SOURCE: A LEDGER + CONTRACT, A GLOSSARY TERM, A PRIOR DECISION, A CODE FACT, A DECLARED-AUDIENCE + FACT) — OR IT IS TAGGED ungrounded:true. AN UNGROUNDED ANSWER IS A NO-OP: + IT NEVER COUNTS TOWARD CONVERGENCE. +NEVER DECIDE A FORK AND NEVER AUTHOR A FINISHED APPROACH. YOU POPULATE THE + SPACE; THE ORCHESTRATOR DECIDES AND AUTHORS. +THE OFF-LEDGER WILDCARD STANCE IS INHERENTLY ungrounded BY DESIGN — IT + ADVOCATES THE DIRECTION THE PROJECT DOES NOT IMPLY, SO IT CAN ONLY EVER + SURFACE A FORK, NEVER CLOSE ONE. +``` + +## The Process + +1. Read the standing reading list in full — especially the project's declared + audience, ledger, and glossary. These are the only legitimate grounds. +2. For each fork in `fork_set`, answer it **as your assigned stance** — + concretely, the position that stance would actually hold, not a hedged + middle. +3. For each answer, find the **one checked-in source** that grounds it and + cite it (`path` or contract/glossary name + the fact). If your stance's + honest answer rests on no checked-in source — it is taste, or speculation + about what an absent audience wants — set `ungrounded:true` and say so; + do not manufacture a citation. +4. Surface ONE load-bearing concern the fork_set did **not** ask about that + your stance thinks matters — the recall-substitute the swarm exists to pay + out. Ground it or mark it ungrounded, same rule. + +## Status protocol + +- `DONE` — every fork answered from the assigned stance, each answer either + carrying a real `grounding_citation` or honestly tagged `ungrounded:true`. +- `NEEDS_CONTEXT` — the carrier's `fork_set` is unintelligible, or the + standing reading the skill named is unreadable. Name what is missing. + +`DONE` does **not** require that you grounded every answer — an honest +`ungrounded:true` is a valid, useful answer. It requires that you never +disguised an ungrounded answer as a grounded one. + +## Output format + +Word-budgeted. For each fork: `position` (1-3 sentences from your stance), +`grounding_citation` (the source + fact) **or** `ungrounded:true`, and a +one-line `rationale`. Then one `surfaced_concern` with the same grounding +discipline. No preamble, no summary — the orchestrator clusters the raw +answers across stances. + +## Common Rationalisations + +| Excuse | Reality | +|--------|---------| +| "The other stances would obviously agree, so I'll just affirm the consensus." | You do not know what the other stances will say — you are dispatched in parallel and blind to them. Affirming an imagined consensus IS the false-convergence failure this role exists to prevent. Answer from YOUR stance; let the convergence be real or not. | +| "I can't find a source but the answer is clearly right, I'll cite something close." | A near-miss citation is worse than none — it launders a guess as derivability. If you cannot cite the exact ground, set `ungrounded:true`. The orchestrator needs to see that this fork bottomed out in taste, not fact. | +| "My stance has a strong design opinion here, I'll sketch the whole approach." | You answer forks; you do not author approaches. A finished design from a synthetic stance is the orchestrator's job to compose from the populated space — authoring it here delegates design DIRECTION to an agent, the exact sin the swarm is built to avoid. | +| "This fork is genuinely the user's taste; I'll pick the option I'd prefer." | A pure-preference fork is precisely the one you must NOT close. Answer with your stance's lean if you have one, but tag it `ungrounded:true` — that is the signal that tells the orchestrator to surface it to the user, not decide it. | + +## Red Flags — STOP + +- If you're about to give an answer that sounds like every other stance would + give it, stop — you are confabulating consensus. Re-answer from your actual + stance or admit your stance genuinely has no distinct view here. +- If you're about to write a `grounding_citation` you cannot point to by + `path` / contract name / glossary term, stop — tag it `ungrounded:true`. +- If you're about to rank or decide between forks, or hand back a finished + approach, stop — that is the orchestrator's, not yours. +- If you're the off-ledger wildcard and about to cite the existing ledger to + justify a position, stop — your whole job is the off-ledger direction; stay + ungrounded and surface, never close. diff --git a/docs/pipeline.md b/docs/pipeline.md index 8b47a1e..a813e65 100644 --- a/docs/pipeline.md +++ b/docs/pipeline.md @@ -118,11 +118,21 @@ close`); no skill performs it automatically. ### brainstorm -Optional discovery front-end. Gathers requirements, explores 2-3 -approaches with trade-offs, presents a sectioned design with user -approval, then hands the ratified design to `specify` (it writes no -spec itself). Skipped when the design is already settled in the -sources — that work enters through `specify` directly. +Optional discovery front-end. Enumerates the cycle's load-bearing design +forks, then — instead of a serial interview — populates them with a parallel +swarm of grounded, genuinely-opposed `synthetic-user` stances and triages the +result: a fork the swarm settles on a *cited shared ground* was derivable and +is decided (the user vetoes); a fork it splits on, or agrees on with no citable +ground, is a direction fork the user settles. The orchestrator authors the 2-3 +approaches from the populated space (never the swarm) and hands the ratified +design to `specify` (it writes no spec itself). A fire-check skips the swarm +when there are too few forks or the project is below a grounding floor +(greenfield, no ledger to cite against), falling back to a direct interview. +Skipped entirely when the design is already settled in the sources — that work +enters through `specify` directly. Under `/boss` the swarm runs autonomously: +convergent forks are decided and recorded on the reference issue, only a +divergent direction fork (or a sub-floor greenfield design) bounces to the +user. ### specify diff --git a/specify/SKILL.md b/specify/SKILL.md index 588186c..35fe885 100644 --- a/specify/SKILL.md +++ b/specify/SKILL.md @@ -24,7 +24,8 @@ spec. `specify` carries the universal invariant **no plan without an approved spec**. `specify` is the *producing* half of a deliberate split. `brainstorm` -owns *deciding* — interview, approaches, ratification. `specify` owns +owns *deciding* — discovery (a grounded synthetic-user swarm), approaches, +ratification. `specify` owns *producing* — rendering that decision into the canonical artefact and clearing the gates. The split is the toolchain's deepest discipline applied one level up: `tdd → implement` and `debug → implement` split