From 594fccc80a3678a97bc90019c794842d786c4e1e Mon Sep 17 00:00:00 2001 From: movq Date: Wed, 29 Apr 2026 21:03:40 -0500 Subject: [PATCH] feat(composer): discovery-phase plugin from "I want an app that..." to tracker-loaded stories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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/-design-system/ and .claude/skills/-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 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) --- composer/CLAUDE.md | 90 ++++++ composer/commands/composer-load.md | 21 ++ composer/commands/composer-mock.md | 28 ++ composer/commands/composer-review.md | 27 ++ composer/commands/composer-status.md | 13 + composer/commands/composer.md | 17 + composer/skills/composer-mocks/SKILL.md | 185 +++++++++++ composer/skills/composer/SKILL.md | 291 ++++++++++++++++++ composer/skills/ui-system/SKILL.md | 137 +++++++++ composer/templates/adr/0000-template.md | 50 +++ composer/templates/architecture.md | 42 +++ composer/templates/concept.md | 16 + composer/templates/design-system/SKILL.md | 94 ++++++ .../templates/design-system/components.md | 52 ++++ composer/templates/design-system/tokens.ts | 101 ++++++ composer/templates/flows.md | 25 ++ composer/templates/ia.md | 50 +++ .../templates/interaction-design/SKILL.md | 112 +++++++ composer/templates/nfr.md | 49 +++ .../planning-pointers/design-system.md | 24 ++ .../planning-pointers/interaction-design.md | 18 ++ composer/templates/requirements.md | 34 ++ composer/templates/roadmap.md | 33 ++ composer/templates/stories.md | 31 ++ composer/templates/users.md | 55 ++++ 25 files changed, 1595 insertions(+) create mode 100644 composer/CLAUDE.md create mode 100644 composer/commands/composer-load.md create mode 100644 composer/commands/composer-mock.md create mode 100644 composer/commands/composer-review.md create mode 100644 composer/commands/composer-status.md create mode 100644 composer/commands/composer.md create mode 100644 composer/skills/composer-mocks/SKILL.md create mode 100644 composer/skills/composer/SKILL.md create mode 100644 composer/skills/ui-system/SKILL.md create mode 100644 composer/templates/adr/0000-template.md create mode 100644 composer/templates/architecture.md create mode 100644 composer/templates/concept.md create mode 100644 composer/templates/design-system/SKILL.md create mode 100644 composer/templates/design-system/components.md create mode 100644 composer/templates/design-system/tokens.ts create mode 100644 composer/templates/flows.md create mode 100644 composer/templates/ia.md create mode 100644 composer/templates/interaction-design/SKILL.md create mode 100644 composer/templates/nfr.md create mode 100644 composer/templates/planning-pointers/design-system.md create mode 100644 composer/templates/planning-pointers/interaction-design.md create mode 100644 composer/templates/requirements.md create mode 100644 composer/templates/roadmap.md create mode 100644 composer/templates/stories.md create mode 100644 composer/templates/users.md diff --git a/composer/CLAUDE.md b/composer/CLAUDE.md new file mode 100644 index 0000000..3c06af0 --- /dev/null +++ b/composer/CLAUDE.md @@ -0,0 +1,90 @@ +# composer + +Discovery-phase companion. Composer interviews you from "I want an app that…" +to a tree of stories in your issue tracker, producing reviewable artifacts in +`docs/planning/` along the way. Pairs with **Symphony** — Composer's output +(stories in the tracker) is Symphony's input (work to dispatch). + +Like Symphony, Composer is **tracker-agnostic**. The project's `CLAUDE.md` +documents how to write to the tracker; Composer's load phase reads those +instructions. + +## Phase order + +| # | Phase | Artifact(s) | Skill | +|---|---|---|---| +| 1 | Concept | `docs/planning/concept.md` | `composer` | +| 2 | Users & workflows | `docs/planning/users.md` | `composer` | +| 3 | Requirements | `docs/planning/{requirements,nfr,ia}.md` | `composer` | +| 4 | Design system | `.claude/skills/-design-system/` (project skill) | `ui-system` (placeholder) | +| 5 | Interaction design | `.claude/skills/-interaction-design/` (project skill) | `ui-system` (placeholder) | +| 6 | Flows | `docs/planning/flows.md` | `composer` | +| 7 | Mocks | `docs/planning/mocks/*.tsx` | `composer-mocks` | +| 8 | Architecture | `docs/planning/architecture.md` + `adr/NNNN-*.md` | `composer` | +| 9 | Stories | `docs/planning/stories.md` | `composer` | +| 10 | Roadmap | `docs/planning/roadmap.md` | `composer` | +| 11 | Load | (project's tracker) | `composer` | + +**Phases 4 and 5 do not write to `docs/planning/`.** The design-system and +interaction-design artifacts are *project-local skills* in `.claude/skills/` +because they need to auto-load via description matching whenever UI work +is happening. A reference doc gets read once and drifts out of context as +the conversation grows; a skill loads on demand every time the trigger +matches. `docs/planning/` gets pointer files so the planning index stays +discoverable. + +**Phase 7 imports tokens directly from the skill**, not from a copy: + +```tsx +import { color, spacing, fontSize } from + "../../.claude/skills/-design-system/tokens"; +``` + +Single source of truth across mocks, real components, themes, and any +future visual code in the project. + +**Architecture is last on purpose.** It's a *response* to a complete spec, +not a setting picked at the start. Stack choices made before the design +system, interaction model, and mocks lock you into shapes that don't fit +the problem. + +## Layout + +- `commands/composer.md` — main entry, state-aware. Continues from the first + missing artifact in `docs/planning/`. +- `commands/composer-review.md` — summon a council on the current artifact. +- `commands/composer-mock.md` — generate or revise a mock for a named flow. +- `commands/composer-load.md` — push stories to the project's tracker. +- `commands/composer-status.md` — show what's done, missing, and stale. +- `skills/composer/SKILL.md` — orchestrator: phase detection + interview. +- `skills/composer-mocks/SKILL.md` — JSX/TSX mock generation + text feasibility audit. +- `skills/ui-system/SKILL.md` — design + interaction system interview *(placeholder; to be fleshed out)*. +- `templates/*` — starter skeletons for each artifact. + +## Council touchpoints + +Composer auto-suggests councils at phase boundaries; users can also invoke +`/composer-review` at any time. + +| After phase | Default council | +|---|---| +| Requirements | Lena (PM), Vera (skeptic), Marge (end-user) | +| Mocks | Marge (end-user), Maya (a11y) | +| Architecture | Tomás (architect), Gerald (sr engineer), Priya (DBA), Aisha (DevOps) | +| Pre-load | Marcus (eng manager), Vera (skeptic) — sanity-check scope honesty | + +Composer scans content and adds: +- **Femi (legal-triage)** when it spots regulated jurisdictions, third-party data flows, or licensing questions +- **Camila (privacy-advocate)** when it spots PII, multi-user data, or DNA/health data +- **Ingrid (finance-controller)** when it spots money flows, billing, refunds, or subscriptions + +## Three things Composer doesn't do + +1. **Invent users.** The interview probes for hidden actors (agents, integrations, future-self) by asking about workflows, not by drafting speculative personas. +2. **Lie in mocks.** Every visible string in a mock is annotated as static / computed / authored, with the source data and transform named. Strings that imply unspecified features get flagged before the mock is committed. +3. **Push to the tracker without confirmation.** Always shows a dry run before creating issues. + +## Handoff to Symphony + +After load, the project has stories in its tracker. Run `/symphony-init` to +set up the orchestrator that will execute them. diff --git a/composer/commands/composer-load.md b/composer/commands/composer-load.md new file mode 100644 index 0000000..1e3455e --- /dev/null +++ b/composer/commands/composer-load.md @@ -0,0 +1,21 @@ +--- +description: Push stories from docs/planning/stories.md into the project's issue tracker. Reads the project's CLAUDE.md to learn how to write to whatever tracker the project uses (GitHub Issues, Gitea, tracker CLI, Linear, etc.). Always shows a dry run before creating anything. +--- + +Invoke the `composer` skill in *load* mode. It will: + +1. Read `docs/planning/stories.md` and `docs/planning/roadmap.md`. +2. Read the project's `CLAUDE.md` for the tracker integration section. If + no tracker section is documented, exit with `tracker_integration_missing` + and point the user at `/symphony-init` (which can write the section) or + suggest adding one manually. +3. Build the planned write set — milestones, epics/parents, stories, labels. +4. **Show a dry run.** Print every command the skill would run, grouped by + epic. Wait for user confirmation. +5. On confirmation, execute the writes. On any failure, stop and report — + do not auto-continue past errors that might leave a partial write. +6. Record the created issue IDs back into `stories.md` so the file becomes the + source-of-truth map between local plan and tracker reality. + +After load, suggest `/symphony-init` if the project doesn't already have +Symphony configured. Composer's job ends here; Symphony's begins. diff --git a/composer/commands/composer-mock.md b/composer/commands/composer-mock.md new file mode 100644 index 0000000..5f1f6f2 --- /dev/null +++ b/composer/commands/composer-mock.md @@ -0,0 +1,28 @@ +--- +description: Generate or revise a JSX/TSX mock for a named user flow. Mocks are high-fidelity but non-functional, reference the design system and interaction design, and pass a text feasibility audit before being committed. +arguments: + - name: flow + description: The flow to mock (must exist in flows.md). If omitted, lists available flows. + required: false +--- + +Invoke the `composer-mocks` skill with `$ARGUMENTS`. + +Prerequisites the skill checks before generating: + +1. `docs/planning/flows.md` exists and names the flow. +2. `docs/planning/design-system.md` exists (tokens, type, components vocabulary). +3. `docs/planning/interaction-design.md` exists (state surfaces, motion, input, i18n, breakpoints). +4. `docs/planning/mocks/tokens.ts` is current with `design-system.md`. + +If any prerequisite is missing the skill stops and points at it. The mock is +only as good as the systems it references. + +After generation the skill runs a **text feasibility pass**: every visible +string is categorized (static, computed, authored), computed strings are +traced to source data and transformations, and any string that implies an +unspecified feature is flagged for the user to either spec properly or remove +from the mock. + +After a clean text pass, the skill optionally summons Marge (end-user) and +Maya (a11y) for a review. diff --git a/composer/commands/composer-review.md b/composer/commands/composer-review.md new file mode 100644 index 0000000..4fc9e59 --- /dev/null +++ b/composer/commands/composer-review.md @@ -0,0 +1,27 @@ +--- +description: Summon a Council of Experts to review the current planning artifact. Defaults to a phase-appropriate council; accepts an explicit council list. Use when you want a stress-test of what you've drafted before moving on. +arguments: + - name: artifact + description: Optional artifact name (e.g. "scope", "requirements", "architecture", "log-feeding"). Defaults to whatever Composer thinks the current phase is. + required: false + - name: council + description: Optional explicit comma-separated council member names (e.g. "Vera,Lena,Femi"). Overrides the phase default. + required: false +--- + +Invoke the `composer` skill in *review* mode with `$ARGUMENTS`. + +The skill will: + +1. Identify which artifact to review — the one named, or the current phase's artifact. +2. Pick a council. Defaults from the phase boundary (see `CLAUDE.md`); user + override accepted. Composer also auto-adds members when content suggests + their domain (PII → Camila, money → Ingrid, regulated data flows → Femi). +3. Read the artifact and any upstream context the council needs. +4. Hand off to the `council-of-experts:council` skill with the question framed + for the artifact under review. +5. Record the synthesis and suggested takeaways in + `docs/planning/reviews/-.md` so future phases see prior feedback. + +The output is the council's standard format: each member in their own voice, +then agreements, disagreements, and prioritized takeaways. diff --git a/composer/commands/composer-status.md b/composer/commands/composer-status.md new file mode 100644 index 0000000..a786224 --- /dev/null +++ b/composer/commands/composer-status.md @@ -0,0 +1,13 @@ +--- +description: Show progress on the current Composer project — what's done, what's next, what artifacts may be stale relative to upstream changes. +--- + +Invoke the `composer` skill in *status* mode. It will: + +1. Read `docs/planning/` and report which artifacts exist. +2. Compare modification times — if `requirements.md` was updated after + `flows.md`, flow content may be stale. +3. Show the next phase Composer would resume on. +4. List any council reviews that have been recorded vs. recommended. + +Read-only — no interview, no writes. diff --git a/composer/commands/composer.md b/composer/commands/composer.md new file mode 100644 index 0000000..229aa57 --- /dev/null +++ b/composer/commands/composer.md @@ -0,0 +1,17 @@ +--- +description: Continue product discovery for this project. State-aware — reads docs/planning/ and picks up at the first missing or stale artifact. Run on a fresh project to start from "I want an app that…"; run again later to resume. +--- + +Invoke the `composer` skill. It will: + +1. Look for `docs/planning/` in the project root. Create it if absent. +2. Detect which phase artifacts exist (`concept.md`, `users.md`, `requirements.md`, etc.). +3. Resume at the first missing or stale phase. +4. Run the appropriate interview, write the artifact, sign off with the user, advance. + +Phases that touch the design or interaction system delegate to the `ui-system` +skill. The mock phase delegates to `composer-mocks`. + +The skill is conversational — it asks one focused question at a time and waits +for the user. To skip ahead or jump back, use `/composer-status` or one of the +phase-specific commands (`/composer-mock`, `/composer-load`). diff --git a/composer/skills/composer-mocks/SKILL.md b/composer/skills/composer-mocks/SKILL.md new file mode 100644 index 0000000..4a16041 --- /dev/null +++ b/composer/skills/composer-mocks/SKILL.md @@ -0,0 +1,185 @@ +--- +name: composer-mocks +description: 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/-design-system/`, + including its `tokens.ts` and `components.md` sidecars. +4. The **interaction-design skill** exists at `.claude/skills/-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 `` 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: + +```tsx +import { color, spacing, fontSize, radius, motion } from + "../../.claude/skills/-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 ``: + +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. +4. Draft `docs/planning/mocks/.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. +5. Run the **text feasibility pass** (below). +6. 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. +- **⚠️ 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/.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: + +```tsx +/** + * Mock: + * Source: docs/planning/flows.md § + * Generated: + * Status: + * + * 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--.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. diff --git a/composer/skills/composer/SKILL.md b/composer/skills/composer/SKILL.md new file mode 100644 index 0000000..359b726 --- /dev/null +++ b/composer/skills/composer/SKILL.md @@ -0,0 +1,291 @@ +--- +name: composer +description: Discovery-phase orchestrator. State-aware skill that walks a user from "I want an app that…" to a tree of stories in their issue tracker, writing reviewable artifacts in docs/planning/ along the way. Use when the user runs /composer, /composer-status, /composer-review, or /composer-load — or asks to "start product discovery", "lay out a project", or "plan an app". For mock generation, the composer-mocks skill is invoked. For design/interaction system, ui-system is invoked. +--- + +# Composer — orchestrator + +You walk a user through product discovery, one phase at a time, producing +artifacts in `docs/planning/`. **Detect first, ask second.** Read what exists +before asking anything; resume at the first missing or stale phase. + +## Modes + +This skill has four modes, dispatched by which command invoked it: + +- **continue** (default, from `/composer`) — resume the interview at the next missing phase. +- **status** (from `/composer-status`) — read-only progress report. +- **review** (from `/composer-review`) — convene a council on an artifact. +- **load** (from `/composer-load`) — push stories to the project's tracker. + +## Phase order and artifacts + +| # | Phase | Artifact path | Skill | +|---|---|---|---| +| 1 | concept | `docs/planning/concept.md` | self | +| 2 | users | `docs/planning/users.md` | self | +| 3 | requirements | `docs/planning/requirements.md` | self | +| 3 | requirements (NFR) | `docs/planning/nfr.md` | self | +| 3 | requirements (IA) | `docs/planning/ia.md` | self | +| 4 | design-system | `.claude/skills/-design-system/SKILL.md`† | `ui-system` | +| 5 | interaction-design | `.claude/skills/-interaction-design/SKILL.md`†| `ui-system` | +| 6 | flows | `docs/planning/flows.md` | self | +| 7 | mocks | `docs/planning/mocks/` | `composer-mocks` | +| 8 | architecture | `docs/planning/architecture.md` + `adr/` | self | +| 9 | stories | `docs/planning/stories.md` | self | +| 10| roadmap | `docs/planning/roadmap.md` | self | +| 11| load | (project tracker) | self | + +†Phases 4 and 5 produce **project-local skills**, not docs in +`docs/planning/`. Skills auto-load via description matching whenever +UI work happens; a doc would not. Each phase also drops a pointer file +in `docs/planning/` (`design-system.md` and `interaction-design.md`) so +the planning index can find the skill location. Detect completion by +the SKILL.md file in the project skill directory, not by the pointer. + +A phase with multiple files (requirements) is "complete" only when all its +files exist. The slug is resolved from `package.json` `name`, then git +remote name, then directory name (kebab-case ASCII). + +## continue mode + +### Detect + +Scan `docs/planning/`. For each phase, decide: +- **missing** — artifact absent, this is where we resume. +- **present** — artifact exists. +- **stale** — artifact exists but an upstream phase was modified after it. + +The first **missing** phase is where to resume. If everything is present, ask +the user whether to advance past load (suggest `/symphony-init`) or revisit a +phase. + +### Phase 1 — Concept + +Goal: one-paragraph north star. + +``` +What are you building? One sentence is fine. +``` + +Probe minimally — surface, audience, platform — then draft `concept.md` from +the template. Show the draft, accept edits, write the file. Do not invent +goals the user didn't state. + +### Phase 2 — Users & workflows + +Goal: surface every actor that touches the system, including non-human ones. + +The interview pattern: + +1. Ask who the user thinks the user is. +2. Ask what they *do* — list verbs. +3. For each verb, ask who or what is on the other side. +4. Probe for: other humans, AI agents, integrations, scheduled jobs, the data + format itself, future-self, backups. + +Example move: if the user says "just me" but later mentions "I want Claude to +read these," surface that explicitly: + +> Then we have at least two users: you (primary), and the agent (read access, +> possibly write?). That changes the data model — agent-readable usually means +> structured-enough to query. Want to add the agent as a named user-class? + +Write `users.md` with: primary persona, anti-personas, named user-classes +(humans + non-humans), and a verb-keyed workflow list. **Never draft a +speculative second human persona.** Hidden actors are surfaced through +workflows, not invented. + +### Phase 3 — Requirements (3 files) + +Three artifacts, one phase. + +**`requirements.md`** — hard / soft / non-goals. + +Ask each in turn: +- Hard: "If the app doesn't do this, it isn't useful — what falls in that bucket?" +- Soft: "Would-be-nice items, deferable." +- Non-goals: "What will we explicitly say *no* to when it comes up?" + +Push back on ambiguous "and" lists. Every conjunction is usually two +requirements pretending to be one. + +**`nfr.md`** — non-functional requirements with thresholds. + +Ask about: performance budgets, scale targets, availability target, security +posture, accessibility level (WCAG AA is the floor), browser/device support, +offline behavior, data retention, observability needs. Each one needs a +**number or named threshold**, not a vibe. "Fast" is not an NFR; "p95 +interaction < 100ms on mid-tier mobile" is. + +**`ia.md`** — information architecture. + +Identify: top-level concepts (entities), how they relate, how they're +named, and how a user navigates between them. This is the taxonomy file — +it's what mocks and architecture both look up later. + +After writing all three, **auto-suggest a council review**: + +``` +Three artifacts written. Summon Lena (PM), Vera (skeptic), and Marge (end-user) +to review before we move on? [Y/n] +``` + +If content suggests it, also propose: +- **Femi (legal-triage)** — regulated data, jurisdictions, third parties, IP +- **Camila (privacy)** — PII, multi-user data, biometrics, minors +- **Ingrid (finance)** — money, billing, refunds, subscriptions + +### Phases 4–5 — Design & Interaction systems + +Delegate to the `ui-system` skill. That skill writes **project-local +skills** to `.claude/skills/-design-system/` and +`.claude/skills/-interaction-design/`, plus pointer stubs in +`docs/planning/`. The skills auto-load on UI work; the pointers exist +only for human discoverability of the planning index. + +`ui-system` is currently a *placeholder* — it captures the minimum needed +for mocks to proceed, with prominent `` markers. Composer +continues to phase 6 once both project skills exist; the user should +revisit `ui-system` to fully specify before mocks are committed. + +**After write, tell the user to verify**: + +``` +Two project skills now installed: + .claude/skills/-design-system/ + .claude/skills/-interaction-design/ + +These auto-load whenever UI work is happening in this repo. If you're +in this session, they should be available now (run /agents to confirm). +If you're starting a new session, they'll load on the first UI-related +prompt. +``` + +### Phase 6 — Flows + +Goal: name every primary user journey, step by step. + +Read `users.md`'s workflow list. Each top-level workflow becomes a named flow +in `flows.md`. For each flow, capture: actor, trigger, preconditions, the +step-by-step interaction, success state, failure modes. + +Don't over-design here — the goal is *naming and sequencing the journeys*, +not specifying every screen. Mocks come next. + +### Phase 7 — Mocks + +Delegate to the `composer-mocks` skill. It generates one mock per flow and +runs the text feasibility pass. + +### Phase 8 — Architecture + +Now the spec is complete. Read `concept.md`, `users.md`, `requirements.md`, +`nfr.md`, `ia.md`, `design-system.md`, `interaction-design.md`, `flows.md`, +and skim the mocks. Surface the constraints to the user: + +``` +Big constraints I'm pulling out: + • [from requirements] hard offline-first + • [from NFR] p95 interaction < 100ms on mid-tier mobile + • [from users] AI agent reads notes — structured data needed + • [from interaction-design] mobile-first, single locale (English) for v1 + ... + +That points at: . Convening a council to pressure-test: + Tomás (architect), Gerald (sr engineer), Priya (DBA), Aisha (DevOps). +``` + +Run the council. Their synthesis informs ADRs. Draft each ADR (one per major +decision) using `adr/0000-template.md`; user signs off; write to +`adr/NNNN-.md`. Compose a summary `architecture.md` referencing the ADRs. + +### Phase 9 — Stories + +Goal: a flat list ready to load into the tracker. + +For each flow, decompose into stories. Each story has: title, description, +acceptance criteria, dependencies (other stories), size estimate (S/M/L/XL), +and an epic/cluster tag. Don't over-decompose at this phase — granularity +shifts as the team starts working. + +Reference flows.md for the source-of-truth on what each story enables. + +### Phase 10 — Roadmap + +Cluster stories into epics and sequence them into milestones. The first +milestone is the **smallest version that's still useful** — push back on +including soft requirements, NFR niceties, or scope creep here. + +### Phase 11 — Load + +See *load mode* below. + +## status mode + +Read-only. Print: + +``` +docs/planning/ ✓ + concept.md ✓ + users.md ✓ + requirements.md ✓ + nfr.md ✓ (modified after flows.md — flows may be stale) + ia.md ✓ + design-system.md ⚠ placeholder (return to flesh out) + interaction-design.md ⚠ placeholder + flows.md ✓ + mocks/ ✓ (3 of 5 flows mocked) + architecture.md — + adr/ — + stories.md — + roadmap.md — + +Next: phase 8 — architecture. +Council reviews recorded: requirements (2026-04-29). +``` + +## review mode + +When invoked from `/composer-review`: + +1. Pick the artifact: argument-named, else current phase's primary artifact. +2. Pick the council: argument-named, else phase default (see CLAUDE.md table) + plus auto-additions when content suggests them. +3. Read the artifact + necessary upstream context. +4. Invoke the `council-of-experts:council` skill with a framed question. +5. Save the synthesis to `docs/planning/reviews/-.md`. +6. Output the full council response to the user (the council skill already + formats this — pass through unchanged). + +## load mode + +When invoked from `/composer-load`: + +1. Read `stories.md` and `roadmap.md`. +2. Read the project's `CLAUDE.md` for the tracker integration section. If + missing, exit with `tracker_integration_missing` and tell the user to + either run `/symphony-init` (which writes the section) or add it manually. +3. Build the planned write set: + - 1 milestone per first-cluster (the MVP slice) + - 1 epic/parent issue per cluster (if the tracker supports parents) + - 1 issue per story, linked to its epic, labeled per `stories.md` +4. Print the dry-run plan grouped by cluster. Show the exact tracker commands. +5. Wait for user confirmation. +6. Execute writes. On failure, stop and report — never auto-continue past an + error that might leave partial state. +7. Update `stories.md` with the created issue IDs (e.g. + `- [ ] PROJ-42 — Log a feeding for an active starter`). The file becomes + the local↔tracker map. +8. Suggest `/symphony-init` if the project doesn't have Symphony set up. + +## Hard rules + +- **One question at a time** during interviews. The user has the floor. +- **Never invent users, requirements, or features the user didn't state.** + Probe to extract; do not auto-complete. +- **Never push to the tracker without a dry run.** +- **Stale-aware.** When an upstream artifact changes, flag downstream + artifacts as `stale` in status; ask the user before silently regenerating. +- **Re-entrant.** Every phase can be re-entered. Re-running on an existing + artifact prompts the user before overwriting. diff --git a/composer/skills/ui-system/SKILL.md b/composer/skills/ui-system/SKILL.md new file mode 100644 index 0000000..d65bf42 --- /dev/null +++ b/composer/skills/ui-system/SKILL.md @@ -0,0 +1,137 @@ +--- +name: ui-system +description: Interview the user and produce two project-local skills — a design-system skill and an interaction-design skill — that auto-load whenever UI work is in progress. Output goes to .claude/skills/-design-system/ and .claude/skills/-interaction-design/, NOT docs/planning/. The skills load themselves into context when anyone codes UI (mock or real); a plain reference doc would not. Currently a placeholder skill that captures the minimum needed for downstream phases to proceed; planned for a fuller specification pass. Use when the composer skill reaches phase 4 or 5, or when the user asks to "set up the design system" or "specify interaction patterns." +--- + +# UI system (placeholder) + +> **Status: PLACEHOLDER.** This skill currently captures the minimum +> design-system and interaction-design content needed for the mocks +> phase to proceed. A fuller specification pass is planned. When the +> user returns to flesh this out, expand the interview sections below +> and the SKILL.md / sidecar templates. + +## Why this is a skill, not a doc + +A reference document at `docs/planning/design-system.md` gets read once +and then drifts out of context as the conversation grows. UI work that +happens later — generating a mock, writing a component, picking a color — +won't have it loaded. + +A **skill** with a description that triggers on UI work is loaded +automatically every time the trigger matches. That's the whole point of +the skill mechanism. The design system and interaction design must be +skills. + +## What this skill produces + +Two project-local skills, plus their sidecar data files: + +``` +.claude/skills/-design-system/ +├── SKILL.md ← the skill itself; auto-loads on UI work +├── tokens.ts ← machine-readable color / type / spacing / motion tokens +└── components.md ← component vocabulary with anatomy + +.claude/skills/-interaction-design/ +└── SKILL.md ← interaction patterns, state surfaces, input modes, i18n +``` + +And two stub pointer files in `docs/planning/` so the planning index +finds them: + +``` +docs/planning/design-system.md ← pointer; tells humans where the skill lives +docs/planning/interaction-design.md ← pointer +``` + +## Slug + +The skills need a project slug for their `name:` frontmatter, so they +don't collide with skills from other projects on the same machine. + +Resolution order: +1. If `package.json` has a `name`, slugify it. +2. Else if a git remote exists, slugify the repo name. +3. Else ask the user. Default to the directory name. + +Slug rule: lowercase, hyphenated, kebab-case, ASCII only. Example: +`SourdoughTracker` → `sourdough-tracker` → skill `sourdough-tracker-design-system`. + +## design-system interview (placeholder pass) + +Ask the user, in order, with sensible defaults: + +1. **Existing material?** Brand assets, mood boards, screenshots, + "make it look like Linear/Notion/Stripe", or nothing. If material + exists, ingest it before asking the rest. +2. **Color**: brand color(s), neutral scale (warm/cool/true), dark mode + (yes/no/system). Offer to generate accessible contrast pairs. +3. **Typography**: one family or two (display + body), size scale base + and ratio, line-height policy. +4. **Spacing**: scale base (4px / 8px), key spacing tokens. +5. **Radii**: tight / medium / pillowy. +6. **Shadows**: flat / subtle / generous. +7. **Visual motion**: default duration, default easing. +8. **Components**: confirm vocabulary against `ia.md`. + +Mark unanswered with `` so the return pass has a worklist. + +### Write phase — design-system + +1. Write `.claude/skills/-design-system/SKILL.md` from + `templates/design-system/SKILL.md`. Substitute the slug into the + `name:` field and the project name into the `description:`. +2. Write `.claude/skills/-design-system/tokens.ts` from + `templates/design-system/tokens.ts`. Fill in the values gathered in + the interview; `` for unanswered. +3. Write `.claude/skills/-design-system/components.md` from + `templates/design-system/components.md`. +4. Write `docs/planning/design-system.md` from the pointer template — + one paragraph saying where the skill lives. + +## interaction-design interview (placeholder pass) + +Ask, in order: + +1. **Primary input**: touch / mouse / keyboard / mixed. Primary, supported, not supported. +2. **State surfaces**: pick one pattern per action class. +3. **Motion**: minimal / restrained / expressive. `prefers-reduced-motion` always honored. +4. **Breakpoints**: count, primary design target. +5. **i18n**: locales planned, RTL, string-length budget. +6. **Empty/loading/error/offline**: one declared posture each. +7. **Time formatting**: relative threshold, absolute format. +8. **Keyboard**: global shortcuts, escape behavior. + +### Write phase — interaction-design + +1. Write `.claude/skills/-interaction-design/SKILL.md` from + `templates/interaction-design/SKILL.md`. +2. Write `docs/planning/interaction-design.md` pointer. + +## Re-entry + +When the user returns to flesh this out fully: +- Expand the interviews above. +- Expand the SKILL.md and sidecar templates. +- Both skills are version-controlled in `.claude/skills/` — re-running + this phase shows the user a diff before overwriting. + +The downstream contract is: `composer-mocks` reads the **skills**, not +the planning pointer files. That contract does not change as the +templates grow. + +## Hard rules even in placeholder mode + +- **Always produce both skills with sidecars.** Mocks can't proceed without them. +- **Always slug-namespace** so projects on the same machine don't collide. +- **Mark unknowns with ``** rather than inventing — TBDs are the return-pass worklist. +- **Don't pretend.** If the user has nothing and no opinions, say so in the SKILL.md: "No design direction set; defaults applied. Revisit before mocks are committed." +- **Tell the user what just happened.** After write, print: + ``` + Wrote two project skills: + .claude/skills/-design-system/SKILL.md + .claude/skills/-interaction-design/SKILL.md + These auto-load whenever UI work is happening. Verify after restart + with /agents (they should appear as project-local skills). + ``` diff --git a/composer/templates/adr/0000-template.md b/composer/templates/adr/0000-template.md new file mode 100644 index 0000000..ca1f348 --- /dev/null +++ b/composer/templates/adr/0000-template.md @@ -0,0 +1,50 @@ +# ADR-NNNN — + +- **Status**: proposed | accepted | superseded by ADR-MMMM | deprecated +- **Date**: YYYY-MM-DD +- **Deciders**: <names / handles> + +## Context + +<!-- +What's forcing this decision. Pull constraints from requirements.md, +nfr.md, ia.md, interaction-design.md. Two or three short paragraphs. +--> + +## Decision + +<!-- +One sentence. The thing we are doing. +--> + +We will … + +## Alternatives considered + +<!-- +Each one with one paragraph: what it was, why we didn't pick it. +--> + +### <Alternative A> + +<why we didn't pick this> + +### <Alternative B> + +<why we didn't pick this> + +## Consequences + +<!-- +What changes because of this decision. Positive AND negative. The +negative list is the more important one. +--> + +**Positive**: +- <…> + +**Negative / accepted costs**: +- <…> + +**Open follow-ups**: +- <thing this decision implies we now have to figure out later> diff --git a/composer/templates/architecture.md b/composer/templates/architecture.md new file mode 100644 index 0000000..211f809 --- /dev/null +++ b/composer/templates/architecture.md @@ -0,0 +1,42 @@ +# Architecture + +<!-- +A response to the spec, not a setting. Written AFTER concept, users, +requirements, NFR, IA, design system, interaction design, flows, and +mocks are in place. Major decisions get their own ADR; this file is the +summary + index. +--> + +## Constraints (extracted from upstream artifacts) + +- <constraint> — *from <source>.md* +- <constraint> — *from <source>.md* + +## Stack at a glance + +| Layer | Choice | ADR | +|---|---|---| +| Frontend | <…> | [ADR-NNNN](adr/NNNN-<slug>.md) | +| Backend | <…> | [ADR-NNNN](adr/NNNN-<slug>.md) | +| Data store | <…> | [ADR-NNNN](adr/NNNN-<slug>.md) | +| Hosting / runtime | <…> | [ADR-NNNN](adr/NNNN-<slug>.md) | +| Auth | <…> | [ADR-NNNN](adr/NNNN-<slug>.md) | +| Observability | <…> | [ADR-NNNN](adr/NNNN-<slug>.md) | + +## Key architectural decisions + +<!-- +One bullet per ADR with the heart of the decision. Full reasoning lives +in the ADR file. +--> + +- **<Decision title>** — <one-line summary> ([ADR-NNNN](adr/NNNN-<slug>.md)) + +## Open questions + +<!-- +Decisions deferred. Each should have a trigger condition that flips it +into a real ADR. +--> + +- <question> — *will decide when <trigger>* diff --git a/composer/templates/concept.md b/composer/templates/concept.md new file mode 100644 index 0000000..0805fd9 --- /dev/null +++ b/composer/templates/concept.md @@ -0,0 +1,16 @@ +# Concept + +<!-- +One-paragraph north star. The thing this app *is*, in plain language. +Not features. Not architecture. The shape of the thing and who it's for. +--> + +<TBD: one paragraph> + +## Platform + +<TBD: web / mobile / desktop / native iOS / native Android / CLI / library> + +## Audience (one line) + +<TBD: who, in one line — full personas live in users.md> diff --git a/composer/templates/design-system/SKILL.md b/composer/templates/design-system/SKILL.md new file mode 100644 index 0000000..ae6f39c --- /dev/null +++ b/composer/templates/design-system/SKILL.md @@ -0,0 +1,94 @@ +--- +name: <SLUG>-design-system +description: Design system for the <PROJECT NAME> project. Color tokens, typography, spacing, radii, shadows, motion durations, and component vocabulary. Load and apply whenever building UI for this project — generating mocks, writing components, picking colors, configuring Tailwind, styling native screens, building themes, designing CSS, or making any visual decision. The canonical visual reference for this project; if anything visible is being touched, this skill should be in context. Pairs with <SLUG>-interaction-design. +--- + +# <PROJECT NAME> design system + +> **Status: <draft | reviewed | locked>** +> Generated by Composer's `ui-system` phase. Re-running that phase +> updates this skill (with confirmation). + +## How to use this skill + +Whenever you generate or edit UI for this project — a mock, a real +component, a theme, a CSS file — read this SKILL.md and the sidecar +files first, then use the tokens. Do not hardcode values. Do not +introduce new components without proposing them here first. + +Sidecar files in this skill directory: +- `tokens.ts` — machine-readable token export. Import in mocks/code. +- `components.md` — component vocabulary with anatomy. + +## Visual posture + +<!-- One or two sentences describing the feel. "Quiet, dense, monochromatic with a single brand accent." Or "Playful, generous spacing, expressive type." --> + +<TBD: visual posture> + +## Color + +### Brand +- Primary: `<#hex>` — <name> +- (Secondary, if any): `<#hex>` — <name> + +### Neutrals +- Tone: <warm | cool | true> +- Scale: 50 / 100 / 200 / 300 / 400 / 500 / 600 / 700 / 800 / 900 / 950 + +### Semantic +| Role | Value | +|---|---| +| Success | `<#hex>` | +| Warning | `<#hex>` | +| Error | `<#hex>` | +| Info | `<#hex>` | + +### Dark mode +<TBD: yes / no / system-following + token mapping> + +## Typography + +- **Display family**: <name>, weights <list> +- **Body family**: <name>, weights <list> +- **Scale base**: <px>, ratio <1.125 | 1.2 | 1.25 | 1.333> +- **Sizes**: xs / sm / base / lg / xl / 2xl / 3xl / 4xl +- **Line-height**: tight for display, normal for body, relaxed for long-form prose + +See `tokens.ts` for exact px values. + +## Spacing + +- **Base unit**: <4px | 8px> +- **Scale (in base units)**: 0, 0.5, 1, 1.5, 2, 3, 4, 6, 8, 12, 16, 24 + +## Radii + +- `sm`, `md`, `lg`, `pill`, `full` — values in `tokens.ts`. + +## Shadows + +- `xs / sm / md / lg / xl` — values in `tokens.ts`. +- (Or: "flat — no shadows" if the posture is flat.) + +## Visual motion + +- **Default duration**: <ms> +- **Default easing**: <named curve or cubic-bezier> + +Behavioral motion (when things animate, what does and doesn't) lives +in the interaction-design skill. + +## Components + +See `components.md` in this directory for the full vocabulary and +anatomy. The TL;DR list: + +- Button (primary / secondary / ghost / destructive / link) +- Input (text / textarea / select / checkbox / radio / toggle) +- Card / Surface +- (project-specific components from `ia.md`) + +## TBD on return + +- <TBD: anything the placeholder pass couldn't answer> diff --git a/composer/templates/design-system/components.md b/composer/templates/design-system/components.md new file mode 100644 index 0000000..9011f89 --- /dev/null +++ b/composer/templates/design-system/components.md @@ -0,0 +1,52 @@ +# Component vocabulary + +The named components for <PROJECT NAME>. Match names from `ia.md` +where applicable. Do not introduce new components without proposing +them here first. + +This file is loaded automatically by the design-system skill — agents +generating UI should be aware of every component in this list and +prefer them to ad-hoc one-offs. + +## Primitives + +### Button +- **Variants**: primary | secondary | ghost | destructive | link +- **Sizes**: sm | md | lg +- **States**: default | hover | active | focus | disabled | loading +- **Anatomy**: optional leading icon · label · optional trailing icon +- **Motion**: <TBD> + +### Input +- **Variants**: text | textarea | select | checkbox | radio | toggle +- **Sizes**: sm | md | lg +- **States**: default | focus | error | disabled | readonly +- **Anatomy**: label · field · helper text · error message +- **Validation pattern**: <TBD — see interaction-design skill> + +### Card / Surface +- **Variants**: <flat | bordered | elevated — pick or list> +- **Anatomy**: <header? · body · footer?> + +## Project-specific components + +<!-- +Pulled from ia.md. One block each, with anatomy and any state-specific +notes that should always apply when this component is rendered. +--> + +### <Component name> + +- **Purpose**: <one line> +- **Anatomy**: <slots / regions> +- **States**: <list> +- **Notes**: <anything load-bearing> + +## Patterns to avoid + +<!-- +Things that come up often and should be vetoed. Saves the agent from +re-inventing them. +--> + +- <TBD: e.g., "no nested cards", "no inline icons in body text", etc.> diff --git a/composer/templates/design-system/tokens.ts b/composer/templates/design-system/tokens.ts new file mode 100644 index 0000000..e2d1fc9 --- /dev/null +++ b/composer/templates/design-system/tokens.ts @@ -0,0 +1,101 @@ +// Design tokens for <PROJECT NAME>. +// Generated by Composer's ui-system phase. +// Single source of truth for colors, type, spacing, radii, shadows, motion. +// Import this in mocks and (eventually) in real UI code; do not hardcode. + +export const color = { + brand: { + primary: "<TBD: #hex>", + // secondary: "<TBD>", + }, + neutral: { + 50: "<TBD>", + 100: "<TBD>", + 200: "<TBD>", + 300: "<TBD>", + 400: "<TBD>", + 500: "<TBD>", + 600: "<TBD>", + 700: "<TBD>", + 800: "<TBD>", + 900: "<TBD>", + 950: "<TBD>", + }, + semantic: { + success: "<TBD>", + warning: "<TBD>", + error: "<TBD>", + info: "<TBD>", + }, + // dark mode tokens (if applicable): + // dark: { ... } +} as const; + +export const fontFamily = { + display: "<TBD: name>, system-ui, sans-serif", + body: "<TBD: name>, system-ui, sans-serif", + mono: "ui-monospace, SFMono-Regular, monospace", +} as const; + +export const fontSize = { + xs: "12px", + sm: "14px", + base:"16px", + lg: "18px", + xl: "20px", + "2xl":"24px", + "3xl":"30px", + "4xl":"36px", +} as const; + +export const lineHeight = { + tight: 1.2, + normal: 1.5, + relaxed: 1.7, +} as const; + +// Spacing scale in base units. Multiply by base (4 or 8) for px. +export const spacingBase = 4; // <TBD: 4 or 8> +export const spacing = { + 0: 0, + 0.5: 0.5 * spacingBase, + 1: 1 * spacingBase, + 1.5: 1.5 * spacingBase, + 2: 2 * spacingBase, + 3: 3 * spacingBase, + 4: 4 * spacingBase, + 6: 6 * spacingBase, + 8: 8 * spacingBase, + 12: 12 * spacingBase, + 16: 16 * spacingBase, + 24: 24 * spacingBase, +} as const; + +export const radius = { + sm: "<TBD: px>", + md: "<TBD: px>", + lg: "<TBD: px>", + pill: "9999px", + full: "9999px", +} as const; + +export const shadow = { + xs: "<TBD>", + sm: "<TBD>", + md: "<TBD>", + lg: "<TBD>", + xl: "<TBD>", +} as const; + +export const motion = { + duration: { + fast: 150, + default: 250, + slow: 400, + }, + easing: { + standard: "cubic-bezier(0.2, 0, 0, 1)", + accel: "cubic-bezier(0.4, 0, 1, 1)", + decel: "cubic-bezier(0, 0, 0.2, 1)", + }, +} as const; diff --git a/composer/templates/flows.md b/composer/templates/flows.md new file mode 100644 index 0000000..3787a8d --- /dev/null +++ b/composer/templates/flows.md @@ -0,0 +1,25 @@ +# Flows + +<!-- +Named user journeys. One per workflow from users.md. The mocks skill +generates one mock per flow. Steps here are conceptual — every screen +is captured in the corresponding mock, not duplicated here. +--> + +## <flow-id> — <Short title> + +- **Actor**: <user-class from users.md> +- **Trigger**: <what kicks this off> +- **Preconditions**: <state that must be true> +- **Steps**: + 1. <action / screen> + 2. <…> + 3. <…> +- **Success**: <observable outcome> +- **Failure modes**: + - <named failure> → <how it's handled> + - <…> + +## <flow-id> — <Short title> + +… diff --git a/composer/templates/ia.md b/composer/templates/ia.md new file mode 100644 index 0000000..7415d61 --- /dev/null +++ b/composer/templates/ia.md @@ -0,0 +1,50 @@ +# Information architecture + +<!-- +The taxonomy file. Top-level concepts, how they relate, how they're +named. Mocks and architecture both look up here. +--> + +## Top-level concepts + +<!-- +The nouns of the app. One block each. +--> + +### <Concept name> + +- **What it is**: <one-line definition> +- **Identifying field(s)**: <what makes one of these unique> +- **Key attributes**: <list> +- **Relationships**: <to other concepts — "has many X", "belongs to Y", "describes Z"> +- **Lifecycle states**: <if it has lifecycle — draft / active / archived / etc.> + +## Relationships + +<!-- +A small relationship diagram in plain text or list form. The shape of +the data, before any database is chosen. +--> + +- <Concept A> 1—N <Concept B> +- <Concept B> N—N <Concept C> via <Concept Join> + +## Vocabulary rules + +<!-- +Words used in two senses on the same screen will hurt. Names every +concept with one canonical word and lists synonyms to avoid. +--> + +| Use | Don't use | Reason | +|---|---|---| +| <word> | <synonym> | <why we picked one> | + +## Navigation top-level + +<!-- +The skeleton of how a user moves through the app. Not screens — the +conceptual map. +--> + +- <section> → <subsection> → <subsection> diff --git a/composer/templates/interaction-design/SKILL.md b/composer/templates/interaction-design/SKILL.md new file mode 100644 index 0000000..f7a456e --- /dev/null +++ b/composer/templates/interaction-design/SKILL.md @@ -0,0 +1,112 @@ +--- +name: <SLUG>-interaction-design +description: Interaction design for the <PROJECT NAME> project. State surfaces (modal vs inline vs drawer vs full-page), motion philosophy, input modes (touch/mouse/keyboard), breakpoints, i18n posture, empty/loading/error/offline state postures, time formatting, and keyboard policy. Load and apply whenever building UI behavior — modals, forms, navigation, transitions, gestures, error handling, async states, focus management. Pairs with <SLUG>-design-system. +--- + +# <PROJECT NAME> interaction design + +> **Status: <draft | reviewed | locked>** +> Generated by Composer's `ui-system` phase. Re-running that phase +> updates this skill (with confirmation). + +## How to use this skill + +When building UI *behavior* — anything beyond static styling — read +this skill first. Don't invent new state-surface patterns, motion +durations, or empty-state postures. They're declared once here and +reused everywhere. + +For visual tokens (color, type, spacing), see the paired +`<SLUG>-design-system` skill. + +## Input modes + +| Mode | Status | +|---|---| +| Touch | <TBD: primary | supported | not supported> | +| Mouse | <TBD> | +| Keyboard | <TBD> | +| Voice | <TBD: usually "not supported" in v1> | + +## State surfaces + +One pattern per action class. Used everywhere. + +| Action class | Pattern | Notes | +|---|---|---| +| Quick edit (single field) | inline edit | <TBD> | +| Multi-field create / edit | <drawer | modal — pick one> | <TBD> | +| Confirm destructive | modal | always | +| Settings / configuration | full-page route | — | +| Top-level navigation | <sidebar | tab bar | header nav> | <TBD> | +| Detail-from-list | <full route | side panel> | <TBD> | + +## Motion + +- **Posture**: <minimal | restrained | expressive> +- **Default duration / easing**: see design-system tokens +- **Reduced motion**: respected via `prefers-reduced-motion` everywhere; fallbacks declared per pattern below +- **When things animate**: + - Page/route transitions: <yes/no, how> + - List item enter/exit: <yes/no, how> + - Modal/drawer open/close: <yes/no, how> + - State changes (toggle, expand): <yes/no, how> + +## Breakpoints + +| Breakpoint | Range | Primary? | +|---|---|---| +| Phone | < <px> | <TBD> | +| Tablet | <px> – <px> | <TBD> | +| Desktop | ≥ <px> | <TBD> | + +**Primary design target**: <which one — "mobile-first", "desktop-first", "fluid"> + +## i18n + +- **Locales at launch**: <list — often just English in v1> +- **RTL support**: <yes | no | planned> +- **String length budget**: assume +30% over English for German/French translations +- **Pluralization**: <TBD: ICU MessageFormat / library / manual> + +## State postures + +One declared posture per state, used everywhere. No inventing on a per-screen basis. + +### Empty +- **Visual**: <icon + heading + body + optional CTA> +- **Tone**: <encouraging | neutral | matter-of-fact> +- **CTA**: <when present, what kind of action> + +### Loading +- **Default pattern**: <skeleton | spinner | blocking> +- **When to use which**: <criteria — "skeleton for list/card containers, spinner for inline buttons, blocking only for explicit user-initiated actions"> +- **Threshold for showing loading at all**: <ms — usually 200–300ms; below that, just let it pop> + +### Error +- **Surface**: <inline | toast | dialog — by error class> +- **Recovery**: <retry button | clear path forward | "contact support" only as last resort> +- **Copy tone**: <plain language, name what happened, name what to do next> + +### Offline +- **Behavior**: <feature subset that works | banner only | "go online to continue"> +- **Sync semantics**: <when reconnected, what happens> + +## Time formatting + +- **Relative time** for events within: <threshold — e.g., < 7 days> +- **Absolute time** otherwise, format: <pattern — e.g., "MMM d, yyyy h:mm a"> +- **Time zones**: <user-local | fixed (which?) | configurable> +- **Date-only vs date+time**: <when each is shown> + +## Keyboard + +- **Global shortcuts**: <list, or "none in v1"> +- **Within-modal**: `Esc` closes; focus trap while open; restore focus on close +- **Tab order**: declared per-flow as needed; focus visible always (per design-system) +- **Forms**: `Enter` submits; `Esc` cancels destructive +- **Lists**: <arrow-key nav? | not in v1> + +## TBD on return + +- <TBD: anything the placeholder pass couldn't answer> diff --git a/composer/templates/nfr.md b/composer/templates/nfr.md new file mode 100644 index 0000000..00f5e8d --- /dev/null +++ b/composer/templates/nfr.md @@ -0,0 +1,49 @@ +# Non-functional requirements + +<!-- +Every entry needs a NUMBER or NAMED THRESHOLD. "Fast" is not an NFR; +"p95 interaction < 100ms on mid-tier mobile" is. +--> + +## Performance + +- <metric>: <threshold> at <load> +- <metric>: <threshold> at <load> + +## Scale + +- Users: <expected at launch> → <year-1 target> +- Data: <volume> at <year-1 target> +- Throughput: <req/s, events/s, etc.> + +## Availability + +- Target uptime: <%> +- RTO / RPO: <values, if applicable> + +## Security + +- Authentication: <method> +- Authorization model: <roles / capabilities / none> +- Sensitive data: <classifications> +- Compliance frameworks in scope: <SOC2 / GDPR / HIPAA / none / TBD> + +## Accessibility + +- Standard: WCAG 2.2 AA (floor — see interaction-design.md for specifics) + +## Browser / device support + +- <list> + +## Offline behavior + +- <does the app function offline? what does it do when it can't reach the network?> + +## Data retention & deletion + +- <policy: how long, who can delete, what's the cascade> + +## Observability + +- <what we log / measure / alert on, at the requirement level> diff --git a/composer/templates/planning-pointers/design-system.md b/composer/templates/planning-pointers/design-system.md new file mode 100644 index 0000000..1fdfe47 --- /dev/null +++ b/composer/templates/planning-pointers/design-system.md @@ -0,0 +1,24 @@ +# Design system + +The design system for this project is implemented as a project skill so +it loads automatically into context whenever UI work is in progress — +not just when someone remembers to read a file. + +**Skill location**: `.claude/skills/<SLUG>-design-system/` + +``` +.claude/skills/<SLUG>-design-system/ +├── SKILL.md ← canonical visual reference +├── tokens.ts ← machine-readable tokens for mocks and code +└── components.md ← component vocabulary and anatomy +``` + +To revise: re-run `/composer` (it'll detect the design phase and ask +whether to update), or edit the files directly. They're version-controlled. + +To verify the skill is loading: open a session in this repo, run +`/agents`, and confirm `<SLUG>-design-system` appears as a project-local +skill. + +The paired interaction-design skill lives at +`.claude/skills/<SLUG>-interaction-design/`. diff --git a/composer/templates/planning-pointers/interaction-design.md b/composer/templates/planning-pointers/interaction-design.md new file mode 100644 index 0000000..91d9862 --- /dev/null +++ b/composer/templates/planning-pointers/interaction-design.md @@ -0,0 +1,18 @@ +# Interaction design + +The interaction-design system for this project is implemented as a +project skill so it loads automatically into context whenever UI behavior +is being built (modals, forms, transitions, error states, focus, etc.). + +**Skill location**: `.claude/skills/<SLUG>-interaction-design/` + +``` +.claude/skills/<SLUG>-interaction-design/ +└── SKILL.md ← state surfaces, motion, input modes, i18n, state postures +``` + +To revise: re-run `/composer`, or edit the SKILL.md directly. It's +version-controlled. + +The paired design-system skill lives at +`.claude/skills/<SLUG>-design-system/`. diff --git a/composer/templates/requirements.md b/composer/templates/requirements.md new file mode 100644 index 0000000..cf25a8a --- /dev/null +++ b/composer/templates/requirements.md @@ -0,0 +1,34 @@ +# Requirements + +<!-- +Hard / soft / non-goals. Functional requirements only — non-functional +thresholds live in nfr.md. Push back on "and" lists; every conjunction +is usually two requirements pretending to be one. +--> + +## Hard + +<!-- +If the app doesn't do this, it isn't useful. +--> + +- <one requirement per bullet, no "and"> + +## Soft + +<!-- +Would be nice. Deferable. Cut first when scope tightens. +--> + +- <one per bullet> + +## Non-goals + +<!-- +Explicit "we will say no when this comes up." This list is as +load-bearing as the hard list — it's how you cut scope without +re-litigating. +--> + +- <thing we are not building> +- <another> diff --git a/composer/templates/roadmap.md b/composer/templates/roadmap.md new file mode 100644 index 0000000..1dc5516 --- /dev/null +++ b/composer/templates/roadmap.md @@ -0,0 +1,33 @@ +# Roadmap + +<!-- +Clusters sequenced into milestones. The first milestone is the smallest +version that's still useful. Push back on bundling soft requirements +into M1 — they belong in later milestones. +--> + +## M1 — <name> + +**Goal**: <one-line. Smallest version that's useful.> + +**Stories**: +- <story-id> — <title> +- <story-id> — <title> + +**Out of scope for M1**: +- <thing that's tempting to include but isn't required for "useful"> + +## M2 — <name> + +**Goal**: <…> + +**Stories**: +- <…> + +## Backlog + +<!-- +Stories not yet sequenced. Don't promise these to anyone. +--> + +- <story-id> — <title> diff --git a/composer/templates/stories.md b/composer/templates/stories.md new file mode 100644 index 0000000..8f4bb0e --- /dev/null +++ b/composer/templates/stories.md @@ -0,0 +1,31 @@ +# Stories + +<!-- +Flat list ready to load into the tracker. Don't over-decompose at +this phase — granularity shifts as the team starts working. Each +story has acceptance criteria; the tracker is the source of truth +once loaded, and this file becomes the local↔tracker map. +--> + +## <Cluster name> + +### <story-id> — <Title> + +- **As a** <user-class> +- **I want** <behavior> +- **So that** <outcome> +- **Acceptance criteria**: + - <observable criterion> + - <observable criterion> +- **Size**: <S / M / L / XL> +- **Depends on**: <other story-ids, if any> +- **Mock**: <mocks/<flow>.tsx if relevant> +- **Tracker ID**: _(filled in by /composer-load)_ + +### <story-id> — <Title> + +… + +## <Cluster name> + +… diff --git a/composer/templates/users.md b/composer/templates/users.md new file mode 100644 index 0000000..f52a7e6 --- /dev/null +++ b/composer/templates/users.md @@ -0,0 +1,55 @@ +# Users & workflows + +<!-- +Every actor that touches the system. Humans AND non-humans: + - other humans (collaborators, viewers, admins) + - AI agents + - integrations / webhooks + - scheduled jobs + - the data / export format itself + - future-self + - backups +Workflows extracted by asking "what do you do?" and then "who or what +is on the other side of each verb?" +--> + +## Primary user + +**<Name or role>** +- **Context**: <what they're doing when they reach for this app> +- **Job to be done**: <what success looks like for them> +- **Frequency**: <daily / weekly / occasional> + +## Other user-classes + +<!-- +List every other actor surfaced by the workflow probe. One block each. +Non-human classes (agents, integrations, format) get the same treatment +as humans. +--> + +### <user-class name> +- **Type**: <human / agent / integration / system / format> +- **Reads**: <what they read> +- **Writes**: <what they write, if anything> +- **Notes**: <anything special about their access pattern or constraints> + +## Anti-personas + +<!-- +Who this app is NOT for. Naming these saves stories later, because +"can't we also support X?" gets a clean answer. +--> + +- <type of user/use case explicitly excluded> +- <another> + +## Workflows + +<!-- +Verb-keyed list. Each workflow is short. Detailed step-by-step lives +in flows.md. +--> + +- **<verb>** — <one-line description, who's on each side> +- **<verb>** — …