Fail a build on taste: wiring a design gate into CI
Eduardo CalvoWrote the skill and the detector this post measures with
Lint catches syntax. Types catch shape. Nothing in a normal pipeline catches a page that is technically fine and visibly generated. That is the gap a design gate fills.
The command
npx ui-craft-detect src --format junit
No config file needed, no model call, no network. It reads source, applies 43 deterministic checks — 38 anti-slop and 5 on accessibility — and exits non-zero when something fails. Same input, same answer, twice. Token discipline and a second accessibility pass live in the score rather than the CLI, which is what takes the whole system to 52 gates.
The GitHub Action
- name: Design gate
run: npx ui-craft-detect src --format junit --threshold 85
--threshold is the score, 0 to 100. Below it, the job fails.
What to gate, and what not to
Gate: the checks with a right answer. Missing focus states. Contrast under the bar. Tables
with no overflow handling. transition: all. Images with no dimensions. Heading levels
skipped. These are defects, and a defect that reaches review wastes a human’s attention on
something a script should have caught.
Do not gate: the judgement calls. Whether six cards in a row is wrong depends on what the six cards are. Whether a page commits enough colour is a decision about the brand. The detector reports these as warnings on purpose — they belong in the pull request conversation, not in a red X.
The distinction matters more than the tooling. A gate that fails on taste teaches the team to route around it.
Start at your current score
The mistake is setting the threshold at 100 on day one and watching everyone add ignore comments. Run the scan, take the number you have, set the threshold there, and raise it when the number goes up on its own.