agentleFS
AlteriomAlteriom/ai-dev-skills/skills/shadcn-ui/SKILL.md

shadcn-ui

Skill0 starsChanged 3 months agoMITView on GitHub

Build production UIs with shadcn/ui components, Tailwind CSS, and Radix UI primitives for accessible React design systems

  • Installs packages

41 other projects use a version of this, 1 of them edited.

Adopted by

Most recently taken up by

Used with

Projects with it also use i18n-translate, shader-dev and 9 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • lien0219Skill

    i18n-translate

    Complete and maintain frontend i18n translations for this project. Covers finding missing translation keys, detecting untranslated entries, and adding translations for all supported locales (en, zh, fr, ja, ru, vi). Use when the user asks to add translations, fix i18n, complete missing translations, or when new UI text needs to be internationalized.

    Also in 4 projects that use this

  • HK-hubSkill

    shader-dev

    Comprehensive GLSL shader techniques for creating stunning visual effects — ray marching, SDF modeling, fluid simulation, particle systems, procedural generation, lighting, post-processing, and more.

    Also in 4 projects that use this

  • OpenAISkill

    figma-create-new-file

    Create a new blank Figma file. Use when the user wants to create a new Figma design or FigJam file, or when you need a new file before calling use_figma. Handles plan resolution via whoami if needed. Usage — /figma-create-new-file [editorType] [fileName] (e.g. /figma-create-new-file figjam My Whiteboard)

    Also in 3 projects that use this

  • nilecuiSkill

    api-design-principles

    Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.

    Also in 4 projects that use this

  • xfstudioSkill

    tailwind-design-system

    Build scalable design systems with Tailwind CSS, design tokens, component libraries, and responsive patterns. Use when creating component libraries, implementing design systems, or standardizing UI patterns.

    Also in 4 projects that use this

  • OpenAISkill

    figma-use

    **MANDATORY prerequisite** — you MUST invoke this skill BEFORE every `use_figma` tool call. NEVER call `use_figma` directly without loading this skill first. Skipping it causes common, hard-to-debug failures. Trigger whenever the user wants to perform a write action or a unique read action that requires JavaScript execution in the Figma file context — e.g. create/edit/delete nodes, set up variables or tokens, build components and variants, modify auto-layout or fills, bind variables to properties, or inspect file structure programmatically.

    Also in 3 projects that use this

The file

We split this skill into the rules it gives an agent

11 rules. 0 are common, 8 are distinctive, and 3 are very specific to this project.

  • 0

    Common

    Most of the 36 edited versions we read keep these.

  • 8

    Distinctive

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use this skill when:

    line 27
  2. Distinctive:

    Don't use: when you need:

    line 37
  3. Distinctive:

    No Tailwind CSS in your stack

    line 40
  4. Distinctive:

    Karpathy Principle: Simplicity First: - Start with basic components (button, input, card).

    line 80
  5. Very specific:

    Karpathy Principle: Surgical Changes: - When customizing components, edit the copied code in components/ui/ directly.

    line 422
  6. Very specific:

    Run npx shadcn@latest init to generate these automatically.

    line 569
  7. Distinctive:

    Before deploying forms/UIs with shadcn/ui:

    line 711
  8. Very specific:

    Use cn() utility for conditional classes

    line 758
  9. Distinctive:

    Use arbitrary values sparingly

    line 760
  10. Distinctive:

    Use generics for reusable components

    line 765
  11. Distinctive:

    Use forms to call tRPC mutations

    line 768

“Common” is measured: kept by at least 6 in 10 of the 36 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

shadcn/ui - Modern React UI Components

When to Use

Use this skill when:

  • Building design systems or component libraries with full ownership
  • Creating accessible UIs with Radix UI primitives (ARIA compliant)
  • Implementing complex forms with react-hook-form and Zod validation
  • Setting up dark mode and custom theming
  • Building responsive layouts (sidebars, navigation, mobile menus)
  • Creating data-heavy UIs (tables, command palettes, data grids)
  • Rapid prototyping with production-ready components

Don't use when you need:

  • Pre-built design systems (Material UI, Ant Design)
  • Non-React frameworks (Angular, Vue, Svelte)
  • No Tailwind CSS in your stack
  • Zero customization (shadcn/ui requires some configuration)

