UI Craft

August 9, 2026 · View on GitHub

Ship designer-grade UI by default. A design engineering system for AI coding agents — install it as a skill or as the ui-craft CLI, and your agent starts designing like it has taste. Ask for a dashboard, get one you'd put in production. Not gradient cards and bounce animations.

Website: skills.smoothui.dev

UI Craft

Ask for a surface. Ship it.

/craft dashboard

Three questions (or none — the defaults are strong), a named composition, a production theme preset, and a build that must pass a 10-item acceptance bar before it reports done: "would a designer retouch this?" If a box fails, it isn't done.

For everything else — reviews, animations, forms, polish — the skill routes by intent: just describe what you're building.

New here? Run /start — it reads your project (framework, tokens, brief, existing UI) and tells you what ui-craft can do right now, then points you at the right next step.

What it does

UI Craft gives AI coding agents the design knowledge they're missing. Not templates. Not component libraries. Actual craft knowledge — opinionated rules about how interfaces should look, move, and feel — plus the tooling to verify the result. Stack-agnostic by design.

Every UI gets tested against a single question: "Would someone believe AI made this?" If yes, it starts over.

The ladder — four rungs

There is one thing to learn, and it's a ladder. Each rung is a real jump in what you get, and each costs a little more than the one below. You only climb when you want the next thing.

RungYou wantYou doYou getEffort
0 · AskBetter UI with zero effortInstall, then ask for UI the way you always doReal hierarchy, your own tokens, no AI slop — same prompt, shippable resultnone
1 · DirectControl over one pass/craft, /critique, /polish, /animate, …A focused pass on one surface, aimed by youone command
2 · PersistConsistency across sessions/brief, /tokens, /rememberDurable design context every future session readswrite once
3 · EnforceProof it cannot regress/finalize, review agents, MCP gates, ui-craft-detectGates in review and CI, plus a deterministic 0-100 scorewire once

Start at rung 0. Most people never leave it — that's the point. Rungs 1 to 3 are there the day you want them, and /start will tell you which rung your project is on right now.

/sddesign is not a fifth rung. It's the express lane that walks rungs 1 to 3 in one guided run, for a single big surface.

What makes this different: the only AI design system that produces a scoreable, defensible critique — Nielsen's 10 usability heuristics × 6 classic design laws (Fitts, Hick, Doherty, Cleveland-McGill, Miller, Tesler) × 5 persona walkthroughs, with every finding tagged by business impact (blocks-conversion / adds-friction / reduces-trust / minor-polish). Paste the scorecard straight into any issue tracker.

Same prompt, different result

Without UI Craft
Hero built without UI Craft
With UI Craft
Hero built with UI Craft
Dashboard built without UI Craft Dashboard built with UI Craft

More before/after comparisons on the landing page.

Install

A single static Go binary that detects your AI coding harness and wires skill+commands, MCP gates, review agents, and design-memory into its native config in one interactive pass. No Node required at install time.

macOS / Linux:

curl -fsSL https://skills.smoothui.dev/install | bash

Windows:

irm https://skills.smoothui.dev/install.ps1 | iex

The script detects your OS/arch, downloads the latest release, verifies its checksum, and installs the ui-craft binary — no brew/scoop required.

Then run:

ui-craft install
Alternative installs (Homebrew, Scoop)

macOS (Homebrew):

brew install --cask educlopez/tap/ui-craft

Windows (Scoop):

scoop bucket add educlopez https://github.com/educlopez/scoop-bucket
scoop install educlopez/ui-craft

ui-craft install detects Claude Code / Cursor / Codex / Gemini / OpenCode, walks you through à-la-carte component selection (interactive TUI or --yes for CI), and writes each chosen component into that harness's native config. All writes are idempotent, backed up before they happen, and rolled back automatically on any failure.

What rides which install?

ComponentCLIClaude Code pluginnpx skills add
Skill + commandsAll harnessesAll harnesses
MCP gates (check_anti_slop, tokens_lint, acceptance_bar, score_ui)All MCP-capable harnesses✅ auto-wiredManual .mcp.json
Review agents (design-reviewer, a11y-auditor)Claude Code + OpenCode
Design memory (.ui-craft/)✅ (component opt-in)

Platform support

Six binaries ship on every release. They are not equally exercised, and the difference is worth knowing before you rely on one.

PlatformBinaryGo suite in CIInstaller end-to-endGatekeeper / fresh install
macOS Apple Silicon · darwin/arm64✅ by hand, every release
macOS Intel · darwin/amd64
Linux x86-64 · linux/amd64✅ Ubuntu · Fedora · Archn/a
Linux arm64 · linux/arm64n/a
Windows x86-64 · windows/amd64n/a
Windows arm64 · windows/arm64n/a

A dash means the binary is built and published but nothing runs on it. Those rows are honest gaps, not oversights we have quietly closed.

Windows has only been covered since v1.0.16. Before that the suite had never been green there, and five Windows-only bugs shipped as a result — one of them deleting files during rollback that it existed to protect. The suite now gates every pull request that touches the CLI.

macOS on Intel is the largest remaining gap: built and shipped, never tested, and not covered by the manual Gatekeeper check either — that one is Apple-Silicon-only.

Two conditions are untested on every platform: installing with the disk nearly full, and two ui-craft install runs racing against the same machine. See RELEASE_CHECKLIST.md for what each release actually verifies, and what a completed checklist does not promise.

