Claude Skill

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

LLM Mart · 0 points · 16 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download radimsem-forge-skills-skills_blueprint-2e1b70d.zip · 15 KB
Part of radimsem/forge-skills — 3 skills

Install

skills CLI npx skills add https://github.com/radimsem/forge-skills/tree/main/skills/blueprint
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install radimsem-forge-skills@llmmart
Git 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.

No comments yet.

Reviews (0)

No reviews yet.

Related