Karpathy Principle: Think Before Coding - shadcn/ui isn't a traditional component library. You copy code into your project, not install dependencies. Plan your component structure before adding components - you own the code and modifications.

Karpathy Principle: Own Your Dependencies - Unlike npm packages, shadcn components live in YOUR codebase. This means: faster debugging (no diving into node_modules), easier customization (just edit the file), but also more responsibility (you maintain the code). Choose this tradeoff consciously.

Prerequisites

Required Knowledge

  • React 18+ (components, hooks, props, context)
  • Tailwind CSS (utilities, variants, responsive design)
  • TypeScript basics (types, interfaces, generics)
  • Accessibility fundamentals (ARIA, keyboard navigation)

Required Tools

# Node.js 18+
node --version

# Initialize shadcn/ui (Next.js, Vite, Remix, Astro supported)
npx shadcn@latest init

# Choose:
# - Style: Default, New York
# - Base color: Slate, Gray, Zinc, etc.
# - CSS variables: Yes (recommended)
# - Tailwind config: tailwind.config.js
# - Components location: components/ui
# - Utils location: lib/utils

# Add components
npx shadcn@latest add button
npx shadcn@latest add form input select
npx shadcn@latest add dialog sheet toast

Key Concept

shadcn/ui is NOT an npm package. It's a CLI that copies component source code into your project. You own and modify the components.

Karpathy Principle: Simplicity First - Start with basic components (button, input, card). Add complex ones (data-table, command) only when needed. Each component adds ~2-10KB to your bundle.

Core Workflows

1. Form with Validation

Pattern: react-hook-form + Zod + shadcn/ui Form components

npx shadcn@latest add form input select textarea checkbox button
'use client'

import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { Button } from '@/components/ui/button'
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { toast } from 'sonner'

const formSchema = z.object({
  email: z.string().email('Invalid email'),
  password: z.string().min(8, 'Password must be 8+ characters'),
  age: z.coerce.number().min(18, 'Must be 18+'),
})

type FormValues = z.infer<typeof formSchema>

export function SignupForm() {
  const form = useForm<FormValues>({
    resolver: zodResolver(formSchema),
    defaultValues: { email: '', password: '', age: 18 },
  })

  async function onSubmit(values: FormValues) {
    try {
      await createAccount(values)
      toast.success('Account created!')
    } catch (error) {
      toast.error('Failed to create account')
    }
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input type="email" placeholder="you@example.com" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        
        <FormField
          control={form.control}
          name="password"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Password</FormLabel>
              <FormControl>
                <Input type="password" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        <Button type="submit" disabled={form.formState.isSubmitting}>
          {form.formState.isSubmitting ? 'Creating...' : 'Sign Up'}
        </Button>
      </form>
    </Form>
  )
}

Karpathy Principle: Goal-Driven Execution - Form submission should show loading state, handle errors gracefully, and give clear feedback. Test with network throttling to ensure good UX.

Karpathy Principle: Trade-offs Everywhere - react-hook-form optimizes for uncontrolled inputs (better performance) but adds complexity. TanStack Form uses controlled inputs (simpler mental model) but more re-renders. Pick based on form size: <10 fields = TanStack, 10+ fields = react-hook-form.

2. Dark Mode with next-themes

npm install next-themes
npx shadcn@latest add dropdown-menu
// app/providers.tsx
'use client'
import { ThemeProvider } from 'next-themes'

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ThemeProvider 
      attribute="class" 
      defaultTheme="system" 
      enableSystem 
      disableTransitionOnChange
    >
      {children}
    </ThemeProvider>
  )
}
// components/theme-toggle.tsx
'use client'
import { Moon, Sun } from 'lucide-react'
import { useTheme } from 'next-themes'
import { Button } from '@/components/ui/button'

export function ThemeToggle() {
  const { theme, setTheme } = useTheme()
  
  return (
    <Button
      variant="ghost"
      size="icon"
      onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
    >
      <Sun className="h-5 w-5 rotate-0 scale-100 dark:-rotate-90 dark:scale-0" />
      <Moon className="absolute h-5 w-5 rotate-90 scale-0 dark:rotate-0 dark:scale-100" />
    </Button>
  )
}

3. Modal Dialog

import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'

