88K-star Impeccable catches AI-looking UI with 62 rules
Tools22 min read

88K-star Impeccable catches AI-looking UI with 62 rules

What Impeccable adds to your project, where its 62 rules run (source, browser, design review), when hooks speak to the agent, and what data leaves your machine.

The frontend-design skill is a guidance document that tells the model “don’t drift toward generic design.” Impeccable adds 62 rules on top that count, directly in the code, whether that advice was followed. Guidance gets read according to the model’s mood, while rules run the same way on every edit. Hand a landing page to an AI and, in nearly any project, every letter is Inter, the background is a purple-to-blue gradient, there are cards inside cards, and each heading carries a rounded-square icon. This project’s job is to define those traces as “the mark of AI” and catch them.

As of Oct 27, 2026 (UTC), GitHub’s pbakaus/impeccable has 88,889 stars, 5.3k forks and 2,574 commits, and it is an Apache-2.0 open-source project that is not archived. The repository was created on Nov 16, 2025, and the README credits Paul Bakaus as its author. Instead of an introduction, this article takes the parts apart. It peels back, layer by layer, what the install puts in a project, then checks the three ways the rules run, when hooks speak to the agent, and which requests leave your machine, so you can decide for yourself whether to install it and whether to turn hooks on.

Four layers one install line puts in your project

It starts when you call the installer from the project root. The installer looks for agent folders such as ~/.claude, ~/.codex, ~/.grok and the project’s .cursor, then asks which tools to install into and whether to install for this project only or globally. In scripts, --providers=claude,cursor and --scope=project|global skip the questions.

npx impeccable install    # pick tools and scope, answer whether to install hooks
npx impeccable update     # update

There are several ways to install. In Claude Code, you can run /plugin marketplace add pbakaus/impeccable and then pick it in /plugin. A team that wants to pin a version can add it as a git submodule at .impeccable and link it into the tool folders with npx impeccable link --source=.impeccable --providers=claude,cursor. Grok Build has its own grok plugin install pbakaus/impeccable#plugin --trust. GitHub Copilot in VS Code has the renaissance-geek.impeccable extension, which installs only the skill and no automatic hooks. Whichever route you take, you have to reload the agent after installing before the new skill shows up. For tools that support hooks (Claude Code, Cursor, Codex, GitHub Copilot, Grok Build), the installer explains what the hooks do and asks whether to install them. The default is yes, and your answer is remembered in .impeccable/config.local.json, which is not committed, so it won’t ask again.

Once installation finishes, the first run is /impeccable init. It reads the project first, asks only about the facts that are missing, and writes PRODUCT.md. Because people may edit this file, correct it by hand if a guess was wrong. If the setup feels outdated, /impeccable doctor checks the hook paths, config keys and old file formats.

