design-doctor
A configurable design-quality compiler for React UI — shadcn/ui, Tailwind v4, motion, design tokens, and accessibility. It scans a project, scores it, governs motion and token drift, and ships as an installable agent skill so AI assistants stop writing UI slop.
Not a prettier linter for Tailwind. It's a configurable design-quality compiler for React, shadcn/ui, Tailwind v4, motion, accessibility, and production SaaS UX.
Most tools catch broken code. Very few catch design entropy.
Linters tell you the code parses. They don't tell you a card hover is jittering your dashboard, that a status color skipped the token system, that a dialog is missing an accessible title, or that three files quietly drifted off the motion easing curve. That's the gap design-doctor lives in.
It owns the product-aware rules, a transparent scoring model, autofix safety, and reports — and it lints itself with its own internal rules. The whole point is to read like a serious open-source compiler with taste, not an AI that dumped regexes into a scripts folder.
Premium in a TTY, boring in CI.
A Bloomberg terminal that went to design school. Deterministic plain output when piped or in CI.
╭────────────────────────────────────────────────────────────╮ │ ◈ Design Doctor │ │ shadcn/ui + Tailwind v4 + motion + design-system scanner │ ╰────────────────────────────────────────────────────────────╯ UI Health 87/100 B+ Policy operator-console · compact · strict motion Files 214 scanned · 18 changed · 1.9s Scan lens tokens ███████████████████░ 94 a11y █████████████████░░░ 88 motion ███████████████░░░░░ 79 drift shadcn ██████████████████░░ 91 tailwind ███████████████████░ 96 data-ux ████████████████░░░░ 82 polish █████████████████░░░ 86 Critical fixes ✖ motion/no-transition-all src/components/card.tsx:44:12 Use named transition properties with global motion tokens. ✖ shadcn/dialog-title-required src/features/orders/ApproveOrderDialog.tsx:31:4 DialogContent must include a DialogTitle (or visually hidden title). Best next move → design-doctor fix --safe → design-doctor explain motion/no-transition-all
A transparent, configurable, PR-delta-aware score.
100 points across seven weighted categories. Fails on regressions in changed files, not on legacy warnings.
Opinions with receipts.
Motion governance
Enforces duration/easing tokens, press-scale, reduced-motion, and a hard "no card hover movement" rule. Catches motion-design entropy almost nothing else does.
Contrast role-ranges
Beyond WCAG floors: defines an intended hierarchy range per role pair, flagging "too low" separately from "outside intended range."
Installable skill
npx design-doctor install-skill drops a compact SKILL.md + references so Codex/Cursor/Claude follow the project's design policy before and after editing UI.
PR-delta action
GitHub Action with sticky PR comment, score/grade outputs, inline review comments, and "fail on regression" — so teams don't hate it by day two.
Fixture-heavy & self-linting
Every rule needs docs, config schema, score impact, and pass/fail fixtures. There's an internal ESLint plugin that lints the linter.
Suppression hygiene
Disables require a reason and an expiry date — no broad file-level silencing, no expired suppressions left rotting in the codebase.
Every rule is typed, documented, and scored.
export const noCardHoverMovement = createRule({ id: "motion/no-card-hover-movement", category: "motion", defaultSeverity: "error", meta: { rationale: "Card hover movement creates spatial noise in dense UIs.", autofix: "none", // requires design judgment subjective: true, }, schema: z.object({ allowedFeedback: z.array(z.enum(["border","shadow","tint","focus-ring"])), }), create(ctx) { return { CssRule(rule) { /* flag translate/scale/float on :hover */ } }; }, });
design-doctor is in active development and is not public yet. The current scope includes the monorepo scaffold, core engine, scoring, rule packs, agent skill, and GitHub Action; the intended public boundary is the tool, its rule catalog, recipes, and before/after fixtures. Want to compare notes on design tooling? Reach out →