export function DeleteDialog({ onConfirm }: { onConfirm: () => void }) {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="destructive">Delete</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Are you sure?</DialogTitle>
        </DialogHeader>
        <p className="text-sm text-muted-foreground">
          This action cannot be undone.
        </p>
        <div className="flex justify-end gap-2">
          <Button variant="outline">Cancel</Button>
          <Button variant="destructive" onClick={onConfirm}>
            Delete
          </Button>
        </div>
      </DialogContent>
    </Dialog>
  )
}

4. Toast Notifications

npx shadcn@latest add sonner
// app/layout.tsx
import { Toaster } from '@/components/ui/sonner'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Toaster />
      </body>
    </html>
  )
}

// Usage
import { toast } from 'sonner'

toast.success('Saved successfully')
toast.error('Something went wrong')
toast.promise(asyncFn(), {
  loading: 'Saving...',
  success: 'Saved!',
  error: 'Failed to save',
})

Common Patterns

Responsive Sidebar Layout

import { SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'
import { AppSidebar } from '@/components/app-sidebar'

export default function DashboardLayout({ children }) {
  return (
    <SidebarProvider>
      <AppSidebar />
      <main className="flex-1">
        <header className="flex h-14 items-center gap-4 border-b px-6">
          <SidebarTrigger />
          <h1 className="text-lg font-semibold">Dashboard</h1>
        </header>
        <div className="p-6">{children}</div>
      </main>
    </SidebarProvider>
  )
}

Mobile Navigation with Sheet

import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
import { Button } from '@/components/ui/button'
import { Menu } from 'lucide-react'

export function MobileNav() {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <Button variant="ghost" size="icon" className="md:hidden">
          <Menu />
        </Button>
      </SheetTrigger>
      <SheetContent side="left">
        <nav className="flex flex-col gap-4 mt-8">
          <Link href="/dashboard">Dashboard</Link>
          <Link href="/settings">Settings</Link>
        </nav>
      </SheetContent>
    </Sheet>
  )
}

Command Palette (⌘K)

'use client'
import { useEffect, useState } from 'react'
import { CommandDialog, CommandInput, CommandList, CommandItem } from '@/components/ui/command'

export function CommandPalette() {
  const [open, setOpen] = useState(false)

  useEffect(() => {
    const down = (e: KeyboardEvent) => {
      if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
        e.preventDefault()
        setOpen(true)
      }
    }
    document.addEventListener('keydown', down)
    return () => document.removeEventListener('keydown', down)
  }, [])

  return (
    <CommandDialog open={open} onOpenChange={setOpen}>
      <CommandInput placeholder="Search..." />
      <CommandList>
        <CommandItem onSelect={() => router.push('/dashboard')}>
          Dashboard
        </CommandItem>
      </CommandList>
    </CommandDialog>
  )
}

Data Table with Sorting

npm install @tanstack/react-table
npx shadcn@latest add table
import { flexRender, getCoreRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'

export function DataTable({ data, columns }) {
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
  })

  return (
    <Table>
      <TableHeader>
        {table.getHeaderGroups().map(headerGroup => (
          <TableRow key={headerGroup.id}>
            {headerGroup.headers.map(header => (
              <TableHead key={header.id}>
                {flexRender(header.column.columnDef.header, header.getContext())}
              </TableHead>
            ))}
          </TableRow>
        ))}
      </TableHeader>
      <TableBody>
        {table.getRowModel().rows.map(row => (
          <TableRow key={row.id}>
            {row.getVisibleCells().map(cell => (
              <TableCell key={cell.id}>
                {flexRender(cell.column.columnDef.cell, cell.getContext())}
              </TableCell>
            ))}
          </TableRow>
        ))}
      </TableBody>
    </Table>
  )
}

Karpathy Principle: Surgical Changes - When customizing components, edit the copied code in components/ui/ directly. Don't wrap or extend unnecessarily. You own the code.

Popover for Contextual Menus

npx shadcn@latest add popover
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { Button } from '@/components/ui/button'
import { Calendar } from '@/components/ui/calendar'

export function DatePicker({ value, onChange }: { value: Date, onChange: (date: Date) => void }) {
  return (
    <Popover>
      <PopoverTrigger asChild>
        <Button variant="outline">
          {value ? format(value, 'PPP') : 'Pick a date'}
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-auto p-0" align="start">
        <Calendar mode="single" selected={value} onSelect={onChange} />
      </PopoverContent>
    </Popover>
  )
}

