Skip to main content

Contributing

How to add a design-system component — from ADR to the quality gates.

The seven steps

Adding a component touches seven artifacts. The order matters: the ADR unblocks everything downstream, and the catalog is the source of truth for the docs site.

  1. ADR first. Modifying the barrel (src/index.ts) or patterns.ts — or adding any new DS component — requires an Architecture Decision Record per the repo escalation rules (see AGENTS.md). The ADR names the component, its layer, and its public API.
  2. Source. Create packages/design-system/src/components/<category>/<Name>/<Name>.tsx (+ .test.tsx beside it). TypeScript strict, no any, tokens only — no raw hex or ad-hoc Tailwind values.
  3. Barrel export. Export the component from src/index.ts. This is the only legal import surface — and remember the barrel itself is ADR-gated.
  4. patterns.ts entry. Add a full PatternMeta entry to src/patterns.ts (slug, name, category, path, description, status, props, interface, assertions, ariaRole, aiHints, examples, antiPatterns, tokens). The entry shape is documented below — the docs pages render from this catalog.
  5. Regenerate the .ai index. Run the TWO-STEP pipeline: pnpm exec tsx scripts/build-agent-index.ts && pnpm exec tsx scripts/sync-index-from-patterns.ts. One script alone leaves the index stale.
  6. Docs + stories + test. Add docs/components/<slug>.mdx (props table matching the source interface), a story if the component is visual, and a unit test beside the source. The docs-consistency gate (pnpm ds:consistency) fails on divergence between these representations.
  7. Run the gates. pnpm check:all must be green before the branch can be reviewed (add --build for the build gates). Conventional commits, one concern per branch, qa-dev review before merge into experimental.

The patterns.ts entry shape

Every field below is required for implemented components (tokens optional when the component reads no DS tokens):

{
  slug: "mywidget",                       // kebab-case, unique, = docs route
  name: "MyWidget",                       // PascalCase, = export name
  category: "atoms" | "molecules" | "organisms" | "templates",
  path: "patterns/<category>/<slug>.html",
  description: "One-line summary shown as the page header.",
  status: "implemented",                  // or "planned" | "deprecated"
  props: [ { name, type, required, default, description } ],
  interface: "interface MyWidgetProps { ... }",  // stringified TS
  assertions: [ { type: "aria" | "type", rule, reference } ],
  ariaRole: "img" | null,
  aiHints: "When an agent should reach for this component.",
  examples: [ "<MyWidget />" ],
  antiPatterns: [ "..." ],
  tokens: [ "ep-mywidget-fg" ],           // DS tokens read/defined
}

Barrel modification rules

The barrel (packages/design-system/src/index.ts) and patterns.ts are the public API of the design system. Changing either — adding, renaming, or removing exports — requires an ADR and a version bump. Deep imports are lint-banned; consumers must import from the package root only.

Corollary: never re-export a storefront component from the DS barrel, and never move an export without a deprecation window.

Index regeneration

The agent index (.ai/INDEX.json) is generated — never hand-edit it. After any patterns.ts change, run both scripts in order:

pnpm exec tsx scripts/build-agent-index.ts
pnpm exec tsx scripts/sync-index-from-patterns.ts

build-agent-index.ts rebuilds component metadata and relationship graphs; sync-index-from-patterns.ts reconciles it with patterns.ts. Skipping the second step causes stale-lease and parity errors in the DS gates.

Quality gates

The commands below must pass before review:

pnpm check:all        # 21 static gates (imports, stylelint, R-metrics, drift)
pnpm check:all --build   # + tsc / medusa / next build gates
pnpm ds:consistency      # 3-layer docs consistency gate

Exit 1 from any gate means the branch is not pushable. pnpm check:all

Contributing — ePassLive Design System