Full reference docs: skills.smoothui.dev/docs.

Claude Code plugin — alternative (skill + commands + agents + MCP, no CLI needed)

One command installs the skill, all 25 slash commands, the 2 review agents, and the MCP quality-gate server — auto-wired, no .mcp.json editing:

/plugin marketplace add educlopez/ui-craft
/plugin install ui-craft

The plugin bundles a .mcp.json (npx -y ui-craft-mcp@0.8.3), so the deterministic gates register automatically on install. The exact package version is declared in distribution-manifest.json, avoiding an implicit upgrade on first launch. This uses Claude Code's own plugin system, so it's not affected by the global-path issue noted below.

Agent Skills — alternative (skill + commands only, any harness)

npx skills add educlopez/ui-craft

Warning

This installs the skill only — no slash commands beyond the ones mirrored as sub-skills, no review agents, no MCP gates, no hooks. For the full system (MCP quality gates, review agents, design memory), use the installer above.

Works with any agent that supports the Agent Skills spec. Each agent gets a pre-built mirror under a dedicated folder (.codex/, .cursor/, .gemini/, .opencode/, .agents/). The main ui-craft skill lands as a peer skill; each slash command is materialized as its own sub-skill in non-Claude harnesses (other agents trigger them by intent: "audit my UI", "polish this page").

Note