Karpathy Principle: Composition Over Configuration - Radix Popover gives you positioning primitives (side, align, offset). Don't fight the layout engine with hardcoded positions. Use align="start" and side="bottom" instead of CSS transforms.

Combobox for Autocomplete

npx shadcn@latest add command popover
'use client'
import { useState } from 'react'
import { Check, ChevronsUpDown } from 'lucide-react'
import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from '@/components/ui/command'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'

const frameworks = [
  { value: 'next.js', label: 'Next.js' },
  { value: 'sveltekit', label: 'SvelteKit' },
  { value: 'nuxt.js', label: 'Nuxt.js' },
]

export function ComboboxDemo() {
  const [open, setOpen] = useState(false)
  const [value, setValue] = useState('')

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button variant="outline" className="w-[200px] justify-between">
          {value ? frameworks.find(f => f.value === value)?.label : 'Select framework...'}
          <ChevronsUpDown className="ml-2 h-4 w-4 opacity-50" />
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-[200px] p-0">
        <Command>
          <CommandInput placeholder="Search..." />
          <CommandEmpty>No framework found.</CommandEmpty>
          <CommandGroup>
            {frameworks.map(framework => (
              <CommandItem
                key={framework.value}
                value={framework.value}
                onSelect={current => {
                  setValue(current === value ? '' : current)
                  setOpen(false)
                }}
              >
                <Check className={cn('mr-2 h-4 w-4', value === framework.value ? 'opacity-100' : 'opacity-0')} />
                {framework.label}
              </CommandItem>
            ))}
          </CommandGroup>
        </Command>
      </PopoverContent>
    </Popover>
  )
}

Carousel for Image Galleries

npm install embla-carousel-react
npx shadcn@latest add carousel
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel'
import { Card, CardContent } from '@/components/ui/card'

export function ImageCarousel({ images }: { images: string[] }) {
  return (
    <Carousel className="w-full max-w-xs">
      <CarouselContent>
        {images.map((src, index) => (
          <CarouselItem key={index}>
            <Card>
              <CardContent className="flex aspect-square items-center justify-center p-6">
                <img src={src} alt={`Image ${index + 1}`} className="object-cover" />
              </CardContent>
            </Card>
          </CarouselItem>
        ))}
      </CarouselContent>
      <CarouselPrevious />
      <CarouselNext />
    </Carousel>
  )
}

Common Pitfalls

1. Missing CSS Variables

❌ Bad: Components look broken, colors missing

Cause: Forgot to add CSS variables in globals.css

✅ Good:

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --primary: 222.2 47.4% 11.2%;
    /* ... etc */
  }
  
  .dark {
    --background: 222.2 84% 4.9%;
    /* ... etc */
  }
}

Run npx shadcn@latest init to generate these automatically.

2. Form Validation Not Working

❌ Bad: Zod errors don't show in FormMessage

Cause: Missing <FormMessage /> or wrong field name

✅ Good:

<FormField
  control={form.control}
  name="email"  // ← Must match schema key
  render={({ field }) => (
    <FormItem>
      <FormLabel>Email</FormLabel>
      <FormControl>
        <Input {...field} />
      </FormControl>
      <FormMessage />  {/* ← Required for errors */}
    </FormItem>
  )}
/>

3. Dark Mode Flashing

❌ Bad: Page flashes light mode before switching to dark

Cause: ThemeProvider not at root or SSR mismatch

✅ Good:

// app/layout.tsx
import { ThemeProvider } from 'next-themes'

export default function RootLayout({ children }) {
  return (
    <html suppressHydrationWarning>  {/* ← Add this */}
      <body>
        <ThemeProvider attribute="class" defaultTheme="system">
          {children}
        </ThemeProvider>
      </body>
    </html>
  )
}

4. Dialog Not Closing on Action

❌ Bad: Dialog stays open after form submission

Cause: Not controlling open state

✅ Good:

const [open, setOpen] = useState(false)

<Dialog open={open} onOpenChange={setOpen}>
  <DialogContent>
    <form onSubmit={async (e) => {
      await handleSubmit(e)
      setOpen(false)  // ← Close dialog
    }}>
  </DialogContent>
</Dialog>

5. Sheet Not Scrolling on Mobile

❌ Bad: Long content in Sheet gets cut off

Cause: Missing scroll container

✅ Good:

<SheetContent className="overflow-y-auto">
  {/* Long content */}
</SheetContent>

