同一套模型,设计提示词写得再长,落地页还是会收成同一副面孔。Paul Bakaus 做的 Impeccable 把这件事从提示词里拆出来。仓库 README 写明,它是 1 个技能、24 条命令、浏览器里的实时迭代,外加 61 条确定性检测规则。命令行和浏览器扩展跑这些规则时不调用模型,也不要 API key。起点是 Anthropic 的 frontend-design 技能。它点名的重复痕迹包括到处用 Inter、紫到蓝的渐变、卡片套卡片、彩色底上的灰字,以及每个标题上方一块圆角方图标。
今日打开 GitHub 仓库页,页面显示 79.9k stars、4.8k forks、213 watching、2419 次提交,许可证 Apache 2.0。同一天 Trending 日榜把它标成今日新增 2870 stars,该页总星数写成 95341、fork 写成 5622。两页对不上。下文不取平均。总量以仓库页为准,热度只引用日榜上的今日增量。装这个技能不是为了再写一段更长的系统提示,而是让保存文件时有一套不靠模型的检查在旁边看着。
提示词为什么压不住同一套模板
模型见过的 SaaS 模板高度同质。系统提示里写不要用 Inter、不要用紫蓝渐变,下一次生成仍可能把这两样一起交出来。负面词只约束这一轮对话,不约束下一次无人值守的编辑。Impeccable 的处理不是再加一条负面提示,而是把耐久的产品事实和表面视觉方向拆开存。
斜杠命令 impeccable init 会检查项目,只追问产品事实里真正缺的部分,然后写入 PRODUCT.md。README 列出的耐久字段包括受众、目的、运行上下文、约束、语气和证据。访客模式和视觉方向不写进这一步,留到每个具体界面再选。已有视觉系统或新做的视觉系统另记在 DESIGN.md。命令 document 负责从现有代码生成根目录的 DESIGN.md。命令 extract 把可复用组件和 token 抽进设计系统。
这个拆分决定了后面的命令读哪份文件。critique 和 polish 如果把产品事实和视觉方向搅在一起,评审会变成口味争论。init 只补缺口,不把视觉风格伪装成产品事实。新界面可以走两条建造路径。一条先出高保真稿再按稿写代码,README 称为 comp-first,视觉更敢、耗时更长。另一条直接在代码里建,把野心写进仅用于开发的方向合同,做完再核对,称为 code-first。两条都依赖前面那份产品事实,不依赖你在聊天框里临时补的一句不要模板味。
团队里最常见的误用,是把 init 当成换肤命令。它不问主色。它问的是这件产品给谁用、在什么上下文里用、哪些约束不能破。视觉方向后选,而且按界面选,不是按仓库选一次就锁死。已有品牌的项目应先跑 document,把代码里已经存在的视觉系统记下来,再决定哪些界面允许偏离。新项目没有可提取的系统,就不要假装 DESIGN.md 已经存在。
六十一条规则不调用模型
61 条确定性规则和另一路只走模型的 critique 检查是两套东西。README 写明,命令行和浏览器扩展跑确定性规则时不调用模型,也不要 API key。审计因此可以进持续集成,不必把每次保存都变成一次付费推理。规则失败时应能在本地复现,不依赖当天模型的随机口味。
检测器配置放在 .impeccable/config.json 和 .impeccable/config.local.json。设计钩子读取的键包括 detector.ignoreRules、detector.ignoreFiles、detector.ignoreValues,以及 detector.designSystem.enabled。hook.enabled 只影响自动钩子,不影响检测器忽略项。命令 hooks 和 npx impeccable detect 共用 detector 这一段。共享配置进仓库,本机覆盖留在 config.local.json,不要把个人忽略写进大家都会拉到的那份。
单文件豁免不写进仓库配置,写在文件注释里。标记在任意注释语法里都生效。impeccable-disable 作用于整文件。impeccable-disable-line 和 impeccable-disable-next-line 作用于一行。参数 no-inline-ignores 或 no-config 会绕过这些标记。调试时把 hook.auditLog 设成一个路径,或使用旧环境变量 IMPECCABLE_HOOK_LOG,每次钩子调用写一行 NDJSON。日常不要开,否则每次编辑都多一次磁盘写。
规则不调用模型,不等于 critique 也不调用模型。critique 仍是体验评审,看层级、清晰度和情绪共鸣。audit 才是技术质量,覆盖无障碍、性能和响应式。把这两条命令当成同一个检查,会漏掉其中一路。确定性规则能抓住灰字压在彩底上、卡片套卡片这类可枚举痕迹。它抓不住一句文案是否让人想点下去。那部分仍要 critique,而且要在 PRODUCT.md 已经写清受众之后再跑,否则评审没有参照。
把忽略写进错误的文件,表现和没装检测器几乎一样。config.local.json 只在本机生效,同事拉仓库看不到你的豁免。config.json 进仓库,所有人一起跳过那条规则。单文件注释只放过那一个文件。三层不要互相替代。先用 detect 在干净配置下扫一遍,再决定哪一层该豁免,而不是一上来就把规则名写进忽略列表。
二十四条命令各自改哪一层
24 条命令都从 impeccable 这一条技能进入。单独输入该命令会列出全部子命令。多数命令可以带一个范围,例如只审页头,或只抛光结账表单。常用的可以钉成独立快捷方式。执行 impeccable pin audit 之后,可以直接用 audit 作为独立入口。钉住的是入口,不是另一套规则。规则仍是那 61 条,外加模型侧的 critique。
| 命令 | 改的是哪一层 | 不该拿它干什么 |
|---|---|---|
| init | 写 PRODUCT.md,记下受众、目的、约束 | 不负责选定视觉风格 |
| document | 从现有代码生成 DESIGN.md | 不替代产品事实 |
| extract | 把组件和 token 抽进设计系统 | 不负责出货前抛光 |
| shape | 写代码前定交互 | 不是最终视觉放大 |
| audit | 无障碍、性能、响应式 | 不是情绪向评审 |
| critique | 层级、清晰度、情绪共鸣 | 不跑那 61 条确定性规则 |
| polish | 对齐设计系统,做出货前收尾 | 不负责把无聊设计放大 |
| bolder | 放大偏平的设计 | 不改信息架构 |
| quieter | 压低过猛的设计 | 不负责补空状态 |
| live | 在浏览器里对元素做变体 | 不写仓库级忽略规则 |
表里只列了职责边界最容易混的十条。README 里其余命令还包括 craft、distill、harden、onboard、animate、colorize、typeset、layout、delight、overdrive、clarify、adapt、optimize、generate。craft 是先定形再建造并带视觉迭代。harden 补错误处理、国际化、文本溢出和边界情况。onboard 处理首次流程、空状态和激活路径。generate 在实时浏览器里为一个具名元素出变体,不需要人手逐个挑。colorize 是有目的地加颜色,不是把紫蓝渐变加回去。typeset 改的是字体选择、层级和字号。layout 改间距和视觉节奏。
Codex 不走 prompts 前缀。要打开 skills,或输入美元符号接 impeccable。仓库内安装落在 .agents/skills/,用户级安装落在家目录下的 .agents/skills/。GitHub Copilot 用 .github/skills/。新装的技能不出现时,先重启工具,不要连续重装。重装不会修复一个还没被信任的钩子文件。
装完技能还不等于 hook 在跑
技能本身没有独立运行时。每个技能副本带一个小启动器。Unix 上是 scripts 目录里的 impeccable,Windows 上是 impeccable.cmd。启动器去跑引擎二进制。二进制可以跟启动器放在一起,也可以在第一次运行时下载到家目录 .impeccable/bin/。Node 只在你用 npx 安装器时参与。手动复制和 Git 子模块都不需要 Node。钩子和技能本身也不需要 Node。缺的是启动器文件时,钩子被做成静默空操作,界面上往往没有红字。
推荐安装是在项目根执行下面三条。第一条指定提供方和范围,第二条刷新已有安装,第三条只查看遥测状态,不改变检测规则。
bash
npx impeccable install --providers=claude,codex,cursor --scope=project
npx impeccable update
npx impeccable telemetry status
不加参数时,安装器会列出它探测到的目录或已安装的命令行,例如家目录下的 .claude、.codex、.grok、.hermes、.veto,或项目里的 .cursor。你可以保留探测结果,或改提供方。scope 决定装进当前项目还是全局。README 写明可配合的工具包括 Cursor、Claude Code、Gemini CLI、Codex CLI、Grok Build、Hermes Agent、Veto,以及 DeepSeek Harness、GitHub Copilot、OpenCode、Pi、Kiro、Trae、Rovo Dev、Qoder、Mistral Vibe、Google Antigravity。
交互式安装会解释钩子并默认提议装上。选择记在被 git 忽略的 .impeccable/config.local.json,下次不再问。参数 no-hooks 只跳过这一次,不记选择。钩子清单如果是坏的,安装和更新默认中止。加 force 会把坏文件备份成 bak 再替换。安装器会保留无关的钩子条目,不会把别的工具写进同一份清单的记录清掉。
有三条容易被当成已经装完。Codex 在安装或更新后要打开 hooks 并批准项目钩子。Codex 按钩子定义跟踪信任,.codex/hooks.json 一变就可能要重新批准。Grok Build 需要项目目录信任,命令是 hooks-trust,或启动时加 trust,否则 .grok/hooks/ 里的脚本不跑。VS Code 市场扩展的标识是 renaissance-geek.impeccable,要求 VS Code 1.109.3 以上和 Copilot Chat。它只装技能,不装自动钩子。同一工作区不要再放一份重复技能。
Claude Code 也可以先把市场加上,命令是 plugin marketplace add pbakaus/impeccable,然后在 plugin 列表里安装。Grok 的瘦包命令是 grok plugin install pbakaus/impeccable 并带 plugin 后缀与 trust。这个后缀装的是技能、代理和钩子,不是整个单体仓库。Claude Code 里已安装的命令钩子独立于模型工具审批。第一次编辑或 Stop 仍可能下载并缓存引擎,即使当前会话拒绝了模型去跑启动器。无人值守前要先审钩子。要在一次运行里关掉 Claude Code 全部钩子,README 给的开关名是 disableAllHooks。
五家工具的拦截时机并不一样
同一条检测器,五家工具交回结果的时机不同。README 写明,Claude Code、GitHub Copilot 和 Codex 在编辑之后交回发现,并在支持的情况下于 Stop 再做一轮更深的检查。Grok Build 在编辑后扫描,用来预热 Stop,真正把发现交给模型是在 Stop。它的 PostToolUse 标准输出到不了模型。Cursor 会在错误的写入落地前拦住。你如果按某家工具的时机去另一家找提示,会把装好的钩子当成没装。
落点文件也不同。Claude Code 写 .claude/settings.local.json,这份文件被 git 忽略,只在本机生效。命令走技能目录里的 impeccable hook。若钩子被挪进共享的 settings.json,仍会就地生效。GitHub Copilot 写 .github/hooks/impeccable.json,这份会提交,Copilot 命令行和云端代理共用。它要等文件出现在仓库默认分支,且目录已信任,才会激活。Cursor 写 .cursor/hooks.json,跑的是 hook-before-edit。Codex 写 .codex/hooks.json,跑 .agents/skills 下的 impeccable hook,并带一个 commandWindows 旁路,给 cmd.exe 调用 impeccable.cmd。Grok Build 写 .grok/hooks/impeccable.json。
Veto 收到的是打好包的技能,放在家目录 .veto/skills/,不跑 Impeccable 原生编辑钩子。子模块安装用 npx impeccable link,从 .impeccable/dist/universal/ 链出各个技能目录。已存在的真实技能目录不会被覆盖,除非加 force。提供方名字要按项目实际写,例如 claude、cursor、gemini、codex、github、grok、hermes、opencode、pi、qoder、trae、trae-cn、rovo-dev、vibe、veto。
国内版 Trae 和国际版 Trae 的目录不同。国内版是家目录下的 .trae-cn/skills/,国际版是 .trae/skills/。复制后要重启 Trae。Google Antigravity 的全局技能落到家目录 .gemini/config/skills。这些路径差一截,技能会装上,钩子却不在你以为的那个文件里。只复制技能目录、不写钩子清单,确定性规则就不会在保存时自动跑。那时仍可以手动执行 npx impeccable detect,但那是人记得去跑,不是钩子。
核对时按这家工具的落点文件找,不要按另一家的时机找。Claude 的发现在编辑之后,Cursor 的拦截在写入之前,Grok 的结论在 Stop。路径对了、时机看错,会被误判成钩子没装。先确认清单文件存在,再看审计日志有没有调用行。
仓库里该提交的只有这几份
命令跑起来之后,.impeccable/ 里会堆工作文件。里面有评审和抛光的截图、实时模式的会话和预览、运行时缓存,以及每个开发者自己的配置。大多数不该提交。README 要求共享的只有这几份:.impeccable/config.json、.impeccable/live/config.json、.impeccable/design.json、.impeccable/surfaces/ 下的 markdown,以及 .impeccable/critique/ 下的评审报告。截图和会话状态进了仓库,评审差异会被二进制文件淹没。
忽略块用注释标记包住,方便以后刷新。下面是 README 要求放进 .gitignore 的核心几行,星号前缀用来同时盖住仓库根和嵌套工作区。
gitignore
# impeccable-ignore-start
**/.impeccable/config.local.json
**/.impeccable/hook.cache.json
**/.impeccable/hook.pending.json
**/.impeccable/*.png
**/.impeccable/review/
**/.impeccable/questions/
**/.impeccable/live/sessions/
**/.impeccable/live/previews/
# impeccable-ignore-end
星号加斜杠的前缀是为了同时盖住仓库根和 apps/web/ 这类嵌套工作区。gitignore 不能把已经跟踪的文件自动移出索引。截图或 config.local.json 如果先被提交过,要执行 git rm --cached 对应路径。本地文件还在,只是不再跟踪。工具自己也会在 .impeccable/questions/、.impeccable/mocks/worlds/ 和 .impeccable/build/state.json 上放忽略。已经进过索引的,下一轮会打印一次性通知,修复命令是 git rm -r --cached .impeccable/questions。
遥测和检测器不是一回事。新设计开始时,技能会向 impeccable.style 的 roll API 要一手视觉世界。这次请求本身是功能,总会发生。除非你退出,它还会匿名记录发了哪一手、哪张牌赢了,用来更新目录。发出去的包括每轮随机 roll key、范围、访客模式、重抽轮次、目录版本、赢的牌类型和位置、客户端版本,以及一个随机选择 id,用来把重复上报只算一次。不发送项目名、文件、代码、PRODUCT.md,也不发送代理写的方向名称。已提交的界面简报只记种子引用。种子是 roll key 在家目录 .impeccable/seed-salt 里的随机盐下的哈希,不是 key 本身。机器上存不住盐,简报就干脆不记种子。roll key 是 128 个随机比特。自己用 from 参数传短 key 时,引用容易被猜到,不要靠它保密。
关闭记录的命令是 npx impeccable telemetry off,状态存在家目录 .impeccable/config.json。也可以设环境变量 DO_NOT_TRACK 为 1,或设 IMPECCABLE_NO_TELEMETRY 为 1。项目级可以在 .impeccable/config.json 里把 telemetry 写成 false,让所有人退出。退出之后发牌仍可用,API 会被告知不要记录。隐私说明在 impeccable.style/privacy。
忽略标记写错,检测器会装聋
检测器装聋通常不是规则太少,而是忽略写错了层。整仓库不该看的文件放 detector.ignoreFiles。某条规则对这个产品不适用,放 detector.ignoreRules。某个具体值是设计系统允许的,放 detector.ignoreValues。只想放过一个文件,用文件内注释,不要把整条规则关死。注释标记被 no-inline-ignores 绕过之后,你以为豁免还在,检查却会重新报出来。这是预期行为,不是规则回潮。no-config 则连仓库配置一起绕过,适合对照一次干净扫描,不适合当成日常开关。
钩子没响也分几种。启动器文件不在,钩子静默空操作,页面上不会有红字。Codex 的 hooks.json 更新后没再批准,钩子不会跑。Grok 的目录没信任,脚本不执行。Copilot 的钩子文件还没到默认分支,云端代理不会激活。Cursor 拦的是写入之前,所以你在编辑器里看不到事后评论,不代表没装。Claude Code 的发现在编辑之后,Stop 上还有一轮。把 Cursor 的事前拦截当成 Claude 的事后评论去找,会误判成没生效。
出问题先看审计日志,而不是再装一遍。把 hook.auditLog 指到一个文件,确认每次编辑是否真的调用了启动器。日志没有行,问题在钩子注册。日志有行但没有发现,问题在忽略配置或规则本身。Windows 上 Codex 走 commandWindows,调用的是 impeccable.cmd。只复制了无扩展名的 impeccable,cmd.exe 找不到启动器,表现同样是静默。
技能更新用 npx impeccable update。子模块路线是先 git submodule update --remote .impeccable,再 npx impeccable link。两条路不要混用同一份技能目录,否则钩子指向的脚本和技能正文会错版。案例可以看官网的 Neo Mirai 前后对比,地址在 impeccable.style/cases/neo-mirai。那是命令改造过的真实项目记录,不是星数本身。仓库页和日榜页的星数对不上时,也不要用星数决定要不要装钩子。要看的是 hooks 文件是否落在这家工具实际读取的路径上,以及第一次编辑之后审计日志里有没有一行调用记录。