Files
ss-tools/.kilo/command/speckit.prototype.md
busya 39aa4a7e0c chore(kilo): consolidate agent skills, commands and workflows
- remove legacy .ai/ knowledge shots and reports, semantic skills
  invariant assessment, and obsolete .kilo/workflows/
- update agent model selection (omniroute/terra) for qa-tester,
  security-auditor, svelte-coder
- add swarm-master agent and speckit openapi/prototype/resume/validate
  plus test.* commands; update speckit plan/ux/implement docs
- refresh skill SKILL.md files (semantics core/testing/svelte/belief,
  molecular-cot-logging, semantic-frontend)
- add semantic curation report
2026-08-02 23:54:30 +07:00

18 KiB
Raw Blame History

description, handoffs
description handoffs
Generate a feature-local interactive HTML prototype from UX contracts, producing specs/<feature>/prototype/index.html plus a prototype manifest and state-coverage report. No production source mutation.
label agent prompt send
Generate OpenAPI Spec speckit.openapi Derive OpenAPI 3.1 from the prototype states and UX contracts true
label agent prompt send
Build Technical Plan speckit.plan Create a Python/Svelte implementation plan using the validated prototype as interaction reference true

User Input

$ARGUMENTS

You MUST consider the user input before proceeding (if not empty).

Applicability

This command is applicable ONLY when the feature has a UI surface. For backend-only features, skip gracefully with: "No UI surface detected — prototype not applicable. Proceed to /speckit.openapi or /speckit.plan."

Decision gate: If FEATURE_DIR/contracts/ux/ exists (from /speckit.ux), generate the full prototype. If only ux_reference.md exists, generate a lightweight prototype from the reference. If neither exists, skip.

Principle

You are generating a read-only, interactive HTML artifact that validates UX contract states against actual browser behavior. The prototype is a design verification tool, not production code. It proves that every declared @UX_STATE can be reached, that @UX_FEEDBACK mechanisms work, and that @UX_RECOVERY paths are traversable — all without touching frontend/src/.

Design fidelity is mandatory, not optional: the prototype MUST visually match the application's real design system. It is built by copying the exact utility classes and design tokens from the production Svelte components, not by inventing a parallel "prototype style". A prototype that looks different from the app fails its purpose — reviewers cannot judge states they will never see in production. If you find yourself writing a custom hex color, custom radius, or custom shadow that is not in frontend/tailwind.config.js, you are doing it wrong.

Outline

Phase 0: Pre-Flight

  1. Setup: Run .specify/scripts/bash/check-prerequisites.sh --json --paths-only from repo root. Parse FEATURE_DIR.
  2. Verify applicability: Check for FEATURE_DIR/contracts/ux/ or FEATURE_DIR/ux_reference.md. If neither exists and no UI surface is indicated, report skip and exit.
  3. Load context:
    • FEATURE_DIR/spec.md — user stories and acceptance criteria
    • FEATURE_DIR/ux_reference.md — interaction reference
    • FEATURE_DIR/contracts/ux/screen-models.md — model inventory (if exists)
    • FEATURE_DIR/contracts/ux/api-ux.md — API shapes for realistic mock data (if exists)
    • FEATURE_DIR/contracts/ux/<screen>-ux.md — per-screen UX contracts (if exists)
    • .opencode/skills/semantics-svelte/SKILL.md — §VI canonical FSM template, §VII design tokens
    • frontend/tailwind.config.jsdesign token SSOT: semantic color palette (primary/secondary/destructive/success/warning/info/ghost/surface/border/text), typography, spacing, radius
    • frontend/src/app.css — global styles and motion preferences
    • frontend/src/lib/ui/ — existing design-system atom inventory (Button, Card, Input, Select, Badge, PageHeader, Skeleton, EmptyState, Pagination, etc.)
    • frontend/src/lib/components/ — existing composite widget inventory
    • frontend/src/lib/ui/index.ts — component export index
    • Every .svelte component the prototype will use — read the full source to copy its exact class strings

Phase 0.5: Design System Alignment (MANDATORY — before any HTML)

Extract the design system truth from production sources. This phase produces a working set of tokens and class recipes that the prototype MUST use verbatim.

Step 1 — Extract design tokens from frontend/tailwind.config.js:

  • Semantic palette: primary.*, secondary.*, destructive.*, success.*, warning.*, info.*, ghost.*, surface.*, border.*, text.*, brand.*, terminal.* (if applicable)
  • Record hex values exactly: e.g. primary.DEFAULT = #2563eb, primary.hover = #1d4ed8, surface.page = #f8fafc, text.muted = #64748b
  • Record widths (sidebar 240px), font families (JetBrains Mono for terminal)

