diff --git a/skills/.curated/shadcn/LICENSE.txt b/skills/.curated/shadcn/LICENSE.txt new file mode 100644 index 00000000..fad4d887 --- /dev/null +++ b/skills/.curated/shadcn/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 shadcn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/skills/.curated/shadcn/SKILL.md b/skills/.curated/shadcn/SKILL.md new file mode 100644 index 00000000..b644e6ad --- /dev/null +++ b/skills/.curated/shadcn/SKILL.md @@ -0,0 +1,241 @@ +--- +name: "shadcn" +description: "Use when the user is working with shadcn/ui or a project that uses `components.json`, including adding, searching, updating, fixing, debugging, styling, composing, or switching presets for shadcn/ui components and registries." +--- + +# shadcn/ui + +A framework for building UI components and design systems. Components are added as source code to the user's project via the CLI. + +> **IMPORTANT:** Run all CLI commands using the project's package runner: `npx shadcn@latest`, `pnpm dlx shadcn@latest`, or `bunx --bun shadcn@latest`, based on the project's `packageManager`. Examples below use `npx shadcn@latest` but substitute the correct runner for the project. + +## Project Context + +For an existing shadcn/ui project, start by running `npx shadcn@latest info --json` from the project root, or the equivalent `pnpm dlx` or `bunx --bun` command for the detected package manager. Use that output as the source of truth for project config, aliases, installed components, Tailwind setup, and resolved paths. + +If `info --json` fails because the project has not been initialized yet, only move to `init` when the user explicitly wants to set up shadcn/ui, create a new app, or switch presets. Otherwise, explain that the project is not initialized and what is missing. + +## Principles + +1. **Use existing components first.** Use `npx shadcn@latest search` to check registries before writing custom UI. Check community registries too. +2. **Compose, don't reinvent.** Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table. +3. **Use built-in variants before custom styles.** `variant="outline"`, `size="sm"`, etc. +4. **Use semantic colors.** `bg-primary`, `text-muted-foreground` — never raw values like `bg-blue-500`. + +## Critical Rules + +These rules are **always enforced**. Each links to a file with Incorrect/Correct code pairs. + +### Styling & Tailwind -> [styling.md](references/rules/styling.md) + +- **`className` for layout, not styling.** Never override component colors or typography. +- **No `space-x-*` or `space-y-*`.** Use `flex` with `gap-*`. For vertical stacks, `flex flex-col gap-*`. +- **Use `size-*` when width and height are equal.** `size-10` not `w-10 h-10`. +- **Use `truncate` shorthand.** Not `overflow-hidden text-ellipsis whitespace-nowrap`. +- **No manual `dark:` color overrides.** Use semantic tokens (`bg-background`, `text-muted-foreground`). +- **Use `cn()` for conditional classes.** Don't write manual template literal ternaries. +- **No manual `z-index` on overlay components.** Dialog, Sheet, Popover, etc. handle their own stacking. + +### Forms & Inputs -> [forms.md](references/rules/forms.md) + +- **Forms use `FieldGroup` + `Field`.** Never use raw `div` with `space-y-*` or `grid gap-*` for form layout. +- **`InputGroup` uses `InputGroupInput`/`InputGroupTextarea`.** Never raw `Input`/`Textarea` inside `InputGroup`. +- **Buttons inside inputs use `InputGroup` + `InputGroupAddon`.** +- **Option sets (2–7 choices) use `ToggleGroup`.** Don't loop `Button` with manual active state. +- **`FieldSet` + `FieldLegend` for grouping related checkboxes/radios.** Don't use a `div` with a heading. +- **Field validation uses `data-invalid` + `aria-invalid`.** `data-invalid` on `Field`, `aria-invalid` on the control. For disabled: `data-disabled` on `Field`, `disabled` on the control. + +### Component Structure -> [composition.md](references/rules/composition.md) + +- **Items always inside their Group.** `SelectItem` -> `SelectGroup`. `DropdownMenuItem` -> `DropdownMenuGroup`. `CommandItem` -> `CommandGroup`. +- **Use `asChild` (radix) or `render` (base) for custom triggers.** Check `base` field from `npx shadcn@latest info`. See [base-vs-radix.md](references/rules/base-vs-radix.md). +- **Dialog, Sheet, and Drawer always need a Title.** `DialogTitle`, `SheetTitle`, `DrawerTitle` required for accessibility. Use `className="sr-only"` if visually hidden. +- **Use full Card composition.** `CardHeader`/`CardTitle`/`CardDescription`/`CardContent`/`CardFooter`. Don't dump everything in `CardContent`. +- **Button has no `isPending`/`isLoading`.** Compose with `Spinner` + `data-icon` + `disabled`. +- **`TabsTrigger` must be inside `TabsList`.** Never render triggers directly in `Tabs`. +- **`Avatar` always needs `AvatarFallback`.** For when the image fails to load. + +### Use Components, Not Custom Markup -> [composition.md](references/rules/composition.md) + +- **Use existing components before custom markup.** Check if a component exists before writing a styled `div`. +- **Callouts use `Alert`.** Don't build custom styled divs. +- **Empty states use `Empty`.** Don't build custom empty state markup. +- **Toast via `sonner`.** Use `toast()` from `sonner`. +- **Use `Separator`** instead of `
`.
+
+## Key Patterns
+
+These are the most common patterns that differentiate correct shadcn/ui code. For edge cases, see the linked rule files above.
+
+```tsx
+// Form layout: FieldGroup + Field, not div + Label.
+
+
+ Email
+
+
+
+
+// Validation: data-invalid on Field, aria-invalid on the control.
+
+ Email
+
+ Invalid email.
+
+
+// Icons in buttons: data-icon, no sizing classes.
+
+
+// Spacing: gap-*, not space-y-*.
+ // correct
+ // wrong
+
+// Equal dimensions: size-*, not w-* h-*.
+ // correct
+ // wrong
+
+// Status colors: Badge variants or semantic tokens, not raw colors.
++20.1% // correct
++20.1% // wrong
+```
+
+## Component Selection
+
+| Need | Use |
+| -------------------------- | --------------------------------------------------------------------------------------------------- |
+| Button/action | `Button` with appropriate variant |
+| Form inputs | `Input`, `Select`, `Combobox`, `Switch`, `Checkbox`, `RadioGroup`, `Textarea`, `InputOTP`, `Slider` |
+| Toggle between 2–5 options | `ToggleGroup` + `ToggleGroupItem` |
+| Data display | `Table`, `Card`, `Badge`, `Avatar` |
+| Navigation | `Sidebar`, `NavigationMenu`, `Breadcrumb`, `Tabs`, `Pagination` |
+| Overlays | `Dialog` (modal), `Sheet` (side panel), `Drawer` (bottom sheet), `AlertDialog` (confirmation) |
+| Feedback | `sonner` (toast), `Alert`, `Progress`, `Skeleton`, `Spinner` |
+| Command palette | `Command` inside `Dialog` |
+| Charts | `Chart` (wraps Recharts) |
+| Layout | `Card`, `Separator`, `Resizable`, `ScrollArea`, `Accordion`, `Collapsible` |
+| Empty states | `Empty` |
+| Menus | `DropdownMenu`, `ContextMenu`, `Menubar` |
+| Tooltips/info | `Tooltip`, `HoverCard`, `Popover` |
+
+## Key Fields
+
+The `info --json` output contains these key fields:
+
+- **`aliases`** -> use the actual alias prefix for imports (e.g. `@/`, `~/`), never hardcode.
+- **`isRSC`** -> when `true`, components using `useState`, `useEffect`, event handlers, or browser APIs need `"use client"` at the top of the file. Always reference this field when advising on the directive.
+- **`tailwindVersion`** -> `"v4"` uses `@theme inline` blocks; `"v3"` uses `tailwind.config.js`.
+- **`tailwindCssFile`** -> the global CSS file where custom CSS variables are defined. Always edit this file, never create a new one.
+- **`style`** -> component visual treatment (e.g. `nova`, `vega`).
+- **`base`** -> primitive library (`radix` or `base`). Affects component APIs and available props.
+- **`iconLibrary`** -> determines icon imports. Use `lucide-react` for `lucide`, `@tabler/icons-react` for `tabler`, etc. Never assume `lucide-react`.
+- **`resolvedPaths`** -> exact file-system destinations for components, utils, hooks, etc.
+- **`framework`** -> routing and file conventions (e.g. Next.js App Router vs Vite SPA).
+- **`packageManager`** -> use this for any non-shadcn dependency installs (e.g. `pnpm add date-fns` vs `npm install date-fns`).
+
+See [references/cli.md](references/cli.md) for the full field reference for `info`.
+
+## Component Docs, Examples, and Usage
+
+Run `npx shadcn@latest docs ` to get the URLs for a component's documentation, examples, and API reference. Fetch these URLs to get the actual content.
+
+```bash
+npx shadcn@latest docs button dialog select
+```
+
+**When creating, fixing, debugging, or using a component, always run `npx shadcn@latest docs` and fetch the URLs first.** This ensures you're working with the correct API and usage patterns rather than guessing.
+
+## Workflow
+
+1. **Get project context** - run `npx shadcn@latest info --json` from the project root and refresh it whenever `components.json`, presets, or installed components change.
+2. **Check installed components first** - before running `add`, inspect the `components` list from `info --json` or list the `resolvedPaths.ui` directory. Do not import components that have not been added, and do not re-add ones already installed.
+3. **Find components** - run `npx shadcn@latest search`.
+4. **Get docs and examples** - run `npx shadcn@latest docs ` to get URLs, then fetch them. Use `npx shadcn@latest view` to browse registry items you have not installed. To preview changes to installed components, use `npx shadcn@latest add --diff`.
+5. **Install or update** - run `npx shadcn@latest add`. When updating existing components, use `--dry-run` and `--diff` first (see [Updating Components](#updating-components) below).
+6. **Fix imports in third-party components** - after adding components from community registries (e.g. `@bundui`, `@magicui`), check the added non-UI files for hardcoded import paths like `@/components/ui/...`. These may not match the project's actual aliases. Use `npx shadcn@latest info` to get the correct `ui` alias (e.g. `@workspace/ui/components`) and rewrite the imports accordingly. The CLI rewrites imports for its own UI files, but third-party registry components may not.
+7. **Review added components** - after adding a component or block from any registry, always read the added files and verify they are correct. Check for missing sub-components (e.g. `SelectItem` without `SelectGroup`), missing imports, incorrect composition, or violations of the [Critical Rules](#critical-rules). Also replace any icon imports with the project's `iconLibrary` from the project context (e.g. if the registry item uses `lucide-react` but the project uses `hugeicons`, swap the imports and icon names accordingly). Fix all issues before moving on.
+8. **Registry must be explicit** - when the user asks to add a block or component, do not guess the registry. If no registry is specified (e.g. user says "add a login block" without specifying `@shadcn`, `@tailark`, etc.), ask which registry to use. Never default to a registry on behalf of the user.
+9. **Switching presets** - ask the user first: **reinstall**, **merge**, or **skip**?
+ - **Reinstall**: `npx shadcn@latest init --preset --force --reinstall`. Overwrites all components.
+ - **Merge**: `npx shadcn@latest init --preset --force --no-reinstall`, then run `npx shadcn@latest info` to list installed components, then for each installed component use `--dry-run` and `--diff` to [smart merge](#updating-components) it individually.
+ - **Skip**: `npx shadcn@latest init --preset --force --no-reinstall`. Only updates config and CSS, leaves components as-is.
+ - **Important**: Always run preset commands inside the user's project directory. The CLI automatically preserves the current base (`base` vs `radix`) from `components.json`. If you must use a scratch or temp directory (e.g. for `--dry-run` comparisons), pass `--base ` explicitly; preset codes do not encode the base.
+
+## Updating Components
+
+When the user asks to update a component from upstream while keeping their local changes, use `--dry-run` and `--diff` to intelligently merge. **NEVER fetch raw files from GitHub manually - always use the CLI.**
+
+1. Run `npx shadcn@latest add --dry-run` to see all files that would be affected.
+2. For each file, run `npx shadcn@latest add --diff ` to see what changed upstream vs local.
+3. Decide per file based on the diff:
+ - No local changes -> safe to overwrite.
+ - Has local changes -> read the local file, analyze the diff, and apply upstream updates while preserving local modifications.
+ - User says "just update everything" -> use `--overwrite`, but confirm first.
+4. **Never use `--overwrite` without the user's explicit approval.**
+
+## Quick Reference
+
+```bash
+# Create a new project.
+npx shadcn@latest init --name my-app --preset base-nova
+npx shadcn@latest init --name my-app --preset a2r6bw --template vite
+
+# Create a monorepo project.
+npx shadcn@latest init --name my-app --preset base-nova --monorepo
+npx shadcn@latest init --name my-app --preset base-nova --template next --monorepo
+
+# Initialize existing project.
+npx shadcn@latest init --preset base-nova
+npx shadcn@latest init --defaults # shortcut: --template=next --preset=base-nova
+
+# Add components.
+npx shadcn@latest add button card dialog
+npx shadcn@latest add @magicui/shimmer-button
+npx shadcn@latest add --all
+
+# Preview changes before adding/updating.
+npx shadcn@latest add button --dry-run
+npx shadcn@latest add button --diff button.tsx
+npx shadcn@latest add @acme/form --view button.tsx
+
+# Search registries.
+npx shadcn@latest search @shadcn -q "sidebar"
+npx shadcn@latest search @tailark -q "stats"
+
+# Get component docs and example URLs.
+npx shadcn@latest docs button dialog select
+
+# View registry item details (for items not yet installed).
+npx shadcn@latest view @shadcn/button
+```
+
+**Named presets:** `base-nova`, `radix-nova`
+**Templates:** `next`, `vite`, `start`, `react-router`, `astro` (all support `--monorepo`) and `laravel` (not supported for monorepo)
+**Preset codes:** Base62 strings starting with `a` (e.g. `a2r6bw`), from [ui.shadcn.com](https://ui.shadcn.com).
+
+## Reference Map
+
+Open only what you need:
+
+- [references/rules/forms.md](references/rules/forms.md) - FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validation states
+- [references/rules/composition.md](references/rules/composition.md) - groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading
+- [references/rules/icons.md](references/rules/icons.md) - `data-icon`, icon sizing, passing icons as objects
+- [references/rules/styling.md](references/rules/styling.md) - semantic colors, variants, `className`, spacing, size, truncate, dark mode, `cn()`, z-index
+- [references/rules/base-vs-radix.md](references/rules/base-vs-radix.md) - `asChild` vs `render`, Select, ToggleGroup, Slider, Accordion
+- [references/cli.md](references/cli.md) - commands, flags, presets, templates
+- [references/mcp.md](references/mcp.md) - MCP-based registry search, view, install, and audit flows when the shadcn MCP server is available
+- [references/customization.md](references/customization.md) - theming, CSS variables, and extending components
diff --git a/skills/.curated/shadcn/agents/openai.yaml b/skills/.curated/shadcn/agents/openai.yaml
new file mode 100644
index 00000000..8a44056d
--- /dev/null
+++ b/skills/.curated/shadcn/agents/openai.yaml
@@ -0,0 +1,6 @@
+interface:
+ display_name: "shadcn/ui"
+ short_description: "Build and maintain shadcn/ui projects"
+ icon_small: "./assets/shadcn-small.png"
+ icon_large: "./assets/shadcn.png"
+ default_prompt: "Use $shadcn to inspect this shadcn/ui project, choose the right components, and implement the UI using the project's existing aliases and conventions."
diff --git a/skills/.curated/shadcn/assets/shadcn-small.png b/skills/.curated/shadcn/assets/shadcn-small.png
new file mode 100644
index 00000000..547154b9
Binary files /dev/null and b/skills/.curated/shadcn/assets/shadcn-small.png differ
diff --git a/skills/.curated/shadcn/assets/shadcn.png b/skills/.curated/shadcn/assets/shadcn.png
new file mode 100644
index 00000000..b7b6814a
Binary files /dev/null and b/skills/.curated/shadcn/assets/shadcn.png differ
diff --git a/skills/.curated/shadcn/references/cli.md b/skills/.curated/shadcn/references/cli.md
new file mode 100644
index 00000000..83748ff3
--- /dev/null
+++ b/skills/.curated/shadcn/references/cli.md
@@ -0,0 +1,257 @@
+# shadcn CLI Reference
+
+Configuration is read from `components.json`.
+
+> **IMPORTANT:** Always run commands using the project's package runner: `npx shadcn@latest`, `pnpm dlx shadcn@latest`, or `bunx --bun shadcn@latest`. Check `packageManager` from project context to choose the right one. Examples below use `npx shadcn@latest` but substitute the correct runner for the project.
+
+> **IMPORTANT:** Only use the flags documented below. Do not invent or guess flags — if a flag isn't listed here, it doesn't exist. The CLI auto-detects the package manager from the project's lockfile; there is no `--package-manager` flag.
+
+## Contents
+
+- Commands: init, add (dry-run, smart merge), search, view, docs, info, build
+- Templates: next, vite, start, react-router, astro
+- Presets: named, code, URL formats and fields
+- Switching presets
+
+---
+
+## Commands
+
+### `init` — Initialize or create a project
+
+```bash
+npx shadcn@latest init [components...] [options]
+```
+
+Initializes shadcn/ui in an existing project or creates a new project (when `--name` is provided). Optionally installs components in the same step.
+
+| Flag | Short | Description | Default |
+| ----------------------- | ----- | --------------------------------------------------------- | ------- |
+| `--template ` | `-t` | Template (next, start, vite, next-monorepo, react-router) | — |
+| `--preset [name]` | `-p` | Preset configuration (named, code, or URL) | — |
+| `--yes` | `-y` | Skip confirmation prompt | `true` |
+| `--defaults` | `-d` | Use defaults (`--template=next --preset=base-nova`) | `false` |
+| `--force` | `-f` | Force overwrite existing configuration | `false` |
+| `--cwd ` | `-c` | Working directory | current |
+| `--name ` | `-n` | Name for new project | — |
+| `--silent` | `-s` | Mute output | `false` |
+| `--rtl` | | Enable RTL support | — |
+| `--reinstall` | | Re-install existing UI components | `false` |
+| `--monorepo` | | Scaffold a monorepo project | — |
+| `--no-monorepo` | | Skip the monorepo prompt | — |
+
+`npx shadcn@latest create` is an alias for `npx shadcn@latest init`.
+
+### `add` — Add components
+
+> **IMPORTANT:** To compare local components against upstream or to preview changes, ALWAYS use `npx shadcn@latest add --dry-run`, `--diff`, or `--view`. NEVER fetch raw files from GitHub or other sources manually. The CLI handles registry resolution, file paths, and CSS diffing automatically.
+
+```bash
+npx shadcn@latest add [components...] [options]
+```
+
+Accepts component names, registry-prefixed names (`@magicui/shimmer-button`), URLs, or local paths.
+
+| Flag | Short | Description | Default |
+| --------------- | ----- | -------------------------------------------------------------------------------------------------------------------- | ------- |
+| `--yes` | `-y` | Skip confirmation prompt | `false` |
+| `--overwrite` | `-o` | Overwrite existing files | `false` |
+| `--cwd ` | `-c` | Working directory | current |
+| `--all` | `-a` | Add all available components | `false` |
+| `--path ` | `-p` | Target path for the component | — |
+| `--silent` | `-s` | Mute output | `false` |
+| `--dry-run` | | Preview all changes without writing files | `false` |
+| `--diff [path]` | | Show diffs. Without a path, shows the first 5 files. With a path, shows that file only (implies `--dry-run`) | — |
+| `--view [path]` | | Show file contents. Without a path, shows the first 5 files. With a path, shows that file only (implies `--dry-run`) | — |
+
+#### Dry-Run Mode
+
+Use `--dry-run` to preview what `add` would do without writing any files. `--diff` and `--view` both imply `--dry-run`.
+
+```bash
+# Preview all changes.
+npx shadcn@latest add button --dry-run
+
+# Show diffs for all files (top 5).
+npx shadcn@latest add button --diff
+
+# Show the diff for a specific file.
+npx shadcn@latest add button --diff button.tsx
+
+# Show contents for all files (top 5).
+npx shadcn@latest add button --view
+
+# Show the full content of a specific file.
+npx shadcn@latest add button --view button.tsx
+
+# Works with URLs too.
+npx shadcn@latest add https://api.npoint.io/abc123 --dry-run
+
+# CSS diffs.
+npx shadcn@latest add button --diff globals.css
+```
+
+**When to use dry-run:**
+
+- When the user asks "what files will this add?" or "what will this change?" — use `--dry-run`.
+- Before overwriting existing components — use `--diff` to preview the changes first.
+- When the user wants to inspect component source code without installing — use `--view`.
+- When checking what CSS changes would be made to `globals.css` — use `--diff globals.css`.
+- When the user asks to review or audit third-party registry code before installing — use `--view` to inspect the source.
+
+> **`npx shadcn@latest add --dry-run` vs `npx shadcn@latest view`:** Prefer `npx shadcn@latest add --dry-run/--diff/--view` over `npx shadcn@latest view` when the user wants to preview changes to their project. `npx shadcn@latest view` only shows raw registry metadata. `npx shadcn@latest add --dry-run` shows exactly what would happen in the user's project: resolved file paths, diffs against existing files, and CSS updates. Use `npx shadcn@latest view` only when the user wants to browse registry info without a project context.
+
+#### Smart Merge from Upstream
+
+See [Updating Components in SKILL.md](../SKILL.md#updating-components) for the full workflow.
+
+### `search` — Search registries
+
+```bash
+npx shadcn@latest search [options]
+```
+
+Fuzzy search across registries. Also aliased as `npx shadcn@latest list`. Without `-q`, lists all items.
+
+| Flag | Short | Description | Default |
+| ------------------- | ----- | ---------------------- | ------- |
+| `--query ` | `-q` | Search query | — |
+| `--limit ` | `-l` | Max items per registry | `100` |
+| `--offset ` | `-o` | Items to skip | `0` |
+| `--cwd ` | `-c` | Working directory | current |
+
+### `view` — View item details
+
+```bash
+npx shadcn@latest view [options]
+```
+
+Displays item info including file contents. Example: `npx shadcn@latest view @shadcn/button`.
+
+### `docs` — Get component documentation URLs
+
+```bash
+npx shadcn@latest docs [options]
+```
+
+Outputs resolved URLs for component documentation, examples, and API references. Accepts one or more component names. Fetch the URLs to get the actual content.
+
+Example output for `npx shadcn@latest docs input button`:
+
+```
+base radix
+
+input
+ docs https://ui.shadcn.com/docs/components/radix/input
+ examples https://raw.githubusercontent.com/.../examples/input-example.tsx
+
+button
+ docs https://ui.shadcn.com/docs/components/radix/button
+ examples https://raw.githubusercontent.com/.../examples/button-example.tsx
+```
+
+Some components include an `api` link to the underlying library (e.g. `cmdk` for the command component).
+
+### `diff` — Check for updates
+
+Do not use this command. Use `npx shadcn@latest add --diff` instead.
+
+### `info` — Project information
+
+```bash
+npx shadcn@latest info [options]
+```
+
+Displays project info and `components.json` configuration. Run this first to discover the project's framework, aliases, Tailwind version, and resolved paths.
+
+| Flag | Short | Description | Default |
+| ------------- | ----- | ----------------- | ------- |
+| `--cwd ` | `-c` | Working directory | current |
+
+**Project Info fields:**
+
+| Field | Type | Meaning |
+| -------------------- | --------- | ------------------------------------------------------------------ |
+| `framework` | `string` | Detected framework (`next`, `vite`, `react-router`, `start`, etc.) |
+| `frameworkVersion` | `string` | Framework version (e.g. `15.2.4`) |
+| `isSrcDir` | `boolean` | Whether the project uses a `src/` directory |
+| `isRSC` | `boolean` | Whether React Server Components are enabled |
+| `isTsx` | `boolean` | Whether the project uses TypeScript |
+| `tailwindVersion` | `string` | `"v3"` or `"v4"` |
+| `tailwindConfigFile` | `string` | Path to the Tailwind config file |
+| `tailwindCssFile` | `string` | Path to the global CSS file |
+| `aliasPrefix` | `string` | Import alias prefix (e.g. `@`, `~`, `@/`) |
+| `packageManager` | `string` | Detected package manager (`npm`, `pnpm`, `yarn`, `bun`) |
+
+**Components.json fields:**
+
+| Field | Type | Meaning |
+| -------------------- | --------- | ------------------------------------------------------------------------------------------ |
+| `base` | `string` | Primitive library (`radix` or `base`) — determines component APIs and available props |
+| `style` | `string` | Visual style (e.g. `nova`, `vega`) |
+| `rsc` | `boolean` | RSC flag from config |
+| `tsx` | `boolean` | TypeScript flag |
+| `tailwind.config` | `string` | Tailwind config path |
+| `tailwind.css` | `string` | Global CSS path — this is where custom CSS variables go |
+| `iconLibrary` | `string` | Icon library — determines icon import package (e.g. `lucide-react`, `@tabler/icons-react`) |
+| `aliases.components` | `string` | Component import alias (e.g. `@/components`) |
+| `aliases.utils` | `string` | Utils import alias (e.g. `@/lib/utils`) |
+| `aliases.ui` | `string` | UI component alias (e.g. `@/components/ui`) |
+| `aliases.lib` | `string` | Lib alias (e.g. `@/lib`) |
+| `aliases.hooks` | `string` | Hooks alias (e.g. `@/hooks`) |
+| `resolvedPaths` | `object` | Absolute file-system paths for each alias |
+| `registries` | `object` | Configured custom registries |
+
+**Links fields:**
+
+The `info` output includes a **Links** section with templated URLs for component docs, source, and examples. For resolved URLs, use `npx shadcn@latest docs ` instead.
+
+### `build` — Build a custom registry
+
+```bash
+npx shadcn@latest build [registry] [options]
+```
+
+Builds `registry.json` into individual JSON files for distribution. Default input: `./registry.json`, default output: `./public/r`.
+
+| Flag | Short | Description | Default |
+| ----------------- | ----- | ----------------- | ------------ |
+| `--output ` | `-o` | Output directory | `./public/r` |
+| `--cwd ` | `-c` | Working directory | current |
+
+---
+
+## Templates
+
+| Value | Framework | Monorepo support |
+| -------------- | -------------- | ---------------- |
+| `next` | Next.js | Yes |
+| `vite` | Vite | Yes |
+| `start` | TanStack Start | Yes |
+| `react-router` | React Router | Yes |
+| `astro` | Astro | Yes |
+| `laravel` | Laravel | No |
+
+All templates support monorepo scaffolding via the `--monorepo` flag. When passed, the CLI uses a monorepo-specific template directory (e.g. `next-monorepo`, `vite-monorepo`). When neither `--monorepo` nor `--no-monorepo` is passed, the CLI prompts interactively. Laravel does not support monorepo scaffolding.
+
+---
+
+## Presets
+
+Three ways to specify a preset via `--preset`:
+
+1. **Named:** `--preset base-nova` or `--preset radix-nova`
+2. **Code:** `--preset a2r6bw` (base62 string, starts with lowercase `a`)
+3. **URL:** `--preset "https://ui.shadcn.com/init?base=radix&style=nova&..."`
+
+> **IMPORTANT:** Never try to decode, fetch, or resolve preset codes manually. Preset codes are opaque — pass them directly to `npx shadcn@latest init --preset ` and let the CLI handle resolution.
+
+## Switching Presets
+
+Ask the user first: **reinstall**, **merge**, or **skip** existing components?
+
+- **Re-install** → `npx shadcn@latest init --preset --force --reinstall`. Overwrites all component files with the new preset styles. Use when the user hasn't customized components.
+- **Merge** → `npx shadcn@latest init --preset --force --no-reinstall`, then run `npx shadcn@latest info` to get the list of installed components and use the [smart merge workflow](../SKILL.md#updating-components) to update them one by one, preserving local changes. Use when the user has customized components.
+- **Skip** → `npx shadcn@latest init --preset --force --no-reinstall`. Only updates config and CSS variables, leaves existing components as-is.
+
+Always run preset commands inside the user's project directory. The CLI automatically preserves the current base (`base` vs `radix`) from `components.json`. If you must use a scratch/temp directory (e.g. for `--dry-run` comparisons), pass `--base ` explicitly — preset codes do not encode the base.
diff --git a/skills/.curated/shadcn/references/customization.md b/skills/.curated/shadcn/references/customization.md
new file mode 100644
index 00000000..f96746be
--- /dev/null
+++ b/skills/.curated/shadcn/references/customization.md
@@ -0,0 +1,202 @@
+# Customization & Theming
+
+Components reference semantic CSS variable tokens. Change the variables to change every component.
+
+## Contents
+
+- How it works (CSS variables → Tailwind utilities → components)
+- Color variables and OKLCH format
+- Dark mode setup
+- Changing the theme (presets, CSS variables)
+- Adding custom colors (Tailwind v3 and v4)
+- Border radius
+- Customizing components (variants, className, wrappers)
+- Checking for updates
+
+---
+
+## How It Works
+
+1. CSS variables defined in `:root` (light) and `.dark` (dark mode).
+2. Tailwind maps them to utilities: `bg-primary`, `text-muted-foreground`, etc.
+3. Components use these utilities — changing a variable changes all components that reference it.
+
+---
+
+## Color Variables
+
+Every color follows the `name` / `name-foreground` convention. The base variable is for backgrounds, `-foreground` is for text/icons on that background.
+
+| Variable | Purpose |
+| -------------------------------------------- | -------------------------------- |
+| `--background` / `--foreground` | Page background and default text |
+| `--card` / `--card-foreground` | Card surfaces |
+| `--primary` / `--primary-foreground` | Primary buttons and actions |
+| `--secondary` / `--secondary-foreground` | Secondary actions |
+| `--muted` / `--muted-foreground` | Muted/disabled states |
+| `--accent` / `--accent-foreground` | Hover and accent states |
+| `--destructive` / `--destructive-foreground` | Error and destructive actions |
+| `--border` | Default border color |
+| `--input` | Form input borders |
+| `--ring` | Focus ring color |
+| `--chart-1` through `--chart-5` | Chart/data visualization |
+| `--sidebar-*` | Sidebar-specific colors |
+| `--surface` / `--surface-foreground` | Secondary surface |
+
+Colors use OKLCH: `--primary: oklch(0.205 0 0)` where values are lightness (0–1), chroma (0 = gray), and hue (0–360).
+
+---
+
+## Dark Mode
+
+Class-based toggle via `.dark` on the root element. In Next.js, use `next-themes`:
+
+```tsx
+import { ThemeProvider } from "next-themes"
+
+
+ {children}
+
+```
+
+---
+
+## Changing the Theme
+
+```bash
+# Apply a preset code from ui.shadcn.com.
+npx shadcn@latest init --preset a2r6bw --force
+
+# Switch to a named preset.
+npx shadcn@latest init --preset radix-nova --force
+npx shadcn@latest init --reinstall # update existing components to match
+
+# Use a custom theme URL.
+npx shadcn@latest init --preset "https://ui.shadcn.com/init?base=radix&style=nova&theme=blue&..." --force
+```
+
+Or edit CSS variables directly in `globals.css`.
+
+---
+
+## Adding Custom Colors
+
+Add variables to the file at `tailwindCssFile` from `npx shadcn@latest info` (typically `globals.css`). Never create a new CSS file for this.
+
+```css
+/* 1. Define in the global CSS file. */
+:root {
+ --warning: oklch(0.84 0.16 84);
+ --warning-foreground: oklch(0.28 0.07 46);
+}
+.dark {
+ --warning: oklch(0.41 0.11 46);
+ --warning-foreground: oklch(0.99 0.02 95);
+}
+```
+
+```css
+/* 2a. Register with Tailwind v4 (@theme inline). */
+@theme inline {
+ --color-warning: var(--warning);
+ --color-warning-foreground: var(--warning-foreground);
+}
+```
+
+When `tailwindVersion` is `"v3"` (check via `npx shadcn@latest info`), register in `tailwind.config.js` instead:
+
+```js
+// 2b. Register with Tailwind v3 (tailwind.config.js).
+module.exports = {
+ theme: {
+ extend: {
+ colors: {
+ warning: "oklch(var(--warning) / )",
+ "warning-foreground":
+ "oklch(var(--warning-foreground) / )",
+ },
+ },
+ },
+}
+```
+
+```tsx
+// 3. Use in components.
+Warning
+```
+
+---
+
+## Border Radius
+
+`--radius` controls border radius globally. Components derive values from it (`rounded-lg` = `var(--radius)`, `rounded-md` = `calc(var(--radius) - 2px)`).
+
+---
+
+## Customizing Components
+
+See also: [rules/styling.md](./rules/styling.md) for Incorrect/Correct examples.
+
+Prefer these approaches in order:
+
+### 1. Built-in variants
+
+```tsx
+
+```
+
+### 2. Tailwind classes via `className`
+
+```tsx
+...
+```
+
+### 3. Add a new variant
+
+Edit the component source to add a variant via `cva`:
+
+```tsx
+// components/ui/button.tsx
+warning: "bg-warning text-warning-foreground hover:bg-warning/90",
+```
+
+### 4. Wrapper components
+
+Compose shadcn/ui primitives into higher-level components:
+
+```tsx
+export function ConfirmDialog({ title, description, onConfirm, children }) {
+ return (
+
+ {children}
+
+
+ {title}
+ {description}
+
+
+ Cancel
+ Confirm
+
+
+
+ )
+}
+```
+
+---
+
+## Checking for Updates
+
+```bash
+npx shadcn@latest add button --diff
+```
+
+To preview exactly what would change before updating, use `--dry-run` and `--diff`:
+
+```bash
+npx shadcn@latest add button --dry-run # see all affected files
+npx shadcn@latest add button --diff button.tsx # see the diff for a specific file
+```
+
+See [Updating Components in SKILL.md](../SKILL.md#updating-components) for the full smart merge workflow.
diff --git a/skills/.curated/shadcn/references/mcp.md b/skills/.curated/shadcn/references/mcp.md
new file mode 100644
index 00000000..adaeeeb4
--- /dev/null
+++ b/skills/.curated/shadcn/references/mcp.md
@@ -0,0 +1,93 @@
+# shadcn MCP Server
+
+The CLI includes an MCP server that lets AI assistants search, browse, view, and install components from registries.
+
+---
+
+## Setup
+
+```bash
+shadcn mcp # start the MCP server (stdio)
+shadcn mcp init # write config for your editor
+```
+
+Editor config files:
+
+| Editor | Config file |
+|--------|------------|
+| Cursor | `.cursor/mcp.json` |
+| VS Code | `.vscode/mcp.json` |
+| OpenCode | `opencode.json` |
+| Codex | `~/.codex/config.toml` (manual) |
+
+---
+
+## Tools
+
+> **Tip:** MCP tools handle registry operations (search, view, install). For project configuration (aliases, framework, Tailwind version), use `npx shadcn@latest info` - there is no MCP equivalent.
+
+### `shadcn:get_project_registries`
+
+Returns registry names from `components.json`. Errors if no `components.json` exists.
+
+**Input:** none
+
+### `shadcn:list_items_in_registries`
+
+Lists all items from one or more registries.
+
+**Input:** `registries` (string[]), `limit` (number, optional), `offset` (number, optional)
+
+### `shadcn:search_items_in_registries`
+
+Fuzzy search across registries.
+
+**Input:** `registries` (string[]), `query` (string), `limit` (number, optional), `offset` (number, optional)
+
+### `shadcn:view_items_in_registries`
+
+View item details including full file contents.
+
+**Input:** `items` (string[]) - e.g. `["@shadcn/button", "@shadcn/card"]`
+
+### `shadcn:get_item_examples_from_registries`
+
+Find usage examples and demos with source code.
+
+**Input:** `registries` (string[]), `query` (string) - e.g. `"accordion-demo"`, `"button example"`
+
+### `shadcn:get_add_command_for_items`
+
+Returns the CLI install command.
+
+**Input:** `items` (string[]) - e.g. `["@shadcn/button"]`
+
+### `shadcn:get_audit_checklist`
+
+Returns a checklist for verifying components (imports, deps, lint, TypeScript).
+
+**Input:** none
+
+---
+
+## Configuring Registries
+
+Registries are set in `components.json`. The `@shadcn` registry is always built-in.
+
+```json
+{
+ "registries": {
+ "@acme": "https://acme.com/r/{name}.json",
+ "@private": {
+ "url": "https://private.com/r/{name}.json",
+ "headers": { "Authorization": "Bearer ${MY_TOKEN}" }
+ }
+ }
+}
+```
+
+- Names must start with `@`.
+- URLs must contain `{name}`.
+- `${VAR}` references are resolved from environment variables.
+
+Community registry index: `https://ui.shadcn.com/r/registries.json`
diff --git a/skills/.curated/shadcn/references/rules/base-vs-radix.md b/skills/.curated/shadcn/references/rules/base-vs-radix.md
new file mode 100644
index 00000000..c1ed7d11
--- /dev/null
+++ b/skills/.curated/shadcn/references/rules/base-vs-radix.md
@@ -0,0 +1,306 @@
+# Base vs Radix
+
+API differences between `base` and `radix`. Check the `base` field from `npx shadcn@latest info`.
+
+## Contents
+
+- Composition: asChild vs render
+- Button / trigger as non-button element
+- Select (items prop, placeholder, positioning, multiple, object values)
+- ToggleGroup (type vs multiple)
+- Slider (scalar vs array)
+- Accordion (type and defaultValue)
+
+---
+
+## Composition: asChild (radix) vs render (base)
+
+Radix uses `asChild` to replace the default element. Base uses `render`. Don't wrap triggers in extra elements.
+
+**Incorrect:**
+
+```tsx
+
+
+
+
+
+```
+
+**Correct (radix):**
+
+```tsx
+
+
+
+```
+
+**Correct (base):**
+
+```tsx
+ }>Open
+```
+
+This applies to all trigger and close components: `DialogTrigger`, `SheetTrigger`, `AlertDialogTrigger`, `DropdownMenuTrigger`, `PopoverTrigger`, `TooltipTrigger`, `CollapsibleTrigger`, `DialogClose`, `SheetClose`, `NavigationMenuLink`, `BreadcrumbLink`, `SidebarMenuButton`, `Badge`, `Item`.
+
+---
+
+## Button / trigger as non-button element (base only)
+
+When `render` changes an element to a non-button (``, ``), add `nativeButton={false}`.
+
+**Incorrect (base):** missing `nativeButton={false}`.
+
+```tsx
+}>Read the docs
+```
+
+**Correct (base):**
+
+```tsx
+} nativeButton={false}>
+ Read the docs
+
+```
+
+**Correct (radix):**
+
+```tsx
+
+```
+
+Same for triggers whose `render` is not a `Button`:
+
+```tsx
+// base.
+ } nativeButton={false}>
+ Pick date
+
+```
+
+---
+
+## Select
+
+**items prop (base only).** Base requires an `items` prop on the root. Radix uses inline JSX only.
+
+**Incorrect (base):**
+
+```tsx
+
+```
+
+**Correct (base):**
+
+```tsx
+const items = [
+ { label: "Select a fruit", value: null },
+ { label: "Apple", value: "apple" },
+ { label: "Banana", value: "banana" },
+]
+
+
+```
+
+**Correct (radix):**
+
+```tsx
+
+```
+
+**Placeholder.** Base uses a `{ value: null }` item in the items array. Radix uses ``.
+
+**Content positioning.** Base uses `alignItemWithTrigger`. Radix uses `position`.
+
+```tsx
+// base.
+
+
+// radix.
+
+```
+
+---
+
+## Select — multiple selection and object values (base only)
+
+Base supports `multiple`, render-function children on `SelectValue`, and object values with `itemToStringValue`. Radix is single-select with string values only.
+
+**Correct (base — multiple selection):**
+
+```tsx
+
+```
+
+**Correct (base — object values):**
+
+```tsx
+
+```
+
+---
+
+## ToggleGroup
+
+Base uses a `multiple` boolean prop. Radix uses `type="single"` or `type="multiple"`.
+
+**Incorrect (base):**
+
+```tsx
+
+ Daily
+
+```
+
+**Correct (base):**
+
+```tsx
+// Single (no prop needed), defaultValue is always an array.
+
+ Daily
+ Weekly
+
+
+// Multi-selection.
+
+ Bold
+ Italic
+
+```
+
+**Correct (radix):**
+
+```tsx
+// Single, defaultValue is a string.
+
+ Daily
+ Weekly
+
+
+// Multi-selection.
+
+ Bold
+ Italic
+
+```
+
+**Controlled single value:**
+
+```tsx
+// base — wrap/unwrap arrays.
+const [value, setValue] = React.useState("normal")
+ setValue(v[0])}>
+
+// radix — plain string.
+const [value, setValue] = React.useState("normal")
+
+```
+
+---
+
+## Slider
+
+Base accepts a plain number for a single thumb. Radix always requires an array.
+
+**Incorrect (base):**
+
+```tsx
+
+```
+
+**Correct (base):**
+
+```tsx
+
+```
+
+**Correct (radix):**
+
+```tsx
+
+```
+
+Both use arrays for range sliders. Controlled `onValueChange` in base may need a cast:
+
+```tsx
+// base.
+const [value, setValue] = React.useState([0.3, 0.7])
+ setValue(v as number[])} />
+
+// radix.
+const [value, setValue] = React.useState([0.3, 0.7])
+
+```
+
+---
+
+## Accordion
+
+Radix requires `type="single"` or `type="multiple"` and supports `collapsible`. `defaultValue` is a string. Base uses no `type` prop, uses `multiple` boolean, and `defaultValue` is always an array.
+
+**Incorrect (base):**
+
+```tsx
+
+ ...
+
+```
+
+**Correct (base):**
+
+```tsx
+
+ ...
+
+
+// Multi-select.
+
+ ...
+ ...
+
+```
+
+**Correct (radix):**
+
+```tsx
+
+ ...
+
+```
diff --git a/skills/.curated/shadcn/references/rules/composition.md b/skills/.curated/shadcn/references/rules/composition.md
new file mode 100644
index 00000000..0e105837
--- /dev/null
+++ b/skills/.curated/shadcn/references/rules/composition.md
@@ -0,0 +1,195 @@
+# Component Composition
+
+## Contents
+
+- Items always inside their Group component
+- Callouts use Alert
+- Empty states use Empty component
+- Toast notifications use sonner
+- Choosing between overlay components
+- Dialog, Sheet, and Drawer always need a Title
+- Card structure
+- Button has no isPending or isLoading prop
+- TabsTrigger must be inside TabsList
+- Avatar always needs AvatarFallback
+- Use Separator instead of raw hr or border divs
+- Use Skeleton for loading placeholders
+- Use Badge instead of custom styled spans
+
+---
+
+## Items always inside their Group component
+
+Never render items directly inside the content container.
+
+**Incorrect:**
+
+```tsx
+
+ Apple
+ Banana
+
+```
+
+**Correct:**
+
+```tsx
+
+
+ Apple
+ Banana
+
+
+```
+
+This applies to all group-based components:
+
+| Item | Group |
+|------|-------|
+| `SelectItem`, `SelectLabel` | `SelectGroup` |
+| `DropdownMenuItem`, `DropdownMenuLabel`, `DropdownMenuSub` | `DropdownMenuGroup` |
+| `MenubarItem` | `MenubarGroup` |
+| `ContextMenuItem` | `ContextMenuGroup` |
+| `CommandItem` | `CommandGroup` |
+
+---
+
+## Callouts use Alert
+
+```tsx
+
+ Warning
+ Something needs attention.
+
+```
+
+---
+
+## Empty states use Empty component
+
+```tsx
+
+
+
+ No projects yet
+ Get started by creating a new project.
+
+
+
+
+
+```
+
+---
+
+## Toast notifications use sonner
+
+```tsx
+import { toast } from "sonner"
+
+toast.success("Changes saved.")
+toast.error("Something went wrong.")
+toast("File deleted.", {
+ action: { label: "Undo", onClick: () => undoDelete() },
+})
+```
+
+---
+
+## Choosing between overlay components
+
+| Use case | Component |
+|----------|-----------|
+| Focused task that requires input | `Dialog` |
+| Destructive action confirmation | `AlertDialog` |
+| Side panel with details or filters | `Sheet` |
+| Mobile-first bottom panel | `Drawer` |
+| Quick info on hover | `HoverCard` |
+| Small contextual content on click | `Popover` |
+
+---
+
+## Dialog, Sheet, and Drawer always need a Title
+
+`DialogTitle`, `SheetTitle`, `DrawerTitle` are required for accessibility. Use `className="sr-only"` if visually hidden.
+
+```tsx
+
+
+ Edit Profile
+ Update your profile.
+
+ ...
+
+```
+
+---
+
+## Card structure
+
+Use full composition — don't dump everything into `CardContent`:
+
+```tsx
+
+
+ Team Members
+ Manage your team.
+
+ ...
+
+
+
+
+```
+
+---
+
+## Button has no isPending or isLoading prop
+
+Compose with `Spinner` + `data-icon` + `disabled`:
+
+```tsx
+
+```
+
+---
+
+## TabsTrigger must be inside TabsList
+
+Never render `TabsTrigger` directly inside `Tabs` — always wrap in `TabsList`:
+
+```tsx
+
+
+ Account
+ Password
+
+ ...
+
+```
+
+---
+
+## Avatar always needs AvatarFallback
+
+Always include `AvatarFallback` for when the image fails to load:
+
+```tsx
+
+
+ JD
+
+```
+
+---
+
+## Use existing components instead of custom markup
+
+| Instead of | Use |
+|---|---|
+| `
` or `` | ` ` |
+| `` with styled divs | ` ` |
+| `` | `` |
diff --git a/skills/.curated/shadcn/references/rules/forms.md b/skills/.curated/shadcn/references/rules/forms.md
new file mode 100644
index 00000000..f451e2f7
--- /dev/null
+++ b/skills/.curated/shadcn/references/rules/forms.md
@@ -0,0 +1,192 @@
+# Forms & Inputs
+
+## Contents
+
+- Forms use FieldGroup + Field
+- InputGroup requires InputGroupInput/InputGroupTextarea
+- Buttons inside inputs use InputGroup + InputGroupAddon
+- Option sets (2–7 choices) use ToggleGroup
+- FieldSet + FieldLegend for grouping related fields
+- Field validation and disabled states
+
+---
+
+## Forms use FieldGroup + Field
+
+Always use `FieldGroup` + `Field` — never raw `div` with `space-y-*`:
+
+```tsx
+
+
+ Email
+
+
+
+ Password
+
+
+
+```
+
+Use `Field orientation="horizontal"` for settings pages. Use `FieldLabel className="sr-only"` for visually hidden labels.
+
+**Choosing form controls:**
+
+- Simple text input → `Input`
+- Dropdown with predefined options → `Select`
+- Searchable dropdown → `Combobox`
+- Native HTML select (no JS) → `native-select`
+- Boolean toggle → `Switch` (for settings) or `Checkbox` (for forms)
+- Single choice from few options → `RadioGroup`
+- Toggle between 2–5 options → `ToggleGroup` + `ToggleGroupItem`
+- OTP/verification code → `InputOTP`
+- Multi-line text → `Textarea`
+
+---
+
+## InputGroup requires InputGroupInput/InputGroupTextarea
+
+Never use raw `Input` or `Textarea` inside an `InputGroup`.
+
+**Incorrect:**
+
+```tsx
+
+
+
+```
+
+**Correct:**
+
+```tsx
+import { InputGroup, InputGroupInput } from "@/components/ui/input-group"
+
+
+
+
+```
+
+---
+
+## Buttons inside inputs use InputGroup + InputGroupAddon
+
+Never place a `Button` directly inside or adjacent to an `Input` with custom positioning.
+
+**Incorrect:**
+
+```tsx
+
+
+
+
+```
+
+**Correct:**
+
+```tsx
+import { InputGroup, InputGroupInput, InputGroupAddon } from "@/components/ui/input-group"
+
+
+
+
+
+
+
+```
+
+---
+
+## Option sets (2–7 choices) use ToggleGroup
+
+Don't manually loop `Button` components with active state.
+
+**Incorrect:**
+
+```tsx
+const [selected, setSelected] = useState("daily")
+
+
+ {["daily", "weekly", "monthly"].map((option) => (
+
+ ))}
+
+```
+
+**Correct:**
+
+```tsx
+import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
+
+
+ Daily
+ Weekly
+ Monthly
+
+```
+
+Combine with `Field` for labelled toggle groups:
+
+```tsx
+
+ Theme
+
+ Light
+ Dark
+ System
+
+
+```
+
+> **Note:** `defaultValue` and `type`/`multiple` props differ between base and radix. See [base-vs-radix.md](./base-vs-radix.md#togglegroup).
+
+---
+
+## FieldSet + FieldLegend for grouping related fields
+
+Use `FieldSet` + `FieldLegend` for related checkboxes, radios, or switches — not `div` with a heading:
+
+```tsx
+
+```
+
+---
+
+## Field validation and disabled states
+
+Both attributes are needed — `data-invalid`/`data-disabled` styles the field (label, description), while `aria-invalid`/`disabled` styles the control.
+
+```tsx
+// Invalid.
+
+ Email
+
+ Invalid email address.
+
+
+// Disabled.
+
+ Email
+
+
+```
+
+Works for all controls: `Input`, `Textarea`, `Select`, `Checkbox`, `RadioGroupItem`, `Switch`, `Slider`, `NativeSelect`, `InputOTP`.
diff --git a/skills/.curated/shadcn/references/rules/icons.md b/skills/.curated/shadcn/references/rules/icons.md
new file mode 100644
index 00000000..bba8102f
--- /dev/null
+++ b/skills/.curated/shadcn/references/rules/icons.md
@@ -0,0 +1,101 @@
+# Icons
+
+**Always use the project's configured `iconLibrary` for imports.** Check the `iconLibrary` field from project context: `lucide` → `lucide-react`, `tabler` → `@tabler/icons-react`, etc. Never assume `lucide-react`.
+
+---
+
+## Icons in Button use data-icon attribute
+
+Add `data-icon="inline-start"` (prefix) or `data-icon="inline-end"` (suffix) to the icon. No sizing classes on the icon.
+
+**Incorrect:**
+
+```tsx
+
+```
+
+**Correct:**
+
+```tsx
+
+
+
+```
+
+---
+
+## No sizing classes on icons inside components
+
+Components handle icon sizing via CSS. Don't add `size-4`, `w-4 h-4`, or other sizing classes to icons inside `Button`, `DropdownMenuItem`, `Alert`, `Sidebar*`, or other shadcn components. Unless the user explicitly asks for custom icon sizes.
+
+**Incorrect:**
+
+```tsx
+
+
+
+
+ Settings
+
+```
+
+**Correct:**
+
+```tsx
+
+
+
+
+ Settings
+
+```
+
+---
+
+## Pass icons as component objects, not string keys
+
+Use `icon={CheckIcon}`, not a string key to a lookup map.
+
+**Incorrect:**
+
+```tsx
+const iconMap = {
+ check: CheckIcon,
+ alert: AlertIcon,
+}
+
+function StatusBadge({ icon }: { icon: string }) {
+ const Icon = iconMap[icon]
+ return
+}
+
+
+```
+
+**Correct:**
+
+```tsx
+// Import from the project's configured iconLibrary (e.g. lucide-react, @tabler/icons-react).
+import { CheckIcon } from "lucide-react"
+
+function StatusBadge({ icon: Icon }: { icon: React.ComponentType }) {
+ return
+}
+
+
+```
diff --git a/skills/.curated/shadcn/references/rules/styling.md b/skills/.curated/shadcn/references/rules/styling.md
new file mode 100644
index 00000000..38d47321
--- /dev/null
+++ b/skills/.curated/shadcn/references/rules/styling.md
@@ -0,0 +1,162 @@
+# Styling & Customization
+
+See [customization.md](../customization.md) for theming, CSS variables, and adding custom colors.
+
+## Contents
+
+- Semantic colors
+- Built-in variants first
+- className for layout only
+- No space-x-* / space-y-*
+- Prefer size-* over w-* h-* when equal
+- Prefer truncate shorthand
+- No manual dark: color overrides
+- Use cn() for conditional classes
+- No manual z-index on overlay components
+
+---
+
+## Semantic colors
+
+**Incorrect:**
+
+```tsx
+
+ Secondary text
+
+```
+
+**Correct:**
+
+```tsx
+
+ Secondary text
+
+```
+
+---
+
+## No raw color values for status/state indicators
+
+For positive, negative, or status indicators, use Badge variants, semantic tokens like `text-destructive`, or define custom CSS variables — don't reach for raw Tailwind colors.
+
+**Incorrect:**
+
+```tsx
++20.1%
+Active
+-3.2%
+```
+
+**Correct:**
+
+```tsx
++20.1%
+Active
+-3.2%
+```
+
+If you need a success/positive color that doesn't exist as a semantic token, use a Badge variant or ask the user about adding a custom CSS variable to the theme (see [customization.md](../customization.md)).
+
+---
+
+## Built-in variants first
+
+**Incorrect:**
+
+```tsx
+
+```
+
+**Correct:**
+
+```tsx
+
+```
+
+---
+
+## className for layout only
+
+Use `className` for layout (e.g. `max-w-md`, `mx-auto`, `mt-4`), **not** for overriding component colors or typography. To change colors, use semantic tokens, built-in variants, or CSS variables.
+
+**Incorrect:**
+
+```tsx
+
+ Dashboard
+
+```
+
+**Correct:**
+
+```tsx
+
+ Dashboard
+
+```
+
+To customize a component's appearance, prefer these approaches in order:
+1. **Built-in variants** — `variant="outline"`, `variant="destructive"`, etc.
+2. **Semantic color tokens** — `bg-primary`, `text-muted-foreground`.
+3. **CSS variables** — define custom colors in the global CSS file (see [customization.md](../customization.md)).
+
+---
+
+## No space-x-* / space-y-*
+
+Use `gap-*` instead. `space-y-4` → `flex flex-col gap-4`. `space-x-2` → `flex gap-2`.
+
+```tsx
+
+
+
+
+
+```
+
+---
+
+## Prefer size-* over w-* h-* when equal
+
+`size-10` not `w-10 h-10`. Applies to icons, avatars, skeletons, etc.
+
+---
+
+## Prefer truncate shorthand
+
+`truncate` not `overflow-hidden text-ellipsis whitespace-nowrap`.
+
+---
+
+## No manual dark: color overrides
+
+Use semantic tokens — they handle light/dark via CSS variables. `bg-background text-foreground` not `bg-white dark:bg-gray-950`.
+
+---
+
+## Use cn() for conditional classes
+
+Use the `cn()` utility from the project for conditional or merged class names. Don't write manual ternaries in className strings.
+
+**Incorrect:**
+
+```tsx
+
+```
+
+**Correct:**
+
+```tsx
+import { cn } from "@/lib/utils"
+
+
+```
+
+---
+
+## No manual z-index on overlay components
+
+`Dialog`, `Sheet`, `Drawer`, `AlertDialog`, `DropdownMenu`, `Popover`, `Tooltip`, `HoverCard` handle their own stacking. Never add `z-50` or `z-[999]`.