What gets placed this way falls into four layers. They run from the outside in, and this article’s sections follow the same order.

  • Command layerOne /impeccable with 24 subcommands. Append a target to narrow the scope, and turn frequently used commands into shortcuts with pin
  • Context record layerPRODUCT.md (who the product is for), DESIGN.md (the visual system), .impeccable/surfaces/*.md (per-screen briefs)
  • Detection engine layerA self-contained binary placed next to the skill or downloaded to ~/.impeccable/bin/ on first run. The skill and hooks don't need Node; only the npx installer uses Node 18.19 or later
  • Connection layerPer-tool hook config files, the detect CLI in the terminal, and a browser extension that inspects the rendered page

Outer layer: grouping the 24 commands by purpose

Grouped by purpose, the README’s table fits all 24 on one sheet. Most of them pick, by name, “which direction to push a screen that already exists,” so you can also just say “rebuild this hero section” without knowing the names.

What you want to do Commands
Design before building shape (design brief only, no implementation), craft (from design to implementation, including visual iteration)
Record context init (PRODUCT.md), document (DESIGN.md), extract (pull repeated UI into shared components and tokens)
Review critique (review of hierarchy, clarity and mood), audit (accessibility, performance, responsiveness), harden (error handling, i18n, text overflow)
Adjust direction bolder, quieter, distill (keep only the essence), overdrive (technically ambitious effects), delight
Targeted touch-ups typeset, layout, colorize, animate, clarify (copy), adapt (per device), optimize, onboard (first run and empty states)
Finish polish (align with the design system and get release-ready)
Iterate in the browser live (pick an element and compare variants), generate (create variants of a named element)

Appending a target narrows the scope. /impeccable audit blog covers the blog list and post pages, and /impeccable polish settings handles the settings screen. If you run /impeccable pin audit once, you can call it afterward as /audit.

Even the same command takes a different approach depending on what the screen does. The command reads the target screen’s purpose, settles on one of four characters, and writes the result into that screen’s brief. A landing or pricing page that pushes visitors to decide is Persuade. A dashboard, settings page or editor where people finish tasks is Operate. Documentation and guides are Read. A place where people browse works, such as a portfolio or gallery, is Experience. A developer tool’s landing page is Persuade while the same product’s docs are Read, so the character splits even within one product, and if the purpose is ambiguous you can simply tell it what visitors should do there.

When you build a new screen from scratch, the path forks once. In tools that can generate images, the default is comp, which makes a mockup first and builds to match it, and there is also code, which builds straight in code. comp can aim for bolder compositions beyond what coding models usually produce, but details drift when moving from image to code, so it needs a few rounds of review and takes more time. code produces a tidy first implementation, but it stays within the model’s natural range and so tends to end up less ambitious. App screens and docs are built code-first on both paths. The choice is saved as "comp" or "code" in buildPath in .impeccable/config.json, and to override the team setting only on your own machine in a tool without image generation, write it in the uncommitted config.local.json.

Middle layer: context that stays in files, and what to put in git

No matter how many commands you add, repeating the same questions every time defeats the purpose, so this tool keeps context in files. PRODUCT.md records only lasting facts, such as who uses the product and what it does, and what its tone and constraints are, and leaves out visual direction. DESIGN.md is where the document command reads the fonts, colors and corner radii of already-settled screens from existing code and records them. The per-screen briefs in .impeccable/surfaces/*.md hold that screen’s character (the four modes above) and direction. These three files fill the spot where guidance documents only said “decide on a mood,” and when DESIGN.md exists, the rule checker also uses its fonts, colors, radii and font sizes as the baseline to find “values not in the document.”

The catch is that these files pile up in the .impeccable/ folder mixed with other byproducts. Running the tool produces critique and finishing screenshots, live-mode sessions and previews, caches, and per-person settings, and the README advises putting temporary files in .gitignore while keeping the deliverables you share.

# impeccable-ignore-start
**/.impeccable/config.local.json
**/.impeccable/hook.cache.json
**/.impeccable/hook.pending.json
**/.impeccable/*.png
**/.impeccable/review/
**/.impeccable/live/server.json
**/.impeccable/live/sessions/
# ...the README continues with more live subitems
# impeccable-ignore-end

