Best for
- Use when "create a design system" or "component library from scratch".
kensaurus/cursor-kenji/skills/design-system/SKILL.md
Build a new design system (tokens, variants, theming). Use when "create a design system" or "component library from scratch". Drifted existing system → housekeep-design. Plan-only unification → plan-uiux-unification.
Decision brief
Degree of freedom: MIXED. Token taxonomy and variants [HIGH freedom]; existing ui/ / token inventory [LOW freedom — run exactly].
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/kensaurus/cursor-kenji --skill "skills/design-system"Inspect the Agent Skill "design-system" from https://github.com/kensaurus/cursor-kenji/blob/28a0bd8403c950f58ed063d47a858ee3493b0038/skills/design-system/SKILL.md at commit 28a0bd8403c950f58ed063d47a858ee3493b0038. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
1. Inventory — components/ui, tokens, cva, shadcn/Radix 2. Tokenize — semantic tokens, not raw hex in components 3. Variant — cva covers real states (default/destructive/disabled) 4. Document — JSDoc, keyboard/focus, dark mode
Inventory: shadcn Button exists; colors are raw 3B82F6 in three pages; no --primary. Tokenize: --primary / --primary-foreground in globals.css; Tailwind maps hsl(var(--primary)). Variant: extend existing buttonVariants — do not add components/Button2.tsx. Document: JSDoc lists v…
Did not fork — existing primitives were extended, not recreated
Before creating ANY design system components, verify:
Review the “Design Tokens [HIGH freedom]” section in the pinned source before continuing.
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 92/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 9 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Degree of freedom: MIXED. Token taxonomy and variants [HIGH freedom];
existing ui/ / token inventory [LOW freedom — run exactly].
Build scalable, maintainable design systems with consistent tokens, variants, and documentation.
components/ui, tokens, cva, shadcn/Radixcva covers real states (default/destructive/disabled)Inventory: shadcn
Buttonexists; colors are raw#3B82F6in three pages; no--primary. Tokenize:--primary/--primary-foregroundinglobals.css; Tailwind mapshsl(var(--primary)). Variant: extend existingbuttonVariants— do not addcomponents/Button2.tsx. Document: JSDoc lists variants/sizes; focus ring + dark.darkoverrides.
housekeep-design; plan-only unification → plan-uiux-unificationBefore creating ANY design system components, verify:
ls -la src/components/ui/
cat package.json | grep -i "shadcn\|radix\|headless"
cat components.json 2>/dev/null # shadcn config
cat tailwind.config.* | head -100
cat src/styles/globals.css | head -50
rg "var\(--" --type css | head -20
rg "cva\(|variants:" --type ts --type tsx | head -10
rg "cn\(|clsx\(|twMerge" --type tsx | head -5
Why: Don't recreate existing primitives. Extend and enhance what exists.
/* globals.css */
:root {
/* Colors - Semantic */
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 221.2 83.2% 53.3%;
/* Spacing */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
/* Border Radius */
--radius: 0.5rem;
--radius-sm: calc(var(--radius) - 4px);
--radius-lg: calc(var(--radius) + 4px);
/* Shadows */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
/* Animation */
--duration-fast: 150ms;
--duration-normal: 200ms;
--duration-slow: 300ms;
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
/* ... dark mode overrides */
}
// tailwind.config.ts
import type { Config } from 'tailwindcss'
const config: Config = {
content: ['./src/**/*.{ts,tsx}'],
darkMode: 'class',
theme: {
extend: {
colors: {
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
primary: {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))',
},
secondary: {
DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))',
},
destructive: {
DEFAULT: 'hsl(var(--destructive))',
foreground: 'hsl(var(--destructive-foreground))',
},
muted: {
DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))',
},
accent: {
DEFAULT: 'hsl(var(--accent))',
foreground: 'hsl(var(--accent-foreground))',
},
},
borderRadius: {
lg: 'var(--radius-lg)',
md: 'var(--radius)',
sm: 'var(--radius-sm)',
},
boxShadow: {
sm: 'var(--shadow-sm)',
DEFAULT: 'var(--shadow)',
md: 'var(--shadow-md)',
lg: 'var(--shadow-lg)',
},
transitionDuration: {
fast: 'var(--duration-fast)',
normal: 'var(--duration-normal)',
slow: 'var(--duration-slow)',
},
},
},
}
export default config
// lib/utils.ts
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
// components/ui/button.tsx
import { cva, type VariantProps } from 'class-variance-authority'
import { forwardRef } from 'react'
import { cn } from '@/lib/utils'
const buttonVariants = cva(
// Base styles
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
outline: 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
},
size: {
default: 'h-9 px-4 py-2',
sm: 'h-8 rounded-md px-3 text-xs',
lg: 'h-10 rounded-md px-8',
icon: 'h-9 w-9',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : 'button'
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = 'Button'
export { Button, buttonVariants }
// components/ui/card.tsx
import { cn } from '@/lib/utils'
import { forwardRef } from 'react'
const Card = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
'rounded-xl border bg-card text-card-foreground shadow',
className
)}
{...props}
/>
)
)
Card.displayName = 'Card'
const CardHeader = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn('flex flex-col space-y-1.5 p-6', className)}
{...props}
/>
)
)
CardHeader.displayName = 'CardHeader'
const CardTitle = forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn('font-semibold leading-none tracking-tight', className)}
{...props}
/>
)
)
CardTitle.displayName = 'CardTitle'
const CardDescription = forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
({ className, ...props }, ref) => (
<p
ref={ref}
className={cn('text-sm text-muted-foreground', className)}
{...props}
/>
)
)
CardDescription.displayName = 'CardDescription'
const CardContent = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
)
)
CardContent.displayName = 'CardContent'
const CardFooter = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn('flex items-center p-6 pt-0', className)}
{...props}
/>
)
)
CardFooter.displayName = 'CardFooter'
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter }
// components/ui/dialog.tsx
'use client'
import * as DialogPrimitive from '@radix-ui/react-dialog'
import { X } from 'lucide-react'
import { cn } from '@/lib/utils'
const Dialog = DialogPrimitive.Root
const DialogTrigger = DialogPrimitive.Trigger
const DialogPortal = DialogPrimitive.Portal
const DialogClose = DialogPrimitive.Close
const DialogOverlay = forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
className
)}
{...props}
/>
))
const DialogContent = forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
))
export { Dialog, DialogTrigger, DialogContent, DialogClose }
// components/ui/button.stories.tsx (or docs)
/**
* Button Component
*
* A versatile button component with multiple variants and sizes.
*
* @example
* ```tsx
* <Button variant="default" size="md">Click me</Button>
* <Button variant="outline" size="sm">Small</Button>
* <Button variant="destructive" disabled>Disabled</Button>
* ```
*
* ## Variants
* - `default` - Primary action button
* - `secondary` - Secondary actions
* - `destructive` - Dangerous actions (delete, remove)
* - `outline` - Less prominent actions
* - `ghost` - Minimal visual weight
* - `link` - Styled as a link
*
* ## Sizes
* - `sm` - 32px height
* - `default` - 36px height
* - `lg` - 40px height
* - `icon` - 36x36px square for icon-only buttons
*
* ## Accessibility
* - Uses native `<button>` element
* - Supports `disabled` attribute
* - Focus ring visible on keyboard navigation
* - Works with `asChild` prop for custom elements
*/
src/
├── components/
│ └── ui/
│ ├── button.tsx
│ ├── card.tsx
│ ├── dialog.tsx
│ ├── input.tsx
│ ├── label.tsx
│ ├── select.tsx
│ ├── textarea.tsx
│ ├── toast.tsx
│ └── index.ts # Barrel export
├── lib/
│ └── utils.ts # cn() helper
├── styles/
│ └── globals.css # CSS tokens
└── tailwind.config.ts # Theme config
After creating design system components:
Frequently asked questions
Degree of freedom: MIXED. Token taxonomy and variants [HIGH freedom]; existing ui/ / token inventory [LOW freedom — run exactly].
The source record exposes this install command: npx skills add https://github.com/kensaurus/cursor-kenji --skill "skills/design-system". Inspect the command and pinned source before running it.
Alternatives
oaustegard/claude-skills
Generate hierarchical _FEATURES.md files that describe what a codebase DOES from a user/consumer perspective, anchored to source symbols via tree-sitting. Supports large complex codebases through feature-driven decomposition into sub-feature files. Uses a multi-pass synthesis: orientation → detail → overview rewrite. Use when someone says "what does this do", "document features", "feature inventory", "_FEATURES.md", or needs to understand a codebase's purpose before modifying it. Complements tre
NintendaDev/unikit-ai
Generate and maintain the project's TECHNICAL documentation from its codebase — scans the project structure, tech stack, and module boundaries, then writes a lean README landing page plus detailed topic pages (architecture, modules, setup, build, APIs), only the docs that are relevant. Use whenever the user wants to create, update, or validate documentation of the CODE or the project itself, e.g. "generate documentation", "create docs", "write the README", "update the project docs", "document th
alirezarezvani/claude-skills
ISO 13485 Quality Management System implementation and maintenance for medical device organizations. Provides QMS design, documentation control, internal auditing, CAPA management, and certification support. Use when working with medical device quality systems, preparing for ISO 13485 audits, managing regulatory compliance documentation, setting up corrective actions, or building audit preparation programs. Useful for quality management, audit preparation, regulatory compliance, medical device d
compozy/compozy
Build terminal user interfaces with Go and Bubbletea framework. Use when creating TUI apps with the Elm architecture, dual-pane layouts, accordion modes, mouse/keyboard handling, Lipgloss styling, and reusable components. Includes production-ready templates, effects library, and battle-tested layout patterns from real projects. Don't use for plain-text CLI scripts without an interactive UI, web/desktop GUIs, or non-Go terminal frameworks (Ink, Textual, Ratatui).