Using npx skills add -g with Claude Code? The skills CLI installs global skills to ~/.agents/skills, but Claude Code reads ~/.claude/skills (vercel-labs/skills#693). If the skill isn't picked up, use the CLI or plugin install above, install per-project (drop -g), or symlink it:

ln -s ~/.agents/skills/ui-craft ~/.claude/skills/ui-craft

Other ways

# Clone
git clone https://github.com/educlopez/ui-craft.git ~/.skills/ui-craft
# Git submodule
git submodule add https://github.com/educlopez/ui-craft.git .skills/ui-craft

CLI

The ui-craft binary is a single static Go binary (see Install above for the recommended install script, plus Homebrew/Scoop alternatives). It is the lifecycle and cross-harness wiring core for the system.

Run ui-craft with no arguments to open the interactive hub — a full-screen menu with an async update check that routes into install, upgrade, backups, and uninstall. Every subcommand below also works directly for scripting/CI.

Commands

CommandDoes
ui-craft (no subcommand)Open the interactive TUI hub: welcome menu + update check → Start installation · Upgrade · Manage backups · Managed uninstall.
ui-craft installDetect harnesses, à-la-carte component selection, write configs.
ui-craft update [harness]Re-apply all installed components at the new embedded version.
ui-craft update [harness] --component <name>Re-apply one component only.
ui-craft uninstall [harness]Remove managed blocks and wired components.
ui-craft doctorHealth check — verifies each harness install is coherent.
ui-craft backupSnapshot all harness configs without installing.
ui-craft backup listList existing snapshots.
ui-craft backup pin <id> / unpin <id>Protect or unprotect a snapshot from retention cleanup.
ui-craft rollback [harness]Restore latest backup for a harness.
ui-craft self-updateUpgrade binary to latest GitHub release (or prints the correct package-manager command when installed via Homebrew/Scoop).
ui-craft versionPrint the binary version.
ui-craft version --jsonPrint { "version": "…" }; there is no separate mirror-version field.
ui-craft version --check-parityVerify the Claude Code install matches the expected surface.

Key flags for install

FlagEffect
--harness <name>Target a specific harness (cursor, codex, gemini, opencode) instead of auto-detecting.
--components <list>Comma-separated components to install (skill-commands, mcp-gates, review-agents, design-memory).
--dry-runPreview all planned writes without touching any file.
--yesNon-interactive — skip TUI prompts and apply defaults.

Scripting flags (global)

FlagEffect
--jsonMachine-readable JSON output. Implies non-interactive.
--quietSuppress non-essential output; print only errors and a final one-line outcome.

Safety

Every install snapshots existing configs to ~/.ui-craft/backups/ (tar.gz, SHA-256 deduped) before writing. Any mid-plan failure rolls back the whole plan. rollback [harness] restores from the latest snapshot at any time. State is persisted to ~/.ui-craft/state.json so update can replay your choices at the new version without re-prompting.

Discovery phase

Before building anything, the skill analyzes your project for existing design decisions — CSS variables, Tailwind config, font imports, component themes. If your project already has a design system, it respects it. If not, it asks 4 quick questions (style, accent color, font, optional animation stack) so it never defaults to generic blue/Inter.

Knobs

Three numeric knobs (1-10) that the skill asks about during Discovery. They change behavior, not just tone.

Knob110
CRAFT_LEVEL (default 7)ships fast, skips Polish Passpixel-perfect, compound details applied
MOTION_INTENSITY (default 5)hover states onlyscroll-linked, page transitions, magnetic cursor
VISUAL_DENSITY (default 5)whitespace-heavy editorialdashboard-dense

At MOTION_INTENSITY 8+ the skill loads references/stack.md only if the user opts into Motion / GSAP / Three.js during Discovery.

Style variants

Three opt-in sibling skills that pre-commit to a style and lock the knobs to matching values. Agents pick them when the user mentions a specific aesthetic or product reference.

VariantTriggers onKnobs lockedStyle anchors
ui-craft-minimal"minimal", "Linear-like", "Notion-like", "whitespace-heavy"CRAFT=8 / MOTION=3 / DENSITY=2Monochrome + one accent, Inter/Geist, hairline borders
ui-craft-editorial"editorial", "magazine", "Medium-like", "Substack-like", "long-form"CRAFT=9 / MOTION=4 / DENSITY=3Serif display + humanist body, wide reading column, OpenType
ui-craft-dense-dashboard"dashboard", "admin panel", "Bloomberg-like", "Retool-like"CRAFT=7 / MOTION=3 / DENSITY=9IBM Plex + mono numbers, semantic palette, 4/8px grid

Each variant defers to the main ui-craft skill for base rules and references — it only overrides knob defaults and adds style-specific guidance.

Style presets

For playful and brutalist aesthetics (Clay / Gumroad / Duolingo / Arc-playful, Nothing-phone / Swiss-print / brutalist), see examples/presets/playful.md and examples/presets/brutalist.md. The main ui-craft skill applies these preset knob values + style overrides on top of the base rules when the user asks for those aesthetics.

Slash commands

25 commands. They are not a flat list — every one belongs to a rung, and the rung tells you what it costs you before you read what it does.

Front door — unsure where you are:

CommandDoes
/ui-craft:startRun this first. Reads the project (framework, tokens, brief, spec, existing UI), reports which rung you are on, and names the one command worth running next. Read-only — no code changes.

Rung 1 · Direct — one focused pass, session-local

Build a surface:

CommandDoesNext step
/ui-craft:craftOne-shot surface build. Outcome recipe pipeline — Craft Read + variance + signature bet → named composition → theme → build order → acceptance bar. Surfaces: dashboard, landing, auth; portfolios use the landing recipe at variance 8./finalize
/ui-craft:shapeWireframe-first. ASCII layout + content inventory + state list + open questions before any JSX. Run when starting a new screen./craft
/ui-craft:redesignRedesign without regression. Audits the existing surface first, classifies what to preserve (brand, IA/SEO, content, conversion paths), picks refresh/reskin/rebuild scope, then modernizes./critique

Adjust one dimension:

CommandDoesNext step
/ui-craft:animateAdd / fix motion. Honors MOTION_INTENSITY + chosen stack./polish
/ui-craft:adaptResponsive pass — mobile, tablet, desktop, touch, safe areas./audit
/ui-craft:typesetTypography pass — fonts, scale, tracking, micro-typography./polish
/ui-craft:colorizeIntroduce color strategically — one accent, 3–5 placements, no decoration./tokens
/ui-craft:clarifyUX copy — button labels, error messages, empty states, CTAs./critique
/ui-craft:extractPull repeated patterns into shared components and tokens./tokens
/ui-craft:distillStrip to essence. Cut every section that doesn't earn its space. Absorbs visual-weight reduction (softer type, less motion)./polish
/ui-craft:delightAdd purposeful micro-interactions — copy first, animation last./finalize
/ui-craft:polishFinal pass — the compound details that turn "done" into "crafted"./finalize
/ui-craft:bolderRaise DESIGN_VARIANCE and motion amplitude — stronger composition, type, and signature without a full rebuild./critique
/ui-craft:quieterLower variance and motion — more restrained grids, type, and color. Honors prefers-reduced-motion./critique

Review a surface:

CommandDoesNext step
/ui-craft:heuristicSignature move. Scored critique — Nielsen 10 + 6 design laws + persona walkthroughs. Markdown scorecard with impact tags. No code changes.fix, then /finalize
/ui-craft:critiqueUX — hierarchy, clarity, anti-slop. No code changes./polish
/ui-craft:auditTechnical — a11y, performance, responsive. Prioritized findings table./harden
/ui-craft:unhappyState-first pass — design every non-happy state (idle/loading/empty/error/partial/conflict/offline) before the happy path./harden
/ui-craft:hardenProduction readiness — loading/empty/error states, i18n, offline, edge cases./finalize

Rung 2 · Persist — written once, read by every future session

CommandDoesNext step
/ui-craft:briefWrite or update the project's durable design brief at .ui-craft/brief.md — 5 required sections + principles workshop. Run before any net-new project./tokens
/ui-craft:tokensAudit or establish the 3-layer token spine (primitive → semantic → component). Light and dark both intentionally crafted, not just inverted./craft
/ui-craft:rememberRecord a learned design constraint into .ui-craft/brief.md — corrections that should persist across sessions.keep working

Rung 3 · Enforce — wired once into review or CI

CommandDoesNext step
/ui-craft:finalizePre-ship gate. Runs the detector + brief/token check + the 10-pass finish bar + feedback hierarchy filter. Output only — no auto-fix.ship

The rest of rung 3 is not commands: the two review agents, the MCP quality gates, the composite score, and ui-craft-detect in CI.

Express lane

CommandDoesNext step
/ui-craft:sddesignFull spec-driven pipeline. brief → tokens → shape → craft → converge → ship. Writes .ui-craft/spec.md. Walks rungs 1 to 3 in one run — reach for it when a surface is big enough to deserve a spec.ship

Rung 0 in practice — you ask, it routes

There is no mode enum to learn. At rung 0 you describe the task and the skill's routing table decides which references to load and which pass to run.

You sayIt runs
"Build a pricing page"A build pass — layout, typography, color, spacing, a11y and responsive decided together, not one at a time
"Add an entrance to this modal"A motion pass — the right easing, duration and origin point
"Review this component"A review pass — generic AI patterns, a11y gaps, missed details
"Polish this dashboard"A polish pass — the twenty small things that turn "done" into "crafted"

Climb to rung 1 when you would rather name the pass yourself.

32 domain references

DomainCovers
Craft intentCraft Read, DESIGN_VARIANCE knob, signature bets, product + marketing build patterns, accent rotation when no brand. Load before /craft or any full-surface build
Dashboard recipeOutcome blueprint: 3 named compositions (Overview / Command / Analytics), exact shell spec, build order, shippable acceptance bar. Run via /craft dashboard
Landing recipeMarketing page compositions (product-forward / message-forward / proof-forward), section grammar, CTA hierarchy, acceptance bar. Run via /craft landing
Auth recipeSign-in/sign-up compositions (split panel / centered card), form contract, trust signals, acceptance bar. Run via /craft auth
Theme presets4 named production token stacks (Graphite, Porcelain, Carbon, Signal) — full OKLCH color, type, radius, shadow, motion; light + dark both intentional
MotionDecision ladder, duration + easing token scales, interaction rules, choreography, motion budget, reduced-motion contract. Rendering performance (compositor, FLIP, scroll timelines, will-change lifecycle)
LayoutSpacing systems, optical alignment, layered shadows, visual hierarchy
Typographytext-wrap: balance, tabular-nums, font scale, curly quotes
ColorOKLCH, design tokens, dark mode, APCA contrast
AccessibilityWAI-ARIA, keyboard nav, focus management, touch targets
Modern CSSView Transitions, Anchor Positioning, Popover, <dialog>, interpolate-size, color-mix(), scroll-driven, container queries
ResponsiveFluid sizing, mobile-first, touch zones, safe areas
SoundWeb Audio API, feedback sounds, appropriateness matrix
UX CopyVoice / tone matrix, reading level, terminology, locale-aware strings, inclusive language, error/empty/CTA tactics
UI ReviewSystematic critique methodology, anti-slop detection, Polish Pass
DashboardSignal-to-noise hierarchy (hero / supporting / context / deep-dive), sidebar, metric cards, data tables
InspirationPattern archetypes from observed mature SaaS — hero archetypes, signature details by pattern type, what mature interfaces never do, reference token values
BriefDurable design brief format — product purpose, primary user, 3-5 ranked principles, success metric, out of scope. Persists across sessions at .ui-craft/brief.md
Tokens3-layer token spine (primitive → semantic → component). Both modes intentional. 7 required categories with cross-refs
Finish bar10-pass finishing protocol with measurable criteria. Hierarchy / type system / surface stack / spacing rhythm / iconography / states / motion / microcopy / pixel honesty / data formatting
Principles catalog42 example principles across 8 product categories, seed material for the /brief workshop
StackMotion, GSAP, Three.js — decision tree, patterns, perf gotchas, anti-patterns (opt-in)
HeuristicsNielsen's 10 + Fitts / Hick / Doherty / Cleveland-McGill / Miller / Tesler with 1-5 scoring rubric and impact framing
Personas5 archetypes (first-timer, power user, low-bandwidth, screen-reader, one-thumb) with walkthrough checklists
State designIdle / loading / empty / error / partial / conflict / offline — design the unhappy path first
Data vizCleveland-McGill perceptual hierarchy, chart selection matrix, ColorBrewer + Okabe-Ito palettes, direct labeling, Tufte
AI / chat surfacesStreaming contract, 7-state model, tool traces, citations, feedback affordances, generative UI, conversation layout
FormsValidation timing, progressive disclosure, multi-step wizards, autosave, optimistic submit, field-specific patterns
Composition spec.ui-craft/spec.md format — per-surface composition choice, layout skeleton, component inventory, state lattice, acceptance bar. Written by /shape Step 6, consumed by /sddesign and /craft.

Agents

Two read-only Claude Code plugin agents form the ui-craft parallel verify team. They complement the slash commands — they do not replace them.

AgentInvocationDoes
design-reviewerui-craft:design-reviewerAdversarial design critique — loads review rules, anti-slop signals, and Nielsen/design-law heuristics. Returns severity-tagged findings (Critical / Warning / Suggestion, file:line). No edits.
a11y-auditorui-craft:a11y-auditorAccessibility audit — keyboard, focus-visible, APCA contrast, ARIA, touch targets, reduced-motion. Returns severity-tagged findings. No edits.

Both agents are read-only (tools: Read, Grep, Glob) and run in a fresh context, making them suitable for dedicated review passes and PR audits where you want independent judgment uncontaminated by the build session.

Parallel verify team

Delegate both agents simultaneously on the same diff or file for a full design + a11y sweep in one pass:

Delegate ui-craft:design-reviewer and ui-craft:a11y-auditor together on [target]. Run both simultaneously. Each returns an independent severity-tagged findings table.

When to use agents vs. commands:

  • Agents — fresh context, parallel, read-only. Best for final review passes, PR audits, and CI-style verification. Invoke as ui-craft:design-reviewer / ui-craft:a11y-auditor.
  • Commands (/critique, /audit) — inline in the caller's context, sequential. Best for interactive build sessions where you want a quick lens mid-work.

When to use what

UI Craft surfaces the same craft knowledge five ways. They don't compete — each fits a different moment. The two axes that decide: does it write code? and is it judgment or a deterministic check?

SurfaceWhat it isReach for it whenWrites code?Judgment / deterministicRuns
The skill (passive)Always-on design knowledge + anti-slop, triggered by intentYou're building or editing any UI — the defaultJudgmentInline, every harness
Slash commandsFocused single-lens passes (/craft, /shape, /polish, /heuristic, /finalize, …)You want one specific pass, mid-workBuild/transform ✅ · review passes ❌JudgmentInline, your session
Agents (design-reviewer, a11y-auditor)Read-only verify team, fresh context, parallelFinal review / PR audit — you want independent judgment uncontaminated by the build sessionJudgmentClaude Code
MCP tools (check_anti_slop, tokens_lint, acceptance_bar, score_ui)Deterministic checks an agent callsA programmatic gate inside any MCP client, or a reproducible scoreDeterministicMCP client / CI
CLI (ui-craft binary, ui-craft-detect, scripts/eval.mjs)Installer + zero-dep scanners + UICraftScoreInstall/update the system across harnesses; run quality gates in CI or git hooksDeterministicTerminal / CI

The short version: taste that writes code → the skill + commands. Independent review, no edits → the agents. A check that must be identical every run → MCP or the CLI. New to it or unsure? Run /start and it picks for you.

Framework agnostic

The skill detects your project's styling approach and adapts:

  • Tailwind CSS — uses utility classes, maps design rules to Tailwind equivalents
  • CSS Modules — writes scoped .module.css files
  • styled-components / Emotion — uses tagged templates
  • Vanilla CSS — uses custom properties and modern features
  • SFC styles (Vue, Svelte, Astro) — writes in <style> blocks

Anti-slop

The skill actively rejects patterns that scream "AI made this":

  • Purple-cyan gradients
  • Glassmorphism with neon accents
  • Identical card grids
  • Bounce and elastic easing
  • Glow effects as affordances
  • Colored accent borders on cards
  • ALL CAPS headings
  • Uniform border-radius everywhere
  • Emoji as icons
  • Background gradient blobs
  • Bento grid abuse
  • Stagger-animate everything on load
  • Star ratings on testimonials
  • Generic CTAs ("Learn more", "Click here")
  • Walls of text on landing pages
  • Pure black (#000) text

Canonical pipeline

Once the spine is in place, the workflow is:

Discovery → /brief → /tokens → build → /finalize → ship

The brief and tokens land as durable artifacts at .ui-craft/brief.md and the project's preferred token destination — they survive across sessions and anchor every subsequent design decision. Build proceeds with full reference loading via the routing table. /finalize runs the 10-pass finish bar before merge, gated on the brief existing.

Project structure

ui-craft/
├── agents/                        # 2 Claude Code plugin agents (auto-discovered)
│   ├── design-reviewer.md        # Adversarial design critic — read-only, severity-tagged output
│   └── a11y-auditor.md           # Accessibility auditor — read-only, severity-tagged output
├── skills/
│   ├── ui-craft/                 # Main skill
│   │   ├── SKILL.md              # Slim entry — knobs, discovery, anti-slop, routing
│   │   └── references/           # 32 domain references (accessibility, motion, layout,
│   │                             #   typography, color, modern-css, responsive,
│   │                             #   sound, copy, review, dashboard, inspiration, stack,
│   │                             #   heuristics, personas, state-design, dataviz,
│   │                             #   ai-chat, forms, brief, tokens,
│   │                             #   finish-bar, principles-catalog, spec, agents)
│   ├── ui-craft-minimal/          # Variant — Linear/Notion aesthetic
│   ├── ui-craft-editorial/        # Variant — Medium/Substack aesthetic
│   └── ui-craft-dense-dashboard/  # Variant — Bloomberg/Retool aesthetic
├── commands/                      # 25 Claude Code slash commands (source of truth)
├── examples/
│   ├── animation-storyboard.md   # Multi-stage animation pattern template
│   └── presets/
│       ├── playful.md            # Clay / Gumroad / Duolingo / Arc aesthetic preset
│       └── brutalist.md          # Swiss print / Nothing / terminal aesthetic preset
├── evals/                         # Eval query sets for description optimizer
│   └── presets/                   # Playful + brutalist eval JSONs (reference material)
├── scripts/
│   ├── detect.mjs                # ui-craft-detect CLI (also shipped on npm)
│   └── validate.mjs              # Manifest + link checker
├── .codex/skills/                 # harness mirror for `npx skills add` / submodule installs
├── .cursor/skills/                # harness mirror
├── .gemini/skills/                # harness mirror
├── .opencode/skills/              # harness mirror
├── .agents/skills/                # harness mirror (generic agent-skills spec)
├── cli/assets/<harness>/          # hand-authored per-harness assets the CLI embeds + installs
├── .github/workflows/
│   └── validate.yml              # Runs validator on PR + push
├── README.md
├── CONTRIBUTING.md
├── LICENSE
└── VERSIONS.md

Anti-slop detection

npm version

Scan a codebase for common AI-generated UI anti-patterns — 43 rules covering AI slop (transition: all, bounce easing, purple gradients, ALL CAPS headings), dark patterns (confirmshaming, destructive actions without confirmation), a11y (icon-only buttons without labels, modal-without-<dialog>, outline: none without :focus-visible replacement, streaming without aria-live, heading-level skips), forms (placeholder-as-label, missing autocomplete), auth tells (caps "OR" dividers, full-bleed saturated brand panels), marketing copy tells (eyebrow floods, scroll cues, numbered section eyebrows, duplicate CTA intent, em-dash floods), perf (images without dimensions → CLS), tables (no overflow handling on mobile), dataviz (categorical rainbow palettes), state design (data fetching without empty/error branches), and placeholder copy shipped to prod (Lorem ipsum, TODO, John Doe). Zero dependencies, works out of the box.

Published as a standalone CLI on npm — use it anywhere without cloning:

npx ui-craft-detect ./src
# or with JSON output:
npx ui-craft-detect ./src --json

Or from a clone of this repo:

node scripts/detect.mjs ./src

Exit code 0 when clean, 1 when findings — usable as a CI gate. Rules mirror the Anti-Slop Test in skills/ui-craft/SKILL.md.

Diff-scoped scanning — --scope, --base, --fail-on

Scope findings to what a branch actually changed, so CI only flags new anti-patterns instead of the entire pre-existing codebase.

FlagValuesDefaultWhat it does
--scopefull | files | changedfullfull scans everything (unchanged behavior). files reports all findings in any file touched vs the base ref. changed reports only findings whose line falls inside an actual diff hunk.
--base <ref>any git refmerge-base of HEAD with the default branchOverrides the comparison ref used for --scope files/changed.
--fail-onnone | warning | errorerrorExit-code gate, evaluated on the scope-filtered findings only. none is always advisory (exit 0). warning fails on any surviving finding. error fails only on critical findings (matches pre-existing default behavior).
# Local pre-commit-style gate: only fail on new critical issues in changed lines
npx ui-craft-detect --scope changed --fail-on error

# Compare against a specific ref instead of the default branch
npx ui-craft-detect --scope changed --base origin/develop

# Advisory mode — see scoped findings without affecting the exit code
npx ui-craft-detect --scope files --fail-on none --json

If git is unavailable, the directory isn't a git repository, or the base ref can't be resolved (e.g. shallow clone), the tool falls back to --scope full automatically and prints a note on stderr — it never crashes or silently drops findings.

Live URL scanning

Point the detector at a deployed page instead of source files:

npx ui-craft-detect https://your-site.com
npx ui-craft-detect https://your-site.com --json --fail-on none

Two engines, picked automatically:

  • puppeteer (optional — npm install puppeteer) loads the page in headless Chromium and scans the JS-rendered DOM, so SPA/client-rendered markup is covered.
  • fetch (zero-dep fallback) scans the server-rendered HTML as delivered. No JS execution.

Force one with --engine puppeteer or --engine fetch. Findings report the URL as the file and line numbers within the fetched HTML document. The core detector stays zero-dependency — puppeteer is resolved via dynamic import only when present.

Agent edit-time hooks — hooks subcommand

Pre-commit and CI catch problems after the fact. Agent hooks catch them while the agent is still working — the detector runs after every agent file edit and feeds findings straight back into the loop:

npx ui-craft-detect hooks install            # both harnesses
npx ui-craft-detect hooks install --harness claude   # just one
npx ui-craft-detect hooks status
npx ui-craft-detect hooks uninstall
HarnessManifestMechanism
Claude Code.claude/settings.jsonPostToolUse hook (matcher Edit|Write|MultiEdit). On critical/major findings the hook exits 2, so the findings summary is fed back to the model as actionable feedback — the agent fixes the slop before finishing.
Cursor.cursor/hooks.jsonafterFileEdit hook (schema version 1). Findings appear in Cursor's Hooks output channel. Committed to the repo, project hooks load for the whole team — including Cloud Agents.

Install is merge-safe and idempotent: existing manifest entries are always preserved, re-running is a no-op, and uninstall removes only the detector's own entries. The hook runner scans just the edited file, stays silent on clean edits and warn-level findings, and fails open on internal errors so a broken hook can never stall an agent.

Pre-commit hooks — init-hook subcommand

ui-craft-detect can install its own pre-commit hook with zero config.

# Auto-detect (uses husky if present, else native .githooks)
npx ui-craft-detect init-hook

# Pick explicitly
npx ui-craft-detect init-hook --native         # .githooks/pre-commit (no deps)
npx ui-craft-detect init-hook --husky          # .husky/pre-commit (assumes husky)
npx ui-craft-detect init-hook --github-action  # .github/workflows/ui-craft-detect.yml (deprecated; use `ci install`)
npx ui-craft-detect init-hook --all            # all three
npx ui-craft-detect init-hook --dry-run        # preview without writing

The native hook scans only staged file content (via git show :path), so working-tree noise is ignored. Skip ad-hoc with git commit --no-verify. This repo's own .githooks/pre-commit also auto-bumps marketplace.json CalVer on every commit.

CI integration — ci install / ci config / ci upgrade

One command sets up a full PR-feedback loop as a GitHub Action — no YAML to hand-write, no octokit dependency (it's all gh api under the hood):

npx ui-craft-detect@latest ci install

This writes .github/workflows/ui-craft-detect.yml, wired to:

  • Sticky PR summary comment — one comment per PR, created on first push and edited (not duplicated) on every subsequent push, matched via a hidden marker.
  • Inline review comments — findings are posted directly on the diff-visible lines that introduced them, scoped to --scope changed so pre-existing issues elsewhere in the file don't get flagged.
  • Commit status — on pushes to the default branch (no PR context), posts a ui-craft-detect status with error/warning counts.
  • Minimal permissionspull-requests: write and statuses: write are each granted only for the steps that need them, with a one-line comment explaining why (same convention as this repo's own CodeQL workflow).

By default the workflow scans --scope changed --fail-on error on pull requests (--scope full on default-branch pushes, since a push has no PR diff to scope against).

Change settings anytime without reinstalling:

npx ui-craft-detect ci config --scope files            # widen scope to whole changed files
npx ui-craft-detect ci config --fail-on warning         # stricter gate
npx ui-craft-detect ci config --comment false           # disable the sticky PR comment
npx ui-craft-detect ci config --inline-comments false   # disable inline review comments
npx ui-craft-detect ci config --status false            # disable the commit status

ci config reads and rewrites a small config marker embedded in the workflow file, so only the settings you pass change — the rest of the file (steps, permissions) is left untouched.

Bump the workflow to the latest template version while keeping your settings:

npx ui-craft-detect ci upgrade

ci upgrade compares the embedded version marker against the installed CLI version; if there's drift, it regenerates the template body and preserves your ci config settings exactly. If you're already current, it's a no-op.

init-hook --github-action still works (it's the same code path ci install wraps) but is deprecated in favor of ci install.

The --scope/--fail-on flags used above aren't CI-only — they work as plain CLI flags for local pre-commit-style gating too (see Diff-scoped scanning above).

Design-quality score

UICraftScore is a deterministic 0-100 composite that turns three static-analysis signals into a single defensible grade. It gives you objective, reproducible design-quality evidence — not vibes.

Formula:

``$ \text{score} = 100 − (\text{antiSlop_critical} \times 8) − (\text{antiSlop_major} \times 4) − (\text{antiSlop_warn} \times 1) − (\text{token_findings} \times 2) − (\text{a11y_critical} \times 8) − (\text{a11y_major} \times 4)

\text{clamped} [0, 100] · \text{A} ≥ 90 · \text{B} ≥ 80 · \text{C} ≥ 70 · \text{D} ≥ 60 · \text{F} < 60 $``

Three dimensions, each with its own subscore:

DimensionSourcePenalty
anti_slop43 rules from ui-craft-detectcritical −8 · major −4 · warn −1
token_disciplineRaw hex / off-scale radius / spacing / z-index−2 per finding (flat)
a11y5 new static checks (no overlap with detect.mjs): img-no-alt, non-semantic-interactive, positive-tabindex, aria-invalid-no-describedby, no-reduced-motioncritical −8 · major −4

The formula, weights, and grade bands are published in evals/quality/score.mjs (WEIGHTS, GRADE_BANDS). Hand-authored fixtures in evals/quality/fixtures/ and bands in evals/quality/baselines.json form the regression gate.

Run the CLI benchmark:

# Score a single file
node scripts/eval.mjs src/components/Hero.tsx

# Score a directory
node scripts/eval.mjs src/components/

# Run the full regression gate (8 fixtures — slop vs. designer separation)
node scripts/eval.mjs --baseline

# JSON output (CI-friendly)
node scripts/eval.mjs src/components/Hero.tsx --json

# Fail if score below threshold (default 70)
node scripts/eval.mjs src/components/Hero.tsx --threshold 80

Exit codes: 0 clean / in-band · 1 below threshold or out of band · 2 arg error.

Score via MCP tool (score_ui):

The score_ui tool in the MCP server exposes the same scorer to any MCP-compatible client:

// Call score_ui with inline code:
{ "code": "<your tsx source>" }

// Or with a file path:
{ "path": "src/components/Hero.tsx" }

Returns { overall: { score, grade }, dimensions: { anti_slop, token_discipline, a11y }, version } — the same envelope as the CLI --json output.

See evals/README.md for how to run the regression gate, add fixtures, and regen baselines after rule changes.

UsabilityScore — the judged companion

UICraftScore is deterministic, which also bounds it: static analysis can't see experience friction (a confusing flow, a missing undo, a 2-second save with no feedback). UsabilityScore covers that axis — a 0-100 score + grade rolled up from the /heuristic scorecard (Nielsen's 10 + 6 design laws):

``$ \text{heuristic_base} = \text{round}( ((\text{mean}(\text{nielsen_scores}) − 1) / 4) \times 100 ) # 10 \text{scores}, \text{each} 1–5 \text{UsabilityScore} = \text{clamp}( \text{heuristic_base} − 5 \times (\text{failed} \text{design} \text{laws}) , 0 , 100 )

\text{Same} \text{bands} \text{as} \text{UICraftScore}: \text{A} ≥ 90 · \text{B} ≥ 80 · \text{C} ≥ 70 · \text{D} ≥ 60 · \text{F} < 60 $``

It is judged, not deterministic — computed by the host agent from the rubric (zero deps, no API key, works in any harness), so it may vary run to run. Gate CI on UICraftScore; use UsabilityScore for review depth. The two render side by side in an extended report and are deliberately never averaged — that would hide which number is reproducible. Run it with /heuristic <path>; rubric + formula live in heuristics.md.

MCP Server

npm version

The ui-craft-mcp package exposes seven deterministic tools over the Model Context Protocol (stdio transport). Works with Claude Desktop, Cursor, and any MCP-compatible client.

Boundary: the MCP server is the checks layer — deterministic, rule-based, identical output for identical input. The SKILL.md is the taste layer — judgment, aesthetics, architectural decisions. These never overlap.

ToolWhat it does
route_taskRoutes a natural-language prompt to the references, commands and tools that cover it, plus the first move — pointers only, never rules
check_anti_slop43-rule anti-slop scanner via scan() from ui-craft-detect — in-process, no subprocess
tokens_lintOff-system token detector: raw hex colors, non-scale radius/spacing px, magic z-index
acceptance_barAcceptance checklist for a UI surface (dashboard, landing, auth, generic) — data only, no scoring
score_uiComposite UICraftScore (0-100 + grade + per-dim subscores) via evals/quality/score.mjs — all three dimensions in one call
fold_candidatesDraws landing-fold composition classes, preferring ones the project has not spent
check_foldRenders a URL and reports what its fold actually is — screenshot, class, drift, invariants

Why route_task exists: the routing table in SKILL.md only fires when your words match our filenames. Ask for "an analytics panel" and nothing points at recipe-dashboard.md, because that file never says analytics. A synonym map fixes a vocabulary mismatch a table cannot, and recipes are indexed by what they contain, so "pricing block" reaches the landing recipe.

Quick start:

# Wire the manifest-pinned release into your project's .mcp.json:
{ "mcpServers": { "ui-craft": { "command": "npx", "args": ["-y", "ui-craft-mcp@0.8.3"] } } }

See mcp/README.md for full install, tool docs, and the acceptance-data.json regen note.

Maintaining harness assets

The canonical skill content lives in skills/ (main skill + variants) and commands/ (the slash-command lenses). Two consumers ship that content:

  • CLI (ui-craft install) — per-harness assets are hand-authored under cli/assets/<harness>/ (claude, cursor, codex, gemini, opencode) and compiled into the binary via go:embed. Command-capable harnesses (Claude Code, OpenCode) receive real commands/*.md; skills-only harnesses (Cursor, Codex, Gemini) receive each lens as a flat depth-1 peer skill. The embedded tree is also the uninstall manifest — cleanup removes exactly what it installed.
  • npx skills add / git submodule — the repo-root mirror dirs (.codex/, .cursor/, .gemini/, .opencode/, .agents/) serve those install paths.

Canonical quality gate

Before publishing or opening a PR, install the MCP development dependencies once with npm ci --prefix mcp, then run:

pnpm verify

This non-fail-fast gate runs distribution-contract checks, plugin/link validation, every mirror drift guard, detector and quality suites, MCP source and bundled smoke tests, plus Go tests, vet, and formatting. pnpm verify:list prints the suite IDs; a focused rerun can use pnpm verify -- --suite=<id>. Component versions and immutable launch specs live in the machine-readable distribution-manifest.json.

When you change a skill or command, edit the canonical source under skills/ + commands/ and then regenerate every copy:

npm run sync            # skills/ + commands/ → cli/assets/ + repo-root mirrors
npm run check:mirrors   # the drift guard CI runs (fails on any stale mirror)

CI does not regenerate mirrors — scripts/check-mirror-copies.mjs only fails the build when one drifts, so run the sync before you push.

Tuning skill descriptions

Every skill's description field is the primary trigger mechanism. The evals/ folder holds query sets for skill-creator's description optimizer (run_loop.py), which evaluates and iterates descriptions against realistic should-trigger / should-not-trigger prompts. See evals/README.md for the commands and how to add new eval sets.

Roadmap

Where ui-craft is heading. Not commitments with dates — a public list of the directions we consider worth building, roughly ordered by how much they'd raise output quality. Feedback and PRs on any of these welcome.

Design-tool integration

  • Figma spec compliance — read component specs (spacing, type, color, variants) via Figma's Dev Mode / REST API and score an implementation against them, the same way the detector scores anti-slop today. "Does the built component match the design?" becomes a deterministic gate instead of eyeball review.
  • Design-token import — pull a token set from Figma variables / Tokens Studio / a design-tokens.json and emit the project's 3-layer spine (/tokens) from it, instead of hand-transcribing values.

Detector

  • Computed-style checks for URL scans — the URL engine currently scans rendered markup; the next layer is computed styles via the browser engine: real contrast ratios (not class-name heuristics), effective tap-target sizes, actual font fallback chains.
  • Screenshot-diff regression (exploratory) — likely as a thin integration over existing visual-regression tooling (Playwright snapshots / Chromatic-style diffs) rather than a bespoke engine.
  • More harnesses for edit-time hookshooks install covers Claude Code and Cursor today; extend to other agents as their hook mechanisms stabilize.

Skill & pipeline

  • Reference-board step — optional pre-build step that generates or collects visual references (mood board, type specimens, palette candidates) before the Craft Read, for briefs where the direction is genuinely open.
  • Multi-page consistency — today's recipes reason about one surface at a time; a site-level pass would enforce shared rhythm, type scale, and CTA vocabulary across pages.
  • UsabilityScore trend tracking — persist /heuristic and UICraftScore results per commit so quality is a curve you watch, not a snapshot.

Evals

  • Automated blind-build harness — run the evals/craft-quality/PROMPTS.md tracks through an agent automatically and score the output, turning today's manual auditor pass into a repeatable regression suite.

Have a strong opinion on priority, or something missing? Open an issue.

Contributing

Spotted a new AI-generated pattern that should be in the anti-slop list? Have a craft rule from a product you admire? Want to add a new reference domain? PRs and issues welcome.

See CONTRIBUTING.md for guidelines on adding rules, improving references, or proposing new domains.

Author

Eduardo Calvo

License

MIT — use it however you want.