关于 hooks-development
hooks-development 是用于开发和调试 Claude Code hooks 的技能,重点说明输出可见性、安全处理输入、shell 与 Bun 的选择及验证步骤。
主要功能
- 01Hook 输出可见性规则
- 02安全处理 AskUserQuestion
- 03Shell 与 Bun 选型建议
- 04创建和调试检查清单
适用场景
- 01创建 PreToolUse 或 PostToolUse hook
- 02排查 Claude 看不到 hook 消息
- 03检查 hook 配置和输出
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ terrylica/ cc-skills --skill hooks-development安装后在 Claude Code 中输入/hooks-development确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/debugging-guide.mdevolution-log.mdhook-templates.mdlifecycle-reference.mdvisibility-patterns.md详细介绍
Hooks 开发
开发 Claude Code hooks 并正确设置输出可见性的指南。
自我演进的技能:此技能会在使用中不断改进。如果指令有误、参数发生偏移,或需要变通方案,请立即修复此文件,不要拖延。仅针对真实、可复现的问题进行更新。
何时使用此技能
- 创建新的 PostToolUse 或 PreToolUse hook
- Claude 看不到 hook 输出(最常见的问题)
- 用户询问
decision: block模式 - 调试 hook 消息为何没有显示
- 用户提到“Claude Code hooks”或“hook 可见性”
快速参考:可见性模式
关键结论:只有当 JSON 包含 "decision": "block" 时,Claude 才能看到 PostToolUse hook 的 stdout。
| 输出格式 | Claude 可见性 |
|---|---|
| 纯文本 | 不可见 |
不含 decision: block 的 JSON | 不可见 |
含 decision: block 的 JSON | 可见 |
退出码行为:
| 退出码 | stdout 行为 | Claude 可见性 |
|---|---|---|
| 0 | 解析 JSON,仅在详细模式下显示 | 仅当包含 "decision": "block" 时 |
| 2 | 忽略,改用 stderr | stderr 会显示给 Claude |
| 其他 | stderr 在详细模式下显示 | 不会显示给 Claude |
绝不重写 AskUserQuestion
PreToolUse hook 绝不能为 AskUserQuestion 返回 updatedInput,无论是直接返回还是通过 allowWithInput 返回。对于此工具,updatedInput 是对话框用于传递用户 answers 的通道,因此 hook 一旦返回该字段,就会被视为已经作答:菜单不会显示,工具会返回“The user did not answer the questions.”。在 2026-09-24 对所有会话记录的测量中,86 次被重写的调用有 86 次都未显示且未获回答;而普通的 allow 调用有 466 次中的 465 次正常显示并获得回答。
- 普通的
allow是安全的;对话框仍会显示。 - 如需更改用户看到的内容,请使用
deny,并在原因中准确说明 Agent 应该重新询问什么;同时确保重新询问时内容不变,以便循环在一轮内结束(pretooluse-pr-premise-annotator.ts是示例)。 - 通过三种方式强制执行:
allowWithInput会在运行时拒绝该工具,TOOL_SCHEMAS中没有该工具的条目,并且当覆盖AskUserQuestion的 hook 输出updatedInput或调用allowWithInput时,scripts/validate-plugins.mjs会使检查失败。
最简可用模式
/usr/bin/env bash << 'SKILL_SCRIPT_EOF'
#!/usr/bin/env bash
set -euo pipefail
# Read hook payload from stdin
PAYLOAD=$(cat)
FILE_PATH=$(echo "$PAYLOAD" | jq -r '.tool_input.file_path // empty')
[[ -z "$FILE_PATH" ]] && exit 0
# Your condition here
if [[ condition_met ]]; then
jq -n \
--arg reason "[HOOK] Your message to Claude" \
'{decision: "block", reason: $reason}'
fi
exit 0
SKILL_SCRIPT_EOF
要点:
- 使用
jq -n生成有效的 JSON - 包含
"decision": "block"以确保可见 - 以代码 0 退出
- “阻塞错误”标签仅是表象——操作仍会继续
语言选择:shell 还是 Bun/TypeScript
hook 默认使用 shell(bash)。 hook 会在每个匹配事件上触发,而约 95% 会立即退出,因此进程启动延迟占主导地位,而非逻辑本身。在工作站上的测量结果:完整的 bash hook(关键词匹配 + 退出)约 7 ms;一个_什么都不做_的 Bun 脚本约 17 ms。bash 也无需运行时依赖,并符合现有 hook 约定。让热路径退出逻辑使用 bash 内置的 case(不调用 jq 或启动进程)——参见 devops-tools SCS hooks 中的 pre-jq-fastpath。
只有当 hook 执行的实际工作足以抵消约 10 ms 的启动开销时,才使用 Bun/TypeScript:解析/转换结构化数据、调用 API、在多个 hook 间共享类型化模块,或维护状态。对于简单的匹配并输出提醒,shell 在速度、可靠性和约定方面更胜一筹。(这正是语言准则中“现有约定 + SOTA 原生生态优先于 Bun 优先默认策略”条款的体现。)
TodoWrite 模板
创建 PostToolUse Hook
1. [pending] Create hook script with shebang and set -euo pipefail
2. [pending] Parse PAYLOAD from stdin with jq
3. [pending] Add condition check for when to trigger
4. [pending] Output JSON with decision:block pattern
5. [pending] Register hook in hooks.json with matcher
6. [pending] Test by editing a matching file
7. [pending] Verify Claude sees the message in system-reminder
调试不可见的 Hook 输出
1. [pending] Verify hook executes (add debug log to /tmp)
2. [pending] Check JSON format is valid (pipe to jq .)
3. [pending] Confirm decision:block is present in output
4. [pending] Verify exit code is 0
5. [pending] Check hooks.json matcher pattern
6. [pending] Restart Claude Code session
参考文档
更改后检查清单(自我演进)
更新此技能时:
- 将发现记录到 evolution-log.md
- 验证代码示例仍能正常运行
- 检查是否需要更新 ADR:PostToolUse Hook Visibility ADR
相关资源
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 钩子输出不可见 | JSON 中缺少 decision:block | 在 JSON 输出中添加 "decision": "block" |
| 钩子中的 JSON 解析错误 | JSON 语法无效 | 使用 jq -n 生成有效的 JSON |
| 钩子未执行 | 匹配器模式错误 | 检查 hooks.json 匹配器正则表达式是否匹配工具名称 |
| 纯文本输出被忽略 | 仅解析 JSON | 将输出包装为包含 decision:block 的 JSON |
| 退出代码 2 的行为 | 使用了 stderr 而非 stdout | 使用 exit 0 并输出 JSON,或使用 exit 2 输出 stderr 消息 |
| 会话未看到更改 | 钩子已缓存 | 更改钩子后重启 Claude Code 会话 |
| 未显示详细模式 | 默认已禁用 | 在 Claude Code 设置中启用详细模式 |
| 找不到 jq 命令 | 未安装 jq | brew install jq |
执行后反思
此技能完成后,在结束前检查:
- 命令是否成功? — 如果没有,修复导致失败的说明或错误表。
- 参数或输出是否发生变化? — 如果底层工具的接口发生了变化,请更新 Usage 示例和 Parameters 表,使其保持一致。
- 是否需要变通方案? — 如果你不得不临时调整(使用不同的标志、增加步骤),请更新此 SKILL.md,以免下次调用时还需要采用相同的变通方案。
仅当问题真实且可复现时才进行更新,不要基于猜测更新。