Files
claude-plugins/composer/skills/composer-mocks/SKILL.md
movq 594fccc80a feat(composer): discovery-phase plugin from "I want an app that..." to tracker-loaded stories
Plugin pairs with Symphony — Composer's output (issues in the project's
tracker) is Symphony's input. State-aware /composer command walks the
user through 11 phases: concept, users (with workflow probing for hidden
actors), requirements/NFR/IA, design system, interaction design, flows,
mocks, architecture, stories, roadmap, load. Each phase produces a
reviewable artifact in docs/planning/ (or, for design and interaction,
a project-local skill — see below).

Architecture is intentionally LAST, after the spec is complete. Mocks
are JSX/TSX regardless of final stack and pass a "text feasibility"
audit — every visible string is categorized (static/computed/authored),
computed strings are traced to source data, and any string implying an
unspecified feature halts the commit.

Design system and interaction design are produced as PROJECT-LOCAL
SKILLS in .claude/skills/<slug>-design-system/ and
.claude/skills/<slug>-interaction-design/, not as docs in
docs/planning/. Skills auto-load via description matching whenever UI
work happens; a reference doc gets read once and drifts out of context.
The mocks skill imports tokens directly from the design-system skill
for a single source of truth across mocks and (eventually) real code.

ui-system is currently a PLACEHOLDER — captures the minimum needed for
mocks to proceed with <TBD: ...> markers as a return-pass worklist.
Full interview specification is the next pass.

Council touchpoints baked in: PM/skeptic/end-user after requirements,
end-user/a11y after mocks, full architecture council after architecture,
plus auto-additions (legal-triage on regulated data, privacy-advocate
on PII, finance-controller on money flows).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 21:03:40 -05:00

7.5 KiB

name, description
name description
composer-mocks Generate or revise high-fidelity JSX/TSX mocks for named user flows in a Composer project. Mocks reference the design system tokens and follow the patterns declared in interaction-design.md. After generation, runs a text feasibility audit — every visible string is categorized (static/computed/authored) and traced to source data, so mocks don't lie about features the app can't yet generate. Use when the user runs /composer-mock, when the composer skill reaches phase 7, or when the user asks to "mock the X flow".

Composer mocks

You generate high-fidelity, non-functional mocks in JSX/TSX. The final application may end up React, React Native, SwiftUI, Flutter, or a plain server-rendered template — JSX is just a fast, expressive way to encode layout, content, and component composition. The mock is a storyboard, not a build artifact.

Prerequisites (hard checks)

Before generating, verify all of:

  1. docs/planning/flows.md exists and contains the named flow.
  2. docs/planning/users.md exists.
  3. The design-system skill exists at .claude/skills/<slug>-design-system/, including its tokens.ts and components.md sidecars.
  4. The interaction-design skill exists at .claude/skills/<slug>-interaction-design/.

If any are missing, stop and tell the user which one — then point at the phase that should produce it. The skills (not docs) are the contract: they're what auto-load when UI work happens, so a missing skill means generated mocks will reference patterns that aren't in context.

The <slug> is resolved the same way the ui-system skill resolves it (package.json → git remote → directory name → ask).

Tokens are the skill's sidecar

The mock imports tokens directly from the design-system skill:

import { color, spacing, fontSize, radius, motion } from
  "../../.claude/skills/<slug>-design-system/tokens";

There is no separate mocks/tokens.ts. The design-system skill's tokens.ts IS the source of truth, and mocks import it directly. This keeps a single token file in scope whenever UI is being touched (mock or real code) — no duplication, no drift.

Generation

For a flow named <flow>:

  1. Read the flow's steps from flows.md.
  2. Read the relevant patterns from the interaction-design skill (state surface for this kind of action, motion policy, breakpoints, locale). The skill should already be in context via description match; read the SKILL.md explicitly if not.
  3. Read the relevant entities from ia.md so component names match the project's vocabulary.
  4. Read components.md from the design-system skill so any component referenced in the mock matches the declared anatomy.
  5. Draft docs/planning/mocks/<flow>.tsx as a single-file mock.
    • Use Tailwind classes referencing token values, or inline styles reading from tokens.ts — whichever the design system declares.
    • Components, not framework abstractions. No state, no effects, no fetchers — this is a still life.
    • Cover the empty/loading/error/offline states declared in interaction-design.md, even if just as commented-out variants.
  6. Run the text feasibility pass (below).
  7. Offer a council review (Marge + Maya).

