关于 hook-development
面向 Claude Code 插件开发者的事件驱动 Hook 配置指南,介绍提示词型与命令型 Hook、事件格式、安全、性能和调试,适用于自动化验证与工作流操作。
主要功能
- 01提示词型与命令型 Hook 模式
- 02Hook 事件配置
- 03匹配器及输入输出格式
- 04安全与性能指导
- 05调试和测试流程
适用场景
- 01在工具执行前验证调用
- 02在工具使用后检查结果
- 03在会话开始时加载项目上下文
- 04调试插件 Hook
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ anthropics/ claude-plugins-official --skill hook-development安装后在 Claude Code 中输入/hook-development确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
examples/load-context.shvalidate-bash.shvalidate-write.shreferences/advanced.mdmigration.mdpatterns.mdscripts/hook-linter.shREADME.mdtest-hook.shvalidate-hook-schema.sh详细介绍
Claude Code 插件的 Hook 开发
概述
Hook 是事件驱动的自动化脚本,会在 Claude Code 事件触发时执行。使用 Hook 可验证操作、强制执行策略、添加上下文,并将外部工具集成到工作流中。
主要功能:
- 在执行前验证工具调用(PreToolUse)
- 对工具结果作出响应(PostToolUse)
- 强制执行完成标准(Stop、SubagentStop)
- 加载项目上下文(SessionStart)
- 自动化开发生命周期中的工作流
Hook 类型
基于提示词的 Hook(推荐)
使用由大模型驱动的决策,实现基于上下文的验证:
{
"type": "prompt",
"prompt": "Evaluate if this tool use is appropriate: $TOOL_INPUT",
"timeout": 30
}
支持的事件: Stop、SubagentStop、UserPromptSubmit、PreToolUse
优势:
- 基于自然语言推理作出上下文感知的决策
- 无需编写 bash 脚本即可实现灵活的评估逻辑
- 更好地处理边缘情况
- 更易维护和扩展
命令 Hook
执行 bash 命令进行确定性检查:
{
"type": "command",
"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh",
"timeout": 60
}
适用场景:
- 快速的确定性验证
- 文件系统操作
- 外部工具集成
- 对性能要求较高的检查
Hook 配置格式
插件 hooks.json 格式
对于插件 Hook,在 hooks/hooks.json 中使用包装格式:
{
"description": "Brief explanation of hooks (optional)",
"hooks": {
"PreToolUse": [...],
"Stop": [...],
"SessionStart": [...]
}
}
要点:
description字段为可选hooks字段为必填包装字段,其中包含实际的 Hook 事件- 这是插件专用格式
示例:
{
"description": "Validation hooks for code quality",
"hooks": {
"PreToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/validate.sh"
}
]
}
]
}
}
设置格式(直接)
对于用户设置,在 .claude/settings.json 中使用直接格式:
{
"PreToolUse": [...],
"Stop": [...],
"SessionStart": [...]
}
要点:
- 无包装层——事件直接位于顶层
- 无 description 字段
- 这是设置格式
重要说明: 以下示例展示的是可放入任一格式中的 Hook 事件结构。对于插件 hooks.json,请将其包装在 {"hooks": {...}} 中。
Hook 事件
PreToolUse
在任何工具运行前执行。用于批准、拒绝或修改工具调用。
示例(基于提示词):
{
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "prompt",
"prompt": "Validate file write safety. Check: system paths, credentials, path traversal, sensitive content. Return 'approve' or 'deny'."
}
]
}
]
}
PreToolUse 的输出:
{
"hookSpecificOutput": {
"permissionDecision": "allow|deny|ask",
"updatedInput": {"field": "modified_value"}
},
"systemMessage": "Explanation for Claude"
}
PostToolUse
在工具完成后执行。用于对结果作出响应、提供反馈或记录日志。
示例:
{
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "prompt",
"prompt": "Analyze edit result for potential issues: syntax errors, security vulnerabilities, breaking changes. Provide feedback."
}
]
}
]
}
输出行为:
- 退出码为 0:stdout 显示在对话记录中
- 退出码为 2:stderr 反馈给 Claude
- systemMessage 会包含在上下文中
Stop
主 Agent 考虑停止时执行。用于验证任务是否完整。
示例:
{
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "prompt",
"prompt": "Verify task completion: tests run, build succeeded, questions answered. Return 'approve' to stop or 'block' with reason to continue."
}
]
}
]
}
决策输出:
{
"decision": "approve|block",
"reason": "Explanation",
"systemMessage": "Additional context"
}
SubagentStop
子 Agent 考虑停止时执行。用于确保子 Agent 已完成任务。
与 Stop Hook 类似,但适用于子 Agent。
UserPromptSubmit
用户提交提示词时执行。用于添加上下文、验证提示词或阻止提示词。
示例:
{
"UserPromptSubmit": [
{
"matcher": "*",
"hooks": [
{
"type": "prompt",
"prompt": "Check if prompt requires security guidance. If discussing auth, permissions, or API security, return relevant warnings."
}
]
}
]
}
SessionStart
Claude Code 会话开始时执行。用于加载上下文并设置环境。
示例:
{
"SessionStart": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/load-context.sh"
}
]
}
]
}
特殊功能: 使用 $CLAUDE_ENV_FILE 持久化环境变量:
echo "export PROJECT_TYPE=nodejs" >> "$CLAUDE_ENV_FILE"
完整示例请参见 examples/load-context.sh。
SessionEnd
会话结束时执行。用于清理、记录日志和保存状态。
PreCompact
上下文压缩前执行。用于添加需要保留的重要信息。
Notification
Claude 发送通知时执行。用于响应用户通知。
Hook 输出格式
标准输出(所有 Hook)
{
"continue": true,
"suppressOutput": false,
"systemMessage": "Message for Claude"
}
continue:若为 false,则停止处理(默认值为 true)suppressOutput:隐藏对话记录中的输出(默认值为 false)systemMessage:显示给 Claude 的消息
退出码
0- 成功(stdout 显示在对话记录中)2- 阻止性错误(stderr 反馈给 Claude)- 其他 - 非阻止性错误
Hook 输入格式
所有 Hook 都会通过 stdin 接收包含通用字段的 JSON:
{
"session_id": "abc123",
"transcript_path": "/path/to/transcript.txt",
"cwd": "/current/working/dir",
"permission_mode": "ask|allow",
"hook_event_name": "PreToolUse"
}
特定事件的字段:
- PreToolUse/PostToolUse:
tool_name、tool_input、tool_result - UserPromptSubmit:
user_prompt - Stop/SubagentStop:
reason
在提示词中使用 $TOOL_INPUT、$TOOL_RESULT、$USER_PROMPT 等访问字段。
环境变量
所有命令钩子均可使用:
$CLAUDE_PROJECT_DIR- 项目根目录路径$CLAUDE_PLUGIN_ROOT- 插件目录(用于可移植路径)$CLAUDE_ENV_FILE- 仅限 SessionStart:在此处持久化环境变量$CLAUDE_CODE_REMOTE- 在远程上下文中运行时设置
钩子命令中始终使用 ${CLAUDE_PLUGIN_ROOT},以确保可移植性:
{
"type": "command",
"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh"
}
插件钩子配置
在插件中,在 hooks/hooks.json 中定义钩子:
{
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "prompt",
"prompt": "Validate file write safety"
}
]
}
],
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "prompt",
"prompt": "Verify task completion"
}
]
}
],
"SessionStart": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/load-context.sh",
"timeout": 10
}
]
}
]
}
插件钩子会与用户的钩子合并并行运行。
匹配器
工具名称匹配
精确匹配:
"matcher": "Write"
多个工具:
"matcher": "Read|Write|Edit"
通配符(所有工具):
"matcher": "*"
正则表达式模式:
"matcher": "mcp__.*__delete.*" // All MCP delete tools
注意: 匹配器区分大小写。
常见模式
// All MCP tools
"matcher": "mcp__.*"
// Specific plugin's MCP tools
"matcher": "mcp__plugin_asana_.*"
// All file operations
"matcher": "Read|Write|Edit"
// Bash commands only
"matcher": "Bash"
安全最佳实践
输入验证
始终在命令钩子中验证输入:
#!/bin/bash
set -euo pipefail
input=$(cat)
tool_name=$(echo "$input" | jq -r '.tool_name')
# Validate tool name format
if [[ ! "$tool_name" =~ ^[a-zA-Z0-9_]+$ ]]; then
echo '{"decision": "deny", "reason": "Invalid tool name"}' >&2
exit 2
fi
路径安全
检查路径遍历和敏感文件:
file_path=$(echo "$input" | jq -r '.tool_input.file_path')
# Deny path traversal
if [[ "$file_path" == *".."* ]]; then
echo '{"decision": "deny", "reason": "Path traversal detected"}' >&2
exit 2
fi
# Deny sensitive files
if [[ "$file_path" == *".env"* ]]; then
echo '{"decision": "deny", "reason": "Sensitive file"}' >&2
exit 2
fi
完整示例请参见 examples/validate-write.sh 和 examples/validate-bash.sh。
为所有变量加引号
# GOOD: Quoted
echo "$file_path"
cd "$CLAUDE_PROJECT_DIR"
# BAD: Unquoted (injection risk)
echo $file_path
cd $CLAUDE_PROJECT_DIR
设置适当的超时时间
{
"type": "command",
"command": "bash script.sh",
"timeout": 10
}
默认值: 命令钩子(60s)、提示词钩子(30s)
性能注意事项
并行执行
所有匹配的钩子都会并行运行:
{
"PreToolUse": [
{
"matcher": "Write",
"hooks": [
{"type": "command", "command": "check1.sh"}, // Parallel
{"type": "command", "command": "check2.sh"}, // Parallel
{"type": "prompt", "prompt": "Validate..."} // Parallel
]
}
]
}
设计影响:
- 钩子无法看到彼此的输出
- 执行顺序不确定
- 应按彼此独立的方式设计
优化
- 使用命令钩子执行快速、确定性的检查
- 使用提示词钩子处理复杂推理
- 将验证结果缓存到临时文件中
- 减少热点路径中的 I/O
暂时启用的钩子
创建可通过检查标记文件或配置来有条件激活的钩子:
模式:通过标记文件激活
#!/bin/bash
# Only active when flag file exists
FLAG_FILE="$CLAUDE_PROJECT_DIR/.enable-strict-validation"
if [ ! -f "$FLAG_FILE" ]; then
# Flag not present, skip validation
exit 0
fi
# Flag present, run validation
input=$(cat)
# ... validation logic ...
模式:通过配置激活
#!/bin/bash
# Check configuration for activation
CONFIG_FILE="$CLAUDE_PROJECT_DIR/.claude/plugin-config.json"
if [ -f "$CONFIG_FILE" ]; then
enabled=$(jq -r '.strictMode // false' "$CONFIG_FILE")
if [ "$enabled" != "true" ]; then
exit 0 # Not enabled, skip
fi
fi
# Enabled, run hook logic
input=$(cat)
# ... hook logic ...
使用场景:
- 仅在需要时启用严格验证
- 临时调试钩子
- 项目专属的钩子行为
- 钩子的功能标志
最佳实践: 在插件 README 中说明激活机制,让用户知道如何启用或禁用临时钩子。
钩子生命周期与限制
钩子在会话开始时加载
重要: 钩子会在 Claude Code 会话启动时加载。更改钩子配置后,必须重启 Claude Code。
无法热切换钩子:
- 编辑
hooks/hooks.json不会影响当前会话 - 新增的钩子脚本不会被识别
- 更改钩子命令或提示词不会生效
- 必须重启 Claude Code:退出后再次运行
claude
测试钩子更改:
- 编辑钩子配置或脚本
- 退出 Claude Code 会话
- 重启:
claude或cc - 加载新的钩子配置
- 使用
claude --debug测试钩子
启动时验证钩子
Claude Code 启动时会验证钩子:
- hooks.json 中的 JSON 无效会导致加载失败
- 缺少脚本会触发警告
- 语法错误会在调试模式下报告
使用 /hooks 命令查看当前会话中已加载的钩子。
调试钩子
启用调试模式
claude --debug
查看钩子注册、执行日志、输入/输出 JSON 和计时信息。
测试钩子脚本
直接测试命令钩子:
echo '{"tool_name": "Write", "tool_input": {"file_path": "/test"}}' | \
bash ${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh
echo "Exit code: $?"
验证 JSON 输出
确保钩子输出有效的 JSON:
output=$(./your-hook.sh < test-input.json)
echo "$output" | jq .
快速参考
钩子事件摘要
| 事件 | 时机 | 用途 |
|---|---|---|
| PreToolUse | 工具调用前 | 验证、修改 |
| PostToolUse | 工具调用后 | 反馈、日志记录 |
| UserPromptSubmit | 用户输入时 | 上下文、验证 |
| Stop | Agent 停止时 | 完整性检查 |
| SubagentStop | 子 Agent 完成时 | 任务验证 |
| SessionStart | 会话开始时 | 加载上下文 |
| SessionEnd | 会话结束时 | 清理、日志记录 |
| PreCompact | 压缩前 | 保留上下文 |
| Notification | 通知用户时 | 日志记录、响应 |
最佳实践
应该:
- ✅ 复杂逻辑使用基于提示词的钩子
- ✅ 使用 ${CLAUDE_PLUGIN_ROOT} 提高可移植性
- ✅ 在命令钩子中验证所有输入
- ✅ 为所有 bash 变量加上引号
- ✅ 设置适当的超时时间
- ✅ 返回结构化 JSON 输出
- ✅ 彻底测试钩子
不应该:
- ❌ 使用硬编码路径
- ❌ 不经验证就信任用户输入
- ❌ 创建长时间运行的钩子
- ❌ 依赖钩子的执行顺序
- ❌ 不可预测地修改全局状态
- ❌ 记录敏感信息
其他资源
参考文件
如需了解详细模式和高级技巧,请参阅:
references/patterns.md- 常见钩子模式(8 种以上经过验证的模式)references/migration.md- 从基础钩子迁移到高级钩子references/advanced.md- 高级用例和技巧
钩子脚本示例
examples/ 中的可运行示例:
validate-write.sh- 文件写入验证示例validate-bash.sh- Bash 命令验证示例load-context.sh- SessionStart 上下文加载示例
实用脚本
script/ 中的开发工具:
validate-hook-schema.sh- 验证 hooks.json 结构和语法test-hook.sh- 部署前使用示例输入测试钩子hook-linter.sh- 检查钩子脚本中的常见问题并验证其是否符合最佳实践
外部资源
- 官方文档:https://docs.claude.com/en/docs/claude-code/hooks
- 示例:参阅 marketplace 中的 security-guidance 插件
- 测试:使用
claude --debug查看详细日志 - 验证:使用
jq验证钩子 JSON 输出
实施工作流
在插件中实现钩子的步骤:
- 确定要接入的事件(PreToolUse、Stop、SessionStart 等)
- 选择基于提示词(灵活)或命令(确定性)钩子
- 在
hooks/hooks.json中编写钩子配置 - 对于命令钩子,创建钩子脚本
- 所有文件引用均使用 ${CLAUDE_PLUGIN_ROOT}
- 使用
scripts/validate-hook-schema.sh hooks/hooks.json验证配置 - 部署前使用
scripts/test-hook.sh测试钩子 - 在 Claude Code 中使用
claude --debug进行测试 - 在插件 README 中记录钩子
大多数用例应优先使用基于提示词的钩子。仅在性能要求严格或需要确定性检查时使用命令钩子。