Hook傻瓜式制成工具(生成即用·自动化钩子)
按需生成 WorkBuddy Hook 的生产型 Skill。本版整合了一次真实的「配置不生效→排查→修复」全过程经验(见第七节),把踩过的坑直接变成生成规则,确保产出的 hook 真的能跑、且不会把正常任务卡死。
一、触发场景
正触发(加载本 Skill 并进入生成流程)
- 用户要求「建/加/配一个 hook」「自动拦截 X」「写文件后自动校验」「发消息自动注入」「任务结束自动提醒」。
- 提到生命周期节点:PreToolUse / PostToolUse / UserPromptSubmit / Stop。
- 关键词:hook、钩子、生命周期、拦截、自动校验、自动善后。
负触发(只解释、不自动改配置)
- 仅讨论 hook 概念 / 求助排错已有 hook / 问「我的 hook 为什么没生效」。
- 要求删除或禁用已有 hook(走第七节「回滚/卸载」说明,不直接改写)。
- 与非
settings.json的配置(MCP、automation、连接器)混淆时,先澄清职责边界。
节点决策树(用户说一句话 → 落到哪个节点)
| 用户意图 | 节点 |
|---|---|
| 「每次写文件后检查/善后」 | PostToolUse |
| 「禁止删/写个人目录」「拦截危险命令」 | PreToolUse |
| 「发消息自动带公司信息/格式约定」 | UserPromptSubmit |
| 「任务结束提醒/通知/自动呈现」 | Stop |
| 不确定 → 用 AskUserQuestion 问 Q1(见第二节) | — |
> 更多节点(SessionStart / SubagentStop / PreCompact 等)可用,但本 Skill 默认只覆盖上表 4 个最常用节点,超出时提示用户确认。
二、生成流程(严格按此执行)
澄清阶段(用 AskUserQuestion 或自然语言二选一):
- Q1 在哪个时机触发? → UserPromptSubmit / PreToolUse / PostToolUse / Stop
- Q2 作用对象/范围? → 哪些工具(matcher)、哪些路径/事件
- Q3 触发后具体做什么? → 拦截 / 校验 / 注入文本 / 通知
- Q4 当前系统? → Windows / macOS / Linux(决定 command 与权限处理)
- Q5 是否现在写入 settings.json? → 是(需确认)/ 否(只给配置)
默认推荐逻辑:
- 脚本形态默认 Python(除非用户明确要 shell 专用)。
- matcher 默认用户点名工具,否则给最小可用集;全工具用 "*"。
- 默认不自动写 settings:先给片段 + 预览,确认后再落(R25 前置)。
落地步骤(写入前必须做):
1. 备份:cp ~/.workbuddy/settings.json ~/.workbuddy/settings.json.bak.<时间戳>。
2. 合并非覆盖:读取现有 hooks,把新条目并入数组(用 assets/settings_merge.py 或手动 append),绝不直接覆盖整个 hooks 段(会删掉用户已有 hook,高危)。
3. 写脚本:放到 ~/.workbuddy/scripts/(或 ~/.workbuddy/hooks/),读 stdin(JSON) 提取参数,逻辑健壮。
4. 写 command:~/.workbuddy/scripts/xxx.py;Windows 前缀 managed python 绝对路径,macOS 同样用 python 绝对路径(最稳,免 chmod 烦恼)。
5. (仅 macOS)权限处理:bash macos_setup.sh <脚本> 设可执行位 + 清 quarantine + 转 LF;若脚本碰 Desktop/Documents/Downloads,需在「系统设置→隐私与安全性→完全磁盘访问」给 WorkBuddy 授权(否则 TCC 会拦脚本读这些目录)。
6. 生成即测(强制,见第九节):在落盘到真实 settings 之前,先对「生成的脚本 + command + settings 片段」构造测试规格(test spec),运行 assets/hook_self_test.py --mode sandbox。该 harness 会真实验证 ① 脚本写入目标文件 ② settings 正确挂载(注册条目 + 用户级铁律)③ 触发条件(事件/matcher/环境)④ 执行效果(退出码/输出/副作用),并模拟宿主派发真实跑一遍脚本。必须 PASS 才能进入下一步;若 FAIL,按它抛出的「原因码 + 修改建议」修复后重测,绝不把无效/未注册代码交付出去。
7. 确认块:落盘前展示——
- [ ] 已备份现有 settings.json
- [ ] 已并入现有 hooks(非覆盖)
- [ ] 权限/环境:macOS 已跑 bash macos_setup.sh 设可执行位 + 清 quarantine + 授予 TCC「完全磁盘访问」;Windows 无需此步(无 quarantine / 不需 chmod / 无 TCC)
- [ ] 已跑 hook_self_test.py --mode sandbox 并 PASS
三、核心概念(生成 hook 时必须遵循)
Hook = settings.json 的 hooks 配置段 + 本地脚本。配置告诉系统在哪个节点跑,脚本是实际干的事。
- 配置跨平台无差异(都是同一套 JSON 结构)。
- 真正 OS 相关只有两处:① command 里的「脚本路径+解释器」;② 脚本本体(换行符/可执行位/隔离标记)。
- 推荐 Python 写脚本(正文两份系统相同),仅 command 解释器前缀不同。
stdin 事件契约
WorkBuddy 将 hook 事件以 JSON 经 stdin 传入,常见字段:tool_name、tool_input(含 file_path 等)、tool_response。
- 提取路径:优先 tool_input.file_path,兜底命令行 argv[1]。
- PreToolUse 脚本非零退出(如 exit 2)即拦截该工具调用;stderr 作为拦截原因展示给用户。
- PostToolUse 脚本非零退出通常不阻断,仅记录。
- 字段名以 WorkBuddy 实际行为为准;不确定时先用 argv 兜底并提示用户验证。
四、安全与边界(底线)
- 涉及写
~/.workbuddy/settings.json属用户级配置修改,落地前必须用户确认(R25 前置,消除原指南 L82 自相矛盾)。 - 全局 fail-open(最高优先级):每个 hook 脚本任何异常/超时一律
exit 0放行,绝不让正常任务卡死。这是不可妥协的底线。 - 单条熔断:每个脚本读取
~/.workbuddy/hooks/hooks.config.json的enabled,false 即直接跳过——秒级启停单条,无需改 settings、无需重启。 - 自查豁免:扫描/校验类钩子跳过
hooks.config.json/settings.json/ 钩子目录自身,避免把已配好的凭证/配置误报。 - 脱敏日志:钩子把发现写入
logs/hook-<规则>.log,靠时间戳+内容判断触发与正确性;敏感内容一律脱敏(绝不写明文)。 - 个人目录保护类 Hook 列出受保护目录,默认含 Desktop/Downloads/Documents,可由用户增删;并设 WHITELIST 显式放行正当编辑,避免 TCC/误伤阻断用户合法操作。
五、验证协议(先验证「加载」再验证「逻辑」)
> 这是 2026-08-09 排查中得出的最关键顺序:静默不生效最危险,务必先排除「没加载」。
- 验证加载:做一次真实
Write/Edit操作 → 查~/.workbuddy/hooks/logs/出现新时间戳记录(探针/校验实锤触发)。若没记录 = 没加载,先查配置层(第六节铁律)。 - 验证逻辑:加载确认后,再调业务逻辑(如写含伪造密钥的
.py看是否被捕获脱敏)。 - 客户端诊断:在对话框直接敲
/hooks可列出已加载钩子。 - 阻断类安全验证:临时把对应
enabled开 → 观察 deny → 回关,不留常开状态。 - 造两类夹具:「会命中」与「不命中」各一个,覆盖正负路径。
六、配置层铁律(来自真实排障,务必遵守)
桌面端钩子只认用户级 ~/.workbuddy/settings.json,不要放项目级。
- 排查实录:把 9 个规则钩子 + 1 个探针写进
<workspace>/.workbuddy/settings.json顶层hooks,重启后静默不生效(日志无记录、探针不动)。 - 根因:桌面端启动参数
--setting-sources user只加载用户级配置,根本不读项目级。 - 验证方法:查桌面端运行日志
~/.workbuddy/logs/<日期>/*.log里--setting-sources的值;或敲/hooks看是否已加载。 - 在线文档可能 404:以本机
plugin-dev插件自带官方hook-developmentSKILL.md + 桌面端启动日志为准,不要盲信在线文档。
七、实战经验整合(2026-08-09 钩子故障排查与修复 · 提炼 Checklist)
7.1 可复用经验(新 Skill / 新钩子开发 Checklist)
- 【P0 配置层】桌面端钩子只认用户级
~/.workbuddy/settings.json,不要放项目级。改前先备份该文件(时间戳副本)。 - 【P0 验证顺序】先验证「加载」再验证「逻辑」:真实工具调用 + 查日志确认钩子被触发,再调业务逻辑。静默不生效最危险。
- 【P0 失败兜底】钩子脚本全局 fail-open:任何异常/超时一律
exit 0放行,绝不让正常任务卡死。 - 【P1 单条熔断】每条钩子读取
hooks.config.json的enabled:false 即直接跳过。秒级启停单条,无需改 settings、无需重启。 - 【P1 matcher 语法】官方通配符是
"*"(不是正则".*");按工具名筛选用Write|Edit,全工具用"*"。 - 【P1 自查豁免】扫描类钩子要跳过自检(不扫
hooks.config.json/settings.json/ 钩子目录自身),避免把已配好的凭证误报。 - 【P1 日志即证据】钩子把发现写
logs/hook-<规则>.log,靠时间戳 + 内容判断触发与正确性;敏感内容一律脱敏(绝不写明文)。 - 【P2 文档不稳】在线 Hooks 文档可能 404;以本机
plugin-dev官方 SKILL.md + 桌面端启动日志(--setting-sources值)为准。 - 【P2 测试技巧】造「会命中」与「不命中」两类夹具;阻断类钩子用「临时开 → 观察 deny → 回关」的方式安全验证,不留常开状态。
7.2 坑位清单(避免重复踩)
| 坑 | 现象 | 正确处理 |
|---|---|---|
| 项目级配置桌面端不读 | 重启后钩子静默不生效 | 写到用户级 ~/.workbuddy/settings.json |
matcher 用 .* |
可能不匹配 | 用官方 "*" |
| 探针 heredoc 顶掉 stdin | 读不到事件名 | 直接读 stdin,不内嵌子进程吃管道 |
| 在线文档 404 | 推断无据 | 查本机 plugin-dev 官方文档 + 启动日志 |
| 静默不生效 | 最难发现 | 先验证加载(真实调用+日志),再调逻辑 |
7.3 真实验证结果(本次排查最终成功态)
- 真实
Write一个文件 →hooks/logs/出现新时间戳记录(探针 / F3 实锤触发)。 - 写含伪造密钥的
.py→secret_scan捕获并脱敏(sk_*******90),全日志零明文。 - 客户端内置诊断
/hooks可列出已加载钩子,确认加载成功。
八、资产索引
references/hook-templates.md— 常见 hook 模板(A 校验 / B 个人目录保护 / C 注入 / Stop 提醒)+ settings 片段 + 跨平台表 + 回滚流程。assets/verify_file.py— 跨平台文件校验脚本(PostToolUse),含 fail-open / 熔断 / 自查豁免 / 脱敏日志。assets/guard_personal_dirs.py— 跨平台个人目录保护脚本(PreToolUse 拦截),含 WHITELIST 放行 / fail-open / 熔断。assets/inject_context.py— 发消息自动注入脚本(UserPromptSubmit),模板 C 落地实现。assets/macos_setup.sh— Mac 权限/换行符一键处理。assets/windows_setup.ps1— Windows 部署前准备与 command 生成(无需 chmod/quarantine)。assets/settings_merge.py— 安全合并 hooks(备份 + 并入数组非覆盖)+ 生成hooks.config.json熔断开关。assets/hook_self_test.py— 生成即测 harness:写盘 + 挂载 + 触发 + 执行效果四层自动验证,失败明确抛错 + 原因码 + 修改建议(见第九节)。
九、自动验证(生成即测 · hook_self_test.py)
> 这是本 Skill 的「防交付无效代码」闸口:生成 hook 代码后立即自动测试,而不是凭感觉说"应该没问题"。
9.1 为什么需要它
手写 hook 最常见的坑:① 脚本根本没写到文件(空文件 / 路径错);② settings 没真正注册(节点名拼错 / 被覆盖);③ matcher 写错导致事件不触发;④ 脚本逻辑有 bug(退出码/副作用不符)。这些问题"看起来生成了"却实际不生效。本 harness 用真实派发模拟把四层都验一遍。
9.2 双模式
--mode sandbox(默认,安全):在临时目录虚拟一套~/.workbuddy树,把生成的脚本写进去、构造 settings、模拟宿主用 stdin(JSON) 真实跑脚本。全程不碰你真实配置,适合"生成后立刻自检"。--mode real(部署后校验):针对已落地的配置做只读 + 模拟验证——读真实settings.json、校验条目注册、并真实运行已部署脚本看效果;额外校验配置是否落在用户级(项目级铁律)。real 模式不写 settings,只模拟派发。
9.3 测试覆盖的四层
| 层 | 验证项 | 失败原因码(示例) |
|---|---|---|
| 写盘 | 脚本真实写入目标文件(存在 / 非空 / 大小正常) | FILE_NOT_WRITTEN / FILE_EMPTY |
| 挂载 | settings 合法 JSON + hooks.<node> 已注册该条目(command/matcher 对齐)+ 用户级铁律 |
SETTINGS_INVALID / HOOK_NOT_MOUNTED / PROJECT_LEVEL_CONFIG |
| 触发 | 事件节点、matcher 命中("*" 或枚举)、OS 环境匹配 | MATCHER_MISMATCH / ENV_OS_MISMATCH |
| 执行 | 模拟派发真实跑脚本 → 退出码 / stdout 预期串 / 副作用文件(状态变更);可选负向夹具防误伤 | EXIT_CODE_MISMATCH / STDOUT_MISSING / SIDE_EFFECT_MISSING / TRIGGER_FALSE_POSITIVE |
| 解释器 | command 中 <PYTHON> 已替换 / 脚本路径存在 |
PYTHON_NOT_FOUND / COMMAND_MISMATCH |
9.4 失败处理(核心要求)
任一不通过 → 打印 🔴 FAIL + 原因码 + 针对性修改建议,并以非零退出。脚本自身不做 fail-open(它的职责就是"明确报错"),但自身崩溃会被捕获并打印可读错误后退出。完整原因码→建议映射见 assets/hook_self_test.py 的 DIAGNOSIS 字典与 references/hook-templates.md。
9.5 典型调用
# 生成 hook 代码 + 写一份 spec.json 后:
<PYTHON> assets/hook_self_test.py --spec spec.json --mode sandbox
# 部署到真实 settings 后,再做一次真实校验:
<PYTHON> assets/hook_self_test.py --spec spec.json --mode real --settings_path ~/.workbuddy/settings.json
spec.json 结构见 references/hook-templates.md「测试规格(test spec)模板」段。