Text feasibility pass

This is the headline pass. Every visible string in the generated mock is categorized:

Category Definition Mock shows…
STATIC UI label, button text, fixed copy The literal string
COMPUTED Derived from data via a transform A representative example + annotation comment
AUTHORED Free text the user types in A placeholder + clear "user-authored" marker

For every COMPUTED string, document:

  • Source: which entity / field. Must trace back to an entity declared in ia.md or a state declared in users.md.
  • Transform: what produces the string from the source.
  • Status: source exists / ⚠️ source not yet specified / implies an unstated feature.

Output the audit to the user before committing the mock to disk (if the source is incomplete) or alongside the mock (if everything traces).

Audit format

log-feeding.tsx — text feasibility audit

14 strings. STATIC: 9, COMPUTED: 4, AUTHORED: 1.

COMPUTED:

  ┌─ "Last fed 6 hours ago"
  │  Source:     starter.feedings[-1].timestamp
  │  Transform:  relative-time formatter, locale-aware
  │  Status:     ✅ source field exists in ia.md
  │  Note:       interaction-design.md should declare relative-time
  │              policy (when do we switch to absolute?)
  │
  ├─ "Activity score: 7.2"
  │  Source:     starter.activityScore
  │  Transform:  format(score, 1 decimal)
  │  Status:     ❌ activityScore not in ia.md — implies a feature
  │              we have not specified
  │  Action:     either add activityScore (with its computation) to
  │              the model and to requirements.md, or remove this
  │              element from the mock
  │
  ├─ "Will peak around 4:30 PM today"
  │  Source:     prediction.peakTime
  │  Transform:  format(peakTime, "around h:mm a")
  │  Status:     ⚠️  prediction is in requirements.md as soft —
  │              call out that "peak prediction" is a real subproject,
  │              not a label
  │
  └─ "3 active starters"
     Source:     count(starters where status='active')
     Transform:  pluralize("active starter", n)
     Status:     ✅ trivial

Halt-vs-warn

  • status in any string → halt. Do not commit the mock until the user resolves: spec the feature properly, or remove the element. Lying mocks anchor stakeholders to capabilities the team has not agreed to build.
  • ⚠️ statuswarn. Commit the mock, but add a comment in the file flagging the implication, and surface it in the post-generation report.
  • everywhere → commit cleanly.

Naming and file shape

docs/planning/mocks/<flow>.tsx. One mock per flow. State variants (empty / loading / error) live in the same file as commented sections or as additional named exports — whichever the user prefers.

Header comment of every mock:

/**
 * Mock: <flow name>
 * Source: docs/planning/flows.md § <flow>
 * Generated: <date>
 * Status: <draft | reviewed | stale>
 *
 * This is a non-functional mock. No state, no fetchers, no logic.
 * Strings are annotated for source/transform per text feasibility pass.
 */

Re-running on an existing mock

If the mock file exists:

  • Compare flows.md § mod-time to the mock file. If flow is newer, regenerate; if mock is newer, ask the user before overwriting.
  • Always re-run the text feasibility pass after changes.
  • Preserve the user's hand-edits where possible: diff before write.

Council review

After a clean text pass, offer:

Mock committed. Summon Marge (end-user) and Maya (a11y) for review? [Y/n]

The review reads the mock and interaction-design.md and produces the standard council output. Save to docs/planning/reviews/mock-<flow>-<date>.md.

Hard rules

  • No mock without a clean (or warned) text feasibility audit. A mock that implies an unspecified feature is a mock that has lied to its viewer.
  • No tokens hardcoded. Everything visual comes from the design-system skill's tokens.ts. Import directly; do not copy.
  • No state, no effects, no async. This is a still life. If the mock needs interaction to communicate, write a second mock for the next state.
  • Match the vocabulary in ia.md. Don't introduce new terms in mocks that the rest of the planning doesn't use.