hooks-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHooks Development
Hooks开发
Guide for developing Claude Code hooks with proper output visibility patterns.
关于开发具有正确输出可见性模式的Claude Code Hooks的指南。
When to Use This Skill
何时使用该技能
- Creating a new PostToolUse or PreToolUse hook
- Hook output is not visible to Claude (most common issue)
- User asks about pattern
decision: block - Debugging why hook messages don't appear
- User mentions "Claude Code hooks" or "hook visibility"
- 创建新的PostToolUse或PreToolUse Hook
- Hook输出对Claude不可见(最常见问题)
- 用户询问模式
decision: block - 调试Hook消息不显示的原因
- 用户提及“Claude Code Hooks”或“Hook可见性”
Quick Reference: Visibility Patterns
快速参考:可见性模式
Critical insight: PostToolUse hook stdout is only visible to Claude when JSON contains .
"decision": "block"| Output Format | Claude Visibility |
|---|---|
| Plain text | Not visible |
JSON without | Not visible |
JSON with | Visible |
Exit code behavior:
| Exit Code | stdout Behavior | Claude Visibility |
|---|---|---|
| 0 | JSON parsed, shown in verbose mode only | Only if |
| 2 | Ignored, uses stderr instead | stderr shown to Claude |
| Other | stderr shown in verbose mode | Not shown to Claude |
关键要点:只有当JSON中包含时,PostToolUse Hook的标准输出才会对Claude可见。
"decision": "block"| 输出格式 | 对Claude的可见性 |
|---|---|
| 纯文本 | 不可见 |
不含 | 不可见 |
含 | 可见 |
退出码行为:
| 退出码 | 标准输出行为 | 对Claude的可见性 |
|---|---|---|
| 0 | JSON被解析,仅在详细模式下显示 | 仅当包含 |
| 2 | 被忽略,改用标准错误输出 | 标准错误输出会显示给Claude |
| 其他 | 标准错误输出在详细模式下显示 | 不会显示给Claude |
Minimal Working Pattern
最简可用模式
bash
/usr/bin/env bash << 'SKILL_SCRIPT_EOF'
#!/usr/bin/env bash
set -euo pipefailbash
/usr/bin/env bash << 'SKILL_SCRIPT_EOF'
#!/usr/bin/env bash
set -euo pipefailRead hook payload from stdin
Read hook payload from stdin
PAYLOAD=$(cat)
FILE_PATH=$(echo "$PAYLOAD" | jq -r '.tool_input.file_path // empty')
[[ -z "$FILE_PATH" ]] && exit 0
PAYLOAD=$(cat)
FILE_PATH=$(echo "$PAYLOAD" | jq -r '.tool_input.file_path // empty')
[[ -z "$FILE_PATH" ]] && exit 0
Your condition here
Your condition here
if [[ condition_met ]]; then
jq -n
--arg reason "[HOOK] Your message to Claude"
'{decision: "block", reason: $reason}' fi
--arg reason "[HOOK] Your message to Claude"
'{decision: "block", reason: $reason}' fi
exit 0
SKILL_SCRIPT_EOF
**Key points**:
1. Use `jq -n` to generate valid JSON
2. Include `"decision": "block"` for visibility
3. Exit with code 0
4. The "blocking error" label is cosmetic - operation continues
---if [[ condition_met ]]; then
jq -n
--arg reason "[HOOK] Your message to Claude"
'{decision: "block", reason: $reason}' fi
--arg reason "[HOOK] Your message to Claude"
'{decision: "block", reason: $reason}' fi
exit 0
SKILL_SCRIPT_EOF
**关键点**:
1. 使用`jq -n`生成有效的JSON
2. 包含`"decision": "block"`以确保可见性
3. 以退出码0退出
4. “blocking error”标签仅为装饰性 - 操作会继续执行
---TodoWrite Templates
TodoWrite模板
Creating a PostToolUse Hook
创建PostToolUse Hook
markdown
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-remindermarkdown
1. [待处理] 创建带有shebang和set -euo pipefail的Hook脚本
2. [待处理] 使用jq从标准输入解析PAYLOAD
3. [待处理] 添加触发条件检查
4. [待处理] 输出带有decision:block模式的JSON
5. [待处理] 在hooks.json中通过匹配器注册Hook
6. [待处理] 通过编辑匹配文件进行测试
7. [待处理] 验证Claude在system-reminder中能看到消息Debugging Invisible Hook Output
调试不可见的Hook输出
markdown
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 sessionmarkdown
1. [待处理] 验证Hook是否执行(向/tmp添加调试日志)
2. [待处理] 检查JSON格式是否有效(通过管道传递给jq .)
3. [待处理] 确认输出中包含decision:block
4. [待处理] 验证退出码为0
5. [待处理] 检查hooks.json中的匹配器模式
6. [待处理] 修改Hook后重启Claude Code会话Reference Documentation
参考文档
- Lifecycle Reference - All 10 hook events, diagrams, use cases, configuration pitfalls
- Visibility Patterns - Full exit code and JSON schema details
- Hook Templates - Copy-paste templates for common patterns
- Debugging Guide - Troubleshooting invisible output
- 生命周期参考 - 全部10种Hook事件、图表、使用场景、配置陷阱
- 可见性模式 - 完整的退出码和JSON架构细节
- Hook模板 - 可直接复制粘贴的常见模式模板
- 调试指南 - 排查不可见输出问题的指南
Post-Change Checklist (Self-Evolution)
变更后检查清单(自我演进)
When this skill is updated:
- Update evolution-log.md with discovery
- Verify code examples still work
- Check if ADR needs updating: PostToolUse Hook Visibility ADR
当本技能更新时:
- 在evolution-log.md中记录更新内容
- 验证代码示例仍可正常工作
- 检查是否需要更新ADR:PostToolUse Hook可见性ADR
Related Resources
相关资源
- ADR: PostToolUse Hook Visibility
- GitHub Issue #3983 - Original bug report
- Claude Code Hooks Reference - Official documentation
- ADR: PostToolUse Hook可见性
- GitHub Issue #3983 - 原始bug报告
- Claude Code Hooks参考 - 官方文档
Troubleshooting
故障排查
| Issue | Cause | Solution |
|---|---|---|
| Hook output not visible | Missing decision:block in JSON | Add |
| JSON parse error in hook | Invalid JSON syntax | Use |
| Hook not executing | Wrong matcher pattern | Check hooks.json matcher regex matches tool name |
| Plain text output ignored | Only JSON parsed | Wrap output in JSON with decision:block |
| Exit code 2 behavior | stderr used instead of stdout | Use exit 0 with JSON, or exit 2 for stderr messages |
| Session not seeing changes | Hooks cached | Restart Claude Code session after hook changes |
| Verbose mode not showing | Disabled by default | Enable verbose mode in Claude Code settings |
| jq command not found | jq not installed | |
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Hook输出不可见 | JSON中缺少decision:block | 在JSON输出中添加 |
| Hook中出现JSON解析错误 | JSON语法无效 | 使用 |
| Hook未执行 | 匹配器模式错误 | 检查hooks.json中的匹配器正则表达式是否匹配工具名称 |
| 纯文本输出被忽略 | 仅解析JSON | 将输出包装在带有decision:block的JSON中 |
| 退出码2的行为 | 使用标准错误输出而非标准输出 | 使用退出码0并输出JSON,或使用退出码2输出标准错误消息 |
| 会话未看到变更 | Hooks被缓存 | 修改Hook后重启Claude Code会话 |
| 详细模式未显示 | 默认处于禁用状态 | 在Claude Code设置中启用详细模式 |
| jq命令未找到 | 未安装jq | |