Step 2 — Extract component class recipes from frontend/src/lib/ui/*.svelte:

  • Read the full source of each component the prototype uses (Button, Card, Badge, PageHeader, Input, Select, Skeleton, EmptyState, Pagination, ConfirmDialog, Toast if used)
  • Copy the exact class strings from the Svelte template, e.g.:
    • Button base: inline-flex items-center justify-center font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 rounded-md
    • Button primary: bg-primary text-white hover:bg-primary-hover focus-visible:ring-primary-ring
    • Button sizes: sm: h-8 px-3 text-xs, md: h-10 px-4 py-2 text-sm, lg: h-12 px-6 text-base
    • Card: rounded-lg border border-border bg-surface-card text-text shadow-sm, padding p-6 (md)
    • Badge variants: bg-success-light text-success, bg-warning-light text-warning, bg-destructive-light text-destructive, bg-info-light text-info, bg-primary-light text-primary, bg-surface-muted text-text-muted; shape rounded-full text-xs font-medium
    • PageHeader: flex items-center justify-between mb-8, title text-3xl font-bold tracking-tight text-text
    • EmptyState: read source, copy its structure and classes
    • Skeleton: animate-pulse + muted surface classes
  • If the app uses dark mode / terminal palette (log viewer, task drawer): replicate terminal.bg/terminal.surface/terminal.border where the feature touches those surfaces

Step 3 — Build the prototype stylesheet as a Tailwind-utility shim:

  • The prototype is a single self-contained HTML file (no build step). Inline the Tailwind utility classes the app actually uses as a minimal CSS shim: for every class string copied in Step 2, write the CSS rule that implements it (e.g. .bg-primary { background-color: #2563eb; }, .hover\:bg-primary-hover:hover { background-color: #1d4ed8; }).
  • Color values MUST come only from tailwind.config.js. No invented hex codes. If a color is needed that is not a token, use the nearest semantic token.
  • Keep the shim scoped and complete: every class used in the HTML body MUST have a definition in the <style> block.

Phase 1: Extract Representational States

From the loaded UX contracts and reference docs, build the representative state inventory:

For each screen identified in the feature:

  1. Mandatory states (from UX contracts or inferred):
    • idle — before any user action
    • loading — during async operation
    • loaded — data visible, ready
    • empty — no data (first use or filtered)
    • error — failure state with recovery
  2. Story-specific states (from per-screen UX contracts):
    • Every distinct @UX_STATE declared in contracts
    • Every @UX_FEEDBACK mechanism (toast, inline error, modal)
    • Every @UX_RECOVERY path (retry, cancel, navigate away)
  3. Edge states (from Phase 2 of /speckit.ux):
    • Stale data with refresh indicator
    • Partial data (some loaded, some failed)
    • Background update notification
    • Rate-limited with countdown
    • Network offline with reconnection

State coverage requirement: Every @UX_STATE declared in UX contracts MUST be represented. Every declared @UX_RECOVERY path MUST be reachable from its error state. Output a state coverage table in the manifest showing contract → prototype mapping.

Phase 2: Build Static Prototype

Create specs/<feature>/prototype/index.html:

Mandatory structure:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>[Feature] — Interactive Prototype</title>
  <style>
    /* Embedded styles — no external deps */
    /* Use Tailwind-like utility classes matching design tokens */
    /* Responsive: mobile-first with breakpoints at 640px, 768px, 1024px */
  </style>
</head>
<body>
  <!-- State Switcher (top bar, always visible) -->
  <nav class="prototype-state-switcher">...</nav>
  
  <!-- Screen content — one <section> per screen -->
  <main>
    <section id="screen-1" class="prototype-screen">...</section>
  </main>
  
  <script>
    // Inline JavaScript for state switching
    // No frameworks, no build step, no external deps
    // All states toggleable via the state switcher
  </script>
</body>
</html>

