* Give DESIGN.md a real type ramp so the design hook stops crying wolf The design hook fired on nearly every CSS file we touched. The cause was DESIGN.md's typography block: it declared seven named roles rather than a scale, and two of those roles used clamp(), which the extractor skipped outright. That left an allowlist of five sizes standing against the 86 distinct font sizes actually in use, so design-system-font-size flagged roughly 500 declarations. Editing any .astro page made it worse, because the companion-stylesheet scan re-reported the whole backlog. Extractor (cli/engine/design-system.mjs): - Read a typography.scale map as the enumerated ramp. - Read both clamp() endpoints as allowed sizes. These stay additive on purpose: clamp endpoints alone cannot switch the rule on, because a fully fluid system enumerates no discrete ramp and inferring one from its endpoints would flag every intermediate size. The existing abstention test still passes, and three new tests cover the added behavior. DESIGN.md: - Document a 19-step ramp, 8px through 72px at a 16px root. - Snap the five discrete role sizes onto ramp steps. This also fixes real drift. DESIGN.md claims to mirror kinpaku-tokens.css verbatim, but wordmark was 1.15rem in the CSS against 1.3rem documented, with tracking at 0.42em against 0.15em. Both are re-synced. Standardization, 64 declarations: - Six near-identical steps between 13.7px and 15.4px collapse onto 14 and 15. - .foundation-card-label, .designing-lane-mock-title and .designing-iterate-name each existed at two different sizes in two files. Now unified. - The wordmark rendered at four sizes (20.8, 18.4, 17, 16.8px). Now 18px, plus one deliberate smaller nav variant. Exemptions, for designs that are foreign on purpose: the antipattern-example fixtures, the neo-mirai case-study build, the periodic-table cell annotations in framework-viz.js (5 to 7px diagram geometry sitting at 2 to 3px offsets), and the .why-slop-* before-state card's Inter and gradient text. Verified by computed style across ten rendered pages: every element lands on a ramp step except clamp() values mid-interpolation, which is what fluid means. Full test suite and build validators pass. Generated provider output is deliberately left out; the sync workflow owns it. Prepared with AI assistance (Claude Code). Co-Authored-By: Claude <noreply@anthropic.com> * Validate clamp() endpoints in usage, not just when reading DESIGN.md Reading clamp endpoints as documented steps without also checking them in source left an asymmetry: `isAllowedFontSizeRaw` returned true for anything failing the px/rem literal test, so `clamp(99rem, 1vw, 200rem)` passed. That is how `.ptable-symbol` at `clamp(1.45rem, 1.8vw, 1.8rem)` stayed invisible until someone measured computed styles, which is not a check the hook can run. Fluid values are now judged on their min and max. The viewport term interpolates between them and is never a fixed step, so it is left alone. Endpoints that cannot be resolved, such as var() or calc() or em, abstain rather than guess. Findings name the offending endpoint and use it as the ignore-value, because the whole clamp string is not actionable on its own. Turning the check on surfaced 22 fluid declarations that had never been looked at. Three used hero sizes above the ramp's 72px cap (80, 83.2 and 88px) alongside the display role's documented 89.6px max, so the top of the ramp was genuinely incomplete. Added the 80 and 88 steps, which gives the display end consistent 8px increments instead of 48/56/64/72 plus an orphan at 89.6, and fixes two declarations outright. The other 20 are snapped by a stated rule: nearest step, ties toward the smaller step, endpoints already matching a documented fluid role left as-is, and where nearest-step would make a breakpoint override meet or exceed its base, the next smaller step so the override still reduces. That last case applies once, to .designing-page-title. Also narrows the framework-viz.js waiver. The periodic-table cell annotations now carry two `impeccable-disable-line` comments naming the reason, instead of a config entry wildcarding the whole file for the rule. Inline waivers travel with the code and cannot silence future drift elsewhere in that file. Verified at 420px, 900px and 1600px across seven pages. The pinned ends are fully on-ramp; the only off-ramp values at 900px are the vw term mid-interpolation, which is what fluid means. Prepared with AI assistance (Claude Code). Co-Authored-By: Claude <noreply@anthropic.com> * Address review: wordmark tracking picked the wrong side, stale ramp count Two review findings, both fair. Wordmark tracking (greptile, bugbot). This PR moved DESIGN.md's wordmark letterSpacing from 0.15em to 0.42em on the grounds that DESIGN.md claims to mirror kinpaku-tokens.css and the token read 0.42em. That was the wrong side to trust. `--ks-type-wordmark-track` has exactly one consumer, design-system.css:570, which is the specimen page. Every production lockup (.ks-wordmark, .kinpaku-chrome .site-header-brand-name, .footer-logo) hardcodes 0.15em, so 0.15em is what every visitor actually sees and what DESIGN.md already documented correctly before this PR touched it. Reverted the doc to 0.15em and moved the token to 0.15em as well, so the specimen now renders the same lockup as production instead of a wider one nothing else uses. Verified by computed style: header and specimen both report 18px with 2.7px tracking. No production visual change. Stale ramp count (copilot). The sidecar described an "18-step ramp, 8px through 72px". It went stale twice inside this PR, once when the 8 step was added and again when 80 and 88 were added for the hero display sizes. It is 21 steps, 8px through 88px. Prepared with AI assistance (Claude Code). Co-Authored-By: Claude <noreply@anthropic.com> * Strip !important from the font-size ignore value Follow-on from the waiver wiring in the hook branch. The ignoreValue is what a `hooks ignore-value` waiver has to match, and `font-size: 1.4rem !important` emitted `1.4rem !important` while a plain declaration emitted `1.4rem`. Once font-size is a direct-value rule, that means the same size needs two different waivers depending on whether it carries a priority marker. font-family already strips the marker before matching, and there is a test for that. font-size now does the same. The snippet still shows the declaration as authored. Prepared with AI assistance (Claude Code). Co-Authored-By: Claude <noreply@anthropic.com> * Have the wordmark rules consume their tokens instead of copying the values Follow-up to the tracking fix, and the residual half of what the reviewers were pointing at. `.ks-wordmark` and the kinpaku chrome lockup each repeated `1.125rem` and `0.15em` literally rather than reading `--ks-type-wordmark-size` and `--ks-type-wordmark-track`. That duplication is exactly how the token drifted to 0.42em while every production lockup stayed at 0.15em and nobody noticed, which is the confusion that started this thread. The values already agree, so this is a no-op visually and is verified as such: computed styles across the home, design-system, docs and changelog pages all still report 18px with 2.7px tracking. What changes is that there is now one place to edit, so the next tracking change cannot silently apply to the specimen page alone. Prepared with AI assistance (Claude Code). Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
Impeccable
Design guidance for AI coding agents. 1 skill, 23 commands, live browser iteration, and 46 deterministic detector rules for AI-generated frontend design.
Quick start: From your project root, run
npx impeccable install, then run/impeccable initinside your AI coding tool. Full docs: impeccable.style.
Why Impeccable?
Anthropic's frontend-design was the first widely-used design skill for Claude. Impeccable started from there.
Every model trained on the same SaaS templates. Skip the guidance and you get the same handful of tells on every project: Inter for everything, purple-to-blue gradients, cards nested in cards, gray text on colored backgrounds, the rounded-square icon tile above every heading.
Impeccable adds:
- One setup flow.
/impeccable initwritesPRODUCT.mdand offersDESIGN.md, so later commands know the audience, brand/product lane, voice, anti-references, colors, type, and components. - 23 commands. A shared design vocabulary with your AI:
polish,audit,critique,distill,animate,bolder,quieter, and more. - 46 deterministic detector rules plus LLM-only critique checks. The CLI and browser extension run the deterministic rules with no LLM and no API key.
What's Included
The Skill: impeccable
The skill installs as one command:
/impeccable <command> <target>
Start every new project with:
/impeccable init
init asks whether the surface is brand (marketing, landing, portfolio) or product (app UI, dashboard, tool), then writes design context that every later command reads.
23 Commands
All commands are accessed through /impeccable:
| Command | What it does |
|---|---|
/impeccable craft |
Full shape-then-build flow with visual iteration |
/impeccable init |
One-time setup: gather design context, write PRODUCT.md and DESIGN.md, configure live mode, recommend next steps |
/impeccable document |
Generate root DESIGN.md from existing project code |
/impeccable extract |
Pull reusable components and tokens into the design system |
/impeccable shape |
Plan UX/UI before writing code |
/impeccable critique |
UX design review: hierarchy, clarity, emotional resonance |
/impeccable audit |
Run technical quality checks (a11y, performance, responsive) |
/impeccable polish |
Final pass, design system alignment, and shipping readiness |
/impeccable bolder |
Amplify boring designs |
/impeccable quieter |
Tone down overly bold designs |
/impeccable distill |
Strip to essence |
/impeccable harden |
Error handling, i18n, text overflow, edge cases |
/impeccable onboard |
First-run flows, empty states, activation paths |
/impeccable animate |
Add purposeful motion |
/impeccable colorize |
Introduce strategic color |
/impeccable typeset |
Fix font choices, hierarchy, sizing |
/impeccable layout |
Fix layout, spacing, visual rhythm |
/impeccable delight |
Add moments of joy |
/impeccable overdrive |
Add technically extraordinary effects |
/impeccable clarify |
Improve unclear UX copy |
/impeccable adapt |
Adapt for different devices |
/impeccable optimize |
Performance improvements |
/impeccable live |
Visual variant mode: iterate on elements in the browser |
Use /impeccable pin <command> to create standalone shortcuts (e.g., pin audit creates /audit).
Usage Examples
/impeccable audit blog # Audit blog hub + post pages
/impeccable critique landing # UX design review
/impeccable polish settings # Final pass before shipping
/impeccable harden checkout # Add error handling + edge cases
Or use /impeccable directly with a description:
/impeccable redo this hero section
Anti-Patterns
The skill includes explicit guidance on what to avoid:
- Don't use overused fonts (Arial, Inter, system defaults)
- Don't use gray text on colored backgrounds
- Don't use pure black/gray (always tint)
- Don't wrap everything in cards or nest cards inside cards
- Don't use bounce/elastic easing (feels dated)
See It In Action
Visit the Neo Mirai case study to see a before/after case study of a real project transformed with Impeccable commands.
Installation
Option 1: CLI installer (Recommended)
From the root of your project, run:
npx impeccable install
This shows the harness folders it detected (for example ~/.claude, ~/.codex, or project-local .cursor), lets you keep the detected set or customize providers, then asks whether to install into the current project or globally. Use --providers=claude,codex,cursor and --scope=project|global to skip those choices in scripts. On Claude Code, Cursor, and Codex, it also installs the provider-native hook manifest for the current project. Works with Cursor, Claude Code, Gemini CLI, Codex CLI, Grok Build, and every other supported tool. Reload your harness afterward.
To refresh an existing install, run:
npx impeccable update
Codex users should open /hooks after install or update and approve the project hook when prompted. Codex tracks trust by hook definition, so updates that change .codex/hooks.json can require approval again.
Option 2: Git Submodule
For teams that want to keep Impeccable vendored and updated through Git, add this repo as a submodule and link the compiled provider build into your harness folders:
git submodule add https://github.com/pbakaus/impeccable .impeccable
npx impeccable link --source=.impeccable --providers=claude,cursor
git add .gitmodules .impeccable .claude .cursor
git commit -m "Add Impeccable skills"
Use the providers your project needs, for example claude, cursor, gemini, codex, github, opencode, pi, qoder, trae, trae-cn, or rovo-dev. The command links individual skill folders from .impeccable/dist/universal/ and leaves existing real skill directories untouched unless you pass --force.
To update later:
git submodule update --remote .impeccable
npx impeccable link --source=.impeccable --providers=claude,cursor
Option 3: Plugin install
Claude Code:
/plugin marketplace add pbakaus/impeccable
Claude Code only. After adding the marketplace, open
/pluginand install Impeccable from the list.
Grok Build:
grok plugin install pbakaus/impeccable --trust
Grok Build only. Then run
/impeccable initin a Grok session.
Option 4: Download from Website
Visit impeccable.style, download the ZIP for your tool, and extract to your project.
Option 5: Copy from Repository
Cursor:
cp -r dist/cursor/.cursor your-project/
Note: Cursor skills require setup:
- Switch to Nightly channel in Cursor Settings → Beta
- Enable Agent Skills in Cursor Settings → Rules
Claude Code:
# Project-specific
cp -r dist/claude-code/.claude your-project/
# Or global (applies to all projects)
cp -r dist/claude-code/.claude/* ~/.claude/
OpenCode:
cp -r dist/opencode/.opencode your-project/
Pi:
cp -r dist/pi/.pi your-project/
Gemini CLI:
cp -r dist/gemini/.gemini your-project/
Note: Gemini CLI skills require setup:
- Install preview version:
npm i -g @google/gemini-cli@preview- Run
/settingsand enable "Skills"- Run
/skills listto verify installation
Codex CLI:
# Project-local
cp -r dist/agents/.agents your-project/
mkdir -p your-project/.codex
cp dist/codex/.codex/hooks.json your-project/.codex/hooks.json
# Or install the skill user-wide. Copy .codex/hooks.json into each project
# where you want the design hook to run.
mkdir -p ~/.agents/skills
cp -r dist/agents/.agents/skills/* ~/.agents/skills/
The asset-producer subagent ships nested inside the skill's own
agents/folder, which Codex auto-discovers. No separate.codex/agents/copy is needed. The hook is project-local because Codex discovers hooks from.codex/hooks.jsonnext to trusted project config.
GitHub Copilot:
cp -r dist/github/.github your-project/
Trae:
# Trae China (domestic version)
cp -r dist/trae/.trae-cn/skills/* ~/.trae-cn/skills/
# Trae International
cp -r dist/trae/.trae/skills/* ~/.trae/skills/
Note: Trae has two versions with different config directories:
- Trae China:
~/.trae-cn/skills/- Trae International:
~/.trae/skills/After copying, restart Trae IDE to activate the skills.
Rovo Dev:
# Project-specific
cp -r dist/rovo-dev/.rovodev your-project/
# Or global (applies to all projects)
cp -r dist/rovo-dev/.rovodev/skills/* ~/.rovodev/skills/
Qoder:
# Project-specific
cp -r dist/qoder/.qoder your-project/
# Or global (applies to all projects)
cp -r dist/qoder/.qoder/skills/* ~/.qoder/skills/
Usage
Once installed, every command runs through the single /impeccable skill:
/impeccable audit # Find issues
/impeccable polish # Final cleanup
/impeccable distill # Remove complexity
/impeccable critique # Full design review
Type /impeccable alone to see the full command list.
Most commands accept an optional argument to focus on a specific area:
/impeccable audit the header
/impeccable polish the checkout form
If you reach for one command often, pin it with /impeccable pin audit to get /audit as a standalone shortcut.
Note: Codex uses skills here, not /prompts: commands. Open /skills or type $impeccable. Repo-local installs live in .agents/skills/; user-wide installs live in ~/.agents/skills/. GitHub Copilot uses .github/skills/. Restart the tool if a newly installed skill does not appear.
Keeping .impeccable out of git
As you run commands, Impeccable writes working files under .impeccable/: critique and polish screenshots, live-mode session and preview state, runtime caches, and per-developer config. Most of it is ephemeral and should not be committed, while a few files are shared project artifacts that belong in the repo. Add this block to your project's .gitignore:
# impeccable-ignore-start
# Ephemeral output, runtime state, and per-dev overrides.
# Unanchored: .impeccable may sit at the repo root or under a nested
# workspace (apps/web/.impeccable/...); anchored patterns would miss it.
# Shared artifacts stay tracked: config.json, live/config.json,
# design.json, critique/*.md.
.impeccable/config.local.json
.impeccable/hook.cache.json
.impeccable/hook.pending.json
.impeccable/*.png
.impeccable/live/server.json
.impeccable/live/sessions/
.impeccable/live/previews/
.impeccable/live/annotations/
.impeccable/live/cache/
.impeccable/live/manual-edit-apply-transaction.json
.impeccable/live/manual-edit-events.jsonl
.impeccable/live/manual-edit-evidence/
.impeccable/live/pending-manual-edits.json
.impeccable/live/deferred-svelte-component-accepts.json
.impeccable/live/*.png
# impeccable-ignore-end
The block is wrapped in # impeccable-ignore-start / # impeccable-ignore-end markers so you can recognize and refresh it later. Patterns are unanchored on purpose: in a monorepo the active project (and its .impeccable/ directory) often lives under a nested workspace path like apps/web/, and a root-anchored pattern would miss it.
Keep these tracked (they are shared project artifacts, do not add them to .gitignore):
.impeccable/config.json(unified shared config).impeccable/live/config.json(live-mode framework wiring).impeccable/design.json(shared design spec).impeccable/critique/*.md(review reports)
If an ephemeral file (a screenshot, config.local.json) was committed before you added the block, .gitignore will not untrack it automatically. Run git rm --cached <path> to stop tracking it without deleting your local copy.
Design hook
On Claude Code, GitHub Copilot, Codex, and Cursor, npx impeccable install and npx impeccable update install a provider-native hook manifest along with the skill payload. The hook runs the Impeccable design detector on direct UI file edits and surfaces findings back into the agent flow. Claude Code, GitHub Copilot, and Codex surface findings after the edit. Cursor blocks bad proposed writes before they land.
Installed hook surfaces:
- Claude Code:
.claude/settings.local.json(gitignored, machine-local) runs${CLAUDE_PROJECT_DIR}/.claude/skills/impeccable/scripts/hook.mjs. A hook moved into the sharedsettings.jsonis honored in place. - GitHub Copilot:
.github/hooks/impeccable.json(committed, shared by the Copilot CLI and the cloud agent) runs.github/skills/impeccable/scripts/hook.mjs. The Copilot CLI activates it once the file is on the repository's default branch and the folder is trusted. - Cursor:
.cursor/hooks.jsonruns.cursor/skills/impeccable/scripts/hook-before-edit.mjs. - Codex:
.codex/hooks.jsonruns.agents/skills/impeccable/scripts/hook.mjs.
The installer preserves unrelated hook entries and settings. If a hook manifest is malformed, install/update aborts by default; rerun with --force to back up the malformed file as .bak and replace it.
On an interactive install/update, Impeccable explains the hook and offers to install it (default yes). Your choice is remembered per-developer in the gitignored .impeccable/config.local.json, so you are not asked again; --no-hooks skips it for that run without recording anything. Hook lifecycle settings live under the hook key of .impeccable/config.json; detector ignores live under detector, shared by /impeccable hooks and npx impeccable detect.
For debugging, set hook.auditLog in .impeccable/config.json to a path (or the legacy IMPECCABLE_HOOK_LOG env var) to write one NDJSON line per hook invocation. Leave it unset for normal use.
Codex requires one platform step that Impeccable cannot safely skip: open /hooks after install or update and approve the project hook. There is no Codex marketplace/plugin install flow for this hook.
Full hook docs: impeccable.style/docs/hooks.
Manual copy commands are fallback/debug instructions. The normal path is:
npx impeccable install
npx impeccable update
CLI
Impeccable includes a standalone CLI for detecting anti-patterns without an AI harness:
npx impeccable detect src/ # scan a directory
npx impeccable detect index.html # scan an HTML file
npx impeccable detect https://example.com # scan a URL (Puppeteer)
npx impeccable detect --json . # CI-friendly JSON output
npx impeccable detect --no-config src/ # raw scan, ignoring project config/context
npx impeccable ignores list # show detector ignores
npx impeccable ignores add-file "src/legacy/**"
npx impeccable ignores add-value overused-font Inter --reason "Brand font"
The detector catches 46 deterministic issues across AI slop (side-tab borders, purple gradients, bounce easing, dark glows) and general design quality (line length, cramped padding, small touch targets, skipped headings, and more).
By default, detect respects the same .impeccable/config.json and .impeccable/config.local.json detector config as the design hook: detector.ignoreRules, detector.ignoreFiles, detector.ignoreValues, and detector.designSystem.enabled. Hook lifecycle settings such as hook.enabled only affect automatic hook execution.
For a waiver that should travel with one file instead of the repo config, add an inline comment in the file: <!-- impeccable-disable overused-font: exported brand doc -->. The marker works in any comment syntax, scopes to the whole file (or one line with impeccable-disable-line / impeccable-disable-next-line), and is bypassed by --no-inline-ignores or --no-config.
Full detector docs: impeccable.style/docs/detector.
Supported Tools
- Cursor
- Claude Code
- GitHub Copilot
- Gemini CLI
- Codex CLI
- Grok Build
- OpenCode
- Pi
- Kiro
- Trae
- Rovo Dev
- Qoder
Community & Ecosystem
Join the community and ecosystem conversations:
- GitHub Discussions: file bugs, request features, and help newcomers.
- Impeccable on npm: grab the CLI, follow releases, and star the package.
- Follow @pbakaus on Twitter for release notes, sample lint reports, and video highlights of new rules.
Contributing
See DEVELOP.md for contributor guidelines and build instructions.
License
Apache 2.0. See LICENSE.
Created by Paul Bakaus