Files

14 KiB

AI Code Generation Guidelines

For AI Assistants: This document contains strict rules for generating code in the PragmaStack project. Follow these rules to ensure generated code matches the design system perfectly.


🎯 Core Rules

ALWAYS Do

  1. Import from @/components/ui/*

    import { Button } from '@/components/ui/button';
    import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
    
  2. Use semantic color tokens

    className = 'bg-primary text-primary-foreground';
    className = 'text-destructive';
    className = 'bg-muted text-muted-foreground';
    
  3. Use cn() utility for className merging

    import { cn } from '@/lib/utils';
    
    className={cn("base-classes", conditional && "conditional-classes", className)}
    
  4. Follow spacing scale (multiples of 4: 0, 1, 2, 3, 4, 6, 8, 12, 16)

    className = 'p-4 space-y-6 mb-8';
    
  5. Add accessibility attributes

    <Label htmlFor="email">Email</Label>
    <Input
      id="email"
      aria-invalid={!!errors.email}
      aria-describedby={errors.email ? 'email-error' : undefined}
    />
    
  6. Use component variants

    <Button variant="destructive">Delete</Button>
    <Alert variant="destructive">Error message</Alert>
    
  7. Compose from shadcn/ui primitives

    // Don't create custom card components
    // Use Card + CardHeader + CardTitle + CardContent
    
  8. Use mobile-first responsive design

    className = 'text-2xl sm:text-3xl lg:text-4xl';
    className = 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3';
    

NEVER Do

  1. NO arbitrary colors

    // ❌ WRONG
    className = 'bg-blue-500 text-white';
    
    // ✅ CORRECT
    className = 'bg-primary text-primary-foreground';
    
  2. NO arbitrary spacing values

    // ❌ WRONG
    className = 'p-[13px] mb-[17px]';
    
    // ✅ CORRECT
    className = 'p-4 mb-4';
    
  3. NO inline styles

    // ❌ WRONG
    style={{ margin: '10px', color: '#3b82f6' }}
    
    // ✅ CORRECT
    className="m-4 text-primary"
    
  4. NO custom CSS classes (use Tailwind utilities)

    // ❌ WRONG
    <div className="my-custom-class">
    
    // ✅ CORRECT
    <div className="flex items-center justify-between p-4">
    
  5. NO mixing component libraries

    // ❌ WRONG - Don't use Material-UI, Ant Design, etc.
    import { Button } from '@mui/material';
    
    // ✅ CORRECT - Only shadcn/ui
    import { Button } from '@/components/ui/button';
    
  6. NO skipping accessibility

    // ❌ WRONG
    <button><X /></button>
    
    // ✅ CORRECT
    <Button size="icon" aria-label="Close">
      <X className="h-4 w-4" />
    </Button>
    
  7. NO creating custom variants without CVA

    // ❌ WRONG
    <Button className={type === 'danger' ? 'bg-red-500' : 'bg-blue-500'}>
    
    // ✅ CORRECT
    <Button variant="destructive">Delete</Button>
    

📐 Layout Patterns

Page Container

<div className="container mx-auto px-4 py-8">
  <div className="max-w-4xl mx-auto space-y-6">{/* Content */}</div>
</div>

Dashboard Grid

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  {items.map((item) => (
    <Card key={item.id}>...</Card>
  ))}
</div>

Form Layout

<Card className="max-w-md mx-auto">
  <CardHeader>
    <CardTitle>Form Title</CardTitle>
  </CardHeader>
  <CardContent>
    <form className="space-y-4">{/* Form fields */}</form>
  </CardContent>
</Card>

Centered Content

<div className="max-w-2xl mx-auto px-4">{/* Readable content width */}</div>

🧩 Component Templates

Custom Component Template

import { cn } from '@/lib/utils';
import { Card } from '@/components/ui/card';

interface MyComponentProps {
  variant?: 'default' | 'compact';
  className?: string;
  children: React.ReactNode;
}

