This is the canonical document for contributing components to the design system. CONTRIBUTING.en.md explains the general setup; this file defines the component workflow and checkpoints every contributor must follow, with or without AI.
Project task → Research → Spec proposal skill → Validated issue spec → wait for `status:approved` → START WORK → Spec review → Visual preflight → Plan → Implementation → Visual review → Pre-PR component review → PR → Review → Merge → END WORK
Core rule: AI executes, the contributor decides. The spec, visual criteria, and checkpoint approvals remain human responsibility. After the validated spec is written in the task, implementation stays blocked until the linked issue has the status:approved label.
| Topic | Source |
|---|---|
| Repo setup | CONTRIBUTING.en.md |
| Architecture and code rules | GUIDELINES.en.md |
| Tokens and visual language | DESIGN.en.md, src/styles/theme.css |
| Component visual states | COMPONENTS.en.md |
| Spec intake and validation | .atl/skills/component-spec-proposer/SKILL.md |
| Detailed AI workflow | .atl/skills/component-contributor/SKILL.md |
| Pre-PR audit | .atl/skills/components-auditor/SKILL.md |
If these sources disagree, the authority order is: GUIDELINES*.md / DESIGN*.md for code and visual rules, .atl/skills/* for agent-assisted execution, and this document for the human workflow.
- Pick a task in the GitHub Projects Board.
- Verify that it has an issue attached. The issue is the implementation contract.
- Do not run START WORK yet if the spec is not defined and approved. The contributor may research and propose the spec, but must not start implementation.
- If the user requested offline/no-network work, do not mutate GitHub: record the required follow-up. Do not start implementation until verifying that the issue has the
status:approvedlabel.
Before asking for implementation, research the component.
Minimum checklist:
- References: Radix UI primitives, MDN, or WAI-ARIA APG as applicable.
- Atomic tier:
atom,molecule, ororganism. - Props: name, type, default, required/optional.
- CVA variants: keys and values.
- States: base, hover, focus, active/pressed, disabled, loading, error, empty when relevant.
- Accessibility: roles,
aria-*, keyboard, focus management, touch target. - Design: surface, color, spacing, radius, shadow/glow, transitions, dark mode.
Do not do partial research. If the issue is incomplete, the component will be incomplete.
Before implementing, use the component-spec-proposer skill to turn the task and its reference into a validated spec.
When to use it:
- The issue references a Radix UI primitive, MDN, APG, or similar.
- The task is still vague or has open decisions.
- You need to prepare the issue before implementation.
Suggested prompt:
Prepare the spec for this component using component-spec-proposer.
Issue: {issue_url}
Reference: {reference_url}
Do not implement yet. First propose the spec, list assumptions to validate, and wait for my approval before writing back to GitHub.
The skill must:
- Read the issue and the reference.
- Propose a spec using the
component-spec-proposertemplate. - List assumptions to validate.
- Wait for human approval.
- Only after approval, write
## Validated component specin the issue. - Leave the task waiting for approval: do not move it to
In progressfromcomponent-spec-proposer. - Indicate the next step: wait for the
status:approvedissue label before startingcomponent-contributor.
Do not use component-contributor to implement until the spec is validated and the issue has the status:approved label.
The validated spec must live in the issue as a verifiable contract.
| Field | What it must say |
|---|---|
| Component name | PascalCase |
| Atomic tier | atom / molecule / organism |
| Props | Name, TypeScript type, default, required/optional |
| CVA variants | Variant keys and possible values |
| States | Visual and behavioral description per state |
| Accessibility | Roles, attributes, keyboard, focus, reduced motion when applicable |
| Reference URL | Radix UI primitives, MDN, APG, etc. |
| Design notes | System-specific visual decisions |
| Story requirements | Default, Disabled, key variants, edge cases |
Golden rule: if it is not in the issue, the agent should not invent it.
After documenting the spec, the contributor must wait for explicit maintainer/project lead approval. The operational signal is the exact GitHub label status:approved on the linked issue; it is not a free-text comment and it does not replace the Project Status field, which still uses Todo, In progress, and Done.
Rules:
- Do not create the implementation branch, plan, or code before
status:approved. - Do not move the Project item to
In progressfrom the spec proposal phase. - When the
status:approvedlabel is present on the issue, run START WORK: assign the issue, move the Project item toIn progress, confirm Team/Category, and record branch/worktree. - If the
status:approvedlabel is missing, stop and request approval; do not replace it with implicit chat approval.
If the task comes from an issue, use issue-derived naming:
branch: {type}/{issue-number}-{slug}
worktree: ../design-system-{type}-{issue-number}-{slug}
Examples:
feat/123-button
fix/128-modal-focus-trap
../design-system-feat-123-button
Prefer sibling worktrees next to the repo. Avoid /tmp unless it is explicitly requested.
git checkout main
git pull --ff-only origin main
git checkout -b feat/123-button
pnpm install
pnpm run storybookIf you use a worktree:
git worktree add -b feat/123-button ../design-system-feat-123-button HEADUse one branch per work unit: feat/, fix/, docs/, refactor/, chore/.
In opencode/gentle-ai, share the issue URL:
Suggested prompt:
Implement this component using component-contributor.
Issue: {issue_url}
Use the `## Validated component spec` section as the contract. Before reading the spec in detail, planning, or writing code, verify that the issue has the `status:approved` label; if it is missing, stop. Run START WORK before implementation intake. Do not invent props or behavior outside the spec. Pause at spec review, visual preflight, and plan checkpoints before writing code.
The agent must load component-contributor, check the status:approved label, run START WORK, and only then consume the validated spec from component-spec-proposer. If it skips a phase, stop it.
Before this phase, the agent must already have verified the status:approved label and completed START WORK. It then reads the ## Validated component spec section in the issue and extracts the component, tier, props, variants, states, accessibility, reference, and design notes.
Expected output:
- spec summary;
- evidence of the
status:approvedlabel and START WORK; - questions if anything is ambiguous;
- reference/token modules it plans to load.
Human checkpoint: do not continue if the agent invents props, states, or behavior that are not in the validated spec. If a new decision appears, go back to spec proposal or update the issue before implementation.
Suggested prompt if inconsistencies appear:
Stop implementation. I found a decision that is not in `## Validated component spec`:
- {decision_or_gap}
Go back to spec mode: propose how to update the spec, list assumptions, and wait for my approval before continuing.
Before planning, the agent critiques the spec.
It must report:
- accessibility gaps;
- missing stories;
- ambiguous variants or props;
- architecture risks;
- proposed improvements.
Human checkpoint: accept the spec, adjust it, or request changes. This is the last cheap moment to fix scope.
Suggested prompt:
Critically review the validated spec before planning.
Look for accessibility gaps, missing stories, ambiguous variants, architecture risks, and concrete improvements. Do not write code. Return: gaps, risks, improvements, and whether it is ready to proceed.
Before the plan, the agent loads and applies:
docs/DESIGN.en.md;docs/COMPONENTS.en.mdwhen relevant;src/styles/theme.css;- relevant token/reference modules.
It must define:
- surface pattern;
- text, background, border, radius, spacing, glow/focus tokens;
- visual states;
- dark mode;
- allowed transitions;
- touch target and reduced motion.
Human checkpoint: confirm that the component is visually aligned before code is written.
Suggested prompt:
Run the visual preflight before the plan.
Load `docs/DESIGN.en.md`, `docs/COMPONENTS.en.md` when relevant, and `src/styles/theme.css`. Define surface, tokens, visual states, focus, disabled, dark mode, transitions, and reduced motion. Do not write code yet.
The agent presents a plan before touching files.
It must include:
- directory and tier;
- the 6 files to create/modify;
- CVA variants;
- hook logic;
- planned stories;
- planned tests;
- visual decisions;
- accessibility.
Required architecture:
types.ts → useComponentName.ts → ComponentName.tsx → ComponentName.test.tsx → ComponentName.stories.tsx → index.ts
Human checkpoint: approve the plan or request changes. No implementation without approval.
Suggested prompt:
Present the implementation plan for {component_name} before writing code.
Include tier, directory, 6 files, CVA variants, hook logic, stories, tests, visual decisions, and accessibility. Wait for my approval before implementing.
The agent implements the 6-file pattern and explains each decision after finishing each file.
| File | Responsibility |
|---|---|
types.ts |
Props, public types, CVA variants, JSDoc controls |
useComponentName.ts |
All logic, handlers, state, refs, computed className |
ComponentName.tsx |
Presentational JSX only, consumes the hook |
ComponentName.test.tsx |
Hook tests and component behavior tests |
ComponentName.stories.tsx |
Storybook docs, args, variants, states; JSDoc above const meta and every story export |
index.ts |
Named component export plus type exports |
Hard rules:
type, neverinterface.- No
any. - No CVA outside
types.ts. - No logic in the presentational
.tsx. - No hardcoded values when a token exists.
- No
playfunctions: interactions are tested in.test.tsx. index.tsuses named component exports plus type exports.
Suggested prompt:
Implement the component according to the approved plan.
Create files in this order: `types.ts`, `use{ComponentName}.ts`, `{ComponentName}.tsx`, `{ComponentName}.test.tsx`, `{ComponentName}.stories.tsx`, `index.ts`.
After each file, explain the important decisions and stop if a blocker appears or a decision is not covered by the spec.
With the files complete, the agent performs a visual review before declaring the work done.
It must verify:
- base, hover, focus, active/pressed, disabled;
- focus-visible with
box-shadow, never nakedoutline; - minimum
44×44pxtouch target on default variants; explicitly approved compact/dense variants may be smaller if they keep keyboard accessibility and focus; - contrast in light/dark;
- explicit transitions, never
transition-all; - no layout-property animation;
- reduced motion if transforms or animations exist.
CRITICAL and MAJOR findings block progress. Fix them before continuing.
Suggested prompt:
Run the visual review for {component_name}.
Review base, hover, focus, active, disabled, glow/shadow, transitions, contrast, touch target, and reduced motion. Classify findings as CRITICAL, MAJOR, MINOR, or SUGGESTION, and fix CRITICAL/MAJOR before continuing.
Before opening a PR, run an explicit audit with components-auditor.
It must review:
- 6-file architecture;
- file responsibilities;
- strict TypeScript;
- CVA in
types.ts; - tokens and theme;
- stories and docs header;
- tests;
- accessibility;
- visual states.
Expected format:
## Pre-PR Component Review — ComponentName
**Verdict**: PASS / PASS WITH WARNINGS / BLOCKED
### Blocking issues
- None
### Warnings
- None
### Evidence
- `npm test -- --run src/components/.../ComponentName.test.tsx`: passed
- `npm run build`: passed
- Storybook/manual visual check: passed or documentedDo not open a PR with CRITICAL or MAJOR issues.
Suggested prompt:
Audit this component using components-auditor before opening a PR.
Component: {component_name}
Path: src/components/{tier}/{kebab_name}/
Review architecture, file responsibilities, CVA, TypeScript, stories, tests, tokens, visual states, and accessibility. Return PASS / PASS WITH WARNINGS / BLOCKED with evidence.
The PR must link the issue and contain evidence.
Minimum checklist:
-
Closes #NNNin the description. - PR title in Conventional Commit format:
<type>(<optional scope>): <description>. - Commits in valid Conventional Commit format for
commitlint. - Relevant tests pass.
- Build or required checks pass.
- Pre-PR component review included or summarized.
- Storybook docs have a JSDoc block above
const metaand above every story export. -
## Descriptionis present. -
## Dependenciesonly when applicable. -
## Usage Guideonly when applicable. - Before commit/review you ran MCP cleanup:
rm -rf .playwright-mcp page-*.png page-*.jpeg *.md.playwright-output.
Suggested prompt:
Prepare the PR for {component_name}.
Link `Closes #{issue_number}`. Include a summary, change table, test/build evidence, the pre-PR component review result, and visual notes when applicable. Do not open the PR if the review is BLOCKED.
Close the GitHub Project task only when there is real closure evidence:
- verified merged PR; or
- explicit maintainer/user approval to close without a PR.
Minimum checklist:
- validation evidence commented on the issue;
- merged PR or explicit approval recorded;
- Project status moved to
Done; - follow-ups documented if anything remains.
If you are offline/no-network, do not try to mutate GitHub: leave END WORK as a follow-up item.
The JSDoc block above const meta must use this structure:
## Description
What the component does and when to use it.
## Dependencies
Only when it uses other design-system components or external primitives.
## Usage Guide
Only when composition or usage has non-obvious constraints.All content inside the JSDoc block must be in English, including headings, prose, and lists.
If the agent proposes any of the following, reject it:
- modifying
src/styles/theme.csswithout explicit approval; - adding dependencies without discussion;
- using a single-file architecture;
- omitting
.test.tsxtests; - putting interactions in
playfunctions instead of tests; - writing stories without args, controls, a JSDoc block above
const meta, or JSDoc above every story export; - using
description.componentinparameters.docs; - using
interfaceorany; - hardcoding colors, spacing, or fonts;
- opening a PR without the pre-PR review;
- leaving MCP artifacts before commit/review.
| Resource | URL |
|---|---|
| GitHub Projects Board | Stack-and-Flow Projects |
| Production Storybook | sf-design-system.netlify.app |
| Guidelines | docs/GUIDELINES.en.md |
| Design | docs/DESIGN.en.md |
| Components | docs/COMPONENTS.en.md |
| Quick Start | docs/QUICK_START.en.md |
| Governance | docs/GOVERNANCE.en.md |
| WAI-ARIA APG | w3.org/WAI/ARIA/apg |