| name | qfai-prototyping |
| title | QFAI Prototyping (DESIGN.md-driven UX Loop) |
| description | Iterate one prototype through up to 10 cycles of generate-capture-review against a frozen DESIGN.md, focusing on information architecture, navigation flow, usability, and functionality. |
| argument-hint | |
| allowed-tools | ["Read","Glob","Write","TodoWrite","Task","Bash"] |
| roles | ["orchestrator","product-experience-architect","product-surface-reviewer","devops-ci-engineer"] |
| routing-profile | ui-surface-aware |
| mode | execution-focused |
/qfai-prototyping
[DRIFT-PROTOCOL:MANDATORY]
This skill is static-first and file-based by default: it runs every
UI-bearing spec resolved at cycle 0 through up to 10 iterations against
a frozen brand SSOT (DESIGN.md) and a frozen spec set, one lineage per
spec × screen pair, no parallel candidates, no mode, fixed 10-cycle
budget. Supported surfaces: web, mobile, desktop, mixed. cli surface is
rejected and ui_bearing: false specs are excluded from prototyping
execution.
Goal
One final prototype satisfying the spec under a locked brand identity, with all four UX axes exceptional, no layout anti-patterns, and no DESIGN.md violations.
Required References
references/iteration-loop.md — flow, exit codes, evidence paths
references/generator-prompt.md — generator system prompt + Tailwind
CDN + DESIGN.md token injection rules
references/reviewer-prompt.md — reviewer schema, 4 UX axes,
layout anti-patterns (lap-001..006 static regex + lap-007..008 semantic),
designMdViolations, pivot rules
references/handoff.md — post-loop design-system.yaml (DESIGN.md
token mirror) and prototype-handoff.yaml
references/design-md-spec.md — DESIGN.md front-matter schema and
validation rules
templates/DESIGN.md.sample — reference content shipped at the
consuming-project root by qfai init
Required Contracts
.qfai/specs/spec-*/{01_Spec.md, 03_Acceptance-Criteria.md}
.qfai/contracts/ui/*.yaml
- root
DESIGN.md
.qfai/contracts/design/DESIGN.md.lock.yaml
The brand identity is governed by root DESIGN.md. The lock yaml records
its sha256 at /qfai-sdd Phase 0 freeze. The loop refuses to run if the
current DESIGN.md hash does not match the lock.
Required Process
Step 2-A — Verify Contract Preconditions
- The skill resolves every UI-bearing spec in one invocation via
resolveAllUiBearingSpecs() (core/prototyping/specResolution.ts):
strict surface_type: ui-bearing frontmatter + matching
.qfai/contracts/ui/<spec-id>*.yaml, with legacy title-marker and
qfai.config.yaml prototyping pinning folded in. Run
qfai doctor --profile prototyping to surface the resolved value.
Zero UI-bearing specs at cycle 0 is a deterministic no-op exit 0.
Confirm each resolved spec has a supported surface.
- Confirm root
DESIGN.md and .qfai/contracts/design/DESIGN.md.lock.yaml
both exist; confirm .qfai/contracts/ui/*.yaml exists.
- Run
qfai prototyping preflight --target-url <url> (alias for
qfai doctor --profile prototyping) — verifies DESIGN.md parses and
matches the lock sha256.
Step 2-B — Verify Environment Preconditions
- Confirm a capture route exists for each declared screen.
- Canonical launcher:
npx --no-install playwright or
node_modules/.bin/playwright when PATH reachability is uncertain.
- Legacy fallback (deprecation window only, emits
D-DEPRECATED-PROBE and will be removed in a future minor release):
npx --no-install playwright-cli or node_modules/.bin/playwright-cli.
Step 2-B.1 — Opt-in iterate flags
Three flags extend qfai prototyping iterate; all default OFF so the
prior invocation pattern is byte-equivalent when no flag is passed:
--capture — enable PNG / HTML capture per screen each cycle via
the default Playwright runner (dynamic import("playwright");
Playwright is optionalDependencies). Use for durable pixel / DOM
evidence; skip for fast prose-only cycles.
--auto-serve — start an in-process node:http server rooted at
the prototype tree for the cycle. SIGINT teardown <= 2 s;
EADDRINUSE on a foreign owner exits 2 (no foreign-process kill).
Use when no external dev server is running.
--check-convergence — read-only peek of prototyping.json.
Exits 0 when converged (stopReason === "axes-exceptional" with
acceptedIterationIndex set), exits 2 otherwise. No writes,
no Playwright launches. Use at cycle 9 before recovery.
Step 2-C — Run the Loop
| Step | Actor | Action | Output |
|---|
| C0 | product-experience-architect | qfai prototyping iterate --cycle 0 --target-url <url>. CLI computes sha256(DESIGN.md); lock match enforced. Generator reads contracts + references/generator-prompt.md + DESIGN.md tokens and writes .qfai/prototypes/iter-00/index.html. Capture + review → iter-00/review.json. Append entry; commit prototyping: iter-00. | iter-00, prototyping.json#designMdSha256 |
| C1..9 | (a) devops, (b) reviewer, (c) orchestrator, (d) generator | (a) playwright-cli writes iter-NN/<screen>.{png,html}; (b) reviewer writes iter-NN/review.json per references/reviewer-prompt.md (4 UX axes ordinal, 200..500 word critique, layoutAntiPatternsDetected[], designMdViolations[], pivotDirective); (c) update prototyping.json#iterations[] + progress.md, commit prototyping: iter-NN; (d) qfai prototyping iterate --cycle <n+1> decides exit. After C9 do NOT call --cycle 10 — the CLI rejects out-of-range cycles. See the "Cycle 9 budget exhaustion" subsection below for recovery. | iter-NN, exit ∈ {0, 64, 65, 66, 2} |
| H | orchestrator | Mirror latest to .qfai/prototypes/final/index.html. Per references/handoff.md: write design-system.yaml (deterministic DESIGN.md token mirror, no HTML extraction) + prototype-handoff.yaml. Run qfai validate --profile prototyping --fail-on error (produces validate.json with counts.error === 0), then /qfai-verify (produces verify.json with status === "PASS"), then qfai prototyping certify — certify requires both gate files to be present and passing before it will seal the certificate. | DONE |
Exit codes: 0 continue (read pivotDirective); 64 convergence (4
axes exceptional AND layoutAntiPatternsDetected empty AND
designMdViolations empty); 65 10 cycles reached; 66 license-verify
failure (imageSources[] resolved to a non-allowlisted source, unknown
license tier, non-HTTPS URL, host mismatch vs the cycle-0 frozen
sourceHosts, or missing / empty attribution — see "License-verify
hard-stop (exit 66)" below for recovery); 2 input error or lock drift
(incl. DESIGN.md hash mismatch — re-run prototyping from cycle 0 after
editing DESIGN.md and refreezing the lock via /qfai-sdd Phase 0; also
covers frozenSurfaceUnion / frozenLicenseCatalog drift on cycle ≥ 1).
License-verify hard-stop (exit 66)
qfai prototyping iterate exits 66 when an imageSources[] entry on
prototyping.json violates the cycle-0 frozen license catalog. The
verifier rejects five distinct error codes:
license-not-allowlisted — source not in allowedSources
license-tier-unknown — license not in licenseTiers[source]
license-non-https-url — url is not HTTPS
license-host-mismatch — URL host not in sourceHosts[source]
license-missing-attribution — attribution empty / whitespace
Recovery path (no in-loop retry — the verifier is fail-closed):
- Inspect
prototyping.json#frozenLicenseCatalog for the frozen
allowedSources / licenseTiers / sourceHosts.
- Edit the offending
imageSources[] entry to use an allowlisted
source / known tier / HTTPS URL / matching host / non-empty
attribution. Do not edit frozenLicenseCatalog mid-loop
(separate exit-2 lock-drift class).
- To change the allowlist, refreeze the catalog by restarting from
cycle 0 with the updated stock-photo configuration.
Cycle 9 budget exhaustion
If convergence is not reached at iter-09, certify rejects the run; H
handoff artifacts and validate / /qfai-verify can still execute for
inspection, but qfai prototyping certify --check will exit non-zero
and prevent DONE.
Use qfai prototyping iterate --cycle 9 --check-convergence for a
read-only peek of prototyping.json before refreezing: exit 0
confirms convergence (no recovery needed), exit 2 confirms the run
did not converge. Recovery: review DESIGN.md, the pivot strategy
in references/reviewer-prompt.md, and the latest review.json
findings, then re-run qfai prototyping iterate --cycle 0 --target-url <url> to refreeze. Do not seal a certificate against
an unconverged iter-09.
Evaluator Inputs (Mandatory)
- Screenshot evidence path:
.qfai/evidence/prototyping/iter-NN/<screen>.png
- HTML snapshot path:
.qfai/evidence/prototyping/iter-NN/<screen>.html
- Review inputs: latest screenshot, latest HTML snapshot, prior
review.json files, progress.md, root DESIGN.md (read-only),
axisDefs, previousScore, designSystemChecklist.
Critical Constraints
- One lineage only — no parallel candidates, no best-of-history; the
latest iter is always accepted.
DESIGN.md is frozen for the run; to change it, edit + rerun
/qfai-sdd to refreeze + start cycle 0.
- Token-only colors / fonts / radii / shadows — non-DESIGN.md hex /
rgb / rgba / hsl / font / radius / shadow values land in
designMdViolations[] and block exit 64.
- DONE only when
qfai prototyping certify --check returns 0.
- No
mode / round / polish / branch / concept-fit artifacts.
Delegation Scope Table
| Work | Allowed Role |
|---|
| Generation | product-experience-architect |
| Playwright CLI execution & capture | devops-ci-engineer |
| Evaluation scoring | product-surface-reviewer |
Reviewer Gate
- Check Drift Protocol compliance before DONE.
- Check
.qfai/assistant/catalog/test-layers.md alignment.
- Treat reviewer findings as signals, not gates, unless
certify/validate/verify fails.
Completion
DONE = completion-certificate.json exists AND
qfai prototyping certify --check returns 0 AND /qfai-verify returns
PASS.
Follow .qfai/assistant/constitution/shared-skill-operating-baseline.md#gate-failure-autorepair-protocol for validate, doctor, and quality-gate failures.
Next
/qfai-atdd / /qfai-implement / /qfai-verify
Default Autopilot Policy
The skill collapses avoidable per-session prompts to 0-1 by classifying every decision into one of three named buckets:
- auto-decide:
- output formatting
- ID / sequence numbering
- append-vs-create on subject overlap
- equivalent-option pick
- ask-user:
- CREATE / DELETE / SPLIT / MERGE / SUPERSEDE / UPDATE:REMOVE triage operations (each with a prompt template that names the target and rationale)
- destructive operations (rm / overwrite / force-push)
- version-pin changes (
package.json#version, branch pin)
- scope expansions outside the active envelope
- hard-required:
companyName
- brand intent
primarySpecId (when absent from inputs)
A skill MAY narrow the auto-decide bucket (drop entries) but MUST NOT widen it. Widening triggers a Reviewer-Gate finding.
project_memory:
- Iteration count cap is 10; --cycle is 0-indexed; reaching cycle 9 on a non-converged iteration set exits 65 directly (no cycle-mismatch path).
- review.json schema-v3 is the only accepted shape; pre-v3 payloads, unknown layoutAntiPatterns codes, or wrong-enum designMdViolations entries fail validate with QFAI-PROT-002.
- DESIGN.md lock sha256 is re-checked every cycle against the live DESIGN.md; mismatch exits 2 and stops the loop.