The 75 is real, but read it carefully: the tiles are green because shadcn carries them. All 61 colours are oklch tokens with zero hex strays — the token architecture is doing its job, and the score credits it. What the score can only partly price is where this repo's mess actually lives: 103 arbitrary bracket values punched through the Tailwind scale. [13px] alone appears 26 times, led by components/chat/sidebar-user-nav.tsx, with [10px], [0.12em] and [3px] close behind. Each one is a precedent: an agent reading this code learns that when the scale doesn't fit, you punch through it.
The quieter finding is worse: the agent rules are stale. .cursor/rules/ultracite.mdc references pages/_document.jsx and pages/_document.js — files this scan cannot find, remnants of a pages-router past in an app-router repo. A rule the agent obeys is worse than no rule when the repo has moved on.
The component layer is disciplined at the top and fraying at the edges: MessageActions is defined in two files, and the button family has grown six members — Button, SubmitButton, ArtifactCloseButton, CodeBlockCopyButton, ConversationScrollButton, PromptInputButton. Most are legitimate specialisations, but nothing in the repo says which are canonical, so the next agent adds a seventh.
The fix, calmly: the bracket values are decisions without names. [13px] used 26 times is a font-size step this design wants and the scale doesn't have — add the step, then fold the brackets in as files get touched. Delete the two dead references from ultracite.mdc today; it is a two-line fix and the cheapest win on this page. And one line in the rules naming Button as the base others wrap would close the family to accidental growth.
One tweak · 75 → 80
so you get a present.
## Design system rules
<!-- Generated by roast-my-design-system from a scan of vercel/ai-chatbot on 2026-08-22.
Paste into CLAUDE.md, .cursor/rules or AGENTS.md. Regenerate after big refactors:
npx roast-my-design-system --rules -->
Follow these rules when writing or editing UI in this repo. Every rule below was derived from a scan of this codebase, with real paths and usage counts.
### Colours and tokens
- Design tokens live in `app/globals.css`. Reach for an existing token before inventing any value.
- Never hardcode colour values in components. The palette already has 49 tokens; the scan still found 12 hardcoded colours sitting next to them. Do not add more.
- This repo uses shadcn/ui; its components live in `components/ui`. Prefer extending it over building parallel pieces.
### Canonical components
- Use these existing components instead of writing new ones, the way this repo already uses them:
- `<Button>` from `components/ui/button.tsx` (used 25x · props: variant, size, asChild)
- `<Tooltip>` from `components/ui/tooltip.tsx` (used 10x)
- most common usage, as in `components/ai-elements/message.tsx` (matching 8 of 10 usages): `<Tooltip>…</Tooltip>`
- `<TooltipContent>` from `components/ui/tooltip.tsx` (used 10x · props: sideOffset)
- `<TooltipTrigger>` from `components/ui/tooltip.tsx` (used 10x)
- most common usage, as in `components/ai-elements/message.tsx` (matching 10 of 10 usages): `<TooltipTrigger asChild>…</TooltipTrigger>`
- `<DropdownMenuItem>` from `components/ui/dropdown-menu.tsx` (used 8x · props: inset, variant)
- `<LoaderIcon>` from `components/chat/icons.tsx` (used 8x · props: size)
- most common usage, as in `components/chat/document.tsx` (matching 5 of 8 usages): `<LoaderIcon />`
- `<SidebarMenuButton>` from `components/ui/sidebar.tsx` (used 7x · props: asChild, isActive, variant, size)
- `<CopyIcon>` from `components/chat/icons.tsx` (used 6x · props: size)
- most common usage, as in `artifacts/code/client.tsx` (matching 3 of 6 usages): `<CopyIcon size={18} />`
### Known duplicates: do not make it worse
- `<MessageActions>` is defined twice and one wraps the other; do not create a third.
### Spacing and sizing
- Stay on the Tailwind spacing scale. If a gap looks wrong on a scale step, flag it instead of nudging by a pixel.
- No new arbitrary bracket values (`p-[13px]`, `text-[10px]`). The scan found 103 already. If a value repeats, it is a decision: name it as a token instead of writing the bracket again.
- Avoid new one-off CSS spacing values; 2 off-scale values are already in play.
### Typography
- The repo uses 3 typefaces: SF Mono, Geist, Geist Mono. Do not introduce another, and do not re-declare font stacks by hand; use the existing setup.
### Styling discipline
- Never write `style={{ ... }}` for static values; styling belongs to classes and tokens where the system can see it.
(7 static inline blocks already exist; do not add to them.)
- Never write !important; the scan found 9 declarations already. When a style does not apply, fix the selector or the source of the conflict instead of shouting over it.
- Before styling anything new, look at a neighbouring component and match how it does it. Consistency with the repo beats personal preference.
---
*Generated by [roast-my-design-system](https://github.com/gregkozakiewicz/roast-my-design-system) ver. 5.2.1. Rescan after refactors to keep these rules honest.*
Your agent reads .cursor/rules. But none of it points at a single source of truth for components and tokens, because there isn't one yet. The numbers below are what your agent actually works from.
Rules rot quietly: nobody edits them when a component is renamed or a file moves. Regenerate them from a fresh scan, or fix the lines by hand.
A healthy product palette is up to ~24 colours: one brand hue with a few tints, one accent, up to 13 greys, and status colours.
a disciplined repo keeps these around a dozen · on-scale Tailwind steps (·) shown for context · off-scale in coral
every distinct declaration is a chance for the next one to be wrong
the 5 files carrying the most off-system styling
an agent asking which one is canonical gets several plausible answers. Paths open in VS Code
styling no system can see
315 components defined · top by adoption · the real system, buried in here
| component | used | defined in | props |
|---|---|---|---|
| <Button> | 25× | components/ui/button.tsx | variant size asChild |
| <Tooltip> | 10× | components/ui/tooltip.tsx | none |
| <TooltipContent> | 10× | components/ui/tooltip.tsx | sideOffset |
| <TooltipTrigger> | 10× | components/ui/tooltip.tsx | none |
| <DropdownMenuItem> | 8× | components/ui/dropdown-menu.tsx | inset variant |
| <LoaderIcon> | 8× | components/chat/icons.tsx | size |
| <SidebarMenuButton> | 7× | components/ui/sidebar.tsx | asChild isActive variant size tooltip |
| <CopyIcon> | 6× | components/chat/icons.tsx | size |
| <SparklesIcon> | 6× | components/chat/icons.tsx | size |
| <ChatItem> | 5× | components/chat/sidebar-history-item.tsx | PureChatItem prevProps |