Hooks
在 Claude 使用工具前后自动运行的确定性脚本。
Hooks vs. CLAUDE.md
关键区别:
- CLAUDE.md — 建议性。Claude 会阅读并_尝试_遵循,但可能遗忘或判断失误。
- Hooks — 确定性。你的脚本每次都会自动运行,无论如何。Claude 无法跳过。
使用 CLAUDE.md 来设置指南和偏好。使用 hooks 来设置绝对不能违反的规则。
Hook 事件类型
Hooks 在 Claude 代理循环的特定节点触发。最常用的事件:
| 事件 | 触发时机 |
|---|---|
PreToolUse | 工具执行前——可批准、拒绝或修改工具调用 |
PostToolUse | 工具成功完成后 |
PostToolUseFailure | 工具执行失败后 |
UserPromptSubmit | 用户提交提示词后、Claude 处理前 |
Stop | 主 Agent 完成响应时 |
SubagentStart / SubagentStop | 子 Agent 启动或完成时 |
TaskCreated / TaskCompleted | Agent team 任务创建或完成时 |
TeammateIdle | Agent team teammate 进入 idle 状态时 |
SessionStart / SessionEnd | 会话开始或结束时 |
PreCompact / PostCompact | 上下文压缩前后 |
Notification | 权限提示、空闲提醒、认证事件 |
PermissionDenied | 自动模式分类器拒绝后(返回 {retry: true} 可让 Claude 重试) |
配置
Hooks 在 .claude/settings.json 的 hooks 键下定义。每个事件映射到一组 matcher 对象,每个 matcher 对象包含一个 hooks 数组:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx eslint --fix"
}
]
}
]
}
}matcher 是对工具名称匹配的正则(大小写敏感),用 | 匹配多个工具:"Write|Edit"。type 字段决定 handler 类型:"command" 运行 shell 脚本,"http" 把事件 JSON POST 到端点,"mcp_tool" 调用已连接的 MCP 工具,"prompt" 让 Claude 评估,"agent" 启动 subagent。
快速确定性检查优先用 command hooks。只有检查真的需要模型判断时,才用 prompt 或 agent hooks;它们会增加延迟和 token 成本。
实用示例
每次写入后自动 Lint
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx eslint --fix"
}
]
}
]
}
}阻止写入敏感文件
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | grep -qE '(\\.env|secrets|credentials)' && exit 2 || exit 0"
}
]
}
]
}
}如果 hook 返回退出码 2,Claude Code 会阻止工具执行并将错误消息反馈给 Claude。退出码 0 表示成功;其他非零退出码是非阻塞错误。
修改后运行测试
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "file=$(jq -r '.tool_input.file_path'); if echo \"$file\" | grep -q 'src/'; then npm test -- --related \"$file\"; fi"
}
]
}
]
}
}Claude 完成时运行脚本
{
"hooks": {
"Stop": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude 完成了\" with title \"Claude Code\"'"
}
]
}
]
}
}Hook 输入与环境变量
Hook 脚本通过 stdin 以 JSON 形式接收完整事件上下文 —— 用 jq 等工具解析。关键字段:
tool_name— 被调用的工具(如Write、Bash、Read)tool_input— 工具参数对象;对于 Write/Edit/Read,tool_input.file_path始终是绝对路径tool_response— (仅 PostToolUse)工具返回的结果session_id、cwd、transcript_path
Hook 命令实际能拿到的环境变量:
$CLAUDE_PROJECT_DIR— 项目根目录$CLAUDE_PLUGIN_ROOT/$CLAUDE_PLUGIN_DATA— 插件定义的 hook 中才会设置$CLAUDE_ENV_FILE— 仅在 SessionStart / Setup / CwdChanged / FileChanged 事件中可用;写入export VAR=value行可把变量持久化到后续 Bash 调用$CLAUDE_EFFORT— 当前 effort 等级(工具调用上下文中)$CLAUDE_CODE_REMOTE— 远程 web 环境下为"true"
文件路径和
session_id只在 stdin JSON 里,没有对应环境变量。请用jq -r '.tool_input.file_path',不要去找不存在的$CLAUDE_TOOL_INPUT_FILE_PATH。
使用 if 的条件 Hook
把 if 字段加在单个 handler 上(位于内层 hooks[] 数组里,不是外层 matcher),命中权限规则时才触发,避免不必要的进程开销:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(git *)",
"command": "echo 'Git 命令被检测到' >> ~/.claude/audit.log"
}
]
}
]
}
}禁用 Hooks
若要在某次会话中禁用所有 hooks(调试时很有用):
{
"disableAllHooks": true
}Hooks 是对 Agent 的确定性控制
建议性与确定性的区别是 Agent 设计中的核心概念。Hooks 让你获得有保障的行为,无论 LLM 做出什么决定——这是所有生产级 Agent 系统中使用的模式。
延伸阅读
- CLAUDE.md 与记忆 — 建议性上下文(与 hooks 互补)
- Skills — 打包可复用工作流
- Subagents — 委托专门任务
- Agent Teams — 协调 team 生命周期事件
- Automation — 将 hooks 与 goals、loops、routines 配合
- 工作流 — 在开发工作流中使用 hooks
继续实践
Hooks 的核心概念已经读完
如果你想把理解变成可复用的能力,可以到 AgentWay 继续练习