Ship UI a senior designer would sign off on.

polish_ audits real UI code for usability, design craft, and accessibility with a self‑hosted Node script, your own API key, no bots in your repo, and no quotas.

3 rubric layers
110 checkable rules
0 dependencies
No cap reviews per month

One component, before and after

The same card, reviewed by the same rubric. The before version is a realistic AI-generated component: inline hex colors, a clickable <div>, a delete action with no confirmation. Fix each finding and the score follows. The verdicts below are live model runs on Groq with the default model, llama-3.3-70b-versatile. Scores shift with the model, so run polish on your own code.

Before
62/100
0 critical, 3 serious, 2 moderate
demo/ProfileCard.before.jsx
No criticals. Three serious and two moderate findings cost 38 points.
After
78/100
0 critical, 1 serious, 3 moderate
demo/ProfileCard.after.jsx + demo/profile.css
Reviewed with its stylesheet. One serious and three moderate residuals.
serious[H1] No loading state for message and delete actions. Clicking gives no feedback. :14
serious[H3] No confirmation for the delete action. Delete runs with no way back. :17
serious[A11Y] Missing alt text for images. The avatar has no accessible name. :5
moderate[H2] Unconventional button labels. Message and Delete are terse and unspecific. :15
moderate[C1] Magic numbers in styles. borderRadius 12 is not from the design scale. :4

What the after review still flags

serious[A11Y] Icon button focus indicator flagged as not visible on all backgrounds. css:106
moderate[H2] Message button label could be more descriptive. :18
moderate[H3] No cancel button on the delete confirmation. :25
moderate[C2] Color tokens could be more semantic. --color-primary could be --color-brand. css:7

Then polish --verify findings.json re-checks each finding against the updated code, at a fraction of the cost of a full re-review. Live verdicts vary between models and runs, so treat any single score as a signal, not a grade.

See the fix in code

ProfileCard.before.jsxProfileCard.after.jsx

See it live

Two real components, each reviewed by the same rubric. Toggle Before and After to see what polish changes, then flip to Code to inspect the source behind each version.

AM

Alice Monroe

Product designer. Coffee powered. Ship small, ship often. Based in Lisbon.

128 posts 9.4k followers
Message Delete

Gradient background, hardcoded hex, divs as buttons, no focus styles, cramped 6px gaps.

Live review: 62/100, 3 serious, 2 moderate

Project Settings
Project name
Description
Visibility
Tags
Save changes

Divs as labels, no <form>, div-as-submit, no validation, no loading state, hardcoded hex.

Live review: 43/100, 1 critical, 2 serious, 3 moderate

Watch it run

The whole pipeline in one terminal: config, prompts, the model call, scoring, and findings with fixes. Recorded from live runs against both demo components with the default model on Groq.

polish demo/ProfileCard.before.jsx

Recorded live run, Groq with llama-3.3-70b-versatile. The same command runs live any time: polish demo/ProfileCard.before.jsx.

The rubric is data. Swap it.

Three layers cover what senior designers check in code. Not screenshots, not vibes. Every rule is written so a model can verify it against source, and the whole thing is plain data, so you can replace it with your own design philosophy.

Usability heuristics

How the system communicates and recovers: feedback, control, consistency, error prevention, and efficiency. Ten heuristics, H1 to H10.

  • Status visibility
  • Real world match
  • User control
  • Consistency
  • Error prevention
  • Recognition
  • Efficiency
  • Minimalism
  • Error recovery
  • Help

Design craft

Design-system discipline and production polish: tokens, type, spacing, motion, components, and the words on the buttons. Seven categories, C1 to C7.

  • Visual craft
  • Color and tokens
  • Typography
  • Spacing and layout
  • Motion
  • Components
  • Writing

Accessibility

Checkable requirements: contrast, keyboard support, semantics, forms, touch targets, and reduced motion. One pass, A11Y.

  • Contrast
  • Focus
  • Semantics
  • Forms
  • Touch targets
  • Reduced motion

One number: is it ready to merge?

Start at 100. Each finding deducts by severity, and criticals cap the ceiling. A score of 60 or above always means zero critical issues. Try it below.

Score simulator

critical
0
serious
3
moderate
2
62
No criticals. Only deductions apply.

How the score is built

SeverityDeductionExample
critical25Unreachable by keyboard
serious10Hardcoded hex, no confirmation
moderate4Magic radius, transition: all

0 criticals score as deducted
1 critical ceiling 59
2 criticals ceiling 49
3 or more ceiling 39
The score never drops below 0.

Install in two commands

Works with Groq, OpenAI, Anthropic, Gemini, OpenRouter, or any OpenAI-compatible endpoint. One provider per run, or set a fallback chain and polish tries them in order. Best for app UI reviews. Not a general code quality or backend linter.

Groqopenai/gpt-oss-120b
OpenAIgpt-4o-mini
Anthropicclaude-sonnet-4
Geminigemini-2.5-flash
OpenRoutergpt-4o-mini
01

Install

# bash
git clone https://github.com/tomiabe/polish.git
cd polish
npm link
02

Point it at a model

# export one key
export GROQ_API_KEY=...        # or OPENAI / ANTHROPIC / GEMINI / OPENROUTER
03

Audit your UI

polish                                   # audit files matched by config globs
polish src/components src/pages/*.tsx    # or specific files
polish --verify findings.json           # re-check that fixes landed
polish --json                           # machine-readable, for CI
polish --dry-run                        # preview cost, no API call

Exits with code 1 when critical findings exist. Wire it into pre-commit or CI.

04

Tailor the rubric

// .polish.json, everything optional
{
  "provider": "anthropic",
  "providers": ["gemini", "groq"],
  "rubric": ["usability", "craft", "accessibility"],
  "include": ["src/**/*.{tsx,css}"],
  "maxFiles": 20
}

polish audits this page too. Running polish --dry-run docs/index.html estimates about 29,000 tokens, under a cent on most models.

Same engine, one more door: MCP

polish also runs as an MCP server over stdio. Coding agents call the exact same engine as the CLI: identical prompts, identical scoring. Terminal users and AI agents can never disagree.

polish_review_files

Review UI files by content. Returns score, counts, assessment, and findings with severity, category, file:line, and a fix.

polish_verify_fixes

Re-check previous findings against updated content. Reports FIXED or STILL PRESENT per finding.

polish_usage

Usage status: always unlimited. Self-hosted means no quota and no subscription, just your own key.