| name | contributing |
| description | Component workflow for keystoneui — triggered when adding, creating, scaffolding, or modifying components, demos, stories, MDX docs, or any AI-agent surface (SKILL.md, AGENTS.md, llms.txt, MCP registry). |
| globs | null |
| alwaysApply | false |
Component Contributing Workflow
See CONTRIBUTING.md for the full guide.
Adding a New Component
Always start with the scaffolding command:
pnpm add:component MyComponent
This creates all files and updates all registries. Then follow the Storybook-first workflow:
- Implement the component in
packages/ui/src/{name}.tsx
- Write Storybook stories in
apps/storybook/stories/{name}.stories.tsx (primary dev surface)
- Create Fumadocs demos in
apps/docs/demos/{name}/ (3-6 simplified demos from stories)
- Register demos in
apps/docs/demos/index.ts
- Write MDX docs in
apps/docs/content/docs/components/{name}.mdx using <ComponentPreview name="{name}-{example}" />. For compound components (≥2 exported parts that nest), include a ## Composition ASCII tree after ## Usage — see Composition tree below.
- LLMs.txt updates automatically (no manual step)
- Sync the AI agent surface — see Sync the AI Agent Surface below
Adding a New Block
Blocks are full-page compositions, hand-registered (no pnpm add:block scaffolder yet). Workflow:
- Author the source under
apps/docs/demos/blocks/<name>.tsx (single-file) or apps/docs/demos/blocks/<name>/ (multi-file with index.tsx re-export).
- Register the demo in
apps/docs/demos/index.ts as "block-<name>": { component: ..., file: "blocks/<name>.tsx" }. The block-<name> key is what <BlockPreview name="block-<name>"> resolves against.
- Add the registry entry by hand-editing
registry.json. The block item must include:
name, type: "registry:block", title, description
dependencies (npm packages) and registryDependencies (other registry items)
files[] with per-file types: registry:page (with target: "app/<slug>/page.tsx") for the page entry; registry:component for everything else
categories: [...] — see the taxonomy below. pnpm sync:registry warns if missing.
- Write the MDX at
apps/docs/content/docs/blocks/<name>.mdx. Required structure: install bash fence, <BlockPreview name="block-<name>">, ## Components Used with links to /docs/components/<primitive>. The lint at pnpm lint:docs blocks merge if any of these are missing or malformed. See apps/docs/content/docs/blocks/_block-template.mdx.
- Regenerate backlinks with
pnpm docs:backlinks — this auto-injects ## Related Blocks into every component MDX referenced under ## Components Used (idempotent, fenced).
- Rebuild the registry with
pnpm registry:build.
Block category taxonomy
Every block must carry at least one category. Current values in use:
| Category | Used by | Mirrors shadcn? |
|---|
authentication | sign-in + sign-up blocks | ✅ |
login | signin-0X (alongside authentication) | ✅ |
signup | signup-0X (alongside authentication) | ✅ |
navigation | profile-dropdown-01 | new |
data | tickets-01 | new |
betting | betting-panel-0X | new |
When adding a new category, prefer single-word lowercase strings that mirror shadcn naming where any overlap exists (/Users/vladsuciu/dev/ui/apps/v4/registry.json is the reference). Document the new category in this table and in AGENTS.md → "Block Authoring".
Updating an Existing Component
API change (new/renamed prop, new sub-component)
- Update component source
- Update Storybook stories
- Update Fumadocs demos if user-facing
- Update MDX API Reference table
- If a sub-component was added/removed/renamed: update the
## Composition ASCII tree in the MDX
- Update
_registry.ts if dependencies changed
- Sync the AI agent surface (below) — if the change affects rules, conventions, or the public API the skill teaches
Visual/styling change
- Update component source only
- Storybook and Fumadocs demos auto-reflect
- No agent-surface changes needed unless the styling change introduces a new rule (e.g., new transition, new token)
Description/copy change
- Update MDX frontmatter or section text only
- LLMs.txt auto-reflects on next deploy
Sync the AI Agent Surface
Three surfaces drift if not maintained explicitly. Run through this checklist after any component add or convention change.
When adding a brand-new component
| Surface | Action |
|---|
packages/ui/src/_registry.ts | Add the component entry (handled by pnpm add:component). |
packages/ui/package.json exports | Add ./{name} subpath. |
packages/ui/tsup.config.ts entryPoints | Add the source path. |
skills/keystoneui-react/SKILL.md | Bump the component count and add a row to the Component List table (kebab-case name). |
skills/keystoneui-react/SKILL.md Component Selection table | Add the component to the appropriate row (e.g. "Form layout" / "Overlays" / "Feedback"). |
apps/docs/content/docs/(getting-started)/agents/mcp-server.mdx | Bump the "all 54+ UI components" count if you reference one. |
README.md | Bump the "54+ accessible" count if it appears. |
apps/docs/public/r/ | Run pnpm registry:build to rebuild registry artifacts. |
When changing a convention or adding a new rule
| Trigger | Surface to update |
|---|
New CSS token (e.g. another --z-*, --ease-*) | AGENTS.md "Styling Conventions" bullet AND skills/keystoneui-react/rules/styling.md AND .claude/skills/design-tokens/SKILL.md. All three. |
| New form pattern (e.g. new Field variant) | skills/keystoneui-react/rules/forms.md AND any block demos that should reflect it. |
New compound component pattern (e.g. new data-slot use) | skills/keystoneui-react/rules/composition.md AND .claude/skills/component-architecture/SKILL.md. |
| New popup behavior (height, animation, z-stack) | skills/keystoneui-react/rules/composition.md AND .claude/skills/popup-patterns/SKILL.md. |
| New install path or CLI flow | skills/keystoneui-react/cli.md AND apps/docs/content/docs/(getting-started)/agents/skills.mdx. |
| New MCP tool | packages/keystoneui-mcp/src/{server,tools,fetcher}.ts AND skills/keystoneui-react/mcp.md AND apps/docs/content/docs/(getting-started)/agents/mcp-server.mdx. |
| New block | Follow Adding a New Block above; then add the block to the Block Selection table in skills/keystoneui-react/SKILL.md, run pnpm docs:backlinks and pnpm registry:build. |
| New block category | AGENTS.md "Block Authoring" taxonomy AND the table in Adding a New Block above AND the Block Selection table in skills/keystoneui-react/SKILL.md. |
| New story or demo variant | Run pnpm lint:stories-demos. If the lint flags it as story-only or demo-only and that's intentional (per-variant story vs consolidated variants.tsx demo, dev-only fixture, etc.), add the entry to scripts/stories-demos-allowlist.json with a one-line rationale in the _notes block. Otherwise author the missing counterpart on the other surface. |
Validation
pnpm --filter @keystoneui/mcp build — confirms MCP changes compile.
pnpm --filter @keystoneui/docs build (or tsc --noEmit) — confirms docs MDX/routes are valid.
pnpm registry:build — refreshes apps/docs/public/r/*.json.
pnpm build:skills — re-tarballs skills/keystoneui-react/ and skills/{others} for keystoneui.io/skills/{name}.tar.gz.
Why this matters
Drift between component source and the skill / AGENTS.md / MCP registry is the single biggest reliability risk for AI consumers. The 6adc8c2 commit is the canonical example: motion/layering tokens were added to AGENTS.md but not to SKILL.md, leaving the skill stale until manual reflow. Treat the agent surface as code — synced together, not as an afterthought.
The eval suite at skills/keystoneui-react/evals/evals.json exists to catch this kind of drift; run it (or extend it) when you change a rule.
Demo File Pattern
Every demo must follow this exact pattern:
"use client";
import { MyComponent } from "@keystoneui/react/my-component";
export default function MyComponentDefault() {
return <MyComponent>Content</MyComponent>;
}
Demo Registry Pattern
In apps/docs/demos/index.ts:
import MyComponentDefault from "./my-component/default";
"my-component-default": { component: MyComponentDefault, file: "my-component/default.tsx" },
MDX Pattern
In apps/docs/content/docs/components/my-component.mdx:
<ComponentPreview name="my-component-default" />
Composition tree
For compound components (≥2 exported parts that nest), insert a ## Composition section after ## Usage with an ASCII tree showing the canonical nesting. Mirrors shadcn/ui's pattern — flows through llms-full.txt automatically since it's plain markdown. Skip for single-piece components (Button, Badge, Input, Spinner, etc.).
## Composition
\`\`\`text
MyComponent
└── MyComponentItem
├── MyComponentTrigger
└── MyComponentContent
\`\`\`
Authoring rules:
- Use box-drawing characters (
├──, └──, │) — copy from an existing MDX if unsure.
- Indent two spaces per level.
- Order children top-to-bottom in the order they appear in the canonical default demo.
- Show one branch per repeating part (don't list two
MyComponentItems).
- Include conventional non-exported nodes when they appear in the standard demo (e.g.
Icon under Alert).
Key File Locations
Component sources
- Component:
packages/ui/src/{name}.tsx
- Exports:
packages/ui/package.json
- Build entries:
packages/ui/tsup.config.ts
- Registry:
packages/ui/src/_registry.ts
- Stories:
apps/storybook/stories/{name}.stories.tsx
- Demos:
apps/docs/demos/{name}/
- Demo registry:
apps/docs/demos/index.ts
- MDX docs:
apps/docs/content/docs/components/{name}.mdx
- Component nav:
apps/docs/content/docs/components/meta.json
AI agent surfaces
- Skill (consumers):
skills/keystoneui-react/SKILL.md + mcp.md, cli.md, customization.md, rules/*.md
- Skill evals:
skills/keystoneui-react/evals/evals.json
- AGENTS.md (root):
/AGENTS.md
- AGENTS.md route:
apps/docs/app/agents-md/route.ts
- LLMs.txt routes:
apps/docs/app/llms{,-full,-components}.txt/route.ts
- MCP server:
packages/keystoneui-mcp/src/{server,tools,fetcher,config}.ts
- MCP docs:
apps/docs/content/docs/(getting-started)/agents/{mcp-server,skills,llms-txt,agents-md}.mdx
Project-internal Claude/Cursor skills
.claude/skills/{component-architecture,design-tokens,popup-patterns,contributing}/SKILL.md
.cursor/rules/*.mdc (symlinks to the same canonical files)