blueprint
Brainstorm UI/UX changes into an approved design through interactive browser proposals rendered in the project's real design language. Option clicks assemble a response prompt copied to the user's clipboard. Use when the user runs /blueprint or wants to brainstorm, redesign, or v
Install
npx skills add https://github.com/radimsem/forge-skills/tree/main/skills/blueprint
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install radimsem-forge-skills@llmmart
git clone https://github.com/radimsem/forge-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole radimsem/forge-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Blueprint
Design it in the browser, approve it at the gate, hand the blueprint to the blacksmith: blueprint → forge → blacksmith-orchestrate.
Overview
Blueprint owns the whole UI/UX brainstorming arc: harvest the project's real design language, push interactive proposal screens, resolve rounds through clipboard-pasted responses, gate on approval, write the spec, and hand off to plans, tickets, or orchestration. The browser never talks back to the agent — the user's paste is the only return channel, so the companion server keeps no state and its death mid-session loses nothing.
The interactive machinery ships in scripts/ and is never reimplemented inline; each session authors only HTML content fragments per references/screens.md.
Parameters
Flags compose and are parsed from anywhere in the invocation; the canonical matrix with composition rules is references/flags.md.
| Flag | Effect |
|---|---|
fresh |
Force a full design re-harvest, ignoring the .brainstorm/ cache |
terminal |
Skip the browser; run every round in the terminal fallback |
resume |
Continue from an existing ledger: restart the server, re-push the last unresolved screen |
When to Use
Use for UI/UX brainstorming: new screens, redesigns, component-level polish, anything where the user should see options before choosing. If the topic has no visual dimension (pure backend or API design), say so in one line and defer to a plain brainstorming workflow instead of forcing a browser on a text problem.
Workflow
Part 1 — Setup (1–3): classify → harvest → start companion
Part 2 — Rounds (4–5): push screen → read pasted response, ledger it (loop)
Part 3 — Close (6–8): [GATE] recap + approval → spec → handoff
Step 1 — Classify & parse
Confirm the topic is visual (see When to Use). Parse flags. Enumerate the UI items in scope — sessions typically batch several; each becomes a track through the rounds.
Step 2 — Design harvest
Build or refresh .brainstorm/style.css and .brainstorm/design-notes.md
per references/harvest.md. No screen may be pushed
before the harvest exists.
Step 3 — Start the companion
Run node <skill>/scripts/serve.mjs --project-dir <project> --open in the
background. Verify aliveness by statting .brainstorm/server-info; share the
printed URL every round as fallback. If the server cannot start twice, or the
terminal flag is set, degrade per the terminal-fallback section of
references/screens.md with a one-line warning.
Step 4 — Push a round
Author a content fragment per references/screens.md
into .brainstorm/screens/, then summarize in the terminal what is on
screen and ask the user to click and paste.
HARD GATE: nothing touches the target codebase before Step 6 approval. No flag bypasses this.
Step 5 — Resolve the round
Parse the pasted response per
references/composer.md: verify the screen header,
map answers by order, treat nits as change requests. Append decisions to the
ledger per references/ledger.md. Revise (new -vN
screen) or advance; push a waiting screen when returning to terminal-only
discussion.
Step 6 — GATE: recap and approval
Push a recap screen rendered from the ledger (data-mode="recap"). The user
approves in the terminal, or clicks Copy approval and pastes the phrase.
No approval → stop here.
Step 7 — Spec
Assemble the design doc from the ledger into
docs/specs/YYYY-MM-DD-<topic>-design.md: design decisions per UI item plus
a one-line-each "Rejected alternatives" appendix. Self-review for
placeholders, contradictions, scope, ambiguity; fix inline; commit.
Step 8 — Handoff
Push the handoff screen per
references/handoff.md: plans route, /to-tickets
route, and the blacksmith invocation builder with generated flag chips.
Anti-patterns
New lessons go to references/anti-patterns.md, the canonical home — not into this file.
Files (forge-skills)
-
references
-
anti-patterns.md 1 KB
# Anti-patterns & red flags Canonical home for blueprint lessons; add new ones here, not to SKILL.md. | Anti-pattern | Correction | |---|---| | Generic-framework mockups that could be any app | No screen before harvest; every fragment leans on `.brainstorm/style.css` | | Re-improvising the frame or composer inline | Interactive machinery ships in `scripts/`; fragments carry content only | | Reusing a screen filename | New file per revision (`layout-v2.html`); the server serves the newest | | Accepting a paste with a stale `[blueprint:…]` header | Stop and ask; never guess which round an answer belongs to | | Leaving a resolved screen up during terminal discussion | Push a fresh `waiting-N.html` | | Implementation before the Step 6 gate | Hard stop — the gate has no bypass in this skill | | Hand-writing flag chips into the handoff builder | Metadata is generated from the two skills' `flags.md` at recap time | | Pushing screens with heredocs | File-creation tool only; heredocs dump noise into the terminal | -
composer.md 2.2 KB
# Composer contract The clipboard is the only return channel: the browser never talks to the agent. Clicks assemble one human-readable prompt; the user pastes it into the terminal; the paste is the user's authoritative answer, merged with any free text they typed around it. ## The pasted response format (canonical) [blueprint:briefing-hero-options] 1) Status card → A 2) Detail layout → A — note: replace the em dash with something more human Nit on run-config.precision-row: align the precision value right like the other rows - The header names the screen (`data-screen`). **A paste whose header names a different round than the current one is a stop-and-ask, never a guess.** - Numbering follows on-screen question order; a question with no selection and no note is omitted from the body but still advances the number, so numbers always match what the user saw. A note without a selection renders the choice as `(no selection)`. - Nit lines follow the questions, one per flagged `data-region`. - The format is deliberately prose, not JSON: the user sees what they are sending, can edit it inline before sending, and terminal-fallback answers look identical — downstream workflow never branches on mode. ## Tray behavior Fixed full-width bottom bar: live `N selections · M notes · K nits` count and one **Copy response** button (`navigator.clipboard` with an `execCommand` fallback; the button flashes "copied — paste it in the terminal"). On recap screens the button becomes **Copy approval** and copies `data-approve-copy`. ## Agent-side parsing rules 1. Verify the `[blueprint:…]` header matches the round you last pushed. 2. Map numbered lines back to questions by order, not by label text. 3. Treat `Nit on <region>:` lines as change requests against that `data-region`; resolve them in the next screen version and record them in the ledger. 4. Anything in the message outside the pasted block is ordinary user text. ## Manual verification recipe Run `sh tests/blueprint_test.sh` — the composer-core assertions check this exact format against `assembleResponse`/`assembleInvocation`. Then perform the browser recipe in [screens.md](screens.md) and diff the copied text against the format above. -
flags.md 698 B
# Blueprint — Flag matrix Flags are orthogonal and parsed from anywhere in the invocation. ## Flags | Flag | Effect | Owner | |---|---|---| | `fresh` | Force a full design re-harvest, ignoring the `.brainstorm/` cache | [harvest.md](harvest.md) | | `terminal` | Skip the browser; run every round in the terminal fallback | [screens.md](screens.md) | | `resume` | Continue from an existing ledger: restart the server, re-push the last unresolved screen | [ledger.md](ledger.md) | ## Composition rules All three compose freely. `terminal` + `resume` resumes without restarting the server. `fresh` affects only Step 2; it never clears ledgers or screens. There are no conflicting combinations. -
handoff.md 2.5 KB
# Handoff After the spec commits (Step 7), push a new recap screen in handoff mode. Three routes, all clipboard-first. ## Route 1 — implementation plans A `data-copy` button whose payload asks for plans from the spec, e.g. "Using the writing-plans skill, create an implementation plan from `docs/specs/<spec>.md`." ## Route 2 — spin off tickets A `data-copy` button whose payload is prefixed with the `/to-tickets` skill invocation, pointing at the committed spec: one issue per decided UI item, preserving chosen-option detail and rejected alternatives; the tail is pre-filled from the ledger (item count, tracker in use). This feeds blacksmith's issue-sourced entry route. ## Route 3 — dispatch to blacksmith (invocation builder) Builder markup (attributes are `composer.js`'s contract): <div data-invocation data-verb="/blacksmith-orchestrate" data-default-source="plan (docs/plans/<plan>.md)"> <span data-source="plan (docs/plans/<plan>.md)" class="bp-selected">plan</span> <span data-source="#441 #442 #443">tickets</span> <div data-flag-group="orchestrator"> <span data-flag="afk" data-on="true" class="bp-selected">afk</span> <span data-flag="unified" data-on="true" class="bp-selected">unified</span> </div> <div data-flag-group="passthrough"> <span data-flag="lookup" data-on="true" class="bp-selected">lookup</span> <span data-flag="worktree" data-on="false">worktree</span> </div> <code data-cmd-preview></code> </div> Assembly grammar: `<verb> <work-source> <orchestrator-flags> - <passthrough-flags>` (the `-` separator is omitted when no pass-through flag is on). **Flag metadata is generated, never hand-written.** At recap time, read the CURRENT flag tables from blacksmith's and forge's `references/flags.md` and emit one chip per flag. Pre-toggle the suggested set and print one line of reasoning per suggestion under its group ("worktree — 4 independent items collide on 0 files"). Which `data-source` segments are enabled follows which of Routes 1–2 actually ran; both ran → user picks. ## Manual verification recipe Author a recap screen with the builder above. Toggling `worktree` must update the preview to append it after the `-`; selecting the tickets segment must swap the work source; **Copy invocation** (`data-copy` on a button whose payload the agent sets to the preview's initial value is NOT enough — the preview is live, so read the copied text) must equal the preview exactly. Cross-check every chip name against the current flag tables of both skills. -
harvest.md 2.1 KB
# Design harvest The harvest turns the target project's real design language into two cached artifacts every screen builds on. **No screen may be pushed before the harvest exists.** This is what separates a blueprint mockup from a generic-framework mockup: the CSS the user sees is the project's own. ## Source priority 1. **Design docs** — `DESIGN.md`, `docs/DESIGN.md`, `docs/design/**` and similar (glob case-insensitively). These carry the *rules*. 2. **Token sources in code** — tailwind config, CSS custom properties, theme files, font imports, and the icon library the project actually imports. 3. **2–3 representative components from the surface being brainstormed** — real components beat prose for idioms: card chrome, spacing rhythm, empty states. Redesigning a page means reading that page's components. ## Cached artifacts (in the target project) - `.brainstorm/style.css` — real CSS variables, font stacks, radii, shadows, spacing scale, plus mockup utility classes named after the project's own idioms. Served by the companion at `/style.css`; every frame imports it. - `.brainstorm/design-notes.md` — prose rules CSS cannot carry ("status text never uses em dashes"), each with a source pointer back to the file it came from. ## Freshness Later sessions re-check only the pointed-at sources (mtime or a short diff) and refresh what changed. The `fresh` flag rebuilds from scratch. Suggest gitignoring `.brainstorm/screens/`, ledgers, `server-info`, and `port`, while **committing** `style.css` and `design-notes.md` — they are shared team assets; screens and ledgers are session ephemera superseded by the spec. ## Manual verification recipe In any project with a design doc: run the harvest, then open `.brainstorm/style.css` and confirm every color/font value also appears in the project's own token sources (grep a sampled hex value). Open `design-notes.md` and follow one source pointer to the file it names; the rule must be visible there. Then delete one pointer target's mtime cache expectation by touching the file and re-run without `fresh`: only that source is re-read. -
ledger.md 1.5 KB
# Decision ledger `.brainstorm/<YYYY-MM-DD>-<topic>.md` in the target project. Append-only during rounds; it is the session's single source of truth and the input to both the recap screen and the spec. ## Per-round block ## Round: briefing-hero-options (screen: briefing-hero-options.html) - Q: Status card — options: A progress bar / B step dots / C ring gauge - **Chosen: A — progress bar.** Full option description copied here. - Note: replace the em dash in the status text. - Nit on run-config.precision-row: align right — resolved in …-v2.html ## Consumers - **Recap screen (Step 6 gate)** renders directly from the ledger, so what the user approves is provably what was recorded. - **Spec (Step 7)** is assembled from it: chosen-option blocks reorganized per UI item, plus a "Rejected alternatives" appendix (one line each) so implementing forge runs do not reintroduce rejected variants. - **`resume` flag**: the ledger IS the session state. Resume = read ledger, restart the server (same `--project-dir`, same persisted port), re-push the last unresolved screen. The ledger is session ephemera: gitignored, superseded by the committed spec. ## Manual verification recipe Mid-session, kill the server and the agent process. Re-invoke with `resume`: the agent must restate every recorded decision from the ledger without re-asking, the tab must reconnect on the same port, and the next screen must be the last unresolved one — not round one. -
screens.md 3 KB
# Screen authoring Screens are HTML *content fragments* written to `<project>/.brainstorm/screens/`. The companion wraps them in the frame (header, tray, harvested `style.css`, `composer.js`) automatically; a file starting with `<!DOCTYPE` or `<html` is served as-is for full-control pages. Never write screens with heredocs — use the file-creation tool. ## Fragment contract Every interactive element is declared with data attributes; `composer.js` does the rest. Attribute names are load-bearing — they must match this contract exactly. <div data-screen="briefing-hero-options"> <section data-question="status-card" data-label="Status card"> <div data-choice="a">…option card A…</div> <div data-choice="b">…option card B…</div> </section> <div class="mockup"> <div data-region="run-config.precision-row">…mockup part…</div> </div> </div> - `data-screen` — round id; it becomes the `[blueprint:…]` header of the pasted response, so name it after the screen file (sans `.html`). - `data-question` + `data-label` — one per question; the label is what the pasted response calls it. - `data-choice` — lowercase letter per option card; click selects, re-click another card moves the selection. - `data-region` — stable id on any mockup part worth a nit; alt-click flags it and asks for a note. Include one hint line per screen teaching the gesture ("⌥/Alt-click any part of a mockup to flag a nit"). - Recap screens set `data-mode="recap"` and `data-approve-copy` on the root; see [handoff.md](handoff.md) for the builder markup. ## Discipline - **Never reuse filenames.** Revisions get `-v2`, `-v3` suffixes; the server serves the newest file by mtime. - **One screen = one round.** 2–4 options per question; explain the question on the page, not only in the terminal. - **Unload when returning to the terminal.** Push a fresh `waiting-N.html` ("Continuing in terminal…") so the user is not staring at a resolved choice. - Every fragment styles itself from the harvested tokens (the frame imports `/style.css`); a screen that only works with generic styling is a red flag per [anti-patterns.md](anti-patterns.md). ## Terminal fallback With the `terminal` flag, no display, or a server that fails to bind twice: the workflow does not branch. Options become terminal multiple-choice questions (the host's question UI where available, numbered lists otherwise); mockups become ledger-grade prose plus small ASCII sketches where genuinely helpful. Answers arrive in the same format as pasted responses, so downstream steps never care which mode ran. ## Manual verification recipe Start the companion on a scratch dir, write the fragment above as `demo.html`, and open the URL. Clicking option A outlines it and the tray reads "1 selections"; alt-clicking the region prompts for a note and the tray counts 1 nit; **Copy response** produces exactly the format in [composer.md](composer.md). Write `demo-v2.html` with changed text: the open tab reloads to it without a refresh.
-
-
scripts
-
composer.js 7.4 KB
// blueprint composer: selection, per-question notes, alt-click nit flags, the // fixed bottom tray, and the recap-mode invocation builder. Classic script by // design: the Node test suite require()s this file and reads // globalThis.blueprintComposer; the DOM wiring below is guarded. function assembleResponse(screenId, answers, nits) { // Numbering follows on-screen question order; questions with no selection // and no note are omitted from the body but still advance the number, so // the numbers always match what the user sees. var lines = ['[blueprint:' + screenId + ']']; var n = 0; answers.forEach(function (a) { n += 1; if (a.choice === null && !a.note) return; var line = n + ') ' + a.label + ' → ' + (a.choice === null ? '(no selection)' : a.choice.toUpperCase()); if (a.note) line += ' — note: ' + a.note; lines.push(line); }); nits.forEach(function (t) { lines.push('Nit on ' + t.region + ': ' + t.note); }); return lines.join('\n'); } function assembleInvocation(meta) { var on = function (fs) { return fs.filter(function (f) { return f.on; }).map(function (f) { return f.name; }); }; var orch = on(meta.orchestrator); var pass = on(meta.passthrough); var parts = [meta.verb, meta.source].concat(orch); if (pass.length) parts = parts.concat(['-'], pass); return parts.join(' '); } globalThis.blueprintComposer = { assembleResponse: assembleResponse, assembleInvocation: assembleInvocation }; if (typeof document !== 'undefined') (function () { var content = document.getElementById('bp-content'); if (!content) return; var root = content.querySelector('[data-screen]'); var screenId = root ? root.getAttribute('data-screen') : 'unnamed-screen'; var nameEl = document.getElementById('bp-screen-name'); if (nameEl) nameEl.textContent = '· ' + screenId; function questionEls() { return Array.prototype.slice.call(content.querySelectorAll('[data-question]')); } // Inject a collapsed note toggle per question. questionEls().forEach(function (q) { var btn = document.createElement('button'); btn.type = 'button'; btn.className = 'bp-note-btn'; btn.textContent = '✎'; btn.addEventListener('click', function () { var input = q.querySelector('.bp-note-input'); if (!input) { input = document.createElement('input'); input.className = 'bp-note-input'; input.placeholder = 'note for this question…'; input.addEventListener('input', update); q.appendChild(input); } else { input.hidden = !input.hidden; } if (!input.hidden) input.focus(); }); q.appendChild(btn); }); function collectAnswers() { return questionEls().map(function (q) { var sel = q.querySelector('[data-choice].bp-selected'); var input = q.querySelector('.bp-note-input'); return { label: q.getAttribute('data-label') || q.getAttribute('data-question'), choice: sel ? sel.getAttribute('data-choice') : null, note: input && !input.hidden && input.value ? input.value : null, }; }); } function collectNits() { return Array.prototype.slice.call(content.querySelectorAll('[data-region].bp-nit')).map(function (el) { return { region: el.getAttribute('data-region'), note: el.getAttribute('data-bp-nit') || '' }; }); } function update() { var a = collectAnswers(); var sels = a.filter(function (x) { return x.choice !== null; }).length; var notes = a.filter(function (x) { return x.note; }).length; var countEl = document.getElementById('bp-count'); if (countEl) countEl.textContent = sels + ' selections · ' + notes + ' notes · ' + collectNits().length + ' nits'; } function renderPreview() { var b = content.querySelector('[data-invocation]'); if (!b) return; var out = b.querySelector('[data-cmd-preview]'); if (!out) return; var grab = function (group) { return Array.prototype.slice .call(b.querySelectorAll('[data-flag-group="' + group + '"] [data-flag]')) .map(function (el) { return { name: el.getAttribute('data-flag'), on: el.getAttribute('data-on') === 'true' }; }); }; var src = b.querySelector('[data-source].bp-selected'); out.textContent = assembleInvocation({ verb: b.getAttribute('data-verb'), source: src ? src.getAttribute('data-source') : b.getAttribute('data-default-source'), orchestrator: grab('orchestrator'), passthrough: grab('passthrough'), }); } function copyText(text, el) { var done = function () { var old = el.textContent; el.textContent = 'copied — paste it in the terminal'; setTimeout(function () { el.textContent = old; }, 1600); }; if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(done, function () { legacyCopy(text); done(); }); } else { legacyCopy(text); done(); } } function legacyCopy(text) { var ta = document.createElement('textarea'); ta.value = text; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); } content.addEventListener('click', function (ev) { var region = ev.target.closest('[data-region]'); if (ev.altKey && region) { ev.preventDefault(); if (region.classList.contains('bp-nit')) { region.classList.remove('bp-nit'); region.removeAttribute('data-bp-nit'); } else { var note = window.prompt('Nit on ' + region.getAttribute('data-region') + ':', ''); if (note) { region.classList.add('bp-nit'); region.setAttribute('data-bp-nit', note); } } update(); return; } var opt = ev.target.closest('[data-choice]'); if (opt) { var q = opt.closest('[data-question]'); if (q) { Array.prototype.slice.call(q.querySelectorAll('[data-choice]')).forEach(function (el) { el.classList.remove('bp-selected'); }); opt.classList.add('bp-selected'); update(); } return; } var srcSeg = ev.target.closest('[data-source]'); if (srcSeg) { var builder = srcSeg.closest('[data-invocation]'); if (builder) { Array.prototype.slice.call(builder.querySelectorAll('[data-source]')).forEach(function (el) { el.classList.remove('bp-selected'); }); srcSeg.classList.add('bp-selected'); renderPreview(); } return; } var flag = ev.target.closest('[data-flag]'); if (flag) { var next = flag.getAttribute('data-on') === 'true' ? 'false' : 'true'; flag.setAttribute('data-on', next); flag.classList.toggle('bp-selected', next === 'true'); renderPreview(); return; } var copyEl = ev.target.closest('[data-copy]'); if (copyEl) copyText(copyEl.getAttribute('data-copy'), copyEl); }); var copyBtn = document.getElementById('bp-copy'); if (copyBtn) { if (root && root.getAttribute('data-mode') === 'recap') { copyBtn.textContent = 'Copy approval'; copyBtn.addEventListener('click', function () { copyText(root.getAttribute('data-approve-copy') || 'Approved — proceed to the spec.', copyBtn); }); } else { copyBtn.addEventListener('click', function () { copyText(assembleResponse(screenId, collectAnswers(), collectNits()), copyBtn); }); } } update(); renderPreview(); })(); -
frame.html 2.4 KB · in bundle
-
serve.mjs 4.6 KB · in bundle
-
-
SKILL.md 4.5 KB
--- name: blueprint description: Brainstorm UI/UX changes into an approved design through interactive browser proposals rendered in the project's real design language. Option clicks assemble a response prompt copied to the user's clipboard. Use when the user runs /blueprint or wants to brainstorm, redesign, or visually verify UI/UX work before implementation. --- # Blueprint > Design it in the browser, approve it at the gate, hand the blueprint to the > blacksmith: **blueprint → forge → blacksmith-orchestrate**. ## Overview Blueprint owns the whole UI/UX brainstorming arc: harvest the project's real design language, push interactive proposal screens, resolve rounds through clipboard-pasted responses, gate on approval, write the spec, and hand off to plans, tickets, or orchestration. The browser never talks back to the agent — the user's paste is the only return channel, so the companion server keeps no state and its death mid-session loses nothing. The interactive machinery ships in [scripts/](scripts/serve.mjs) and is never reimplemented inline; each session authors only HTML content fragments per [references/screens.md](references/screens.md). ## Parameters Flags compose and are parsed from anywhere in the invocation; the canonical matrix with composition rules is [references/flags.md](references/flags.md). | Flag | Effect | |---|---| | `fresh` | Force a full design re-harvest, ignoring the `.brainstorm/` cache | | `terminal` | Skip the browser; run every round in the terminal fallback | | `resume` | Continue from an existing ledger: restart the server, re-push the last unresolved screen | ## When to Use Use for UI/UX brainstorming: new screens, redesigns, component-level polish, anything where the user should *see* options before choosing. If the topic has no visual dimension (pure backend or API design), say so in one line and defer to a plain brainstorming workflow instead of forcing a browser on a text problem. ## Workflow Part 1 — Setup (1–3): classify → harvest → start companion Part 2 — Rounds (4–5): push screen → read pasted response, ledger it (loop) Part 3 — Close (6–8): [GATE] recap + approval → spec → handoff ### Step 1 — Classify & parse Confirm the topic is visual (see When to Use). Parse flags. Enumerate the UI items in scope — sessions typically batch several; each becomes a track through the rounds. ### Step 2 — Design harvest Build or refresh `.brainstorm/style.css` and `.brainstorm/design-notes.md` per [references/harvest.md](references/harvest.md). **No screen may be pushed before the harvest exists.** ### Step 3 — Start the companion Run `node <skill>/scripts/serve.mjs --project-dir <project> --open` in the background. Verify aliveness by statting `.brainstorm/server-info`; share the printed URL every round as fallback. If the server cannot start twice, or the `terminal` flag is set, degrade per the terminal-fallback section of [references/screens.md](references/screens.md) with a one-line warning. ### Step 4 — Push a round Author a content fragment per [references/screens.md](references/screens.md) into `.brainstorm/screens/`, then summarize in the terminal what is on screen and ask the user to click and paste. **HARD GATE: nothing touches the target codebase before Step 6 approval. No flag bypasses this.** ### Step 5 — Resolve the round Parse the pasted response per [references/composer.md](references/composer.md): verify the screen header, map answers by order, treat nits as change requests. Append decisions to the ledger per [references/ledger.md](references/ledger.md). Revise (new `-vN` screen) or advance; push a waiting screen when returning to terminal-only discussion. ### Step 6 — GATE: recap and approval Push a recap screen rendered from the ledger (`data-mode="recap"`). The user approves in the terminal, or clicks **Copy approval** and pastes the phrase. No approval → stop here. ### Step 7 — Spec Assemble the design doc from the ledger into `docs/specs/YYYY-MM-DD-<topic>-design.md`: design decisions per UI item plus a one-line-each "Rejected alternatives" appendix. Self-review for placeholders, contradictions, scope, ambiguity; fix inline; commit. ### Step 8 — Handoff Push the handoff screen per [references/handoff.md](references/handoff.md): plans route, `/to-tickets` route, and the blacksmith invocation builder with generated flag chips. ## Anti-patterns New lessons go to [references/anti-patterns.md](references/anti-patterns.md), the canonical home — not into this file.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.