Appearance
用 Hooks 自动化工作流
Hooks 是用户自定义的 shell 命令,在 Claude Code 生命周期的特定节点自动执行——确保某些操作必然发生,而不是依赖 LLM 去"选择"是否执行。本文涵盖最常用的自动化场景:编辑后代码格式化、保护敏感文件、桌面通知、上下文压缩后重注入关键信息、配置变更审计、目录切换时重载环境变量,以及自动批准特定权限请求。每个场景都附有可直接使用的配置块。
Hooks 让你对 Claude Code 的行为有确定性控制,确保某些操作总是发生,而不是依赖 LLM 来决定要不要执行。可以用 Hooks 来强制执行项目规范、自动化重复任务,以及将 Claude Code 与现有工具集成。
对于需要"判断力"而非确定性规则的场景,还可以使用基于 prompt 的 hooks 和基于 agent 的 hooks,让 Claude 模型来评估条件。
其他扩展 Claude Code 的方式:skills(给 Claude 添加指令和可执行命令)、subagents(在隔离上下文中运行任务)、plugins(打包扩展以跨项目共享)。
配置第一个 Hook
创建 Hook 需要在设置文件中添加 hooks 块。下面以"桌面通知"为例演示:当 Claude 等待你输入时发送通知,这样就不用一直盯着终端了。
第一步:添加配置
打开 ~/.claude/settings.json,添加 Notification hook:
macOS
json
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}Linux
json
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Claude Code needs your attention'"
}
]
}
]
}
}Windows(PowerShell)
json
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')\""
}
]
}
]
}
}macOS 通知不显示?osascript 通过内置 Script Editor 应用发送通知。如果 Script Editor 没有通知权限,命令会静默失败。在终端运行一次 osascript -e 'display notification "test"',然后打开系统设置 → 通知,找到 Script Editor,开启允许通知。
常用自动化场景
编辑后自动格式化代码
每次 Claude 编辑文件后自动运行 Prettier,保持格式统一。这个 hook 使用 PostToolUse 事件配合 Edit|Write matcher,只在文件编辑工具后触发。命令用 jq 从事件中提取编辑的文件路径,传给 Prettier。
将以下配置添加到项目根目录的 .claude/settings.json:
json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}保护敏感文件不被修改
防止 Claude 修改 .env、package-lock.json、.git/ 等文件。Claude 会收到说明被拦截原因的反馈,从而调整方案。这个例子使用独立脚本文件,检查目标文件路径是否匹配保护规则,匹配则以退出码 2 拦截操作。
第一步:创建脚本 .claude/hooks/protect-files.sh
bash
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
exit 2
fi
done
exit 0第二步:赋予执行权限
bash
chmod +x .claude/hooks/protect-files.sh第三步:在 .claude/settings.json 注册 Hook
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}上下文压缩后重注入关键信息
上下文窗口满了会触发压缩(compaction),可能丢失重要细节。用带 compact matcher 的 SessionStart hook,在每次压缩后自动重注入关键信息。命令写到 stdout 的文本都会加入 Claude 的上下文。
json
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "echo 'Reminder: use Bun, not npm. Run bun test before committing. Current sprint: auth refactor.'"
}
]
}
]
}
}可以将 echo 替换为动态输出的命令,比如 git log --oneline -5 显示最近提交。
如果要在每次会话开始时注入上下文(而非只在压缩后),考虑使用 CLAUDE.md。环境变量的持久化参见 CLAUDE_ENV_FILE。
记录配置变更审计日志
追踪会话中 settings 或 skills 文件的变更,可用于合规或拦截未授权修改。这个例子把每次变更追加到审计日志:
json
{
"hooks": {
"ConfigChange": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "jq -c '{timestamp: now | todate, source:.source, file:.file_path}' >> ~/claude-config-audit.log"
}
]
}
]
}
}matcher 过滤配置类型:user_settings、project_settings、local_settings、policy_settings 或 skills。以退出码 2 退出或返回 {"decision": "block"} 可以阻止变更生效。详见 ConfigChange 参考。
目录切换时重载环境变量
有些项目根据目录设置不同的环境变量,direnv 在普通 shell 中可以自动处理,但 Claude 的 Bash 工具不会自动感知目录变更。CwdChanged hook 在每次 Claude 切换目录时运行,写入 CLAUDE_ENV_FILE 的值会在每条 Bash 命令前应用:
json
{
"hooks": {
"CwdChanged": [
{
"hooks": [
{
"type": "command",
"command": "direnv export bash >> \"$CLAUDE_ENV_FILE\""
}
]
}
]
}
}自动批准特定权限请求
对于总是允许的操作,可以跳过确认对话框。这个例子自动批准 ExitPlanMode 权限请求(Claude 展示计划后请求继续执行时):
json
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
}
]
}
]
}
}尽量缩小 matcher 范围。空 matcher 会自动批准所有权限请求,包括文件写入和 shell 命令,非常危险。
Prompt-based Hooks
对于需要判断而非规则的场景,可以使用 type: "prompt" hooks,让 Claude 模型(默认 Haiku)来评估条件,返回 {"ok": true} 或 {"ok": false, "reason": "..."}。
Agent-based Hooks
需要访问文件或运行命令来验证条件时,用 type: "agent" hooks。子代理可以读文件、搜索代码,再返回决策,比 prompt hook 更强大。
配置文件位置
Hook 配置写在 hooks 块中,添加到任意设置文件即可。不同位置的设置文件作用范围不同:
| 文件 | 作用范围 |
|---|---|
~/.claude/settings.json | 所有项目(全局) |
.claude/settings.json | 当前项目(可提交到版本控制) |
.claude/settings.local.json | 当前项目本地(不共享) |
故障排查题排查
Hook 没有触发
- 运行
/hooks确认 hook 出现在正确事件下 - 检查 matcher 是否大小写匹配(区分大小写)
- 非交互模式(
-p)下PermissionRequesthook 不触发,改用PreToolUse
命令找不到 用绝对路径或 $CLAUDE_PROJECT_DIR 引用脚本;确保脚本有执行权限(chmod +x)。
Stop hook 死循环 在 hook 脚本中检查 stop_hook_active 字段:
bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0
fi用 claude --debug 或 Ctrl+O 开启详细模式查看 hook 执行详情。
相关文档
- Hooks 完整参考:事件完整列表、JSON schema、HTTP hooks
- Skills:给 Claude 添加自定义指令和可执行命令
- Sub-agents:在隔离上下文中运行任务
常见问题
Q: Hooks 和 CLAUDE.md 有什么区别,什么时候该用哪个?
CLAUDE.md 是静态指令,Claude 读取后"知道"要怎么做,但不一定每次都会执行。Hooks 是确定性的,事件触发时必然执行,不依赖 Claude 的判断。需要"每次都要发生"的操作(格式化、通知、保护文件)用 Hooks;需要 Claude 理解项目规范用 CLAUDE.md。
Q: Hook 命令可以访问哪些上下文信息?
通过 stdin 以 JSON 格式接收事件数据,用 jq 提取需要的字段。不同事件包含不同字段,例如 PreToolUse 包含 tool_name 和 tool_input,SessionStart 包含 trigger(启动原因)。完整字段列表见 Hooks 参考。
Q: 如何安全地自动批准权限请求,防止过度授权?
用精确的 matcher 限定只自动批准特定工具或操作,绝不用空 matcher 批准所有请求。比如 Bash(npm test) 只允许 npm test,而不是所有 Bash 命令。批准范围越小越安全。