Hooks 是 Claude Code 的自动化利器:在特定事件发生时,自动执行你的脚本。
比如:
- 每次写文件后自动运行 ESLint
- 提交代码前自动检查敏感信息
- 会话开始时自动加载项目配置
快速上手
配置文件位置
~/.claude/settings.json # 用户全局设置
.claude/settings.json # 项目设置(提交到 Git)
.claude/settings.local.json # 本地项目设置(不提交)
基本结构
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx eslint --fix \"$CLAUDE_PROJECT_DIR/src\"",
"timeout": 30
}
]
}
]
}
}
matcher:匹配工具名称,支持正则(Write|Edit)或*匹配所有command:要执行的 bash 命令timeout:超时时间(秒),默认 60 秒
Hook 事件类型
PreToolUse - 工具执行前
在 Claude 调用工具之前触发,可以阻止或修改工具调用。
常见匹配器:
Bash- Shell 命令Write- 写文件Edit- 编辑文件Read- 读文件Task- 子代理任务
场景:阻止写入敏感目录
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-path.sh"
}
]
}
]
}
}
PostToolUse - 工具执行后
工具成功执行后触发,用于后处理。
场景:写文件后自动格式化
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_PROJECT_DIR/src/**/*.{js,ts}\""
}
]
}
]
}
}
UserPromptSubmit - 用户提交提示时
用户发送消息后、Claude 处理前触发,可以验证或增强提示。
场景:自动注入项目上下文
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "cat \"$CLAUDE_PROJECT_DIR\"/.claude/context.md"
}
]
}
]
}
}
stdout 输出会被添加到 Claude 的上下文中。
SessionStart - 会话开始时
新会话启动或恢复时触发。
匹配器:
startup- 新启动resume- 恢复会话clear- /clear 命令compact- 压缩操作
场景:自动设置环境变量
#!/bin/bash
# .claude/hooks/setup-env.sh
if [ -n "$CLAUDE_ENV_FILE" ]; then
echo 'export NODE_ENV=development' >> "$CLAUDE_ENV_FILE"
echo 'export API_URL=http://localhost:3000' >> "$CLAUDE_ENV_FILE"
fi
exit 0
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/setup-env.sh"
}
]
}
]
}
}
Stop - Claude 完成响应时
Claude 完成回复后触发,可以阻止停止让 Claude 继续。
场景:自动运行测试
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run-tests.sh"
}
]
}
]
}
}
Notification - 通知时
Claude 发送通知时触发(等待权限、空闲超时等)。
SessionEnd - 会话结束时
会话结束时触发,用于清理任务。
PreCompact - 压缩前
上下文压缩前触发。
SubagentStop - 子代理完成时
Task 工具调用完成时触发。
Hook 输入输出
输入格式
Hooks 通过 stdin 接收 JSON:
{
"session_id": "abc123",
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/current/directory",
"permission_mode": "default",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
},
"tool_response": {
"success": true
}
}
输出控制
简单方式:退出码
exit 0:成功,stdout 显示给用户exit 2:阻止操作,stderr 反馈给 Claude- 其他:非阻止错误,stderr 显示给用户
高级方式:JSON 输出
{
"continue": true,
"stopReason": "停止原因",
"suppressOutput": false,
"systemMessage": "警告信息"
}
PreToolUse 可以控制权限:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "自动批准的原因",
"updatedInput": {
"file_path": "/modified/path.txt"
}
}
}
allow:绕过权限确认deny:阻止执行ask:要求用户确认
环境变量
CLAUDE_PROJECT_DIR:项目根目录CLAUDE_ENV_FILE:环境变量持久化文件(仅 SessionStart)CLAUDE_CODE_REMOTE:是否远程环境
MCP 工具匹配
MCP 工具命名格式:mcp__<server>__<tool>
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__memory__.*",
"hooks": [
{
"type": "command",
"command": "echo 'Memory operation' >> ~/mcp.log"
}
]
}
]
}
}
实用示例
代码提交前检查敏感信息
#!/bin/bash
# .claude/hooks/check-secrets.sh
input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty')
content=$(echo "$input" | jq -r '.tool_input.content // empty')
# 检查敏感模式
if echo "$content" | grep -qE '(api[_-]?key|secret|password|token)\s*[:=]'; then
echo "检测到可能的敏感信息,请检查后再提交" >&2
exit 2
fi
exit 0
自动添加文件头注释
#!/bin/bash
# .claude/hooks/add-header.sh
input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty')
# 只处理新建的 JS/TS 文件
if [[ "$file_path" =~ \.(js|ts)$ ]]; then
content=$(echo "$input" | jq -r '.tool_input.content // empty')
# 检查是否已有头注释
if ! echo "$content" | head -1 | grep -q "^/\*\*"; then
header="/**\n * @file $(basename "$file_path")\n * @created $(date +%Y-%m-%d)\n */\n\n"
# 输出修改后的内容
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"updatedInput\":{\"content\":\"${header}${content}\"}}}"
exit 0
fi
fi
exit 0
会话开始时加载 nvm
#!/bin/bash
# .claude/hooks/load-nvm.sh
ENV_BEFORE=$(export -p | sort)
source ~/.nvm/nvm.sh
nvm use 20 > /dev/null 2>&1
if [ -n "$CLAUDE_ENV_FILE" ]; then
ENV_AFTER=$(export -p | sort)
comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi
exit 0
调试技巧
使用 claude --debug 查看 hook 执行详情:
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Found 1 hook commands to execute
[DEBUG] Hook command completed with status 0
安全注意事项
- 验证输入:永远不要盲目信任 hook 输入
- 引用变量:使用
"$VAR"而不是$VAR - 检查路径:防止路径遍历攻击
- 跳过敏感文件:避免处理
.env、密钥文件 - 测试充分:在安全环境中测试后再用于生产
Hooks 配置修改后需要重启 Claude Code 或在 /hooks 菜单中确认才能生效。