使用 Hooks
Claude Code Hooks 在生命周期事件上执行确定性自动化。学会事件、matcher、if、exit code、JSON 输出、command/prompt/agent/HTTP hooks 和安全边界。
Hook 是把“希望 Claude 记得做”变成“事件发生时一定运行”。凡是必须发生、可脚本化、可判定的动作,都不应该只写在 prompt 里。——翔宇
这一章用 16 分钟换什么:前面讲了 Skills 和 Subagents。Skills 给 Claude 方法,Subagents 做隔离任务,Hooks 则在 Claude Code 生命周期上做确定性自动化。读完你应该能配置通知、格式化、阻断、审计、环境重载、permission 自动处理,并知道什么时候该用 command、prompt、agent 或 HTTP hook。
1. Hook 解决什么问题
Hook 是在 Claude Code 生命周期事件上自动执行的动作。
典型用途:
- Claude 等待输入时发通知。
- Edit / Write 后自动格式化。
- PreToolUse 阻止危险命令。
- 禁止修改
.env、.git/、lockfile 等受保护文件。 - compaction 后重新注入关键上下文。
- 配置文件变化时审计。
- 目录变化时重载
direnv、devbox、nix 环境。 - PermissionRequest 出现时自动处理特定低风险请求。
- Subagent 开始和结束时做 setup / cleanup。
Hook 和 prompt 的区别:
- Prompt 是让 Claude 记住并判断。
- Hook 是事件发生时直接运行。
第一性原理:需要推理和自由裁量,用 Skill 或 Subagent;需要每次固定执行,用 Hook;需要安全硬边界,优先 permissions + Hook。
flowchart TD
Rule["一条规则或动作"]
MustRun["必须每次发生?"]
NeedsLLM["需要模型判断?"]
NeedsTools["需要读文件或跑命令判断?"]
External["需要通知外部系统?"]
Prompt["CLAUDE.md / Skill"]
CommandHook["Command Hook"]
PromptHook["Prompt Hook"]
AgentHook["Agent Hook"]
HttpHook["HTTP Hook"]
Rule --> MustRun
MustRun -->|否| Prompt
MustRun -->|是| NeedsLLM
NeedsLLM -->|否| External
External -->|是| HttpHook
External -->|否| CommandHook
NeedsLLM -->|是| NeedsTools
NeedsTools -->|否| PromptHook
NeedsTools -->|是| AgentHook
style CommandHook fill:#dcfce7,stroke:#22c55e,stroke-width:2px
style PromptHook fill:#e0f2fe,stroke:#0284c7,stroke-width:2px
style AgentHook fill:#fef3c7,stroke:#f59e0b,stroke-width:2px
style HttpHook fill:#fee2e2,stroke:#ef4444,stroke-width:2px
2. Hook 和 Skill 的边界
Skill 适合:
- 发布 checklist。
- 代码审查流程。
- API 风格指南。
- 调试 playbook。
- 需要 Claude 推理、取舍、适配上下文的工作方法。
Hook 适合:
- 每次编辑后跑 formatter。
- 每次 Bash 前检查命令。
- 每次会话结束写日志。
- 每次 permission prompt 出现时处理某类低风险请求。
- 每次配置文件变化时审计。
错误用法:
- “不要改
.env”只写在 Skill 里。 - “每次保存后格式化”只写在
CLAUDE.md里。 - “发布前一定跑测试”只靠 Claude 自觉。
正确做法:
- 知识和流程写 Skill。
- 确定动作写 Hook。
- 安全拒绝写 permissions deny,必要时再加 Hook 给反馈。
Hook 不是更强提示词:它是自动化执行点。不要把需要人类判断的危险动作做成无确认 Hook。
3. Hook 配在哪里
Hook 写在 settings 里:
- User:
~/.claude/settings.json - Project:
.claude/settings.json - Local:
.claude/settings.local.json - Managed:组织级 managed settings
- Plugin:plugin 里的 hook 配置
- Subagent frontmatter:只在该 subagent 生命周期内生效
基础结构:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}同一个 hooks object 里可以有多个事件。不要新增一个 hooks key 把旧配置覆盖掉。
查看入口:
/hooks官方说明 /hooks 是只读浏览器。新增、修改、删除仍然要编辑 settings JSON,或让 Claude 帮你改配置文件。
Project Hook 适合团队规则;User Hook 适合个人通知和日志;Local Hook 适合本机路径;Managed Hook 适合组织强制自动化。
4. 第一个 Hook:等待输入时发通知
macOS 示例:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}验证:
- 写入
~/.claude/settings.json。 - 运行
/hooks,确认Notification下有配置。 - 触发一个 permission prompt 或让 Claude 完成任务等待输入。
macOS 如果没有通知,先在 Terminal 跑一次:
osascript -e 'display notification "test"'然后去 System Settings 里给 Script Editor 开通知权限。
Notification 的空 matcher 表示全部通知类型。只想匹配权限提示时,用 permission_prompt。
5. 常见事件:先记这几类
Hook 事件很多,新手先记这几类。
SessionStart:会话开始或恢复。UserPromptSubmit:用户 prompt 提交后、Claude 处理前。PreToolUse:工具执行前,可以阻断。PermissionRequest:权限弹窗即将出现。PermissionDenied:auto mode 分类器拒绝工具调用。PostToolUse:工具成功执行后。PostToolUseFailure:工具失败后。PostToolBatch:一批并行工具调用完成后。Notification:Claude Code 发送通知时。SubagentStart/SubagentStop:subagent 开始和结束。TaskCreated/TaskCompleted:任务创建和完成。Stop:Claude 完成响应。StopFailure:本轮因 API 错误结束。ConfigChange:配置文件变化。CwdChanged:工作目录变化。FileChanged:被监听文件变化。WorktreeCreate/WorktreeRemove:worktree 创建和移除。PreCompact/PostCompact:compaction 前后。InstructionsLoaded:CLAUDE.md或 rules 加载到上下文。Elicitation/ElicitationResult:MCP elicitation 相关事件。
事件决定能力边界:阻断工具要用 PreToolUse;工具完成后格式化用 PostToolUse;权限弹窗自动处理用 PermissionRequest;上下文补充用 SessionStart 或 PostCompact。
6. Hook 怎么收到输入
Command hook 会从 stdin 收到 JSON。
常见字段包括:
hook_event_namesession_idtranscript_pathcwdtool_nametool_input- 事件专属字段
例如 PreToolUse / PostToolUse 里,通常会有:
{
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "git status"
}
}脚本里一般用 jq 解析:
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // empty')先保存输入样本:写复杂 Hook 前,先把 stdin JSON append 到临时日志,确认字段名和事件结构。
7. Exit code 语义
Command hook 通过 exit code 和 stdout / stderr 告诉 Claude Code 下一步怎么做。
- Exit
0:继续。对UserPromptSubmit、UserPromptExpansion、SessionStart等事件,stdout 会加入 Claude 上下文。 - Exit
2:尝试阻断。stderr 会反馈给 Claude 或用户。对部分事件不能阻断,只会显示错误后继续。 - 其他 exit code:非阻断错误。流程继续,stderr 第一行显示在 transcript,完整 stderr 写 debug log。
例子:阻止 Bash 里出现危险 SQL。
#!/usr/bin/env bash
set -euo pipefail
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // empty')
if echo "$command" | rg -i "drop table|delete from|truncate table" >/dev/null; then
echo "Blocked: destructive SQL is not allowed" >&2
exit 2
fi
exit 0不要混用 exit 2 和 JSON allow/deny:官方说明 exit 2 时 JSON 会被忽略。要结构化控制,用 exit 0 + stdout JSON。
8. Structured JSON 输出
Exit code 只能粗略 allow / block。需要更细控制时,exit 0 并向 stdout 输出 JSON。
PreToolUse 可以返回:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Use rg instead of grep for repository search."
}
}效果:
- 工具调用被取消。
permissionDecisionReason会反馈给 Claude。- Claude 可以调整做法后继续。
PermissionRequest 可以返回 allow:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow"
}
}
}也可以更新当前 session 的权限模式:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedPermissions": [
{ "type": "setMode", "mode": "acceptEdits", "destination": "session" }
]
}
}
}自动 allow 要极窄:PermissionRequest matcher 不要写空或 .*,否则可能自动批准文件写入、shell 命令和外部工具。
9. matcher 怎么工作
matcher 用来筛选某类事件。
不同事件的 matcher 匹配对象不同:
PreToolUse/PostToolUse:工具名,例如Bash、Edit、Write、mcp__github__.*。Notification:通知类型,例如permission_prompt、idle_prompt。SubagentStart/SubagentStop:agent type,例如Explore、Plan、custom agent name。PreCompact/PostCompact:manual或auto。ConfigChange:user_settings、project_settings、local_settings、policy_settings、skills。FileChanged:要监听的 literal filenames,例如.envrc|.env。SessionEnd:结束原因,例如clear。
一些事件不支持 matcher,会每次触发:
UserPromptSubmitPostToolBatchStopTaskCreatedTaskCompletedCwdChangedWorktreeCreateWorktreeRemove
先用 matcher 粗筛:例如 Edit|Write。再用 if 或脚本内部逻辑做细筛。
10. if 字段:按工具名和参数过滤
if 字段要求 Claude Code v2.1.85 或更高。旧版本会忽略它,导致 hook 对所有 matcher 命中的调用运行。
if 使用和 permissions 相同的规则语法。
例子:只检查 git 命令,而不是所有 Bash。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(git *)",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-git-policy.sh"
}
]
}
]
}
}if 只适用于工具类事件:
PreToolUsePostToolUsePostToolUseFailurePermissionRequestPermissionDenied
把 if 放到其他事件上,会阻止 hook 运行。
matcher 按事件对象过滤,if 按工具和参数过滤。需要按 Bash 子命令、Edit 路径、MCP tool 细分时,用 if。
11. PostToolUse:编辑后自动格式化
项目级格式化适合放 .claude/settings.json。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}这个 Hook 的执行逻辑:
- Claude 用
Edit或Write改文件。 - Hook 从 JSON 里取
.tool_input.file_path。 - 把文件路径传给 Prettier。
边界:
- 如果项目不用 Prettier,不要套用这个例子。
- Python、Go、Rust 等项目应该替换成对应 formatter。
- 格式化失败不要静默吞掉,要让 Claude 看到错误。
格式化适合 PostToolUse:不要让 Claude 自己记住“改完跑 formatter”。让 Hook 负责。
12. PreToolUse:阻止受保护文件
脚本示例:.claude/hooks/protect-files.sh
#!/usr/bin/env bash
set -euo pipefail
input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty')
case "$file_path" in
*.env|*.env.*|*/.git/*|*package-lock.json)
echo "Blocked: protected file path $file_path" >&2
exit 2
;;
esac
exit 0注册:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}脚本要可执行:
chmod +x .claude/hooks/protect-files.sh保护敏感文件优先用 permissions deny。Hook 的价值是给更具体的反馈和处理复杂条件。
13. SessionStart / PostCompact:注入上下文
SessionStart 可以在会话开始、恢复、clear 或 compact 后注入上下文。
示例:compaction 后提醒关键规则。
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "echo 'Reminder: use pnpm, run pnpm test before committing, and do not edit generated files.'"
}
]
}
]
}
}注意:
- 每次都要知道的稳定规则,优先写
CLAUDE.md。 - Hook 注入适合动态信息,例如最近 commit、当前 sprint、环境状态。
- 不要注入大段内容,避免上下文污染。
静态规则进 CLAUDE.md,动态上下文用 Hook。
14. ConfigChange:审计配置变化
ConfigChange 在配置文件被外部进程或编辑器修改时触发。
示例:记录配置变化。
{
"hooks": {
"ConfigChange": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "jq -c '{timestamp: now | todate, source: .source, file: .file_path}' >> ~/claude-config-audit.log"
}
]
}
]
}
}matcher 可以过滤:
user_settingsproject_settingslocal_settingspolicy_settingsskills
要阻止变化生效,可以 exit 2,或返回 structured JSON block。
审计日志不要写敏感值:只记录文件、来源、时间和动作,避免把 token、路径隐私和账号写进日志。
15. CwdChanged / FileChanged:重载环境
有些项目依赖 direnv、devbox、nix,根据目录或文件变化加载环境。
SessionStart + CwdChanged 示例:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "direnv export bash > \"$CLAUDE_ENV_FILE\""
}
]
}
],
"CwdChanged": [
{
"hooks": [
{
"type": "command",
"command": "direnv export bash > \"$CLAUDE_ENV_FILE\""
}
]
}
]
}
}监听特定文件:
{
"hooks": {
"FileChanged": [
{
"matcher": ".envrc|.env",
"hooks": [
{
"type": "command",
"command": "direnv export bash > \"$CLAUDE_ENV_FILE\""
}
]
}
]
}
}FileChanged 的 matcher 是 literal filenames 列表,不是正则。
加载 .env 要小心:不要把敏感值打印到 stdout。环境注入写 CLAUDE_ENV_FILE,不要回显到对话。
16. PermissionRequest:自动批准要极窄
自动批准某个低风险权限请求可以用 PermissionRequest。
示例:只自动批准 ExitPlanMode。
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"allow\"}}}'"
}
]
}
]
}
}不要这样做:
- 空 matcher 自动批准所有请求。
.*自动批准所有请求。- 对
Bash、Edit、MCP 写操作做无条件 allow。
PermissionRequest Hook 是高风险能力:只自动处理极小、明确、低风险的权限项。其他保持 ask。
17. PermissionDenied:让 auto mode 重试
PermissionDenied 在 auto mode 分类器拒绝工具调用时触发。
某些情况下,你可以返回:
{
"retry": true
}告诉模型这次可以重试。
适合:
- 分类器误拒绝了低风险操作。
- 你有额外脚本确认这次行为安全。
不适合:
- 用来绕过真实风险。
- 对高风险 Bash / Edit / MCP 写操作统一 retry。
retry 不是 allow all:它只是让模型可重试被 auto mode 拒绝的调用。仍要窄匹配、可解释。
18. Prompt-based hooks
Prompt hook 用 LLM 做判断,适合输入数据本身就足够判断的场景。
示例:Stop 时检查任务是否完成。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Check if all requested tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains to be done\"}."
}
]
}
]
}
}输出协议:
{"ok": true}:继续结束。{"ok": false, "reason": "..."}:根据事件执行阻断或反馈。
适合:
- 检查回答是否覆盖用户请求。
- 判断 summary 是否缺关键信息。
- 基于 hook input 做轻量评估。
不适合:
- 需要读文件、跑测试、查日志。
- 生产级确定性规则。
Prompt hook 是判断,不是执行:需要实际查代码状态时用 agent hook 或 command hook。
19. Agent-based hooks
Agent hook 会 spawn subagent。官方标注为 experimental,生产工作流优先用 command hooks。
适合:
- 需要读文件。
- 需要搜索代码。
- 需要跑命令验证。
- 单次 prompt 判断不够。
示例:Stop 前检查测试是否通过。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
"timeout": 120
}
]
}
]
}
}边界:
- 默认 timeout 比 prompt hook 长。
- 最多会使用一定数量的 tool-use turns。
- 更贵、更慢、更复杂。
Agent hook 不适合替代 CI:它可以做本地预检,但真正发布前仍要依赖可重复的测试和 CI。
20. HTTP hooks
HTTP hook 适合把事件发送到外部系统:
- Slack。
- Discord。
- 内部 webhook。
- 审计平台。
- 任务系统。
- 监控系统。
适合做通知和记录,不适合直接做高风险生产操作。
安全要点:
- 使用 HTTPS。
- token 放在环境变量或凭据系统。
- 不要把完整 prompt、完整 diff、密钥、路径隐私发出去。
- 给外部系统加最小权限。
- 设置合理 timeout。
HTTP hook 是数据外发通道:默认只发送必要字段。不要把 transcript 或 tool input 原样推到第三方。
21. Async hooks
Async hook 适合不需要阻塞 Claude 的后台动作。
适合:
- 发送通知。
- 写审计日志。
- 上传指标。
- 异步触发慢任务。
不适合:
- 阻止工具调用。
- 决定是否继续。
- 必须在下一步前完成的检查。
阻断用同步,旁路用 async:需要影响当前流程就不要异步。
22. Subagent hooks
Subagent 可以在自己的 frontmatter 里定义 hooks。
示例:
---
name: db-reader
description: Execute read-only database queries.
tools: Bash
hooks:
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "./scripts/validate-readonly-query.sh"
---
You are a database analyst with read-only access.
Only execute SELECT queries.Subagent hooks 的特点:
- 只在这个 subagent 生命周期内生效。
- agent 作为 subagent 或通过
--agent作为 main session 时都会运行。 - plugin-shipped agents 不支持
hooks、mcpServers、permissionMode这几个字段。
Project settings 也有:
SubagentStartSubagentStop
适合做 setup / cleanup。
Subagent 工具边界粗,Hook 边界细:例如只允许 SELECT,要用 PreToolUse 校验 Bash 内容。
23. Hooks 和 permission modes
Hooks 与 permission modes 是两层不同机制。
PreToolUse在工具调用前触发,可以阻断。PermissionRequest在权限弹窗前触发,可以自动回答某些请求。PermissionDenied可以处理 auto mode 拒绝。bypassPermissions仍然会影响权限提示出现与否。
不要假设 Hook 可以解决所有模式差异。尤其是:
- auto mode 下部分请求可能先被分类器拒绝。
- background subagents 预批准后会 auto-deny 未批准项。
- managed settings 可能禁用 bypass 或强制策略。
Hook 不是权限系统替代品:权限边界写 permissions;Hook 用来补自动化、反馈、审计和复杂条件判断。
24. Hook 合并和执行模型
官方说明:事件触发时,所有匹配 hooks 会并行运行。相同命令会自动去重。
这带来几个后果:
- 多个 scope 的 hooks 可能都会执行。
- 不要假设 hooks 按顺序串行。
- 如果一个 hook 依赖另一个 hook 的输出,设计就不稳。
- 要串行流程,就写成一个脚本内部步骤。
- Hook 输出越多,越可能污染上下文。
Hook 要独立幂等:同一事件下每个 Hook 都应该能独立运行,多次运行也不破坏状态。
25. 安全边界
Hook 是自动运行命令,所以风险很真实。
默认原则:
- 不要在 Hook 里删除文件。
- 不要自动发布生产。
- 不要自动
git push。 - 不要把密钥写到日志。
- 不要把完整 transcript 发给外部服务。
- 不要对权限请求做宽 matcher allow。
- 不要执行仓库里不可信脚本,除非已信任 workspace。
- Project Hook 进 git 前要 review。
- Managed Hook 应由管理员维护。
脚本建议:
- shell 脚本首行使用 shebang。
- 使用
set -euo pipefail。 - 用
jq解析 JSON,避免字符串硬拆。 - 对路径做白名单或严格匹配。
- 出错时 stderr 写明确原因。
- 对网络调用设置 timeout。
Hook 的能力取决于本机权限:Claude Code 能运行什么,Hook 就可能运行什么。不要把不可信 Hook 当普通提示词看待。
26. 常见故障:Hook 不触发
按这个顺序查:
- 运行
/hooks,确认事件下有配置。 - 检查写入的是正确 settings scope。
- 确认 JSON 没有被另一个
hookskey 覆盖。 - 检查 event name 拼写。
- 检查 matcher 是否匹配事件对象。
- 如果用了
if,确认 Claude Code 版本至少 v2.1.85。 - 确认脚本有执行权限。
- 检查脚本路径,优先用
$CLAUDE_PROJECT_DIR。 - 打开 verbose / debug log 看 stderr。
先写最小 echo hook:确认事件能触发,再逐步加 matcher、if、脚本逻辑。
27. 常见故障:Hook 报 JSON validation failed
常见原因:
- stdout 输出了非 JSON 内容,但事件期待 JSON。
- prompt hook 返回的不是
{"ok": true}或{"ok": false, "reason": "..."}。 - command hook 同时写了 JSON 和普通日志到 stdout。
- exit code 2 时还期待 stdout JSON 生效。
- JSON 引号被 shell 转义破坏。
修法:
- 普通日志写 stderr。
- stdout 只写机器要读的 JSON。
- 用
jq -n生成 JSON,减少转义错误。 - 需要阻断就 exit 2 + stderr,不要混 JSON。
stdout 是协议通道:不要随便 echo debug 到 stdout。调试日志写 stderr 或文件。
28. 常见故障:Stop hook 无限循环
Stop hook 如果一直返回 ok: false,Claude 会继续工作,然后再次触发 Stop。
常见原因:
- 判定条件过于理想化。
- reason 不可执行。
- Claude 无法满足 Hook 要求。
- Hook 没有最大尝试次数。
修法:
- reason 写具体下一步。
- 增加外部状态计数。
- 只检查本轮用户明确要求。
- 复杂验证交给 CI,不要用 Stop hook 无限追求完美。
Stop hook 要能收敛:它应该推动完成,不应该把会话锁进无法满足的循环。
29. 常见故障:Hook 影响太大
表现:
- 所有 Bash 都被检查,速度变慢。
- 所有权限都被自动批准。
- 每次编辑都跑整个测试套件。
- 大量 stdout 被塞进上下文。
- 多个 Hook 并行写同一个文件导致日志乱序。
处理:
- 缩小 matcher。
- 加
if。 - 用文件路径筛选。
- 把慢任务改 async 或 CI。
- stdout 限制在必要内容。
- 日志写文件并加锁。
Hook 要窄、快、可解释:越靠近高频事件,越要克制。
30. 推荐落地顺序
不要一上来做复杂 Hook 系统。按这个顺序:
- User scope 加 Notification。
- Project scope 加格式化 Hook。
- Project scope 加敏感文件保护。
- 给 Bash / MCP 高风险调用加 PreToolUse 校验。
- 需要时加 ConfigChange 审计。
- 复杂项目再加 CwdChanged / FileChanged 环境重载。
- 只对低风险、明确事件加 PermissionRequest 自动处理。
- 最后再考虑 prompt / agent / HTTP / async hooks。
先从低风险、可观察开始:通知和格式化最适合入门;自动批准和生产动作最晚考虑。
31. 自检清单
学完这一章,你应该能做到:
- 我能解释 Hook 和 prompt / Skill 的区别。
- 我知道 Hook 配在 settings 的
hooksblock 里。 - 我能用
/hooks查看当前配置。 - 我知道
PreToolUse、PostToolUse、PermissionRequest、Notification、Stop的用途。 - 我知道 matcher 匹配对象随事件变化。
- 我知道
if使用 permission rule syntax。 - 我知道 exit 0、exit 2 和其他 exit code 的差别。
- 我知道 structured JSON 输出必须走 stdout。
- 我知道 command、prompt、agent、HTTP、async hooks 的取舍。
- 我知道 Hook 不是 permissions 的替代品。
- 我知道自动批准权限请求必须极窄。
- 我知道怎么排查 hook 不触发和 JSON validation failed。
32. 术语速查
Hook:Claude Code 生命周期事件上的自动化动作。Command hook:运行本机 shell 命令的 Hook。Prompt hook:用 LLM 根据 hook input 做判断的 Hook。Agent hook:spawn subagent 做验证的 Hook。HTTP hook:把事件发到 HTTP endpoint 的 Hook。Async hook:后台执行、不阻塞当前流程的 Hook。matcher:按事件对象筛选 hook group。if:按工具名和参数进一步筛选工具类 hook。PreToolUse:工具执行前事件。PostToolUse:工具成功执行后事件。PermissionRequest:权限弹窗出现前事件。PermissionDenied:auto mode 拒绝工具调用后事件。Notification:Claude Code 发送通知时事件。Stop:Claude 完成响应时事件。ConfigChange:配置变化事件。CwdChanged:工作目录变化事件。FileChanged:监听文件变化事件。CLAUDE_ENV_FILE:Claude Code Bash preamble 环境文件。hookSpecificOutput:structured JSON 输出里的事件专属控制字段。