Impeccable 设计检测 Hook 实战指南:`/impeccable hooks` 命令、双层级规则与多 Harness 接入
2026/9/10 10:01:00 网站建设 项目流程

Impeccable 设计检测 Hook 实战指南:/impeccable hooks命令、双层级规则与多 Harness 接入

【免费下载链接】impeccableThe design language that makes your AI harness better at design.项目地址: https://gitcode.com/GitHub_Trending/im/impeccable

Impeccable 为 AI 编码助手(Claude Code、Codex、Cursor、GitHub Copilot、Grok Build)提供一套自动化的设计检测 Hook:每当 Agent 直接编辑 UI 相关文件(.tsx.jsx.html.vue.svelte.astro.css.scss.sass.less.ts.js)时,Hook 会运行 impeccable 设计检测器,把机械性、明确无歧义的视觉问题(破图、溢出/裁剪、对比度与可读性失败、渐变文字、发光阴影、设计系统漂移)即时推送给 Agent,把其余更偏“品味”的检查(文案节奏、调色板与字体品味、布局韵律)延迟到会话结束的 Stop 深扫描。本文围绕.trae-cn/skills/impeccable/reference/hooks.md展开,结合仓库源码,系统讲解/impeccable hooks命令的用法、路由动作、配置项、异常(ignore)分流策略,以及它在各 Harness 下的安装与运行机制。读完你可以独立完成 Hook 的启用/关闭、忽略规则管理、finding 分级处置,并理解它背后的双层级设计与去重缓存原理。

Hook 是什么:一次编辑,一次机械化的设计体检

设计检测 Hook 的核心是机械化(mechanical):它只做规则引擎能百分之百确定的事,把不可判定的“审美”判断留给人类与 Agent 本身。/impeccable hooks命令负责管理这个 Hook 的项目级开关与忽略配置,而真正的扫描逻辑由 crates/hook 中的三个入口承载:

  • impeccable hook:对应 PostToolUse 逐编辑扫描 + Stop 深扫描(hook.rs);
  • impeccable hook-before-edit:对应 Cursor 的 preToolUse 写入拦截(before_edit.rs);
  • impeccable hooks <action>:即本文主角,hook 管理/配置命令(admin.rs)。

不同 Harness 的接入方式差异很大,这是理解 Hook 行为的第一把钥匙:

