Loading...
Loading...
Weekly AI insights —
Real strategies, no fluff. Unsubscribe anytime.
Written by Gareth Simono, Founder and CEO of Agentik {OS}. Full-stack developer and AI architect with years of experience shipping production applications across SaaS, mobile, and enterprise platforms. Gareth orchestrates 267 specialized AI agents to deliver production software 10x faster than traditional development teams.
Founder & CEO, Agentik {OS}
Design systems take months to build right. With AI and shadcn/ui as a foundation, you can ship a consistent, documented system in days. Here's how.

Design systems are one of those investments that teams defer indefinitely. The ROI is real but delayed. The cost is immediate. And every time you try to start, you end up arguing about button border radius while shipping features feels more urgent.
AI changes this calculus completely. What used to take a dedicated designer-developer duo two to three months can now be done in three to five days, and with genuinely better documentation than most teams produce manually.
Here's the approach that works.
The mistake most teams make: trying to build a design system from scratch. Custom component library. Custom design tokens. Custom everything.
The right approach: build on shadcn/ui as the primitive layer, customize the theme and extend with your specific components. This gives you:
Your design system is the layer of customization, extension, and documentation on top of this foundation.
With Tailwind CSS v4, theme configuration moves to CSS:
/* app/globals.css */
@import "tailwindcss";
@theme {
/* Color scale using oklch for perceptually uniform colors */
--color-primary: oklch(0.45 0.15 250);
--color-primary-foreground: oklch(0.98 0 0);
--color-secondary: oklch(0.96 0.02 250);
--color-secondary-foreground: oklch(0.15 0.02 250);
--color-muted: oklch(0.96 0.01 250);
--color-muted-foreground: oklch(0.55 0.02 250);
--color-accent: oklch(0.96 0.02 250);
--color-accent-foreground: oklch(0.15 0.02 250);
--color-destructive: oklch(0.52 0.22 29);
--color-destructive-foreground: oklch(0.98 0 0);
--color-border: oklch(0.90 0.01 250);
--color-input: oklch(0.90 0.01 250);
--color-ring: oklch(0.45 0.15 250);
--color-background: oklch(1 0 0);
--color-foreground: oklch(0.09 0.01 250);
--color-card: oklch(1 0 0);
--color-card-foreground: oklch(0.09 0.01 250);
--color-popover: oklch(1 0 0);
--color-popover-foreground: oklch(0.09 0.01 250);
/* Border radius */
--radius: 0.5rem;
/* Font families */
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
}
/* Dark mode overrides */
@media (prefers-color-scheme: dark) {
:root {
--color-background: oklch(0.09 0.01 250);
--color-foreground: oklch(0.98 0 0);
--color-card: oklch(0.13 0.01 250);
--color-card-foreground: oklch(0.98 0 0);
--color-border: oklch(0.22 0.01 250);
--color-muted: oklch(0.22 0.01 250);
--color-muted-foreground: oklch(0.65 0.02 250);
}
}Beyond shadcn/ui primitives, you'll have components specific to your product. Here's how to build them consistently.
Every custom component follows this structure:
// components/ui/stat-card.tsx
import { Card, CardContent } from "@/components/ui/card";
import { cn } from "@/lib/utils";
import { LucideIcon } from "lucide-react";
export interface StatCardProps {
title: string;
value: string | number;
description?: string;
icon?: LucideIcon;
trend?: {
value: number;
label: string;
direction: "up" | "down" | "neutral";
};
className?: string;
}
export function StatCard({
title,
value,
description,
icon: Icon,
trend,
className,
}: StatCardProps) {
return (
<Card className={cn("", className)}>
<CardContent className="flex items-center justify-between">
<div className="space-y-1">
<p className="text-sm font-medium text-muted-foreground">{title}</p>
<p className="text-2xl font-bold">{value}</p>
{description && (
<p className="text-xs text-muted-foreground">{description}</p>
)}
{trend && (
<div className="flex items-center gap-1 text-xs">
<span
className={cn(
"font-medium",
trend.direction === "up" && "text-green-600",
trend.direction === "down" && "text-red-600",
trend.direction === "neutral" && "text-muted-foreground"
)}
>
{trend.direction === "up" ? "+" : trend.direction === "down" ? "-" : ""}
{Math.abs(trend.value)}%
</span>
<span className="text-muted-foreground">{trend.label}</span>
</div>
)}
</div>
{Icon && (
<div className="rounded-md bg-primary/10 p-3">
<Icon className="h-5 w-5 text-primary" />
</div>
)}
</CardContent>
</Card>
);
}This is where AI provides the most dramatic value. Documentation is the part everyone skips. AI makes it effortless.
For each component, Claude generates:
Here's the prompt pattern that works:
// scripts/generate-docs.ts
import Anthropic from "@anthropic-ai/sdk";
import * as fs from "fs/promises";
import * as path from "path";
const anthropic = new Anthropic();
async function generateComponentDocs(componentPath: string): Promise<void> {
const componentCode = await fs.readFile(componentPath, "utf-8");
const componentName = path.basename(componentPath, ".tsx");
const response = await anthropic.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 2048,
messages: [
{
role: "user",
content: `Generate comprehensive documentation for this React component.
Include:
1. Brief description (1-2 sentences)
2. Props table (name, type, required, default, description)
3. Three usage examples (basic, with optional props, edge case)
4. Accessibility notes
5. When to use / when not to use
Format as MDX. The component:
${componentCode}`,
},
],
});
const docsContent = response.content[0].type === "text" ? response.content[0].text : "";
const docsPath = componentPath.replace("/ui/", "/docs/").replace(".tsx", ".mdx");
await fs.mkdir(path.dirname(docsPath), { recursive: true });
await fs.writeFile(docsPath, docsContent);
console.log(`Generated docs for ${componentName}`);
}
// Run for all components
async function generateAllDocs() {
const componentsDir = "./components/ui";
const files = await fs.readdir(componentsDir);
const componentFiles = files.filter(f => f.endsWith(".tsx"));
for (const file of componentFiles) {
await generateComponentDocs(path.join(componentsDir, file));
await new Promise(resolve => setTimeout(resolve, 1000)); // Rate limiting
}
}
generateAllDocs().catch(console.error);Document your token system so every developer on your team uses it consistently:
// tokens.ts - The reference document
export const tokens = {
colors: {
primary: "oklch(0.45 0.15 250)",
// Used for: Primary CTAs, links, selected states
// Avoid: Decorative use, icons that aren't interactive
muted: "oklch(0.55 0.02 250)",
// Used for: Secondary text, placeholders, metadata
// Avoid: Body text, headings
destructive: "oklch(0.52 0.22 29)",
// Used for: Delete actions, error states, warnings
// Avoid: Non-destructive actions, decorative red
},
spacing: {
// Use Tailwind spacing scale directly
// Component padding: p-6 (24px)
// Section gaps: gap-8 (32px)
// Page sections: py-16 sm:py-24 (64px / 96px)
},
typography: {
h1: "text-4xl font-bold tracking-tight",
h2: "text-3xl font-semibold tracking-tight",
h3: "text-2xl font-semibold",
h4: "text-xl font-semibold",
body: "text-base leading-7",
small: "text-sm text-muted-foreground",
code: "font-mono text-sm bg-muted px-1.5 py-0.5 rounded",
},
} as const;For teams, Storybook provides a living component library:
npx storybook@latest initAI can generate stories for each component:
// components/ui/stat-card.stories.tsx
import type { Meta, StoryObj } from "@storybook/react";
import { TrendingUp, TrendingDown, Users } from "lucide-react";
import { StatCard } from "./stat-card";
const meta: Meta<typeof StatCard> = {
component: StatCard,
tags: ["autodocs"],
};
export default meta;
type Story = StoryObj<typeof StatCard>;
export const Basic: Story = {
args: {
title: "Total Revenue",
value: "$45,231.89",
},
};
export const WithTrend: Story = {
args: {
title: "Active Users",
value: "2,350",
description: "Last 30 days",
icon: Users,
trend: {
value: 20.1,
label: "from last month",
direction: "up",
},
},
};The first component you document properly takes time. The second takes less. By the tenth, the process is fast and the documentation quality is consistent.
The real value of a design system isn't in any individual component. It's in the consistency and speed it enables across your entire product. When every developer knows which component to reach for and how it should look, design decisions stop being individual negotiations and start being systematic applications of shared standards.
AI makes the investment required to reach that state dramatically smaller.
Q: How do you create a design system with AI?
Create an AI-assisted design system by defining design tokens (colors, spacing, typography) in CSS custom properties, generating a component library with consistent patterns using AI agents, implementing light and dark themes through token switching, and documenting components with usage examples. AI generates consistent variants from your token definitions.
Q: What are the components of a good design system?
A good design system includes design tokens (colors, spacing, typography, shadows), a component library (buttons, forms, cards, navigation), layout patterns (grids, containers, responsive breakpoints), documentation with usage examples, and accessibility compliance built into every component. AI agents maintain consistency across all components.
Q: How does AI help maintain design system consistency?
AI agents maintain consistency by always referencing the same design tokens, generating new components that match existing patterns, catching inconsistencies during code review, and applying the same accessibility standards across all components. This is where AI excels — applying rules consistently across large codebases without fatigue.
Full-stack developer and AI architect with years of experience shipping production applications across SaaS, mobile, and enterprise. Gareth built Agentik {OS} to prove that one person with the right AI system can outperform an entire traditional development team. He has personally architected and shipped 7+ production applications using AI-first workflows.

How I Built a SaaS in 19 Days with AI (Build Log)
One person. AI doing 70% of the coding. A fully functional SaaS with paying customers in 19 days. Here's the exact process, decisions, and mistakes.

Automated Testing: The Stack That Won't Slow You
Testing setups that make developers slow are abandoned. Here's the fast, modern testing stack for Next.js apps that actually gets used and maintained.

Deploying to Vercel: A Real Production Checklist
Vercel deploys are easy until they're not. Env vars missing, build errors in prod only. Here's the production checklist to get it right.
Stop reading about AI and start building with it. Book a free discovery call and see how AI agents can accelerate your business.