Rules:

  • Single file: index.html is self-contained. All CSS and JS are inline. No external dependencies by default.
  • USE THE REAL CLASS RECIPES — verbatim: Every interactive element, container, and label in the prototype MUST carry the exact same Tailwind class strings as the production component it represents (from Phase 0.5 Step 2). Do NOT simplify, rename, or "clean up" production classes. Examples:
    • Buttons: class="inline-flex items-center justify-center font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 rounded-md bg-primary text-white hover:bg-primary-hover focus-visible:ring-primary-ring h-10 px-4 py-2 text-sm"
    • Cards: class="rounded-lg border border-border bg-surface-card text-text shadow-sm p-6"
    • Badges: class="inline-flex items-center gap-1.5" wrapper + class="rounded-full px-2.5 py-1 text-xs font-medium bg-success-light text-success"
    • PageHeader: class="flex items-center justify-between mb-8" + class="text-3xl font-bold tracking-tight text-text"
  • Tokens from tailwind.config.js only: The CSS shim's color/radius/shadow/spacing values MUST be the exact hex/px from frontend/tailwind.config.js. Zero invented values. If you cannot find a token for a needed style, use the nearest semantic token or note it in the manifest as a design gap.
  • Match component behavior: Disabled buttons get disabled:opacity-50 + disabled:pointer-events-none; loading buttons show the spinner SVG with animate-spin; skeletons use animate-pulse; badges use the semantic variant pair (bg-*-light text-*).
  • No production source mutation: The prototype lives in specs/<feature>/prototype/. It NEVER writes to frontend/src/.
  • Accessibility: All interactive elements MUST have: appropriate ARIA roles, aria-live regions for dynamic content, keyboard navigation (Tab/Enter/Space), focus management (match focus-visible:ring-2 classes), minimum 44×44px touch targets on mobile, and alt text for images/icons.
  • Responsive: Match the app's actual breakpoints (mobile-first; Tailwind sm 640px / md 768px / lg 1024px). Test on both viewports via the state switcher's viewport toggle.
  • State switcher: A fixed toolbar at the top of the prototype that allows:
    • Switching between screens (if multiple)
    • Toggling between states for each screen
    • Toggling viewport size (desktop 1280px / mobile 375px)
    • Shows CURRENT state name, can trigger transitions (loading → loaded, loaded → error, etc.)
    • The switcher itself is a prototype chrome, not app UI — it may use plain styling, but every element INSIDE the screen sections must use production classes
  • Realistic mock data: Use data shapes from api-ux.md to populate loaded states with plausible content. Empty states show realistic empty-state components. Error states show realistic error messages.

Phase 3: Generate Prototype Manifest

Create specs/<feature>/prototype/manifest.md:

#region Std.Opencode.PrototypeManifest [C:3] [TYPE ADR] [SEMANTICS prototype,manifest,[DOMAIN]]
@defgroup Prototype Interactive HTML prototype manifest for [FEATURE].

## Prototype Metadata
- **Feature**: [feature name]
- **Source contracts**: contracts/ux/
- **Screens represented**: N
- **Total states**: N
- **Accessibility validations**: keyboard nav, ARIA roles, touch targets, focus management
- **Responsive breakpoints**: 375px (mobile), 1280px (desktop)

## State Coverage
| Screen | @UX_STATE Contract | Prototype State | Reachable? | Recovery Path |
|--------|-------------------|-----------------|------------|---------------|
| Dashboard | idle | idle (default) | ✅ | — |
| Dashboard | loading | loading (3s auto) | ✅ | — |
| Dashboard | loaded | loaded (with mock data) | ✅ | — |
| Dashboard | empty | empty (no data mock) | ✅ | — |
| Dashboard | error | error (network fail) | ✅ | retry button → loading |
| Dashboard | stale | stale (cached + indicator) | ✅ | refresh button |

## Screen ↔ Story Traceability
| Prototype Screen | User Story | UX Contract | Acceptance Criteria Verified |
|-----------------|------------|-------------|------------------------------|
| /dashboard | US1: View Dashboards | DashboardUx | AC1: list loads, AC2: empty state |
| /migration | US2: Migrate Items | MigrationUx | AC1: step wizard, AC2: error recovery |

## Validation Results
- [ ] All @UX_STATE contracts reachable via state switcher
- [ ] All @UX_RECOVERY paths traversable
- [ ] Keyboard navigation: Tab order verified
- [ ] Touch targets: ≥44×44px on mobile viewport
- [ ] ARIA: live regions for loading/error states
- [ ] No broken links or dead-end states
- [ ] Responsive layout: mobile viewport does not overflow

