Claude Code Hooks
------官方 8 大事件、全部字段、10+ 脚本,一步到位
一、一分钟总览
- Hooks = 在 Claude Code 生命周期 8 个固定节点插入「用户脚本」。
- 用 JSON 声明,分「全局」(~/.claude/settings.json) 与「项目」(.claude/settings.local.json)。
- 每个 Hook 由「事件 + 匹配器 + 命令」三元组组成。
- 官方事件 8 个,变量 10+ 个,全部列在后面。
二、官方 8 大事件全表
事件 | 触发时机 | 官方给出变量 | 能否阻断 | 典型用途 |
---|---|---|---|---|
SessionStart | 会话新建 / resume | 无 | ❌ | 初始化环境 |
UserPromptSubmit | 用户按回车前 | prompt | ✅ | 危险指令过滤 |
PreToolUse | 工具准备执行前 | tool_name, tool_input | ✅ | 权限/审计 |
PostToolUse | 工具执行结束 | tool_name, tool_input, tool_output | ❌ | 自动格式化 |
Notification | Claude 需要用户输入 | notification_text | ❌ | 桌面/Slack 通知 |
Stop | 回答整体结束 | 无 | ❌ | 汇总日志 |
SubagentStop | 子代理任务结束 | subagent_name, result | ❌ | 子任务统计 |
PreCompact | 压缩对话缓存前 | 无 | ❌ | 备份历史 |
三、配置文件结构(全局 vs 项目)
路径规则
• 全局:~/.claude/settings.json
• 项目:.claude/settings.local.json
(优先级高)
最小合法骨架
json5
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "echo PreToolUse" }
]
}
]
}
}
字段说明
字段 | 类型 | 必填 | 说明 |
---|---|---|---|
matcher | string | ✅ | 工具名或正则,支持 Bash|Edit|Write* |
type | enum | ✅ | command / script |
command | string | 二选一 | 直接写 shell |
script | string | 二选一 | 指向可执行文件路径 |
env | object | ❌ | 额外环境变量 |
working_dir | string | ❌ | 工作目录,缺省为项目根 |
四、匹配器(Matcher)语法精讲
- 单工具:
Bash
- 多工具:
Edit|Write|MultiEdit
- 正则:
Bash(rm -rf .*)
仅匹配含rm -rf
的 Bash 命令 - 通配:
*
匹配所有
五、官方环境变量全集
变量 | 出现事件 | 内容示例 |
---|---|---|
CLAUDE_EVENT | 全部 | PreToolUse |
CLAUDE_TOOL_NAME | Pre/PostToolUse | Bash |
CLAUDE_TOOL_INPUT | Pre/PostToolUse | JSON 字符串 |
CLAUDE_TOOL_OUTPUT | PostToolUse | 工具返回值 |
CLAUDE_FILE_PATH | Edit/Write | /home/me/src/index.ts |
CLAUDE_LINE_START | Edit/Write | 12 |
CLAUDE_LINE_END | Edit/Write | 15 |
CLAUDE_NOTIFICATION_TEXT | Notification | Claude needs your input |
CLAUDE_SUBAGENT_NAME | SubagentStop | planner |
CLAUDE_SUBAGENT_RESULT | SubagentStop | JSON 结果 |
CLAUDE_PROJECT_DIR | 全部 | /home/me/project |
六、可视化配置 vs 手写 JSON
• 运行 /hooks
进入 TUI,可增删改查。
• 改动后需 ccr restart
或重启 Claude Code 才生效。
• 最终仍落盘到 settings.json,可直接编辑。
七、10 个示例
- 全局 Bash 命令审计(PreToolUse)
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"type": "command",
"command": "jq -r '\"[$(date -Iseconds)] $tool_name: $tool_input.command\"' <<< \"$CLAUDE_TOOL_INPUT\" >> ~/.claude/audit.log"
}
]
}
}
- TypeScript 自动 Prettier(PostToolUse)
json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"type": "command",
"command": "[[ \"$CLAUDE_FILE_PATH\" == *.ts ]] && npx prettier --write \"$CLAUDE_FILE_PATH\""
}
]
}
}
- 阻止删除生产文件(PreToolUse)
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"type": "script",
"script": ".claude/hooks/protect_rm.sh"
}
]
}
}
protect_rm.sh
bash
#!/usr/bin/env bash
set -e
cmd=$(jq -r '.tool_input.command' <<< "$CLAUDE_TOOL_INPUT")
[[ $cmd =~ rm\ -rf.*(src|dist|\.env) ]] && { echo "Protected!"; exit 2; }
- Markdown 自动补语言标签 (PostToolUse)
Python 脚本:.claude/hooks/md_lang.py
python
#!/usr/bin/env python3
import re, json, sys, os
path = os.environ["CLAUDE_FILE_PATH"]
if not path.endswith(".md"): sys.exit(0)
with open(path) as f: txt = f.read()
new = re.sub(r"```\n(.*?)\n```", lambda m: f"```{guess(m.group(1))}\n{m.group(1)}\n```", txt, flags=re.S)
if new != txt:
with open(path,"w") as f: f.write(new)
os.system(f"git add {path}")
def guess(code):
if re.search(r"^\s*(import|def|class)\s", code, re.M): return "python"
if re.search(r"^\s*(const|let|function|import)\s", code, re.M): return "javascript"
return ""
Hook 配置
json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"type": "script",
"script": ".claude/hooks/md_lang.py"
}
]
}
}
- 桌面通知"等你输入"(Notification)
json
{
"hooks": {
"Notification": [
{
"matcher": "*",
"type": "command",
"command": "notify-send Claude \"$CLAUDE_NOTIFICATION_TEXT\""
}
]
}
}
- 会话启动打印欢迎横幅(SessionStart)
json
{
"hooks": {
"SessionStart": [
{
"matcher": "*",
"type": "command",
"command": "echo 'Welcome to Claude Code 🧑💻' | lolcat"
}
]
}
}
- 子代理结束统计(SubagentStop)
json
{
"hooks": {
"SubagentStop": [
{
"matcher": "*",
"type": "command",
"command": "jq -c '{agent: env.CLAUDE_SUBAGENT_NAME, status: env.CLAUDE_SUBAGENT_RESULT}' >> ~/.claude/subagent-report.jsonl"
}
]
}
}
- 压缩前备份对话(PreCompact)
json
{
"hooks": {
"PreCompact": [
{
"matcher": "*",
"type": "command",
"command": "cp ~/.claude/session.json ~/.claude/session-backup-$(date +%s).json"
}
]
}
}
- 用户提示强制加前缀(UserPromptSubmit)
json
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "*",
"type": "script",
"script": ".claude/hooks/prefix.sh"
}
]
}
}
bash
#!/usr/bin/env bash
prompt=$(jq -r '.' <<< "$CLAUDE_PROMPT")
new="[SAFE MODE] $prompt"
jq -n --arg p "$new" '$p'
- Stop 事件自动提交 Git(Stop)
json
{
"hooks": {
"Stop": [
{
"matcher": "*",
"type": "command",
"command": "git add -A && git commit -m 'claude auto save'"
}
]
}
}
八、调试与故障排查官方清单
-
/hooks
→ TUI 查看配置。 -
ccr restart
让修改生效。 -
/debug
打开详细日志。 -
本地单测:
bashCLAUDE_EVENT=PreToolUse \ CLAUDE_TOOL_INPUT='{"tool_input":{"command":"ls"}}' \ ./your-hook.sh
-
日志追加:脚本首行
exec >> ~/.claude/hooks.log 2>&1 && set -x
九、安全红线(官方原文提炼)
- Hook 以当前用户身份执行,勿用 root 跑 Claude Code。
- 避免
eval
、bash -c "$untrusted"
。 - 项目级钩子优先,全局钩子仅放审计类脚本。
- 审查第三方脚本后再启用。
十、一键速查表(打印贴墙)
我做这件事 | 用哪个事件 | 示例 matcher |
---|---|---|
拦截 rm -rf | PreToolUse | Bash(rm -rf) |
自动 prettier | PostToolUse | Edit|Write |
提示词加前缀 | UserPromptSubmit | * |
桌面通知 | Notification | * |
备份对话 | PreCompact | * |
子代理统计 | SubagentStop | * |
欢迎横幅 | SessionStart | * |
自动 commit | Stop | * |
结语
掌握「8 大事件 + 2 个配置文件 + 10+ 环境变量」,你就能把 Claude Code 变成:
- 自动格式化器
- 文件守护者
- 审计机器人
- 通知中心