Harness触发方式行为特点
Claude CodePostToolUse(Edit\|Write)+ Stop编辑后把一段简短的 system reminder 推入 Agent 上下文;有 finding 给修正提示,遗留问题再提醒一次,干净的 UI 文件给一句简短确认(除非开启hook.quiet
CodexPostToolUse(Edit\|Write\|apply_patch)+ Stop与 Claude Code 类似;首次需通过/hooks授权
GitHub CopilotpostToolUse(edit\|create\|apply_patch同样的 post-tool-use 模式;没有可用的 Stop 深扫描,因此每次编辑都跑全量规则
CursorpreToolUse在坏写入落地前直接拒绝;允许干净写入时保持沉默;拒绝消息以工具错误形式可见
Grok BuildPostToolUse + Stop(additionalContext逐编辑扫描只做“标记”,finding 在 Stop 时统一上浮;不要期待逐编辑提醒——Grok 会丢弃该 stdout

其中.ts/.js文件虽然也在扫描范围(见 hook_lib.rs 中的ALLOWED_EXTS),但默认安静:除非检测器真的发现问题,否则不会对纯 TS/JS 文件发出确认类输出。

双层级规则:即时层 + Stop 深扫描

规则分两层运行,这是避免“每次编辑都被海量建议轰炸”的关键设计。

即时层(immediate tier):每次编辑触发,只上浮机械性、无歧义、值得打断一次编辑的问题。完整的即时规则清单定义在 registry.rs 的IMMEDIATE_TIER_RULES,从源码看共四组 13 条:

  • 破坏性输出broken-image(破图)、text-overflow(文字溢出)、clipped-overflow-container(容器裁剪溢出)、body-text-viewport-edge(正文贴视口边缘);
  • 客观对比度/可读性失败low-contrast(低对比)、gray-on-color(彩色背景上的灰色文字)、tiny-text(过小文字);
  • 单属性机械 slopgradient-text(渐变文字)、dark-glow(发光阴影);
  • 设计系统漂移design-system-fontdesign-system-colordesign-system-radiusdesign-system-font-size——这类问题在编辑当下不纠正会不断累积。

深扫描层(deep pass):其余规则(文案节奏、调色板与字体品味、布局韵律)全部延迟到会话结束的StopHook 事件,对本次会话触碰过的每个 UI 文件跑全量规则集,并对逐编辑扫描已报告过的内容做去重,只上浮一次新问题。会话没有任何遗留问题时,Stop 静默退出。

从 hook_lib.rs 的per_edit_tiering_active实现可以看到分层并非对所有 Harness 生效:

pub fn per_edit_tiering_active(config: &HookConfig, harness: &str) -> bool { if harness == "cursor" || harness == "github" { return false; // 没有 Stop 深扫描,延迟会导致规则永远不执行 } config.per_edit_rules != "all" }

即 Cursor 与 GitHub Copilot 没有可用的 Stop 深扫描,强制关闭分层、每次编辑跑全量规则,否则非即时规则会被静默丢弃;Claude Code、Codex、Grok Build 原生分发Stop事件,因此走分层。若你想在支持分层的 Harness 上也恢复“每次编辑跑全量规则”,在.impeccable/config.json里设置hook.perEditRules: "all"即可。

Grok Build 还有一个细节:它在end_turn之后还会补发一次reason: "shutdown"的 observe-only Stop——必须跳过这次,只扫描end_turn,否则同样的 finding 会被重复上浮(hook.rs 中的 Stop 入口对 Grok 的reason做了专门判断)。

最后要强调:任何 Hook 都是机械化扫描。扫描器抓不到的“手感/直觉”类规则(reflexes)存在于 craft-floor.md,skill 在编辑 UI 前会加载它,所以无论 Hook 是否接线都生效。完全没有自动 Hook 的会话,impeccable context会下发一条MANUAL_DETECTOR_REQUIRED指令,要求会话结束时手动跑一次检测。

配置模型:共享配置与本地覆盖

Hook 是按项目管理的,配置写入.impeccable/config.json(统一 Impeccable 配置;Hook 运行时设置位于其hook键下,共享的检测器忽略规则位于detector键下)。每位开发者的本地覆盖(包括 CLI 记录的安装同意hook.consent)写入被 gitignore 的.impeccable/config.local.json

对应源码 hook_lib.rs 中的默认值:

HookConfig { enabled: true, quiet: false, audit_log: None, design_system_enabled: true, per_edit_rules: "immediate".to_string(), advisory_rules: "exclude".to_string(), limits: Limits { max_findings: 5.0, max_chars: 8000.0, max_file_bytes: 131072.0, }, }

常用配置项速查:

配置键默认值作用
hook.enabledtrue设为false关闭自动 Hook(不影响手动 CLI 扫描)
hook.quietfalse设为true静默干净/遗留确认消息
hook.auditLog设为文件路径,写 NDJSON 审计日志
hook.perEditRules"immediate"设为"all"恢复每次编辑全量规则
hook.consentCLI 在on时记录的本地安装同意(config.local.json
detector.ignoreRules[]项目级整规则忽略
detector.ignoreFiles[]匹配文件的全部规则忽略
detector.ignoreValues[]规则/取值级忽略(可带filesreason
detector.designSystem.enabledtrue设计系统检测开关
detector.extensions[]追加服务端模板扩展名(见下)

三个遗留环境变量仍然生效,且优先级高于配置文件:IMPECCABLE_HOOK_DISABLEDIMPECCABLE_HOOK_QUIETIMPECCABLE_HOOK_LOGIMPECCABLE_HOOK_DISABLED=1常被当作“跟随 shell 的一次性开关”使用。

服务端模板扩展名:detector.extensions

项目使用 Blade、Twig、ERB 或 Handlebars 文件时,必须把扩展名声明在detector.extensions下,否则 Hook 会因为它们不在内置扩展名列表中而跳过。一条扩展名一个条目:

{ "ext": ".blade.php", "engine": "html" }

engine选择分析器:html用于标记模板(走静态 HTML 引擎),text用于 JS/TS/CSS 类文件,默认html。匹配方式是文件名末尾匹配,因此.blade.php.html.erb这类双扩展名都能命中。配置只能追加扩展名,内置列表始终生效。

手动扫描与配置的联动

手动npx impeccable detect默认使用同样的项目过滤配置:detector.ignoreRulesdetector.ignoreFilesdetector.ignoreValuesdetector.designSystem.enabled。注意hook.enabled只控制自动 Hook 执行,不影响手动 CLI 扫描。需要绕过项目配置/上下文做一次“裸扫描”时用:

npx impeccable detect --no-config ...

要对同样的 detector 忽略规则做直接的 CLI 增删改查,则用:

npx impeccable ignores ...

路由动作:/impeccable hooks <action>

命令的第一个参数是 action,缺省为status。完整路由表(与 admin.rs 中的ACTIONS常量一致):

Action作用
status打印当前状态、共享/本地配置路径、被忽略的规则/文件/值、环境变量覆盖
on.impeccable/config.json写入enabled: true,在本地记录 hook consent 为 accepted,并在 skill 已安装时安装/修复各 provider 的 hook manifest
off.impeccable/config.json写入enabled: false
ignore-rule <id><id>追加进detector.ignoreRules;对overused-font必须加--all-values。项目全局压制该规则
ignore-file <glob><glob>追加进detector.ignoreFiles。匹配文件的所有规则全部压制
ignore-value <id> <value> [--shared] [--reason "..."]追加一条共享的规则/取值压制(写.impeccable/config.json
ignore-value <id> <value> --local [--reason "..."]追加一条私有的规则/取值压制(写.impeccable/config.local.json
ignore-value <id> "*" --file <glob> [--file <glob>...]只在匹配文件中关掉某一条规则,其余位置保持生效。--file可重复,也支持--file=<glob>/--files=<glob>。裸"*"不带--file会被拒绝:真想全局压制请用ignore-rule <id>
reset删除项目配置、去重缓存与 Cursor pending 队列,并从on安装过的每个 provider manifest(包括已提交的 Copilot 文件)中移除 Hook 条目;on从不写入的团队共享settings.json不会被触碰

status的输出内容对应源码 admin.rs 的status_report:state、shared file、local file、ignoreRules、ignoreFiles、ignoreValues(含文件作用域)、maxFindings、maxChars、env override、cache file。配置或本地文件损坏时,会以(malformed; ignored)标注。

命令流程(Flow)

在 skill 中执行/impeccable hooks时按以下流程走:

  1. 从用户参数解析 action;无参数则默认status

  2. 调用管理脚本并把用户输出原样透传:

    .trae-cn/skills/impeccable/scripts/impeccable hooks <action> [args...]
  3. 若 action 为off,追加一行说明:“Done. New edits will not trigger the design hook in this project until you run/impeccable hooks on.”;

  4. 若 action 为on,追加:“Done. The design hook will fire after the next Edit/Write on a UI file.”;

  5. 若 action 为ignore-valueignore-fileignore-rule,直接打印脚本输出即可。默认作用域是共享的.impeccable/config.json;只有用户明确要求私有例外时才加--local

  6. 若 action 为status,直接打印脚本输出,除非用户追问,否则不要添加评论。

排查 finding:三分法分流与“最窄异常”原则

Hook 自身从不直接写 ignore 配置——所有例外都必须经过impeccable hooks,这样写入才能被校验、文件结构才能保持一致。收到 finding 时把它分流到三种结果之一:

  • 真设计问题:直接修。永远不要为了跳过修复或放行被拦截的写入而加 ignore;
  • 确信的误报或合规例外:自行持久化最窄的 ignore,并在回复中披露。判据必须是可以点名道姓的证据:有意的 demo 或 fixture、对坏设计的文档说明、字面或领域恰当的动效(比如弹跳的球)、或用户已经确认过的选择。把证据写进--reason,格式为"<谁决定的: 证据>";只有用户真的确认过,才写 “user confirmed”;
  • 不确定:保留 finding,用一句话问用户。只问一次——一行问题比 Hook 在之后的每次编辑上反复触发便宜得多。

自助权限止步于ignore-valueignore-fileignore-rule静默的范围太大,不能凭自己的判断添加,必须先问用户。

按“最窄异常”递减的优先顺序:

  1. 如果 finding 行给出了ignore-value <rule> <value>对,就带上--reason执行impeccable hooks ignore-value(默认写共享.impeccable/config.json);
  2. overused-fontbounce-easing这类取值特定的 finding,用ignore-value针对具体取值;不要为了一个具体字体用ignore-rule overused-font
  3. 若 finding 没有取值级命令(如side-tab),把该规则限定到文件:ignore-value <id> "*" --file <path>。执行前先跑npx impeccable detect <path>看这个文件实际触发了什么;
  4. 只有当整个文件都不在设计审查范围内(fixture、生成产物、故意制作的 slop demo)时才用ignore-file <path>——它会永久静默该文件的所有规则,包括还没写出来的未来规则;一个只是某条规则噪音较多的真实 UI 界面,应该用上面的文件级取值 ignore;
  5. ignore-rule <id>只在用户要求项目全局压制某条规则时使用;对 overused-font 的大范围压制,只有用户要求“普遍忽略 overused 字体”时才用ignore-rule overused-font --all-values

默认优先使用上述配置类 ignore(把压制集中在一个可审查的地方);只有豁免必须随单个文件一起离开仓库时(生成/导出的独立文档、通过邮件发送的 HTML 文件),才用行内注释。支持标记为:impeccable-disable <rule>(整文件)、impeccable-disable-line/impeccable-disable-next-line(单行),任意注释语法均可,可在:--后附加原因。检测器默认尊重行内标记;--no-inline-ignores--no-config可绕过(见 detect/src/cli.rs)。

命令示例

取值级例外(用户确认 Inter 是有意为之):

.trae-cn/skills/impeccable/scripts/impeccable hooks ignore-value overused-font Inter --shared --reason "User confirmed Inter is intentional"

自助例外的示例,证据点名(字面弹球动画,bounce easing 正是主题):

.trae-cn/skills/impeccable/scripts/impeccable hooks ignore-value bounce-easing bounce-ball --shared --reason "Agent: literal ball-bounce animation, bounce easing is the subject"

整规则字体例外:

.trae-cn/skills/impeccable/scripts/impeccable hooks ignore-rule overused-font --all-values --reason "User asked to ignore overused fonts generally"

“某文件只关某条规则”的例外(该文件其余检查仍值得做):

.trae-cn/skills/impeccable/scripts/impeccable hooks ignore-value design-system-font-size "*" --file "src/overlay/widget.js" --reason "Injected widget builds its own type scale; DESIGN.md's ramp describes the site"

整文件例外(文件完全不在审查范围):

.trae-cn/skills/impeccable/scripts/impeccable hooks ignore-file "src/legacy/Card.tsx"

从源码看,ignore-value的写入会做惰性条目拒绝(admin.rs 的add_ignore_value):如果某规则根本没有可提取的 ignore 值,直接报错并提示改用ignore-value <rule> "*" --file <glob>——避免写入一条永远匹配不到任何东西的“死配置”。

各 Harness 的安装与 manifest

Hook 随 Impeccable skill 捆绑,通过项目级 manifest 安装:

Harnessmanifest 路径备注
Claude Code.claude/settings.local.json(项目内,被 gitignore,Hook 保持机器本地)移到共享settings.json也会原位生效
Codex.codex/hooks.json(项目内)首次需通过/hooks授权
Cursor.cursor/hooks.json(项目内)确认 Settings -> Hooks 已启用
Grok Build.grok/hooks/impeccable.json(项目内)需要/hooks-trust--trust
GitHub Copilot.github/hooks/impeccable.json(项目内,团队共享、可提交)CLI 与云端 agent 都读它;CLI 在文件提交到仓库默认分支后生效

各 manifest 的命令形如在 admin.rs 的常量中:Claude 用${CLAUDE_PROJECT_DIR}/.claude/skills/impeccable/scripts/impeccable hook并挂PostToolUse+Stop;Codex 走.agents/skills/impeccable/scripts/impeccable hook(含 Windows 的.cmdshim 与commandWindows);Cursor 走hook-before-edit(preToolUse);Copilot 走bash形式的$(git rev-parse --show-toplevel)/.github/skills/impeccable/scripts/impeccable hookon安装时会做manifest 修复:识别旧的node hook.mjs形态并改写到 launcher 形态,损坏的 manifest 备份为.bak后再写,已有的其他 Hook 条目会与 impeccable 条目合并保留。

Cursor 的 preToolUse 拦截值得一提:hook-before-edit(before_edit.rs)会先解析工具输入中提议写入的内容——content/streamContent/text直接取用,old_string+new_stringedits数组则先在原文件上投影出编辑后的完整内容,甚至能解析teecp、heredoc、PythonPath.write_text等 shell 写入方式——然后运行真实检测器,只在确实发现问题时才返回{"permission":"deny"}。拒绝消息会作为工具错误展示给 Agent,让它在坏写入落地前重新考虑。该 gate 默认 fail-open:超过 1MB 的内容、无法读取的原文件、检测器抛错等场景一律 allow。

约束与失败模式

约束(Constraints)

  • 绝不要手工改.impeccable/config.json.impeccable/config.local.json:一律走impeccable hooks,保证写入被校验、文件结构一致。唯一例外是detector.extensions——它没有管理 action,用户要求覆盖某模板栈时,直接编辑该字段,其余部分不动;
  • 不要从本流程编辑impeccable hook/impeccable hook-before-edit背后的 launcher 或二进制——那是 skill 内部管道;
  • Cursor 能在检测到真实问题时拦截提议写入;Claude Code、Codex、GitHub Copilot 不拦截,而是发出 post-edit 提醒。关闭 Hook 会同时停掉拦截与提醒。

失败模式(Failure modes)

  • .impeccable/config.json.impeccable/config.local.json不可读或畸形,Hook忽略该文件,用剩余有效配置/默认值运行;impeccable hooks status会把畸形文件显示为(malformed; ignored)(对应 hook_lib.rs 的safe_read_json容错与 admin.rs 的read_raw_config_file);
  • 用户说“全局禁用 hook”时,先用/impeccable hooks off(对项目持久生效,写hook.enabled: false);遗留的IMPECCABLE_HOOK_DISABLED=1环境变量也能作为跟随 shell 的一次性覆盖。

底层原理小结:去重缓存与审计

Hook 的“不重复打扰”建立在会话级缓存上:.impeccable/hook.cache.jsonsession_id为键保存每个文件已报告过的 finding 签名、editCount、clean ack 状态;每次编辑 bumpeditCount,同一文件同一签名超过阈值(EDIT_COUNT_THRESHOLD = 6,见 hook_lib.rs)后,Hook 会发出 suppression 提示并停止继续提醒同一问题,避免 Agent 被循环打断。Stop 深扫描只对本次会话 touch 过的文件(上限STOP_MAX_FILES = 20)重跑全量规则,并对即时层已报告内容去重。所有运行都会在配置hook.auditLog指向的文件里追加 NDJSON 审计记录(含harnesseventdurationMsemittedfreshFindings等字段),方便事后排查“为什么这条提醒没出现”。这一整套行为都有 crates/hook/tests/hook_tests.rs 等测试用例覆盖,例如per_edit_tiering_active断言了 Cursor/GitHub 强制关闭分层、Claude 默认开启分层等关键语义。

对团队而言,推荐的落地路径是:/impeccable hooks status确认状态 →/impeccable hooks on开启并按提示在各 Harness 完成首次授权 → 在真实编辑中根据三分法分流 finding → 用ignore-value沉淀最窄异常(共享配置 +--reason留痕)→ 需要整体退出时/impeccable hooks offreset清理干净。

【免费下载链接】impeccableThe design language that makes your AI harness better at design.项目地址: https://gitcode.com/GitHub_Trending/im/impeccable

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询