export function MyComponent({ variant = 'default', className, children }: MyComponentProps) {
  return (
    <Card
      className={cn(
        'p-4', // base styles
        variant === 'compact' && 'p-2',
        className // allow overrides
      )}
    >
      {children}
    </Card>
  );
}

Component with CVA (class-variance-authority)

import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';

const componentVariants = cva(
  'base-classes-here', // base
  {
    variants: {
      variant: {
        default: 'bg-primary text-primary-foreground',
        destructive: 'bg-destructive text-destructive-foreground',
      },
      size: {
        sm: 'h-8 px-3 text-xs',
        default: 'h-10 px-4 text-sm',
        lg: 'h-12 px-6 text-base',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  }
);

interface ComponentProps
  extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof componentVariants> {}

export function Component({ variant, size, className, ...props }: ComponentProps) {
  return <div className={cn(componentVariants({ variant, size, className }))} {...props} />;
}

📝 Form Pattern Template

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Alert } from '@/components/ui/alert';

const formSchema = z.object({
  email: z.string().email('Invalid email address'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
});

type FormData = z.infer<typeof formSchema>;

export function MyForm() {
  const form = useForm<FormData>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      email: '',
      password: '',
    },
  });

  const onSubmit = async (data: FormData) => {
    // Handle submission
  };

  return (
    <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
      {/* Email Field */}
      <div className="space-y-2">
        <Label htmlFor="email">Email</Label>
        <Input
          id="email"
          type="email"
          {...form.register('email')}
          aria-invalid={!!form.formState.errors.email}
          aria-describedby={form.formState.errors.email ? 'email-error' : undefined}
        />
        {form.formState.errors.email && (
          <p id="email-error" className="text-sm text-destructive">
            {form.formState.errors.email.message}
          </p>
        )}
      </div>

      {/* Submit Button */}
      <Button type="submit" disabled={form.formState.isSubmitting}>
        {form.formState.isSubmitting ? 'Submitting...' : 'Submit'}
      </Button>
    </form>
  );
}

🎨 Color Token Reference

Always use these semantic tokens:

Token Usage
bg-primary text-primary-foreground Primary buttons, CTAs
bg-secondary text-secondary-foreground Secondary actions
bg-destructive text-destructive-foreground Delete, errors
bg-muted text-muted-foreground Disabled states
bg-accent text-accent-foreground Hover states
bg-card text-card-foreground Card backgrounds
text-foreground Body text
text-muted-foreground Secondary text
border-border Borders
ring-ring Focus rings

📏 Spacing Reference

Use these spacing values (multiples of 4px):

Class Value Pixels Usage
2 0.5rem 8px Tight spacing
4 1rem 16px Standard spacing
6 1.5rem 24px Section spacing
8 2rem 32px Large gaps
12 3rem 48px Section dividers
16 4rem 64px Page sections

🔑 Decision Trees

When to use Grid vs Flex?

Need equal-width columns? → Use Grid
  className="grid grid-cols-3 gap-6"

Need flexible item sizes? → Use Flex
  className="flex gap-4"

Need 2D layout (rows + columns)? → Use Grid
  className="grid grid-cols-2 grid-rows-3 gap-4"

Need 1D layout (single row OR column)? → Use Flex
  className="flex flex-col gap-4"

When to use Margin vs Padding?

Spacing between sibling elements? → Use gap or space-y
  className="flex gap-4"
  className="space-y-4"

Internal element spacing? → Use padding
  className="p-4"

External element spacing? → Avoid margins, use parent gap
  // ❌ Child with margin
  <div className="mb-4">

  // ✅ Parent with gap
  <div className="space-y-4">

🚨 Common Mistakes to Avoid

Mistake 1: Hardcoding colors

// ❌ WRONG
<div className="bg-red-500 text-white">Error</div>

// ✅ CORRECT
<Alert variant="destructive">Error message</Alert>

Mistake 2: Arbitrary spacing

