详情

首页手游攻略 Claude Code Hooks 类型与使用指南实践整理

Claude Code Hooks 类型与使用指南实践整理

佚名 2026-08-20 11:50:01

平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“Claude Code Hooks 类型与使用指南”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际使用顺序,把思路、关键写法和容易踩坑的地方讲清楚,方便你直接对照操作。

在这个场景下,本文总结 Claude Code / 本仓库恢复版 claude-code 中 hooks 的类型、触发时机、典型采用场景、设置方式与注意事项。

从实现思路看,Hooks 是 Claude Code 在会话、工具调用、权限、压缩、子代理、任务等生命周期节点执行的自定义动作。它们适合做自动校验、权限治理、日志审计、上下文注入、格式化、通知和资源清理。

0. 整体流程图

整体流转可以理解为:会话启动后触发 SessionStart;用户提交 prompt 后、Claude 处理前触发 UserPromptSubmit;Claude 推理中如果要调用工具,先在权限弹窗前触发 PermissionRequest,再在工具真正执行前触发 PreToolUse;工具成功后触发 PostToolUse,失败后触发 PostToolUseFailure,权限被拒绝后触发 PermissionDenied;子代理、上下文压缩、通知和任务事件会在各自生命周期点触发;最后在回复结束前触发 Stop,会话退出时触发 SessionEnd。

1. 设置位置

