Turn a requirement or an unproven technique into a single self-contained HTML prototype that doubles as a design spike, rebuilt at high fidelity from the app's own source
77
97%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Build one self-contained HTML file that executes a requirement's interpretation against the real system, for two audiences at once.
Outward it asks the client is this what you meant? — its output is deltas, not approval. Inward it asks the team does this technique work, and what should the contract be? — its output is a settled decision. States are indexed by open questions: some are acceptance criteria, some are unproven mechanisms. Flipping a control re-runs the reading.
Three files, every run, written beside the prototype:
<anchor>-<slug>.html — the prototypeharvest-table.md — where every borrowed value came fromspike-report.md — what the run settled, and where each answer belongsspike-report.md is opened at ANCHOR and appended to as you go — not composed at the end. A run
that ends early still leaves its answers behind, and answers are the part that outlives the file: a
technique proven in a run that stopped short otherwise ends up recorded nowhere but a code comment.
Treat it the way you would a lab notebook, not a closing summary.
Four invariants:
Independent. A stub payload inside a source-faithful UI is a good prototype. Mixing fidelity within one axis without marking it is the failure.
| Axis | Ladder | Gate |
|---|---|---|
| UI — does it read like the app they use daily? | from-source > from-screenshot > schematic (whole file, declared up front) | G2: every non-annotated element traces to the harvest table |
| Token — are the colors and type the app's own? | harvested-and-cited > prototype-only-and-justified | G1: zero uncited constants |
| Data — is what the screen shows real? | live > recorded capture > labeled stub | G3: no rung below stub; never invent a payload |
Two legitimate anchors, either or both:
docs/requirements/index.md, never ls or grep -r over the folder. Take every acceptance
criterion, the frozen-interface section, the pending-dependency section, and linked ADRs.Proposed ADR, or a contract nobody has shaped
("will srcDoc render this without leaking the session?", "what should this route look like?").
Needs no FR.Refuse only when neither exists — a feature description with settled mechanics is a design-comp request, and a generative-design skill owns that.
Open spike-report.md now, before any other work, and write the questions this run is meant to
settle under Still open:. Every later phase moves lines out of that list.
LSP first (ToolSearch select:LSP). Grep only for string literals. Full recipes:
references/harvest-playbook.md.
| What | LSP | Fallback |
|---|---|---|
| Screen structure | workspaceSymbol on the view → documentSymbol → read the template in full | glob the view folder |
| Copy strings | read them from the source that renders them | grep the literal — a string absent from the app is invented, full stop |
| Icons | goToDefinition on the icon imports | grep the sprite or package |
| Design tokens | workspaceSymbol on the token module → documentSymbol | hex grep in constants/, theme/, tokens.* |
| Theming truth | goToDefinition on the theme resolver — read for early returns and dead code | read the resolver body |
| Feature flag | workspaceSymbol → findReferences for every gating site | grep the config key or flag SDK |
| Contract + timing | goToDefinition on the data hook | grep the route literal |
| Isolation posture | goToDefinition on the rendering component — read sandbox/CSP verbatim | grep iframe, sandbox, srcDoc |
Produce a harvest table — element | value | path:line | verbatim? — covering copy and structure,
not just tokens. findReferences is not optional: a flag usually gates more than one site, and
describing only the one you noticed misstates the change.
State which branch each value is in:
ESTABLISHED HERE and append it to spike-report.md as you find it, while the reasoning is in
front of you rather than reconstructed later.Where a screen cannot be read (no source, third-party surface), fall back to a screenshot and say so in the file. Where neither exists, declare the whole prototype schematic up front rather than faking selective realism.
Build the question↔control matrix. Catalogue and template: references/control-derivation.md.
Every control traces to a question. Every question reaches an observable state or carries a caption saying why it cannot be seen — an invisible guarantee still has to be stated, or the client cannot falsify it.
Then run the annotation audit: classify every element on every screen as harvested or invented, and check invented ⟺ annotated in both directions.
Zero-dependency HTML/CSS/JS. Inline SVG only: no <img>, <link>, @import, or CDN. Two-pane shell
collapsing to one column on narrow viewports, sticky stage. Structure and the copyable shell block:
references/anatomy.md.
Data ladder, decision procedure in references/fidelity-tiers.md:
| Tier | When | Requirement |
|---|---|---|
| A — live | the contract is reachable, or can be made reachable through a dev proxy holding credentials the browser never sees | wire the proxy with the secret injected server-side; real parameters from a gitignored source via a params route |
| B — recorded | the service exists but is unreachable from the dev box | capture once with curl; inline the exact bytes; a comment carries the literal command and the capture date |
| C — labeled stub | the service does not exist yet | visibly a stub; the caption names it as one |
If neither A nor B is reachable, ask the operator for a capture. For a technique spike Tier A is a validity condition rather than a preference — a mechanism is only proven against real content — but fidelity is a function of what already exists, so Tier C is not failure.
Every tier degrades, never dead-ends. The fetch-failure path falls back to the Tier-B/C payload with an honest caption, so the same file works at its dev route and opened standalone.
Treat the dev proxy as a first-class artifact: it is where a proposed edge contract gets written.
Use Chrome, not Playwright: this artifact is disposable and will be frozen, so a retained spec file is maintenance debt. Load in one call:
ToolSearch select:mcp__claude-in-chrome__navigate,mcp__claude-in-chrome__computer,mcp__claude-in-chrome__read_console_messages,mcp__claude-in-chrome__read_network_requests,mcp__claude-in-chrome__read_pageIf ToolSearch returns none of these, the Chrome tools are not configured in this environment.
Do not skip the gate silently and do not substitute reading the source: finish the build, then
report G4 as UNVERIFIED, naming which checks could not run. Steps 2 and 3 below are mechanical
proofs that source reading cannot supply.
Full checklist: references/verification.md. All mandatory:
navigate to the served routeread_console_messages → zero errorsread_network_requests → zero origins other than the dev server. This is the mechanical proof of
self-containment; never assert it by reading the sourcecomputer walks every question↔control cell; screenshot per stateClose out spike-report.md — the file you opened at ANCHOR and appended to throughout. Here you
only fill the fidelity ledger and move anything still unresolved into Still open:. If the run is
running short, this is the step to protect: finish the report and leave a rougher prototype rather
than a polished file whose findings exist only in a chat message nobody reads six months later.
Settled by this spike:
- <technique>: <what was proven>, evidence <state> → belongs in an ADR
- <route shape>: proposed as <path>, awaiting confirmation → belongs in the integration + its ADR
Still open:
- <question>: unreachable at this fidelity tier because <reason>
Fidelity ledger:
- UI: <n> harvested, <n> invented (all annotated), <n> unreadable → <fallback>
- Data: tier <A|B|C>, <source or capture command + date>
Client-facing deltas to record:
- → hand to your spec-playback / client-confirmation stepThen, only where the environment allows it: register the dev route, and run the secret/PII grep against every environment value and against identity-document and customer-name patterns, refusing to recommend a commit on a hit. Where either is impossible, say so in the report and move on — their absence never suppresses the report.
Draft nothing else. This skill never writes a ## Playback block, never drafts an ADR, never edits
requirement docs. It names destinations; a human decides.
A scan-before-you-ship checklist; the phases above carry the reasoning.
:root groups — shell, app-harvested (each line path:line), prototype-only-and-justified.fetch is fine; a CDN font is not.path:line. Tell them apart by the render condition, not the disabled expression — a control the
app never renders in that state is one you are inventing.<frontend-root>/prototypes/FR-NNN-<slug>.html, or <slug>.html in pure-spike mode. Track it in git
once the secret/PII grep is clean — an untracked prototype behind a committed dev route breaks on a
fresh clone. Scope dev-server changes to one dev-only route; never production routing, never the
build. Prefer a directory route over a per-file constant so the second prototype needs no server edit.
Freeze, don't delete. Usefulness expires when the requirement ships; evidentiary value does not — the file is the evidence behind whatever decision the spike produced. Mark it frozen with a date and stop maintaining it.
references/anatomy.md — shell structure, the single screen switcher, the copyable shell blockreferences/ui-fidelity.md — the UI axis: reading a screen out of source, copy-string discipline,
list completeness, the annotation audit, the recognition check, fallbacksreferences/harvest-playbook.md — LSP recipes, citation format, mirror-vs-prove branchingreferences/control-derivation.md — question shapes → controls, the matrix templatereferences/fidelity-tiers.md — data tiers, dev-proxy recipe, capture form, degrade pathreferences/verification.md — the full browser drivereferences/exemplar-visit-report.md — a worked example walked through, including its defects