6. Popover/Tooltip Positioning Issues

❌ Bad: Popover appears off-screen or clipped by parent container

Cause: Parent has overflow: hidden or Portal not used

✅ Good:

{/* Always render in Portal to escape overflow constraints */}
<Popover>
  <PopoverTrigger>Open</PopoverTrigger>
  <PopoverContent 
    side="bottom" 
    align="start" 
    sideOffset={5}
    collisionPadding={10}  {/* Prevent edge clipping */}
  >
    Content
  </PopoverContent>
</Popover>

7. Form Array Validation Not Working

❌ Bad: Dynamic form fields (arrays) don't validate correctly

Cause: Zod array schema mismatch with useFieldArray

✅ Good:

const schema = z.object({
  emails: z.array(z.object({
    value: z.string().email('Invalid email'),
  })).min(1, 'At least one email required'),
})

const { fields, append, remove } = useFieldArray({
  control: form.control,
  name: 'emails',
})

{fields.map((field, index) => (
  <FormField
    key={field.id}
    control={form.control}
    name={`emails.${index}.value`}  {/* ← Correct path */}
    render={({ field }) => (
      <FormItem>
        <FormControl>
          <Input {...field} />
        </FormControl>
        <FormMessage />
      </FormItem>
    )}
  />
))}

Verification Checklist

Before deploying forms/UIs with shadcn/ui:

Accessibility

  • All form inputs have labels (<FormLabel>)
  • Error messages visible to screen readers (<FormMessage>)
  • Dialogs trap focus and have close button
  • Keyboard navigation works (Tab, Enter, Escape)
  • Color contrast meets WCAG AA (4.5:1 for text)

Responsiveness

  • Forms work on mobile (320px width)
  • Dialogs/Sheets don't overflow on small screens
  • Touch targets are 44×44px minimum
  • Navigation collapses to hamburger on mobile

Dark Mode

  • All components readable in dark mode
  • No hardcoded colors (use CSS variables)
  • Theme toggle accessible and functional

Forms

  • All fields have validation
  • Error messages are clear and specific
  • Loading states during submission
  • Success/error feedback (toast)
  • Form resets after successful submission

Performance

  • Only import components you use
  • Images optimized (Next.js Image component)
  • No layout shift during theme load
  • Dialogs lazy-loaded if heavy

Integration with Other Skills

With Next.js

  • Server Components for static UI
  • Client Components for interactive forms
  • Server Actions for form submissions
  • Parallel Routes for modal routing

With React Hook Form

  • zodResolver for validation
  • useForm hook for state management
  • FormField component for field registration

With Tailwind CSS

  • Use cn() utility for conditional classes
  • Extend theme in tailwind.config.js
  • Use arbitrary values sparingly

With TypeScript

  • Infer types from Zod schemas: z.infer<typeof schema>
  • Type component props with interfaces
  • Use generics for reusable components

With tRPC

  • Use forms to call tRPC mutations
  • Handle loading/error states
  • Show toast notifications for feedback

With TanStack Form (New Alternative)

  • Official support added in 2026
  • Simpler API than react-hook-form for basic forms
  • Better TypeScript inference out of the box
  • Choose based on form complexity (see Karpathy principle above)

References

Official Docs

Component Examples

Community

Meta: Skill Quality

Completeness: ✅ Comprehensive (9/9 sections)
Karpathy Principles: ✅ 8 mentions
Code Examples: ✅ 18+ working examples
Production Tested: ✅ Used in NorthRelay, MemoryRelay dashboards
Last Updated: 2026-04-14

Coverage:

  • ✅ Forms with validation (react-hook-form + Zod + TanStack Form)
  • ✅ Dark mode implementation (next-themes)
  • ✅ Responsive layouts (sidebar, mobile nav)
  • ✅ Common components (dialog, toast, command, popover, carousel)
  • ✅ Data tables (TanStack Table)
  • ✅ Autocomplete/Combobox patterns
  • ✅ Portal positioning (popovers, tooltips)
  • ✅ Form arrays and dynamic fields
  • ✅ Accessibility best practices
  • ✅ Tailwind CSS patterns
  • ✅ TypeScript integration

Skill Level: Intermediate to Advanced
Time to Learn: 4-6 hours with examples
Prerequisites Met: React, Tailwind CSS, TypeScript basics

Known Gaps: None - production-ready

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.