作用域设置文件或来源适用场景是否建议提交到仓库
用户级~/.claude/settings.json个人通用习惯,比如所有项目都禁止危险 Bash 命令否
项目级.claude/settings.json团队共享规则,比如项目统一 formatter、lint、测试钩子是
项目本地级.claude/settings.local.json个人在当前项目的本地设置,比如本机路径、本地通知脚本否
插件级~/.claude/plugins/*/hooks/hooks.json由插件提供的通用 hook 能力否
会话级运行时内存注册临时 hook,随会话结束清除否

基础设置结构:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/hooks/check.py",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

2. Hook 执行类型

理解这一步时,Hook 事件描述“什么时候触发”,hook 执行类型描述“触发后用什么方式执行”。

执行类型关键字段什么时候采用如何采用注意事项
commandcommand, shell, timeout, statusMessage, once, async, asyncRewake, if需执行本地脚本或 shell 命令时;最常用从实现思路看,写一个脚本从 stdin 读取 JSON,输出文本或 JSON,再在 settings.json 设置 commandhook 可执行任意命令,只运行可信脚本;建议设置合理 timeout
promptprompt, model, timeout, statusMessage, once, if需用模型判断某个事件是否合规,或生成简短建议落到代码里,设置 prompt,让 Claude Code 把 hook 输入交给模型分析适合判断和文本分析,不适合强制性安全边界
agentprompt, model, timeout, statusMessage, once, if需启动代理做更完整的验证或检查设置 agent prompt,要求代理审查输入、输出结论成本和延迟更高;适合较重的检查
httpurl, headers, allowedEnvVars, timeout, statusMessage, once, if需把 hook 事件发送到外部服务,比如审计、通知、策略引擎结合项目来看,Claude Code 向 url POST hook 输入 JSON,服务得到 JSONHTTP hook 必须得到 JSON;不要把敏感信息发到不可信服务

callback 和 function 类型属于程序内或会话内注册机制,不适合直接写入持久化 settings.json。

3. Hook 事件类型总表

Hook 类型触发时机什么时候采用如何采用常用 matcher
PreToolUseClaude 准备调用工具之前阻止危险命令、限制文件写入范围、校验工具输入、改写工具输入在这个场景下,设置在 hooks.PreToolUse 下,按工具名匹配;脚本读取 tool_name 和 tool_input,必要时得到 permissionDecision 或 updatedInput工具名,比如 Bash, Write, Edit, Read
PostToolUse工具调用成功之后自动格式化、运行 lint/test、记录工具结果、补充上下文、处理 MCP 工具输出结合项目来看,设置在 hooks.PostToolUse 下;脚本读取 tool_response 同时得到普通输出或结构化 JSON工具名
PostToolUseFailure工具调用失败之后收集失败诊断、记录错误、提示修复建议理解这一步时,设置在 hooks.PostToolUseFailure 下;脚本读取 error 字段工具名
PermissionRequestClaude Code 需权限决策时自动批准低风险命令、拒绝高风险命令、改写工具输入、接入组织策略在这个场景下,设置在 hooks.PermissionRequest 下,得到 hookSpecificOutput.decision.behavior 为 allow 或 deny,可附带 updatedInput工具名
PermissionDenied工具权限被拒绝后记录拒绝原因、通知用户、决定是否引导换方案结合项目来看,设置在 hooks.PermissionDenied 下,读取被拒绝的工具和原因工具名
NotificationClaude Code 发出通知时转发到桌面、Slack、企业 IM、日志系统设置在 hooks.Notification 下;按通知类型匹配notification_type
UserPromptSubmit用户提交 prompt 后、Claude 处理前注入项目上下文、审计用户输入、阻止违规请求、补充团队规则落到代码里,设置在 hooks.UserPromptSubmit 下;得到 additionalContext 可给模型增加上下文通常不按工具匹配
SessionStart会话开始、恢复、清空后重新进入等场景加载项目上下文、设置 watch paths、输出初始化提示在这个场景下,设置在 hooks.SessionStart 下;可得到 additionalContext, initialUserMessage, watchPathssource
SessionEnd会话结束、清空或退出时清理资源、保存状态、发送结束通知设置在 hooks.SessionEnd 下;脚本应很快完成reason
StopClaude 完成一次响应、即将停止时最后质量检查、检查待办未完成项、要求 Claude 继续修复设置在 hooks.Stop 下;得到阻塞结果可促使继续处理通常无 matcher
StopFailureStop hook 或停止流程失败时记录停止失败、诊断异常设置在 hooks.StopFailure 下,读取错误信息error
SubagentStart子代理启动时给子代理注入上下文、记录代理开始执行设置在 hooks.SubagentStart 下agent_type
SubagentStop子代理完成时校验代理输出、收集报告、阻止不合格结果进入主流程设置在 hooks.SubagentStop 下agent_type
PreCompact上下文压缩前保存关键状态、导出中间结论、阻止不合适的压缩设置在 hooks.PreCompact 下trigger
PostCompact上下文压缩后恢复关键上下文、重新注入摘要或提醒设置在 hooks.PostCompact 下trigger
Setup初始化或 setup 流程触发时初始化环境、准备上下文、执行一次性设置设置在 hooks.Setup 下trigger
TeammateIdle协作 agent 或 teammate 空闲时自动分派任务、提醒、状态检查设置在 hooks.TeammateIdle 下通常无 matcher
TaskCreated任务新建时记录任务、同步到外部系统、通知协作方设置在 hooks.TaskCreated 下通常无 matcher
TaskCompleted任务完成时结果校验、归档、通知、触发后续流程设置在 hooks.TaskCompleted 下通常无 matcher
ElicitationMCP elicitation 请求发起时自动接受、拒绝或取消 MCP 服务提出的问题设置在 hooks.Elicitation 下mcp_server_name
ElicitationResultMCP elicitation 得到结果时校验得到内容、审计用户/系统响应设置在 hooks.ElicitationResult 下mcp_server_name
ConfigChange设置发生变化时刷新缓存、记录设置变更、重新加载策略设置在 hooks.ConfigChange 下source
WorktreeCreate新建 worktree 时接管或参与 worktree 新建,并在得到路径前完成必要初始化在这个场景下,设置在 hooks.WorktreeCreate 下;必须借助 stdout 或 hookSpecificOutput.worktreePath 得到非空 worktree 路径通常无 matcher
WorktreeRemove删除 worktree 时清理资源、释放锁、删除临时文件设置在 hooks.WorktreeRemove 下通常无 matcher
InstructionsLoaded指令文件加载完成后审计或追加说明上下文、提示冲突规则设置在 hooks.InstructionsLoaded 下load_reason
CwdChanged当前工作目录变化时更新路径相关环境、刷新项目上下文设置在 hooks.CwdChanged 下通常无 matcher
FileChanged被的文件变化时自动刷新上下文、重新加载设置或规则在这个场景下,先借助 SessionStart 得到 watchPaths,再设置 FileChanged 处理变更文件 basename

4. 常用目标与建议 hook

目标建议 hook建议 matcher典型做法
阻止危险 Bash 命令PreToolUseBash在这个场景下,读取 tool_input.command,命中 rm -rf, git reset --hard, `curl
限制只能改某些目录PreToolUse`WriteEdit
编辑后自动格式化PostToolUse`WriteEdit
工具失败后自动诊断PostToolUseFailure`BashRead
自动批准低风险只读命令PermissionRequestBash对 git status, ls, pwd 等得到 hookSpecificOutput.decision.behavior: "allow"
用户输入后补充上下文UserPromptSubmit无得到 additionalContext,比如项目当前规范或安全边界
会话启动时加载项目信息SessionStartsource得到项目说明、默认任务提醒、需的文件路径
响应结束前质量门禁Stop无检查是否运行测试、是否完成待办;不满足则阻塞并说明原因
子代理完成后校验SubagentStopagent_type检查代理输出是否包含必需字段或是否发现高危问题
上下文压缩前保存状态PreCompacttrigger把关键任务状态写入文件或外部系统
任务完成后通知TaskCompleted无发桌面通知、Webhook 或企业 IM 消息
接管 worktree 新建WorktreeCreate无新建或初始化 worktree 后,得到最后 worktree 路径

5. Hook 输入协议

实际处理时,Claude Code 会把结构化 JSON 写入 hook 进程的 stdin。

通用字段:

字段类型含义
session_idstring当前会话 ID
transcript_pathstring当前 transcript 文件路径
cwdstring当前工作目录
permission_modestring?当前权限模式,可能不存在
agent_idstring?子代理 ID,主线程通常不存在
agent_typestring?agent 类型,可能不存在
hook_event_namestring当前 hook 事件名

工具相关 hook 额外字段:

字段出现于含义
tool_namePreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied工具名
tool_input工具相关 hook工具输入
tool_responsePostToolUse工具成功输出
error失败类事件错误信息

示例脚本读取输入:

#!/usr/bin/env python3
import json
import sys

payload = json.load(sys.stdin)
print(json.dumps({"suppressOutput": True}))

6. Hook 输出协议

command hook 的 stdout 如果去掉空白后以 { 开头,会被当成 JSON 解析;否则按普通文本处理。http hook 必须得到 JSON。

通用输出字段:

字段类型作用
continuebooleanfalse 表示阻止 Claude 继续
suppressOutputboolean是否隐藏 hook stdout
stopReasonstringcontinue: false 时展示的停止原因
decisionstring常用值为 approve 或 block
reasonstring决策原因
systemMessagestring展示给用户的系统消息或警告
hookSpecificOutputobject针对具体 hook 的结构化输出

常用 hookSpecificOutput:

Hook可用字段用法
PreToolUsepermissionDecision, permissionDecisionReason, updatedInput允许、拒绝或改写即将执行的工具输入
PermissionRequestdecision.behavior, decision.updatedInput, decision.message对权限请求得到允许或拒绝决策
UserPromptSubmitadditionalContext给 Claude 追加上下文
SessionStartadditionalContext, initialUserMessage, watchPaths初始化会话上下文和文件
PostToolUseupdatedMCPToolOutput更新 MCP 工具输出,仅对 MCP 工具有效
WorktreeCreateworktreePath理解这一步时,HTTP hook 得到新建好的 worktree 路径;command hook 可直接输出路径

权限请求允许示例:

{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "allow",
      "updatedInput": {}
    }
  }
}

权限请求拒绝示例:

{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "deny",
      "message": "该命令不允许自动执行"
    }
  }
}

阻止危险命令示例:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "禁止执行破坏性 rm 命令"
  }
}

注入上下文示例:

{
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "本项目要求修改代码后运行相关测试。"
  }
}

会话启动示例:

{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "已加载项目上下文。",
    "initialUserMessage": "请先阅读 README.md 和 AGENTS.md。",
    "watchPaths": ["/absolute/path/to/AGENTS.md"]
  }
}

7. 退出码语义

退出码行为什么时候采用
0成功hook 检查借助,或只输出信息
2阻塞错误,Claude 会收到 hook feedback需明确阻止当前动作或要求 Claude 修正
其他非零值非阻塞错误,通常展示给用户但不一定阻止流程hook 自身失败但不应中断主流程

也可以用 JSON 表达阻塞:

{
  "decision": "block",
  "reason": "该命令不允许执行"
}

8. Matcher 与条件

8.1 matcher

matcher 用来筛选 hook 是否执行。

写法含义示例
省略或 *匹配全部所有工具调用后都运行日志 hook
精确工具名只匹配单个工具Bash
管道分隔匹配多个工具`Write
正则表达式更灵活的匹配^mcp__.*

8.2 if 条件

if 是更细粒度的工具条件,适用来工具相关事件:

  • PreToolUse
  • PostToolUse
  • PostToolUseFailure
  • PermissionRequest

示例:

{
  "type": "command",
  "command": "python3 .claude/hooks/check-git.py",
  "if": "Bash(git *)"
}

9. 设置示例

9.1 禁止危险 Bash 命令

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/hooks/block-dangerous-bash.py",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

.claude/hooks/block-dangerous-bash.py:

从实现思路看,接下来脚本只是最小演示,不能覆盖所有 shell 绕过方式;生产环境更建议 allowlist、命令解析器或组织级策略引擎。

#!/usr/bin/env python3
import json
import re
import sys
payload = json.load(sys.stdin)
command = payload.get("tool_input", {}).get("command", "")
blocked = [r"brms+-rfb", r"bgits+resets+--hardb", r"bgits+pushs+--forceb"]
if any(re.search(pattern, command) for pattern in blocked):
    print(json.dumps({
        "hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "permissionDecision": "deny",
            "permissionDecisionReason": "检测到高风险命令,请先获得用户明确确认。"
        }
    }))
    sys.exit(0)
print(json.dumps({"suppressOutput": True}))

9.2 编辑后自动格式化

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/hooks/format-changed-file.py",
            "timeout": 60
          }
        ]
      }
    ]
  }
}

9.3 会话开始时注入项目上下文

settings.json 里只设置 hook 什么时候运行、运行什么命令;hookSpecificOutput 是该命令执行后输出到 stdout 的 JSON,不是直接嵌在 settings.json 里的字段。

.claude/settings.json:

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|resume|clear|compact",
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/hooks/session-context.py",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

matcher 匹配 source 字段,可用值如下所示:

source含义适用场景
startup新会话启动加载项目上下文、初始化提示
resume恢复旧会话恢复会话状态、提醒历史上下文
clear清空会话后重新开始重新注入基础规则
compact压缩上下文后继续重新注入关键摘要或状态

SessionStart hook 收到的输入 JSON 结构大致如下所示:

{
  "session_id": "session-id",
  "transcript_path": "/absolute/path/to/transcript.jsonl",
  "cwd": "/absolute/path/to/project",
  "permission_mode": "default",
  "hook_event_name": "SessionStart",
  "source": "startup",
  "agent_type": "default",
  "model": "claude-sonnet-4-6"
}

字段说明:

字段类型必填说明
session_idstring是当前会话 ID
transcript_pathstring是当前 transcript 文件路径
cwdstring是当前工作目录
permission_modestring否当前权限模式
hook_event_name"SessionStart"是固定为 SessionStart
source"startup" | "resume" | "clear" | "compact"是SessionStart 的触发来源,也是 matcher 匹配字段
agent_typestring否当前 agent 类型
modelstring否当前会话采用的模型

脚本 stdout 得到的完整 hookSpecificOutput JSON 结构:

{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "本仓库是 Claude Code 恢复版源码;修改前请优先阅读 README.md。",
    "initialUserMessage": "请先阅读 README.md 和 AGENTS.md,然后再开始任务。",
    "watchPaths": [
      "/absolute/path/to/project/README.md",
      "/absolute/path/to/project/AGENTS.md"
    ]
  }
}

SessionStart.hookSpecificOutput 字段说明:

字段类型必填作用
hookEventName"SessionStart"是必须与当前 hook 事件一致,否则会被视为错误输出
additionalContextstring否注入给 Claude 的额外上下文,适合放项目规则、恢复提示、环境说明
initialUserMessagestring否作为会话开始时的初始用户消息,适合自动触发启动任务或提醒
watchPathsstring[]否要的绝对路径;文件变化后可触发 FileChanged hook

最小脚本示例:

#!/usr/bin/env python3
import json
print(json.dumps({
    "hookSpecificOutput": {
        "hookEventName": "SessionStart",
        "additionalContext": "本项目要求修改代码后运行相关测试。"
    }
}))

9.4 用户提交 prompt 后追加规则

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/hooks/user-prompt-context.py",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

脚本输出:

{
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "如果要修改代码,请先检查现有测试和相关实现。"
  }
}

10. 关键注意事项

注意事项说明建议
Hooks 能执行任意命令.claude/settings.json 中的 hook 是代码执行入口只信任可信仓库与可信设置;审查外部 PR 中的 hook 变更
交互模式可能需 workspace trust未信任工作区时,交互模式下 hook 可能被跳过对安全边界不要只依赖 hook;结合权限模式和人工确认
同一事件的多个 hook 可能并行执行不应依赖 hook 之间的执行顺序需顺序时把逻辑放进同一个脚本
默认超时可能较长工具 hook 默认可能等待较久为每个 hook 显式设置 timeout
SessionEnd 要更快完成结束 hook 默认超时很短只做轻量清理;重任务放到后台或外b队列
stdout JSON 解析敏感stdout.trim() 以 { 开头会按 JSON 解析普通文本不要以 { 开头;结构化输出确保合法 JSON
HTTP hook 必须得到 JSON空响应会按 {} 处理,非 JSON 是错误外部服务统一得到 JSON envelope
HTTP hook 不适合所有事件SessionStart / Setup 等场景不适合 HTTP hook初始化类逻辑优先用 command
PreToolUse 可改写输入updatedInput 会影响即将执行的工具只做确定、安全、可审计的改写
PostToolUse 不应假设能改所有输出updatedMCPToolOutput 只对 MCP 工具有效普通工具结果用日志或上下文提示处理
async hook 后台运行可减少等待,但结果不会同步阻塞当前流程只用来通知、审计、异步归档等非关键路径
asyncRewake 会唤醒模型后台 hook 退出码为 2 时可注入阻塞反馈谨慎采用,避免噪音或循环唤醒
once 只运行一次执行后 hook 会被移除适合一次性初始化,不适合长期策略
shell 可设置兼容 bash 和 powershell跨平台项目要明确 shell 与路径差异

11. 设计建议

设计原则建议做法
安全优先从实现思路看,对破坏性操作采用 PreToolUse 或 PermissionRequest,但仍保留人工确认
更快失败hook 内部校验失败时输出清晰原因,不要静默失败
最小权限hook 只读取必要字段,只访问必要文件或外部服务
可观察关键 hook 记录事件、决策和原因,便于排查
不依赖顺序多个独立 hook 不共享隐式状态
保持轻量同步 hook 只做更快检查;耗时任务改为异步或外b队列
设置分层团队规则放项目级,个人偏好放用户级或本地级
明确边界不把 hook 当作唯一安全机制;配合权限模式、代码审查和测试

12. 速查表

你想做什么首选 hook执行类型得到什么
阻止命令执行PreToolUsecommandpermissionDecision: "deny"
自动批准权限PermissionRequestcommandhookSpecificOutput.decision.behavior: "allow"
改写工具输入PreToolUsecommandupdatedInput
编辑后格式化PostToolUsecommand普通输出或 suppressOutput
工具失败后提示PostToolUseFailurecommand / prompt文本建议或系统消息
增加用户 prompt 上下文UserPromptSubmitcommandadditionalContext
会话开始加载上下文SessionStartcommandadditionalContext, initialUserMessage, watchPaths
响应结束前检查Stopcommand / agentdecision: "block" 或退出码 2
通知外部系统Notification / TaskCompletedhttp / command{} 或通知结果
压缩前保存状态PreCompactcommand成功状态或阻塞原因
新建 worktreeWorktreeCreatecommand / httpstdout 路径或 hookSpecificOutput.worktreePath

结合项目来看,总的来说,Claude这部分内容适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。

点击查看更多
推荐专题
热门阅读