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>
This commit is contained in:
movq
2026-04-29 21:03:40 -05:00
parent cd3032458c
commit 594fccc80a
25 changed files with 1595 additions and 0 deletions

90
composer/CLAUDE.md Normal file
View File

@@ -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/<slug>-design-system/` (project skill) | `ui-system` (placeholder) |
| 5 | Interaction design | `.claude/skills/<slug>-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/<slug>-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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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/<artifact>-<date>.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.

View File

@@ -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.

View File

@@ -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`).

View File

@@ -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/<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:
```tsx
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.
4. 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.
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/<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:
```tsx
/**
* 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` § <flow> 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.

View File

@@ -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/<slug>-design-system/SKILL.md`† | `ui-system` |
| 5 | interaction-design | `.claude/skills/<slug>-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 45 — Design & Interaction systems
Delegate to the `ui-system` skill. That skill writes **project-local
skills** to `.claude/skills/<slug>-design-system/` and
`.claude/skills/<slug>-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 `<TBD: ...>` 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/<slug>-design-system/
.claude/skills/<slug>-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: <stack hypothesis>. 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-<slug>.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/<artifact>-<YYYY-MM-DD>.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.

View File

@@ -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/<slug>-design-system/ and .claude/skills/<slug>-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/<slug>-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/<slug>-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 `<TBD: ...>` so the return pass has a worklist.
### Write phase — design-system
1. Write `.claude/skills/<slug>-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/<slug>-design-system/tokens.ts` from
`templates/design-system/tokens.ts`. Fill in the values gathered in
the interview; `<TBD>` for unanswered.
3. Write `.claude/skills/<slug>-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/<slug>-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 `<TBD: ...>`** 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/<slug>-design-system/SKILL.md
.claude/skills/<slug>-interaction-design/SKILL.md
These auto-load whenever UI work is happening. Verify after restart
with /agents (they should appear as project-local skills).
```

View File

@@ -0,0 +1,50 @@
# ADR-NNNN — <Title>
- **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>

View File

@@ -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>*

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.>

View File

@@ -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;

View File

@@ -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>

50
composer/templates/ia.md Normal file
View File

@@ -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>

View File

@@ -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 200300ms; 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>

49
composer/templates/nfr.md Normal file
View File

@@ -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>

View File

@@ -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/`.

View File

@@ -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/`.

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>** — …