What to leave in commits is config.json, live/config.json, design.json, surfaces/*.md and critique/*.md. If you have already committed temporary files, adding them to .gitignore does not stop tracking them, so run git rm --cached <path> separately. The questions/ and mocks/worlds/ folders that the decision rounds create carry their own .gitignore, so new files don’t end up in commits even in projects without the block above.

One engine, three entrances, three kinds of eyes

The innermost layer is a single self-contained binary, and the hooks, the CLI and the browser extension all run the same rules through this engine. The site’s rule catalog marks each rule as “AI slop” (a tell that AI makes by habit) or “quality” (a problem that makes things hard to use), and also which kind of eye sees it. There are three kinds of eyes. One reads the CSS and markup in source code, one measures the layout of the page as actually rendered, and one is a design review where the model reads the purpose and judges.

The figure below shows which eye each entrance leads to and which ones run without an LLM. The two eyes in the green area at the top use no model and no API key.

Diagram of entrances, scans and examples: hooks and the detect CLI and extension lead to source scan and browser scan, and critique leads to design review Figure 1. Three entrances split into three kinds of eyes. The eye assignment of catalog entries is the editors’ count of the 67 listed on the site’s catalog page

The eyes are split because the same problem shows up in different places. A font name and gradient text can be seen from CSS alone, but text overflowing its box, a clipped menu or a line that is too long can only be found by actually rendering, and the impression that “the same card repeats down the page” needs an eye that knows the screen’s purpose. So of the 67 listed in the catalog, 50 are source, 11 are browser and 6 are design review. The catalog’s total on the site is 68, which is 62 detectors plus 6 design reviews.

How the 67 catalog slots are distributed

The catalog is organized into nine groups. The thickest slots are typography (13) and layout (12), and the named design-system checks, at 4, are among the thinnest.

Donut chart splitting the 67 catalog entries into nine groups, such as typography 13, layout 12 and general quality 10 Figure 2. Number of entries per group (based on the site’s catalog page, counted by the editors)

Representative rules give a feel for what each group looks at. The names are the catalog’s wording spelled out.

Group Notable rules
Typography Common fonts (Inter and the like), small label above a heading, badge above a heading, a last line left with a single word, headings with a short trailing line, crushed letter spacing, body text set entirely in capitals
Layout and spacing Card inside a card, monotonous spacing, content overflowing its box, clipped menus and popovers, lines that are too long, text hidden behind other elements
Color and contrast Purple gradients and AI palettes, gradient text, glowing accent colors on dark backgrounds, reflexively chosen cream and beige, gray text on colored backgrounds
Visual details Thick side border on one side only, decorative grids, cards stacking a 1px border with a wide shadow
Motion Bounce and elastic easing, pulsing status dots, auto-scrolling logo rows, decorative blinking cursors
Copy An em dash in every sentence, generic promo phrases like “supercharge,” forced contrasts repeated like slogans
Images Placeholder-like shape illustrations, images hidden under a nearly opaque overlay, broken src
General quality JS errors on load, contrast below WCAG AA, skipped heading levels, body text that is too small
Design system Fonts, colors, radii and font sizes not in DESIGN.md

The six design-review items are patterns that code can’t catch, so critique handles them. They are glass effects everywhere, overly rounded card corners, crude SVG illustrations, solving everything with a single font, big-number placement in the hero, and identical card grids. The last two are closer to a “feel” that a few lines of source can’t decide, so leaving them to the model’s eye is how this tool divides the work. One more thing: v4.7.0 added the straggler and unbalanced-heading checks to typography, which also flag paragraphs whose last line is left with one word and headings with a short tail.

What comes out of one detect run

detect is the way to run only the rules without an installed agent. All of it is read-only checking, so it doesn’t modify your source.

npx impeccable detect src/                               # code and styles in a folder
npx impeccable detect http://localhost:3000              # rendered page (needs Chrome, Chromium or Edge)
npx impeccable detect --viewport 390x844 http://localhost:3000   # at mobile width
npx impeccable detect --scope type,layout src/           # typography and layout rules only
npx impeccable detect --json src/ > findings.json        # for scripts and CI
npx impeccable detect --list-rules                       # list rules only (no scan)

Given a folder, it finds the supported UI and style files (.tsx, .jsx, .html, .vue, .svelte, .astro, .css, .scss and so on), and server templates (Blade, ERB and the like) are included if you list their extensions in detector.extensions. Given a URL, it looks at the rendered DOM, the computed layout and the accessible stylesheets, but it cannot read CSS from another origin without CORS permission because of browser security, and it writes nothing to your source. Human-readable results go to standard error, and JSON goes to standard output.

The terminal below strings together the shape of one result taken from a real scan in the official docs, the exit code, and one exception line. One result consists of a rule name, a line number and the problem condition on that line, and the card in the docs adds guidance on how to reconsider it.

Terminal screen showing the rule name and line number of a detect result, exit code 2, and the command that registers an Inter exception Figure 3. One result and the exit code. The output format follows the example in the official detector docs

You connect it to automation through the exit code.

Exit code Meaning
0 Scan finished with no main issues (advisories may exist)
2 Scan finished with main issues
1 At least one target could not be scanned. Treated as a failure even if other targets produced issues

Advisories are separately counted notes and don’t make a scan fail. A sharp shadow offset by 4px or more may be intentional neo-brutalism, so since v4.7.1 it comes out as an advisory rather than a failure, and adding data-impeccable-ignore="hard-offset-shadow" to that element silences it. As the docs themselves stress, a clean scan is evidence and not proof of visual or accessibility quality, so opening the real screen at several widths remains your job.

In a team repository, running npx impeccable detect --github src/ in GitHub Actions on every pull request attaches problems as comments on the lines that caused them. However, GitHub shows only 10 annotations per type per step and 50 per job, with the rest left in the log, and results from the HTML engine may lack line numbers, in which case the annotation attaches to the file. If your brand font is Inter and keeps getting flagged, don’t turn off the whole rule; record just that value as an exception (the last command in Figure 3). The exception goes by default into the committed .impeccable/config.json and applies to the whole team, and adding --local puts it only in the uncommitted config.local.json. To apply it to a single file, narrow it with --file or leave an impeccable-disable comment in the file; the reason in that comment is written for people to read, and the scanner discards it. The rule-ignore settings are read by both manual scans and hooks, and turning off hooks does not affect manual scans.

Desktop apps have a route too. Since v4.7.0, Electron, NW.js, CEF and WebView2 apps with a debugging port open can be inspected with npx impeccable detect --cdp 9222; it reads the windows currently open without touching them, and if there are several windows you pick one with --target. For a live website, the options are to give its URL or to use the browser extension, and injecting live mode into a production site is not supported.

What falls outside the rules is for audit and critique

The detector only says “this line trips a rule.” Everything beyond that is split between two commands. audit scores five areas, accessibility, performance, theming, responsiveness and implementation consistency, from 0 to 4 each, writes a report out of 20 points, and doesn’t fix code. One line from the official docs looks like this.

/impeccable audit the checkout flow
P1 · The pay button has no visible keyboard focus indicator. Tab reaches it, but nothing shows it is selected.

The second line above is an example sentence the editors translated from the docs’ report format. Read the report’s grades this way.

Grade Meaning When to fix
P0 · Blocking Someone cannot finish the task Right away
P1 · Major Large inconvenience or accessibility failure Before release
P2 · Minor A problem with a workaround At the next improvement
P3 · Polish A small point with almost no effect on use After the above are done

A high score can still hide one blocker, so the docs advise reading the individual items over the total. critique does the opposite: it judges whether the screen fits the brief’s purpose, whether the hierarchy is weak, and what mood it gives off, and saves the report in .impeccable/critique/. The polish that follows picks up the priorities written there.

So if you’re handling the checkout screen the day before launch, the order goes like this. If the screen feels flat and you don’t know why, critique; for blockers and accessibility, audit; for missing states and exceptions, harden; for slowness, optimize; for the final cleanup, polish; and after the fixes, run audit again to confirm. The order is an example the editors built by stringing together the command descriptions in the official docs, and the 62 rules keep helping from behind on every edit anywhere in this flow.

Hooks: right after an edit and at the end of a turn, when do they speak?

Hooks are the connection layer that runs the detector when an agent edits a UI file and sends the result back into the agent’s workflow. The point is to report a problem while the agent still remembers the code it just wrote, and each tool speaks at a different moment. Suppose three edits happen within one turn, and they split like this.

Timeline with one lane per tool showing when Claude Code and Codex, Cursor and Copilot, and Grok Build deliver results, either on each edit or at the end of the turn, within one agent turn Figure 4. Blue and green dots are moments that reach the agent; hollow dots are moments that only scan and hold the result until the turn ends

Claude Code and Codex report only quickly the problems that stand out immediately after an edit (broken images, overflow, readability, gradient text, glow, design-system deviations), and at the moment the agent finishes its response they look at all the files touched in that session with a wider set of rules. The design avoids nagging on every edit while the agent is in the middle of building, and if you need the full rules on each edit, change hook.perEditRules to "all". Cursor and Copilot run the full rules after an edit. Grok Build only scans during edits and delivers the results all at once when the turn ends. Cursor reviewed proposed writes before they were applied as of v3.6.0, but the README and the v4.7.1 changelog say it moved to checking right after the write, and npx impeccable update migrates old settings to the new method.

The wide check at the end of a turn filters out what has already been reported so it doesn’t repeat itself. There is one more thing. When the baseline before the edit can be confirmed (currently the text scan that uses Claude’s Edit and Write results), problems that already existed are hidden, and other results are marked as either a new problem or a problem of unknown origin. The README explains that an “unknown origin” mark does not mean this session created the problem.

Where hooks live and how trust works differ by tool.

Tool Config location What to do before turning it on
Claude Code .claude/settings.local.json (local settings, not committed) Accept workspace trust, then check the PostToolUse and Stop hooks in /hooks
GitHub Copilot .github/hooks/impeccable.json (committed, shared with the team) Must be on the default branch before Copilot CLI and the cloud agent use it
Cursor .cursor/hooks.json Re-reads the file when it changes
Codex .codex/hooks.json Approve once in /hooks after install, and approve again after an update that changes the definition
Grok Build .grok/hooks/impeccable.json Does not run without /hooks-trust or --trust

Check the status with /impeccable hooks status, and turn them on and off with /impeccable hooks on and /impeccable hooks off. Silence doesn’t mean there are no problems. It may be a clean edit, quiet mode, or hooks being off, and /impeccable doctor finds mismatches in the hook script path and between installed state and enabled state. Hooks check only web code and skip projects where PRODUCT.md declares ios, android or adaptive. If you need to debug, you can write a path in hook.auditLog in .impeccable/config.json to leave one log line per call.

Read this before turning hooks on. In Claude Code, installed hook commands run separately from the model’s tool approvals. So on the first edit or at exit, they may download the engine binary and place it in ~/.impeccable/bin/, and the README states this holds even if you denied the model’s command in the session. Read the hook contents before running unattended, and to turn them off use /impeccable hooks off, the environment variable IMPECCABLE_HOOK_DISABLED, or --no-hooks at install. Claude Code can also disable all hooks for a single run with --settings '{"disableAllHooks": true}'.

Four requests that leave your machine, and what builds up locally

The privacy policy states that project files and scan results are not uploaded to Impeccable’s servers. The detector and hooks run locally and return results only to the agent, and the prompts and files a coding tool sends to an AI provider follow that tool’s settings and terms. Four things go out.

  1. A new-version check about once a day. Turn it off with IMPECCABLE_NO_UPDATE_CHECK=1.
  2. When you start a new design, a request to impeccable.style’s roll API for “visual world” candidates. This is the feature itself, so it can’t be turned off.
  3. An anonymous record of which candidates were shown and what was selected. It can be turned off.
  4. Installation and the engine download. These come from npm or GitHub.

The selection record consists of values such as a random roll key, the kind and position of the candidates, the version, and whether the selection came from the decision screen or from the agent, and it reportedly does not send the project name, files, code, PRODUCT.md, or the direction names the agent made up. The committed screen brief keeps not the roll key itself but only a hash mixed with a random value from ~/.impeccable/seed-salt. The server says it does not record IP addresses or device identifiers, but this record has no fixed deletion deadline, and the privacy policy says that because it doesn’t identify individuals, one person’s records can’t be found and deleted. To turn it off, use one of npx impeccable telemetry off, DO_NOT_TRACK=1 or IMPECCABLE_NO_TELEMETRY=1; for the whole team, write "telemetry": false in .impeccable/config.json, and check the current state with npx impeccable telemetry status. Since v4.6.0, when it is off, the roll request also tells the server not to record. The candidate request and the preview images are needed for the feature, so they still go out even when it’s off.

Live mode and image generation carry their own costs and permissions. Live mode is in beta and edits a local dev server or static HTML, so it can’t be used on a deployed production site. When applying a copy edit it runs the optional impeccable:manual-edit-validate script in package.json with your permissions, so in an unfamiliar repository you should read that script first. For image generation on the mockup path, it uses the built-in generator if the tool has one, as Codex and Cursor do. If not, a fallback path using OPENAI_API_KEY opens up, and charges accrue separately to your OpenAI API project. Keep the key in the agent’s environment, not in chat or config files. The tool itself is free. Costs arise only from the coding tool and model usage fees and from this image generation.

From frontend-design to v4.7.1, and the check-only route

This layered structure was not built in one go. The README names Anthropic’s frontend-design skill as the starting point. Its SKILL.md lays out a flow: write a design plan covering color, fonts and layout first, review whether that plan is just a default that would appear for any topic, then write the code, and critique your own work as you build. It also lists the shapes AI design tends to converge on these days: a cream background with a serif heading and a terracotta accent, a black background with one fluorescent accent, newspaper-style rules and columns, a SaaS card bundle with the same rounded cards and the same shadows, and uppercase labels attached to any topic. Impeccable stacked context files and a checker on top of this, and by the changelog’s dates (skill versions) it grew like this.

Date Version What changed
Apr 8 v2.0 Skill renamed from frontend-design to impeccable and rewritten against evaluations
Apr 9 v2.1 Commands consolidated from 21 to 18 (later grown again, now 24)
Jun 14 v3.6.0 Project hooks that help while the agent is editing (Claude, Codex, Cursor)
Jul 21 v4.0.0 Roll method that draws the design direction from an outside seed instead of the model’s first idea, 58 detector rules at that time
Sep 4 v4.2.0 Unified on one self-contained engine instead of a Node runtime
Oct 15 v4.6.0 When telemetry is off, roll records are also asked not to be kept; Oh My Pi support
Oct 20 v4.7.0 Inspection of running desktop apps (--cdp), straggler and unbalanced-heading added
Oct 23 v4.7.1 detect --github annotation output and --list-rules, engine 0.1.17 included

The reason the roll method came in lies in a measurement in the v4.0.0 changelog. The project’s own measurement was that when it asked for something creative in sixteen different phrasings, 30 of 35 answers came back as the same concept. It concluded that what is missing is not creativity but variation, so it made directions come from an outside random seed rather than the model’s own ranking. Of the 360 it reviewed by hand, 188 are in the catalog as approved visual worlds, and six challengers sit next to the direction the model derived from the project, with the build going to a challenger only when it wins.

By burden, there are three entrances. The lightest is to skip installing and just run npx impeccable detect src/ to see how many findings your project has now. It gives up the guidance, but there is no agent, no hook and no network traffic, and results come out the same way every time. Above that is the route of adding only a guidance document, like Anthropic’s frontend-design, and at the top is the full Impeccable install, which stacks context files, 24 commands, rules that run on every edit, and hooks. Because this tool’s rules and commands grow often, it’s worth skimming the changelog once before you update.

#Impeccable#Agent Skills#frontend#design#Claude Code#open source