## Design System Reuse
| Element | Source | Prototype Mapping |
|---------|--------|-------------------|
| Button | $lib/ui/Button.svelte | Same class string: `bg-primary text-white hover:bg-primary-hover ... h-10 px-4 py-2 text-sm` |
| Card | $lib/ui/Card.svelte | Same class string: `rounded-lg border border-border bg-surface-card text-text shadow-sm p-6` |
| Badge | $lib/ui/Badge.svelte | Same class string: `rounded-full px-2.5 py-1 text-xs font-medium bg-{variant}-light text-{variant}` |
| Skeleton | $lib/ui/Skeleton.svelte | `animate-pulse` + muted surface |
| EmptyState | $lib/ui/EmptyState.svelte | Copy structure + classes from source |
| PageHeader | $lib/ui/PageHeader.svelte | Same class string: `flex items-center justify-between mb-8` + `text-3xl font-bold tracking-tight text-text` |
| Input | $lib/ui/Input.svelte | Copy classes from source |
| Select | $lib/ui/Select.svelte | Copy classes from source |

## Design Token Audit (MANDATORY)

Every color/radius/shadow/spacing value used in the prototype MUST trace to `frontend/tailwind.config.js`. Complete this table during build:

| Token (tailwind.config.js) | Hex / Value | Used in prototype (elements) |
|----------------------------|-------------|------------------------------|
| `primary.DEFAULT` | `#2563eb` | primary buttons, active states |
| `primary.hover` | `#1d4ed8` | primary button hover |
| `primary.light` | `#eff6ff` | `bg-primary-light` badge variant |
| `destructive.DEFAULT` | `#dc2626` | destructive buttons, error accents |
| `destructive.light` | `#fef2f2` | `bg-destructive-light` badge variant |
| `success.DEFAULT` / `success.light` | `#22c55e` / `#f0fdf4` | success badges |
| `warning.DEFAULT` / `warning.light` | `#f59e0b` / `#fffbeb` | warning badges |
| `info.DEFAULT` / `info.light` | `#0ea5e9` / `#f0f9ff` | info badges |
| `surface.page` | `#f8fafc` | page background |
| `surface.card` | `#ffffff` | card background |
| `border.DEFAULT` | `#e2e8f0` | borders |
| `text.DEFAULT` / `text.muted` | `#0f172a` / `#64748b` | body / secondary text |
| `brand.gradient-*` | `#0ea5e9 → #06b6d4 → #4f46e5` | brand elements (if applicable) |
| `terminal.*` | dark palette | only if feature touches log/task surfaces |

**Audit gate**: scan the final `index.html` for any hex color (`#[0-9a-fA-F]{3,6}`) or hardcoded px radius that does NOT appear in the token table above. Every such value is a FAIL — replace with the nearest semantic token or document in the manifest as an intentional design gap with the production source that defines it.

#endregion Std.Opencode.PrototypeManifest

Phase 4: Browser Validation

Open specs/<feature>/prototype/index.html in the browser and validate:

  1. State coverage: Cycle through every state via the state switcher. Confirm each declared @UX_STATE is visually represented.
  2. Recovery paths: From each error state, verify the recovery action leads to the correct next state (retry → loading, dismiss → idle, etc.).
  3. Keyboard navigation: Tab through all interactive elements. Confirm focus rings are visible (match focus-visible:ring-2 classes). Confirm Enter/Space activate buttons and links.
  4. Responsive: Toggle viewport size. Confirm layout adapts without overflow or broken alignment.
  5. Accessibility snapshot: Use browser DevTools accessibility tree to confirm ARIA roles and labels are correct.
  6. Design fidelity (MANDATORY): Visually compare the prototype against the real app's equivalent components (open frontend/ dev server or reference screenshots). Confirm:
    • Colors match the semantic palette (buttons, badges, alerts use identical hues)
    • Typography scale matches (PageHeader text-3xl font-bold, buttons text-sm, badges text-xs)
    • Spacing/padding matches (Card p-6, Button px-4 py-2, gaps gap-1.5/gap-4)
    • Radius matches (rounded-md buttons, rounded-lg cards, rounded-full badges)
    • Shadows match (shadow-sm cards)
    • Any mismatch is recorded in the manifest as a design gap with a fix note

Record results in manifest.md under "Validation Results" and "Design Token Audit".

Phase 5: Report

Report:

  • Prototype path: specs/<feature>/prototype/index.html
  • Manifest path: specs/<feature>/prototype/manifest.md
  • Screens represented: N
  • Total states: N
  • State coverage: N/N contracts reachable (100% required)
  • Recovery paths: N/N traversable
  • Accessibility: keyboard nav /, ARIA /, touch targets /
  • Design fidelity: all colors/radius/shadows from tailwind.config.js; N production components replicated with verbatim class strings; N design gaps documented
  • Token audit: N/N hex values traced to tailwind.config.js (100% required)
  • Recommended next command: /speckit.openapi (if API surface) or /speckit.plan