Validated against the plugin-dev:skill-development checklist and applied conformance fixes: Description style — all five skill descriptions now use the canonical "This skill should be used when..." third-person form, with expanded trigger-phrase coverage. Previously used imperative "Use when..." which the spec calls out as wrong. Writing voice — body prose changed from "You are the dispatcher / You walk a user through..." to imperative "Act as the dispatcher / Walk the user through...". Remaining "you" usage is confined to quoted output text the agent prints to the user, which is correct usage. Progressive disclosure — composer/skills/ui-system/SKILL.md was 2513 words (over the 2000-word ideal). Refactored to 1063 words by moving detailed phase content into: - references/design-interview.md (D1–D11 phase specifications) - references/interaction-interview.md (I1–I11 phase specifications) - references/inspiration-presets.md (Linear/Notion/Stripe/etc. table) The SKILL.md now points at each reference as needed; agents load only what's relevant for the current phase. Other four skills already within the 1000–2000 word range, no refactor needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.6 KiB
name, description
| name | description |
|---|---|
| composer-mocks | Generates or revises 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 the interaction-design skill. 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. This skill should be used when the user runs /composer-mock, when the composer skill reaches phase 7, or when the user asks to "mock the X flow", "generate a mock for X", "draft a UI for X flow", or "wireframe the X screen". |
Composer mocks
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.