// ❌ WRONG
<div className="p-[15px] mb-[23px]">

// ✅ CORRECT
<div className="p-4 mb-6">

Mistake 3: Missing accessibility

// ❌ WRONG
<input type="email" />

// ✅ CORRECT
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" />

Mistake 4: Creating custom components unnecessarily

// ❌ WRONG - Custom component for simple composition
function MyCard({ title, children }) {
  return <div className="card">{children}</div>;
}

// ✅ CORRECT - Use shadcn/ui primitives
<Card>
  <CardHeader>
    <CardTitle>{title}</CardTitle>
  </CardHeader>
  <CardContent>{children}</CardContent>
</Card>;

Mistake 5: Not using cn() utility

// ❌ WRONG
<div className={`base-class ${isActive ? 'active-class' : ''} ${className}`}>

// ✅ CORRECT
<div className={cn("base-class", isActive && "active-class", className)}>

📚 Reference Documentation

Before generating code, check these resources:

  1. Quick Start - Essential patterns
  2. Components - All shadcn/ui components
  3. Layouts - Layout patterns
  4. Spacing - Spacing rules
  5. Forms - Form patterns
  6. Reference - Quick lookup tables

Code Generation Checklist

Before outputting code, verify:

  • All imports from @/components/ui/*
  • Using semantic color tokens (no bg-blue-500)
  • Using spacing scale (multiples of 4)
  • Using cn() for className merging
  • Accessibility attributes included
  • Mobile-first responsive design
  • Composing from shadcn/ui primitives
  • Following established patterns from docs
  • No inline styles
  • No arbitrary values

🤖 AI Assistant Configuration

For Claude Code / Cursor

Add this to your project context:

When generating React/Next.js components:
1. Always import from @/components/ui/*
2. Use semantic tokens (bg-primary, text-destructive)
3. Use cn() utility for classNames
4. Follow spacing scale (4, 8, 12, 16, 24, 32)
5. Add accessibility (labels, ARIA)
6. Use component variants (variant="destructive")
7. Reference: /docs/design-system/08-ai-guidelines.md

For GitHub Copilot

Add to .github/copilot-instructions.md:

# Component Guidelines

- Import from @/components/ui/\*
- Use semantic colors: bg-primary, text-destructive
- Spacing: multiples of 4 (p-4, mb-6, gap-8)
- Use cn() for className merging
- Add accessibility attributes
- See /docs/design-system/08-ai-guidelines.md

📊 Examples

Good Component (AI Generated)

import { cn } from '@/lib/utils';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';

interface DashboardCardProps {
  title: string;
  value: string;
  trend?: 'up' | 'down';
  className?: string;
}

export function DashboardCard({ title, value, trend, className }: DashboardCardProps) {
  return (
    <Card className={cn('p-6', className)}>
      <CardHeader>
        <CardTitle className="text-sm font-medium text-muted-foreground">{title}</CardTitle>
      </CardHeader>
      <CardContent>
        <div className="text-2xl font-bold">{value}</div>
        {trend && (
          <p
            className={cn(
              'text-xs',
              trend === 'up' && 'text-green-600',
              trend === 'down' && 'text-destructive'
            )}
          >
            {trend === 'up' ? '↑' : '↓'} Trend
          </p>
        )}
      </CardContent>
    </Card>
  );
}

Why it's good:

  • Imports from @/components/ui/*
  • Uses semantic tokens
  • Uses cn() utility
  • Follows spacing scale
  • Composes from shadcn/ui primitives
  • TypeScript interfaces
  • Allows className override

🎓 Learning Path for AI

  1. Read Quick Start - Essential patterns
  2. Read this document - Rules and templates
  3. Reference Component Guide - All components
  4. Check Reference Tables - Token lookups

With these guidelines, you can generate code that perfectly matches the design system. Always prioritize consistency over creativity.


Last Updated: November 2, 2025 For AI Assistants: Follow these rules strictly for optimal code generation.