impeccable
有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。——蒲松龄
所有 AI 做的页面,为什么长得像同一批人做的
一张你肯定见过的截图
浅灰背景。左上角一个圆角方形图标块,里面塞着一个细线条的几何图形。大标题用的是 Inter。按钮是一片从紫到蓝的渐变,圆角十六像素,底下压着一层淡淡的紫色光晕。内容区被切成三张卡片,卡片里又套着两层卡片。
这套东西不丑。它的问题在于太熟了——熟到你打开任何一个「AI 生成的落地页」,都能在第三秒猜到第七屏长什么样。
Impeccable 就是冲这件事来的。它的描述只有一句:让你的 AI harness 更懂设计的那个设计语言。
项目地址:https://github.com/pbakaus/impeccable
文档的第一行把它的构成讲得很干脆:一个 skill、24 个命令、浏览器里的实时迭代,以及 62 条针对 AI 生成前端的确定性检测规则。
四个数字,对应四种不同的干预方式。skill 是教材,命令是词汇,实时迭代是手,检测规则是尺子。
问题的根源,不在模型笨
Impeccable 对这件事的诊断,写得比大多数批评都准:
每一个模型,都是在同一批 SaaS 模板上训练的。
这句话解释了为什么不同公司的模型会犯同样的错。它们看见的世界是同一份世界——同一批用 Inter、同一批紫蓝渐变、同一批嵌套卡片的落地页。当你要它「做一个现代、简洁、专业的网站」,它给出的答案当然是那些页面的平均值。
平均值不难看,平均值只是没有观点。
所以问题不是「AI 不会设计」,而是「AI 太擅长复现平均值」。而设计这件事,恰恰是从平均值里偏出去才开始成立的。
它的出身,是一份被继承的作业
文档里有一段很坦诚的交代:Anthropic 的 frontend-design 是第一个被广泛使用的 Claude 设计技能,Impeccable 从那里出发。
「从那里出发」这四个字很重要。它没有宣称自己是凭空发明的,而是承认站在一份已有的作业上,然后往前推了一步。
推的方向也很清楚:frontend-design 给的是一套设计判断的准则,Impeccable 给的是一套可以执行、可以检查、可以复用的流程——把准则拆成命令,把品味拆成规则,把「这样不好看」拆成「第 37 条:不要在彩色背景上放灰字」。
先记住产品,再谈好看
整套流程的入口只有一个:/impeccable init。
这个命令做的事,听上去平淡,其实是整份设计里最关键的一步。它会检查项目,只问那些真正缺失的、关于产品的持久事实,然后写进一份 PRODUCT.md。
写进去的是:受众、目的、运行环境、约束、语气、证据。
这段话里有个很硬的区分:这些事实不能被混淆成表层的视觉方向。 换句话说,PRODUCT.md 回答「这是给谁用的、在什么场景下用、说话该是什么调子」,它不回答「用紫色还是用绿色」。
视觉方向被推到了后面,而且是按面逐个决定。已经存在的视觉体系、或者新建立的视觉体系,另外记在 DESIGN.md 里。
这个分层解决了一个很常见的事故:一开始就把「我们想要科技感」写进需求,然后整个项目被这句话绑死,连错误提示的文案都带着科技感。产品事实是长期的,视觉方向是每个界面自己的事,混在一起,两边都做不好。
24 个命令,一套可以吵架的词汇
命令列表很长,值得整张抄下来,因为它本身就是一份设计的工序表。
| 命令 | 做什么 |
|---|---|
craft |
完整的先成形再建造流程,带视觉迭代 |
init |
一次性设置:收集持久的产品上下文,写 PRODUCT.md,在适用时配置实时模式,推荐下一步 |
document |
从既有项目代码生成根目录的 DESIGN.md |
extract |
把可复用组件与 token 抽进设计系统 |
shape |
在写代码之前先规划 UX 与 UI |
critique |
UX 设计评审:层级、清晰度、情绪共鸣 |
audit |
跑技术质量检查:可访问性、性能、响应式 |
polish |
终局打磨,对齐设计系统,准备上线 |
bolder |
把无聊的设计放大 |
quieter |
把过头的设计收回来 |
distill |
剥到只剩本质 |
harden |
错误处理、国际化、文字溢出、边界情况 |
onboard |
首次运行流程、空状态、激活路径 |
animate |
加入有目的的动效 |
colorize |
引入有策略的颜色 |
typeset |
修正字体选择、层级、字号 |
layout |
修正布局、间距、视觉节奏 |
delight |
加入让人开心的瞬间 |
overdrive |
加入技术上出格的效果 |
clarify |
改善不清楚的 UX 文案 |
adapt |
适配不同设备 |
optimize |
性能改进 |
live |
视觉变体模式:在浏览器里对元素逐一迭代 |
generate |
在实时浏览器里为指定元素生成变体,不需要手动挑选 |
24 个。数一遍会发现它们不是平级的,而是成组的:shape、craft 负责从零到一;critique、audit、polish 负责从一到好;bolder 和 quieter 是一对反向旋钮;distill 和 delight 是另一种反向——一个减到最少,一个加到刚好;harden、adapt、optimize 管的是「上线之后会不会出事」。
这套命名的价值不在于命令本身,而在于它给了你和 AI 一套共享词汇。以前你说「这里感觉不对」,AI 只能猜;现在你说 /impeccable quieter,它知道你要把音量调小,而不是换个配色。
指令的模糊,是 AI 设计工作里最大的隐性成本。这些命令在做的事,是把形容词换成动词。
用法也很轻。大部分命令接受一个可选的目标:
1 | /impeccable audit blog # 审博客首页和文章页 |
或者干脆不用命令,直接用一句话描述:/impeccable redo this hero section。
如果某个命令你天天用,可以钉住它:/impeccable pin audit,之后就有独立的 /audit 快捷方式。
五条反模式,是这份技能的骨头
比 24 个命令更能说明立场的,是那份「明确不要做什么」的清单:
- 不要用被用滥的字体,Arial、Inter、系统默认字体都在名单里
- 不要在彩色背景上放灰色文字
- 不要用纯黑或纯灰,永远带一点色相
- 不要把一切包进卡片,也不要卡片套卡片
- 不要用弹跳或弹性缓动,那感觉过时了
五条,都是具体的、可判定的。注意它们的形式——不是「要有品味」这种无法执行的劝告,而是「不要卡片套卡片」这种一眼能验的禁令。
设计指导最容易失败的地方,就是写成格言。格言很美,但 agent 没法执行。禁令可以。
它不需要运行时,只需要一个可以被调用的二进制
安装那一节里藏着一个很克制的工程决定。
这份 skill 自己不需要任何运行时。每一份 skill 副本里都带一个小小的启动器,Windows 上是 impeccable.cmd,其余平台是 scripts/impeccable。启动器去跑 Impeccable 引擎——一个自包含的二进制,要么就躺在启动器旁边,要么在第一次运行时下载一次到 ~/.impeccable/bin/。
Node 只在用 npx impeccable 安装器的时候才出现,而那个安装器也只是同一份二进制外面套的一层壳。
这个设计的意义在于:你的机器上不必为了一个设计检查工具装 Node 生态。 手动安装和 Git 子模块这两条路,完全不需要 Node。
对一个要嵌进别人仓库、跑在别人编辑器里的工具来说,依赖越少,被接受的概率越高。
五条安装路径,各有各的场合
推荐的方式是 CLI 安装器。在项目根目录跑一条命令,它会:
- 列出检测到的 harness 目录或已安装的 CLI,比如
~/.claude、~/.codex、~/.grok、~/.hermes、~/.veto,或者项目本地的.cursor - 让你保留检测到的集合,或者自定义
- 问你是装进当前项目,还是装到全局
脚本里可以用 --providers= 和 --scope=project|global 跳过这两个选择。
在 Claude Code、Cursor、Codex、GitHub Copilot 和 Grok Build 上,它还会顺手把 provider 原生的 hook 清单装进当前项目。
第二条路是 Git 子模块,适合那种希望把 Impeccable 一起 vendor 进仓库、靠 Git 更新来管理的团队:加子模块,用 npx impeccable link 把编译好的 provider 构建链进各 harness 目录,然后一次性提交。link 会从 .impeccable/dist/universal/ 里逐个链接技能目录,而且不碰已经存在的真实技能目录,除非你加 --force。
第三条是插件市场:VS Code 里从扩展市场装,Claude Code 里加 marketplace 再装,Grok Build 用一条带 #plugin 后缀的命令装精简包。
第四条是从官网下 ZIP,第五条是从仓库手动复制——后者在文档里被明确定位为「兜底与调试用」,正常路径是 install 和 update。
五种方式摆在一起,是一种现实主义的体贴。团队规模不同、工具链不同、对供应链的信任程度不同,安装方式就该不同。
设计 hook:在你改完文件的那一刻出面
这是整套东西里最像「工具」而不是「教材」的部分。
在 Claude Code、GitHub Copilot、Codex、Cursor 和 Grok Build 上,安装或更新会带上一份 provider 原生的 hook 清单。这个 hook 会在你直接编辑 UI 文件时跑一遍设计检测器,然后把发现推回 agent 的流程里。
各家的落地位置不一样,文档列得很清楚:Claude Code 写进机器本地的 settings.local.json;Copilot 写进会提交的 .github/hooks/impeccable.json,由 CLI 和云端 agent 共用;Cursor 挂在 postToolUse 上;Codex 用 .codex/hooks.json,另配一个给 cmd.exe 的 commandWindows 兄弟项;Grok Build 需要先信任目录,而且它的发现要等到 Stop 才到达模型,不是每次编辑后。
有两条细节值得单独说。
第一条:安装器不会覆盖你原有的 hook 配置。 如果发现某份 hook 清单格式坏了,默认直接中止,加 --force 才会把坏文件备份成 .bak 再替换。一个会改别人配置的工具,最该有的品德就是这个。
第二条,也是更值得警惕的一条:在 Claude Code 里,已安装的命令 hook 独立于模型工具审批运行。所以第一次编辑或 Stop 事件,有可能在会话拒绝了模型启动器命令的情况下,仍然把引擎下载并缓存下来。文档没有把这件事说成优点,而是直说:无人值守运行之前,先审一遍装了什么 hook;要全部关掉,启动时传 --settings '{"disableAllHooks": true}'。
这种把风险主动摊开的写法,比任何安全承诺都更让人放心。
62 条规则,和一套很讲究的退出码
CLI 是可以脱离 AI 单独用的:npx impeccable 是一个小壳,跑的还是同一份引擎二进制。
检测的用法很朴素:
1 | npx impeccable detect src/ # 扫一个目录 |
这 62 条确定性规则分两类。一类针对「AI 味」:侧边标签式的边框、紫色渐变、弹跳缓动、暗色光晕。另一类针对通用的设计质量:行宽过长、内边距局促、触摸目标过小、跳级使用标题,等等。
分类这件事本身就有意思。它等于承认,「AI 生成的丑」有两种:一种是模型的口音,一种是人类也会犯的基本功错误。前者需要专门针对模型,后者需要一把通用的尺子。
然后是退出码,这一段设计得相当专业:
0表示扫描完成且没有主要发现2表示扫描完成但有主要发现1表示至少有一个目标扫不了
把「有问题」和「扫不了」分成两个不同的非零码,是 CI 集成的分水岭。很多工具把两者都返回 1,于是流水线无法区分「代码有问题」和「工具坏了」,最后只能一律放行。
文档还留了一句让人信服的免责声明:一次干净的检测是证据,不是证明;它不能替代在相关视口下真正看一眼渲染出来的体验。
一个卖检测工具的项目,主动说检测不等于质量,这需要一点底气。
检测之外,还有一份「这个世界该长什么样」的登记
Impeccable 不只是检查你写的东西对不对,它还会在每次新设计开始时,向 impeccable.style 的 roll API 要一手「视觉世界」的牌。
这一步是功能本身,所以它总会发生。
而这里紧接着就是隐私边界。默认情况下,它会记一条匿名记录:发出了哪一手牌、哪张牌赢了。发出去的内容包括:roll key、作用域、访客模式、重摇轮次、目录版本、获胜卡片的类型与目录 id 与位置、客户端版本、这个选择来自决策页还是 agent、以及一个用来去重的随机 id。
不发出去的内容也列得很清楚:你的项目名、文件、代码、PRODUCT.md,以及你的 agent 写下的方向名字。
再往下是一个更细的设计:提交进仓库的 surface brief 里,只记录一个种子引用——用 ~/.impeccable/seed-salt 里的随机盐对 roll key 做的哈希,而不是 key 本身。如果一台机器上留不住这个盐,brief 就干脆不记种子,而不是记一个更弱的哈希。
这句话值得念两遍。宁可少记,也不记一个看起来安全的东西。
关掉的方式给了四种:一条 telemetry off 命令、两个环境变量、或者项目级的配置项。关掉之后,摇牌照常工作,只是 API 被告知不要记录。
comp 还是 code,这不是审美问题
新界面开始设计时,Impeccable 有两条路。
comp-first:先生成一张全保真的设计稿,再照着它写代码。
code-first:直接在代码里建,把野心写进 surface brief 里一份仅开发期使用的方向契约,最后再对着检查。
文档给的评价很干脆:comp-first 更有胆量,也更慢;code-first 更精简,也更快。这个选择覆盖落地页和展示型界面。而 app 内的屏幕和文档,无论选哪种,都走 code-first——因为做出来比画出来更好。
/impeccable init 会问一次,把答案记成 buildPath,只认 comp 和 code 两个值。想在某台机器上覆盖团队的选择,写进本地的 config.local.json 就行——尤其是当你的 harness 没有图像生成能力时。
而且这个选项只在有图像生成能力的地方出现。没有画笔,就没什么可 comp 的。
最贴心的一段是迁移路径:老项目不必重跑 init,也不必手动改文件。每个决策页底部都有一个开关,翻一下只对当前会话生效;如果项目还没记录过任何值,翻完之后它会问一次要不要保留,然后写下来。
记录的是默认值,不是锁。 这七个字,值得所有做配置系统的人抄一遍。
哪些文件该进 git,哪些不该
跑命令的过程中,Impeccable 会在 .impeccable/ 下写不少东西:评审和打磨的截图、实时模式的会话与预览状态、运行时缓存、每个开发者自己的配置。
大部分是临时的,不该提交。少数是共享的项目产物,应该提交。
所以文档给了一段用 # impeccable-ignore-start 和 # impeccable-ignore-end 包起来的 .gitignore 片段,前缀用 **/,这样无论 .impeccable/ 在仓库根目录还是在 apps/web/ 这样的嵌套工作区里,都能匹配上。
要保留的是五样:统一的共享配置、实时模式的框架接线、共享的设计规格、每个面的策略与方向契约、评审报告。
还有一句很实在的提醒:.gitignore 没法让 Git 停止追踪一个已经被追踪的文件。如果某个临时文件早就被提交过,得手动 git rm --cached。
这些细节跟「设计」没什么关系,但它们决定了一个工具能不能在团队里活下来。
实时模式的边界,划得很硬
实时模式改的是本地检出:通过开发服务器,或者本地静态 HTML。
而文档紧接着就把话说死了:不支持把它的 localhost HTTP 助手注入到已部署的生产站点,包括 HTTPS 站点。不要为了让它能用而关掉浏览器安全策略,也不要削弱生产环境的 CSP。
还有一条更少见的提醒:应用文案编辑时,会自动在一个 shell 里跑 package.json 里的 impeccable:manual-edit-validate 命令,用的是你的用户权限。所以在不熟悉的检出里用实时模式之前,先看看那个脚本写了什么。
想检查生产站点,就走 detect 或者浏览器扩展。它们看的是渲染后的页面,不提供实时变体编辑,也不会把改动写回源码。
这三种能力的边界划得清清楚楚:改本地、看线上、绝不动线上。
十七个工具,一份共用的话术
支持列表最后拉了很长:Cursor、Claude Code、GitHub Copilot、DeepSeek Harness、Gemini CLI、Codex CLI、Grok Build、Hermes Agent、OpenCode、Pi、Kiro、Trae、Rovo Dev、Qoder、Mistral Vibe、Veto、Google Antigravity。
十七个。这个数字说明它赌的不是某一家 harness 会赢,而是「给 agent 加技能」这件事本身会变成常态。
也说明它愿意为不同平台的差异付代价:Codex 用的是 skills 不是斜杠命令,得打 /skills 或者 $impeccable;Copilot 的技能住在 .github/skills/;Hermes 对项目本地技能有一道每仓库的信任门,因为技能是过程文档,从任何克隆下来的仓库自动加载都被视为提示注入的入口。
最后这条几乎是整份文档里最清醒的一句话。它承认了:教 agent 做事的那份文件,本身就是攻击面。
最后
回到那张截图。
那套设计不是错的,它只是在做一件很安全的事——复现训练数据里的平均值。要让结果偏出平均值,不能靠再喊一遍「要有创意」,得靠三样东西:一份记住产品事实的文档、一套双方都认的词汇、一把能量出偏差的尺子。
Impeccable 把这三样都做成了文件:PRODUCT.md 记事实,24 个命令当词汇,62 条规则当尺子。它们都在你的仓库里,可以被读、被改、被提交、被 review。
设计这件事最难自动化的部分,是品味。但品味之下有一层是可拆解的——你知道为什么这张卡片不该套在那张卡片里,你知道为什么这段灰字放在紫底上读起来是脏的。把这些拆出来,剩下的才是真正需要人的部分。
工具能做的,是把你从平均值里推出来一点点。剩下的那一步,还得你自己走。
