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>
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:
docs/planning/flows.mdexists and contains the named flow.docs/planning/users.mdexists.- The design-system skill exists at
.claude/skills/<slug>-design-system/, including itstokens.tsandcomponents.mdsidecars. - 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>:
- Read the flow's steps from
flows.md. - 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.
- Read the relevant entities from
ia.mdso component names match the project's vocabulary. - Read
components.mdfrom the design-system skill so any component referenced in the mock matches the declared anatomy. - Draft
docs/planning/mocks/<flow>.tsxas 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.
- Use Tailwind classes referencing token values, or inline styles
reading from
- Run the text feasibility pass (below).
- 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.mdor a state declared inusers.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.
- ⚠️ status → warn. 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.