@colmbyrne/specflow
Advanced tools
| # daily-use-teardown.yaml — the front door for products ALREADY BUILT. | ||
| # The shipped product is the artifact. Map its journeys, get the human to confirm the map, | ||
| # walk the confirmed journeys as real users, return an evidence-grounded do-list → spec-build. | ||
| # The prompt does NOT restate this. Each tick: load this path, LOCATE the current stage from | ||
| # committed artifacts, advance ONE gate, persist, stop/escalate. | ||
| loop: daily-use-teardown | ||
| principle: > | ||
| investigate BEFORE judging — a teardown of the wrong journeys is worse than none. | ||
| The human confirms the map (they know what the product is FOR; the agent can only infer). | ||
| Personas walk only the confirmed map. Screenshots are the oracle. | ||
| progress_display: | ||
| rule: > | ||
| Re-render at the start of every tick: ✓ done · ▶ current · · pending · ⛔ gate. | ||
| GATE_HITL stays ⛔ until the human has confirmed the journey map in writing. | ||
| template: | | ||
| ┌────────────────── DAILY-USE TEARDOWN ──────────────────┐ | ||
| INVESTIGATE ─▶ ╣⛔HITL╠ ─▶ DEEP-DIVE ─▶ DO-LIST ─▶ handoff(spec-build) | ||
| {i} {h} {d} {l} | ||
| └─────────────────────────────────────────────────────────┘ | ||
| now: {current_stage} next: {next_stage} blocked-on: {blocker_or_none} | ||
| inputs: | ||
| slug: ${slug} # e.g. claim-alert-teardown | ||
| app: ${app} # the LIVE app (URL/env) — real backend, never a mock | ||
| personas: ${personas} # optional; if absent, the investigate stage PROPOSES them for the human to confirm | ||
| state: # durable, never chat | ||
| journey_map: docs/teardown/${slug}/journey-map.md # stage-1 output; the HITL gate signs THIS | ||
| evidence: docs/teardown/${slug}/evidence/ # screenshots — the oracle | ||
| findings: docs/teardown/${slug}/findings.md # per journey: WORKS / CONFUSING / BROKEN | ||
| do_list: docs/teardown/${slug}/do-list.md # prioritized; becomes spec-build's grounding_ref | ||
| stages: | ||
| - id: investigate # what ARE the journeys? | ||
| do: > | ||
| Explore the live app (nav, routes, screens) + the repo. Enumerate the MAIN routes, | ||
| each with: its PURPOSE (what is a user trying to achieve here?), entry points, and | ||
| who uses it. Propose the personas if not supplied. Output: a ONE-PAGE journey map a | ||
| human can review in five minutes. No judgments yet — inventory, not critique. | ||
| gate: journey map committed — routes + purpose + personas, human-readable | ||
| - id: GATE_HITL # HARD — the human knows what the product is FOR | ||
| type: hard (human) | ||
| gate: > | ||
| The human reviews the journey map: confirms/corrects each route's purpose, kills | ||
| stale/irrelevant routes, adds missed ones, signs off the personas. Confirmation is | ||
| written into the journey map (a "confirmed-by" line), not just said in chat. | ||
| rule: NO deep dive until the map is confirmed — walking the wrong journeys wastes the whole run. | ||
| - id: deep_dive # tier: judge — top thinkers, never tiered down | ||
| do: > | ||
| For each CONFIRMED journey × persona: walk the LIVE app (Playwright, real backend) as | ||
| that persona doing their normal task. Judge BOTH: (a) clarity — is it confusing? where | ||
| does the persona stall, squint, mis-click? and (b) correctness — does the journey | ||
| actually achieve its purpose, doing the right thing? Capture a screenshot at every | ||
| stall/surprise/dead-end. Verdict per journey: WORKS / CONFUSING / BROKEN — with evidence. | ||
| Bugs found get logged immediately (don't sit on them). | ||
| gate: every confirmed journey walked; findings ledger complete — no journey silently skipped | ||
| - id: do_list | ||
| do: > | ||
| Consolidate findings into a prioritized do-list. Each item: journey, persona, what's | ||
| wrong, evidence link (the screenshot), severity. OBSERVATIONS + priorities — NOT | ||
| solutions. (The PRD designs solutions; spec-build's adversary attacks them.) | ||
| gate: do-list committed AND the human approves the priorities (second, lighter HITL touch) | ||
| - id: handoff | ||
| do: > | ||
| Invoke spec-build with grounding_ref = the do-list (findings + evidence dir are the | ||
| oracle). Typically one spec-build run per top-priority cluster, not one giant PRD. | ||
| repair: | ||
| on_gate_fail: route back to the owning stage with a targeted prompt | ||
| budget: investigate revisions ≤ 2 (if the human keeps correcting the map, the agent is | ||
| guessing — escalate and map it TOGETHER); deep-dive re-walks ≤ 2 per journey | ||
| on_exhausted: escalate with what couldn't be walked and why | ||
| escalate_when: | ||
| - the app can't be reached / personas can't authenticate (no real walk possible — never fake it) | ||
| - the human rejects the journey map twice (map it together instead) | ||
| - a CRITICAL bug is found mid-walk (surface immediately; don't wait for the do-list) | ||
| never_without_human: [starting the deep dive before the map is confirmed, creating tickets directly (that is spec-build's job, behind its own gates)] | ||
| done_when: | ||
| - journey map confirmed-by-human; findings complete; do-list committed + priorities approved | ||
| - handoff: spec-build launched on the top items (prd → adversary → tickets → build → done) | ||
| cadence: schedulable — run monthly/quarterly; the product re-generates its own backlog from observed friction. |
| # Example — daily-use teardown of Claim Alert (a built product) | ||
| A filled invocation of [`../prompts/daily-use-teardown.prompt.md`](../prompts/daily-use-teardown.prompt.md). Claim Alert is already shipped — the question isn't "what should we build," it's **"are the journeys confusing, and are they doing the right thing?"** Run with the agent pointed at the Claim Alert repo (after `specflow init .`). | ||
| ``` | ||
| Goal: a human-confirmed journey map + evidence-grounded do-list for Claim Alert, feeding spec-build | ||
| Path: QA/loops/daily-use-teardown.yaml | ||
| Inputs: { slug: claim-alert-teardown, app: <Claim Alert live URL/env>, personas: "propose in stage 1 — I'll confirm at the gate" } | ||
| ``` | ||
| ## What a correct run looks like | ||
| 1. **INVESTIGATE** — the agent explores the live app + repo and returns a **one-page journey map**: the main routes, each with its *purpose* ("what is the user trying to achieve here?"), entry points, and proposed personas. Inventory, not critique. It **stops**. | ||
| 2. **⛔ GATE HITL (you)** — five minutes: confirm/correct each route's purpose, kill stale routes, add what it missed, sign the personas. Your confirmation is written into the map. *This is the step that keeps the whole run honest — the agent can only infer what Claim Alert is for; you know.* | ||
| 3. **DEEP DIVE** — per confirmed journey × persona, a top-thinker walk of the **live app**: where it works, where it's confusing (stalls, squints, mis-clicks), where it's broken (doesn't achieve its purpose). Screenshot at every stall. Verdict per journey: WORKS / CONFUSING / BROKEN. Critical bugs surface immediately. | ||
| 4. **DO-LIST** — prioritized, every item traceable to a screenshot of a real stuck moment. Observations + priorities, **no solutions** yet. You approve the priorities (second, lighter touch). | ||
| 5. **HANDOFF** — the do-list becomes `grounding_ref` for **spec-build**: PRD → adversary → tickets → build → done. One spec-build run per top-priority cluster. | ||
| ## Red flags that the run is wrong | ||
| - It starts walking journeys **before** you confirmed the map → the HITL gate isn't landing; stop it. | ||
| - A journey verdict with **no screenshot** → "I walked it" is not evidence. | ||
| - The do-list proposes **solutions** → it's doing the PRD's job without the adversary; push it back to observations. | ||
| Precedent: the same shape ran on timebreez as EPIC #673 (3-persona walkthrough → grounding → PRD survived Gate A → 9 sliced tickets, **plus a live bug found during the walk itself**). |
| # daily-use-teardown invocation prompt (template) | ||
| For a product that's **already built**. Fill the values and paste into your agent. Don't restate the path — point at it. | ||
| ``` | ||
| Goal: a human-confirmed journey map + evidence-grounded do-list for <app>, feeding spec-build | ||
| Path: QA/loops/daily-use-teardown.yaml | ||
| Inputs: { slug: <name>-teardown, app: <live URL/env>, personas: <list, OR "propose in stage 1 — I'll confirm at the gate"> } | ||
| Load the path and follow it — do not restate it. Each tick: | ||
| 1. Render the path's progress_display. | ||
| 2. Locate the current stage from the committed artifacts (journey-map.md, findings.md, do-list.md). | ||
| 3. Advance exactly ONE gate; persist to those artifacts (never only to chat). | ||
| 4. STOP at GATE_HITL — present the one-page journey map and wait for my written confirmation | ||
| before any deep dive. Stop again for my priority sign-off on the do-list. | ||
| Hard rules from the path: walk the LIVE app with a real backend (never fake a walk you couldn't | ||
| do); judge clarity AND correctness per journey (WORKS / CONFUSING / BROKEN, each with screenshot | ||
| evidence); the do-list is observations + priorities, not solutions; tickets only ever come from | ||
| spec-build behind its own gates. | ||
| ``` |
+23
-2
| #!/usr/bin/env node | ||
| const { execSync } = require('child_process'); | ||
| const { resolve, dirname } = require('path'); | ||
| const { existsSync } = require('fs'); | ||
| const { resolve, dirname, join } = require('path'); | ||
| const { existsSync, readFileSync, writeFileSync, readdirSync } = require('fs'); | ||
@@ -10,2 +10,20 @@ // Specflow root is one level up from bin/ | ||
| // Self-heal CRLF: bash (Linux/Mac) fails on Windows line endings. The published tarball | ||
| // can ship CRLF if it was packed from a Windows checkout, so normalize the shell scripts | ||
| // we're about to run — at runtime, via node, which always runs (unlike npm lifecycle scripts). | ||
| function stripCR(p) { | ||
| try { | ||
| const s = readFileSync(p, 'utf8'); | ||
| if (s.includes('\r')) writeFileSync(p, s.replace(/\r\n/g, '\n')); | ||
| } catch (_) { /* ignore unreadable/missing */ } | ||
| } | ||
| function normalizeShellScripts(root) { | ||
| for (const dir of ['.', 'hooks', 'scripts']) { | ||
| const abs = join(root, dir); | ||
| if (!existsSync(abs)) continue; | ||
| for (const f of readdirSync(abs)) if (f.endsWith('.sh')) stripCR(join(abs, f)); | ||
| } | ||
| for (const hook of ['hooks/commit-msg', 'hooks/pre-push']) stripCR(join(root, hook)); | ||
| } | ||
| const COMMANDS = { | ||
@@ -17,2 +35,3 @@ init: { | ||
| const target = resolve(args[0] || '.'); | ||
| normalizeShellScripts(SPECFLOW_ROOT); | ||
| exec(`bash "${SPECFLOW_ROOT}/setup-project.sh" "${target}"`); | ||
@@ -25,2 +44,3 @@ }, | ||
| run: () => { | ||
| normalizeShellScripts(SPECFLOW_ROOT); | ||
| exec(`bash "${SPECFLOW_ROOT}/verify-setup.sh"`); | ||
@@ -35,2 +55,3 @@ }, | ||
| const target = resolve(args.find(a => a !== '--ci') || '.'); | ||
| normalizeShellScripts(SPECFLOW_ROOT); | ||
| exec(`bash "${SPECFLOW_ROOT}/install-hooks.sh" "${target}" ${ciFlag}`); | ||
@@ -37,0 +58,0 @@ }, |
+34
-0
@@ -9,2 +9,36 @@ # Changelog | ||
| ## 0.8.0 (2026-06-10) | ||
| **New loop: `daily-use-teardown` — the front door for products that are already built.** | ||
| For a shipped product, the question isn't "what should we build" — it's *"are the journeys confusing, and are they doing the right thing?"* The new loop (`QA/loops/daily-use-teardown.yaml` + prompt + a filled Claim Alert example): | ||
| 1. **INVESTIGATE** — map the live app's main routes, each with its *purpose* + proposed personas. Inventory, not critique. | ||
| 2. **⛔ GATE HITL (hard, human)** — *you* confirm/correct the journey map before any judging. The agent can only infer what the product is for; you know. A teardown of the wrong journeys is worse than none. | ||
| 3. **DEEP DIVE** — top-thinker persona walks of the live app (real backend), judging clarity *and* correctness per journey: **WORKS / CONFUSING / BROKEN**, every verdict with screenshot evidence. | ||
| 4. **DO-LIST** — prioritized observations (not solutions), each traceable to a screenshot; you approve priorities. | ||
| 5. **HANDOFF** — the do-list becomes spec-build's `grounding_ref`: PRD → adversary → tickets → done. | ||
| Schedulable (monthly/quarterly): the product re-generates its own backlog from observed friction. Precedent: timebreez EPIC #673 (3-persona walkthrough → PRD survived Gate A → 9 sliced tickets + a live bug found mid-walk). | ||
| --- | ||
| ## 0.7.6 (2026-06-10) | ||
| **spec-build: two-touch personas — a persona/simulation lens joins the adversary panel.** | ||
| Persona walkthroughs now run **twice**: (1) at the adversary stage, in parallel with the structural review, walking real personas through the *PRD's* journeys on paper — design flaws get caught while only the PRD exists (the lens informs the verdict; the adversary still decides); (2) Gate B.5 unchanged, walking the *tickets* — catches ticketization flaws (a journey sliced wrong, a missing step). Both are top-thinker work: a shallow persona walk launders design gaps into a green check. Encoded in `templates/loops/spec-build.yaml` + the PROCESS docs. | ||
| (Note for upgraders: re-run `specflow init .` to refresh `QA/loops/` — it's refreshed on every init.) | ||
| --- | ||
| ## 0.7.5 (2026-06-10) | ||
| **The CLI now self-heals CRLF at runtime — works on Linux/Mac even if the tarball shipped with Windows line endings.** | ||
| 0.7.3/0.7.4 still shipped CRLF because the publisher's npm skipped the normalize hooks *and* the manual step wasn't run. Rather than keep depending on a clean publish, `bin/specflow.js` (which always runs — it's the node entry point, not an npm lifecycle script) now strips CR from the shell scripts **right before it invokes bash**. So `npx @colmbyrne/specflow init/update/verify` works on Linux/Mac regardless of how the package was published. The publish-time hooks remain as a secondary measure. | ||
| --- | ||
| ## 0.7.4 (2026-06-10) | ||
@@ -11,0 +45,0 @@ |
+1
-1
| { | ||
| "name": "@colmbyrne/specflow", | ||
| "version": "0.7.4", | ||
| "version": "0.8.0", | ||
| "description": "Specs that enforce themselves. Contract tests, journey hooks, and agent orchestration for LLM-driven development.", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -62,2 +62,4 @@ # Loops — run the whole pipeline | ||
| For every ticket the spec-build loop produced, copy [`prompts/feature-build.prompt.md`](prompts/feature-build.prompt.md), fill `issue`, paste/automate. It builds on the 5 rails → **Gate C (CI on real data)**. Output: a branch ready for review. | ||
| **Already-built product?** Start one loop earlier: **daily-use-teardown** ([`daily-use-teardown.yaml`](daily-use-teardown.yaml), prompt in [`prompts/`](prompts/)) — investigate the app's main journeys + their purpose, **you confirm the map (hard human gate)**, then top-thinker persona walks judge each journey WORKS / CONFUSING / BROKEN with screenshot evidence, ending in a prioritized do-list that becomes spec-build's `grounding_ref`. Filled example: [`examples/claim-alert.daily-use-teardown.md`](examples/claim-alert.daily-use-teardown.md). | ||
| 3. **Mistake-harvest** (meta, optional) — schedule `docs/routines/daily-mistake-harvest.md` (timebreez). It reads runs of both loops and improves the skills/contracts they depend on. | ||
@@ -64,0 +66,0 @@ |
@@ -37,5 +37,13 @@ # spec-build.yaml — the reusable PATH for the spec-build loop (PROCESS.md Steps 0–5). | ||
| gate: JTBD, scope boundary, acceptance, success metrics, deps all present | ||
| - id: adversary # one hostile critic | ||
| - id: adversary # one hostile critic, informed by parallel lenses | ||
| do: adversarial-prd-reviewer — 7-pass rubric + Special Mandate | ||
| (reality-grounding ledger over every repo/schema claim; loophole hunt) | ||
| persona_lens: | # runs IN PARALLEL with the structural review — first persona touch | ||
| A fresh-context persona/simulation lens walks real personas through the PRD's | ||
| journeys ON PAPER ("can a human actually do this?") and returns CRITICAL design | ||
| gaps, each with a repro. Top-thinker work — never a cheap model; a shallow walk | ||
| launders design gaps into a green check. The lens INFORMS the verdict; the | ||
| adversary still DECIDES (one critic, not a committee). | ||
| Why here: persona walks find PRD-level design flaws — catching them now costs a | ||
| PRD edit; catching them at B.5 costs redone tickets, audit, and uplift. | ||
| do_until: verdict issued; fix each FATAL/SERIOUS in the document, re-review | ||
@@ -53,5 +61,8 @@ - id: GATE_A # HARD — the trust gate | ||
| gate: requirement→journey→test→issue complete; no orphans; no duplicate IDs | ||
| - id: GATE_B5 # soft | ||
| - id: GATE_B5 # soft — SECOND persona touch (first ran at the adversary stage) | ||
| type: soft | ||
| do: pre-flight-simulator — walk real personas through each ticket before code | ||
| do: pre-flight-simulator — walk real personas through each TICKET before code. | ||
| Different artifact than the adversary's persona lens — that walked the PRD | ||
| (design flaws); this walks the tickets (ticketization flaws — a journey sliced | ||
| wrong, a missing step, a walk that breaks at a ticket boundary). Top-thinker work. | ||
| gate: no CRITICAL design gap survives | ||
@@ -58,0 +69,0 @@ |
@@ -34,4 +34,6 @@ # Running the WHOLE pipeline in Claude Code (the `Workflow` runtime) | ||
| assertSeedMatchesTemplate(seed) // a primed seed cannot launch | ||
| // 2. Perspective panel (lens coverage — NOT a U2 substitute): | ||
| const lenses = ['schema-reality','loophole-security','contradicts-contracts'] | ||
| // 2. Perspective panel (lens coverage — NOT a U2 substitute). 'persona-walkthrough' is the | ||
| // experiential lens: walk real personas through the PRD's journeys on paper, CRITICAL gaps | ||
| // with repro. Top-thinker work — never tier this lens down. (Second persona touch = B.5, vs tickets.) | ||
| const lenses = ['schema-reality','loophole-security','contradicts-contracts','persona-walkthrough'] | ||
| const verdicts = await parallel(lenses.map(l => () => agent(seed.for(l), {schema:VERDICT}))) | ||
@@ -38,0 +40,0 @@ // 3. If correctness-critical (U2 trigger list) → a pass that does NOT share Claude's training. |
@@ -23,2 +23,3 @@ # PROCESS — idea → merged code you can trust | ||
| - **The Special Mandate** (honesty-critical specs): a **reality-grounding ledger** (open every concrete repo claim the author makes and verify it) + a **loophole hunt** (actively try to find the gamed gate / fake backend / skip-to-green / always-green metric *surviving*). | ||
| - **The persona/simulation lens** (in parallel with the structural review): walk real personas through the PRD's journeys *on paper* — "can a human actually do this?" — returning CRITICAL design gaps with a repro. An experiential way to fail that the structural passes can't see. The lens *informs* the verdict; the adversary still *decides*. (Personas get a **second touch** at Gate B.5, against the tickets.) Top-thinker work, like the adversary itself. | ||
@@ -43,3 +44,3 @@ *Output:* a hardened PRD. (Where the adversary catches "a real backend with nobody home," "all-green smuggled in as the metric," etc.) | ||
| `pre-flight-simulator` walks real personas through each ticket *before* code. A CRITICAL design gap blocks. (Cheaper to find "new staff land at zero balance" here than in the build.) | ||
| `pre-flight-simulator` walks real personas through each ticket *before* code. A CRITICAL design gap blocks. (Cheaper to find "new staff land at zero balance" here than in the build.) This is the **second** persona touch — the first ran at Step 1 against the *PRD* (design flaws); this one walks the *tickets* (ticketization flaws: a journey sliced wrong, a missing step, a walk that breaks at a ticket boundary). | ||
@@ -46,0 +47,0 @@ ## Step 6 — Build (the 5 rails, one journey at a time) |
893337
1.75%95
3.26%1343
1.51%