Skip to content

Claude Code 钩子 ​

Claude Code 钩子是用户自定义的 Shell 命令,会在 Claude Code 生命周期的特定节点自动执行。

借助钩子,你可以对 Claude Code 的行为实现精准控制,确保某些操作(如代码格式化、日志记录)必定触发,而非依赖大模型自主选择是否执行。

钩子的典型应用场景 ​

钩子能帮你实现很多实用功能,常见场景包括:

  • 消息通知:当 Claude Code 等待输入或需要权限时,自动发送桌面/邮件提醒
  • 自动格式化:编辑 .ts 文件后自动运行 prettier,修改 .go 文件后执行 gofmt
  • 操作日志:记录 Claude 执行的所有命令,用于合规审计或调试排障
  • 代码规范校验:若 Claude 生成的代码不符合项目规范(如命名规则),自动给出反馈
  • 文件权限管控:阻止 Claude 修改生产环境配置文件或敏感目录(如 .env、.git)

相比于通过提示词约束 Claude 的行为,钩子是应用级的硬规则,只要触发对应事件就会强制执行,稳定性和可靠性更高。

重要安全提醒 ​

钩子运行时会直接使用当前系统环境的凭证(如环境变量、用户权限),存在一定安全风险:

  • 恶意钩子代码可能泄露你的敏感数据(如 API 密钥、项目源码)
  • 错误的钩子命令可能导致文件误删、系统异常

必做安全操作:

  1. 注册钩子前,务必逐行审查命令的逻辑和权限
  2. 避免在钩子中执行来源不明的脚本
  3. 详细安全最佳实践,可参考官方文档的 安全注意事项

钩子事件类型说明 ​

Claude Code 内置了多个生命周期事件,你可以为不同事件绑定钩子命令。每个事件会传递不同的上下文数据,且对 Claude 行为的影响方式不同。

事件名称触发时机核心作用
PreToolUse工具调用之前可拦截工具执行(如阻止修改敏感文件),并向 Claude 反馈调整建议
PermissionRequest弹出权限请求对话框时自动批准或拒绝权限申请
PostToolUse工具调用完成后执行后置操作(如格式化代码、记录日志)
UserPromptSubmit用户提交提示词后、Claude 处理前预处理用户输入(如补充上下文信息)
NotificationClaude 发送通知时自定义通知方式(如桌面弹窗、短信提醒)
StopClaude 完成响应时执行收尾工作(如清理临时文件)
SubagentStop子代理任务完成时处理子代理的执行结果
PreCompact即将执行上下文压缩操作时自定义压缩规则
SessionStart启动新会话或恢复旧会话时初始化会话环境(如加载项目配置)
SessionEnd会话结束时保存会话数据、清理环境

快速入门:实现命令日志记录 ​

下面以 记录 Claude 执行的所有 Bash 命令 为例,带你一步步完成钩子的配置和使用。

前置准备 ​

安装 jq 工具(用于命令行解析 JSON 数据):

  • macOS:brew install jq
  • Linux:sudo apt install jq / sudo yum install jq
  • Windows:下载 jq 官方安装包,或通过 WSL 安装

步骤 1:打开钩子配置界面 ​

在 Claude Code 的交互界面中,输入斜杠命令 /hooks,回车后选择要绑定的事件 —— 这里我们选 PreToolUse(工具调用前触发,适合记录命令)。

步骤 2:添加事件匹配器 ​

匹配器的作用是 限定钩子的触发条件,只在指定工具被调用时执行钩子命令。

  1. 选择 + Add new matcher…

  2. 输入匹配关键词 Bash,表示仅当 Claude 调用 Bash 工具时触发钩子

    小技巧:输入 * 可以匹配所有工具,实现全局钩子

步骤 3:添加钩子命令 ​

选择 + Add new hook…,输入以下命令(功能:提取命令内容和描述,写入日志文件):

bash
jq -r '"\(.tool_input.command) - \(.tool_input.description // "无描述信息")"' >> ~/.claude/bash-command-log.txt

命令说明:

  • jq -r ...:提取 JSON 中的命令(command)和描述(description),无描述时显示"无描述信息"
  • >> ~/.claude/...:将内容追加写入用户主目录下的日志文件

步骤 4:选择配置存储位置 ​

配置保存位置决定钩子的生效范围:

  • User settings:保存到用户级配置(~/.claude/settings.json),所有项目生效
  • Project settings:保存到当前项目配置(.claude/settings.local.json),仅当前项目生效

这里我们选 User settings,实现全局命令日志记录。选择后按 Esc 键退出配置界面,钩子即注册完成。

步骤 5:验证钩子配置 ​

  1. 再次输入 /hooks 命令,可查看已配置的钩子列表

  2. 或直接打开配置文件 ~/.claude/settings.json,会看到如下配置内容:

    json
    {
      "hooks": {
        "PreToolUse": [
          {
            "matcher": "Bash",
            "hooks": [
              {
                "type": "command",
                "command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"无描述信息\")\"' >> ~/.claude/bash-command-log.txt"
              }
            ]
          }
        ]
      }
    }

步骤 6:测试钩子效果 ​

  1. 在 Claude Code 中输入指令:帮我执行 ls 命令

  2. 执行完成后,在终端中查看日志文件:

    bash
    cat ~/.claude/bash-command-log.txt
  3. 若日志中出现如下内容,说明钩子配置成功:

    bash
    ls - Lists files and directories

实用钩子示例 ​

下面提供几个常用的钩子配置,你可以直接复制使用或按需修改。

📌 完整示例代码可参考官方仓库:bash 命令验证器示例

示例 1:自动格式化 TypeScript 文件 ​

功能:编辑/写入 .ts 文件后,自动用 prettier 格式化代码

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write", // 匹配“编辑”和“写入”工具
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '\\.ts$'; then npx prettier --write \"$file_path\"; fi; }"
          }
        ]
      }
    ]
  }
}

示例 2:自动修复 Markdown 文件格式 ​

功能:为无语言标签的代码块自动补全标签、清理多余空行

第一步:添加钩子配置 ​

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/markdown_formatter.py"
          }
        ]
      }
    ]
  }
}

第二步:创建格式化脚本 ​

在项目目录下新建文件 .claude/hooks/markdown_formatter.py,粘贴以下代码:

实例 ​

bash
#!/usr/bin/env python3

"""

Markdown 格式化工具:自动补全代码块语言标签、清理多余空行

"""

import json

import sys

import re

import os

def detect_language(code):

    """根据代码内容自动检测编程语言"""

    code = code.strip()

    # 检测 JSON

    if re.search(r'^\s*[{\[]', code):

        try:

            json.loads(code)

            return 'json'

        except:

            pass

    # 检测 Python

    if re.search(r'^\s*def\s+\w+\s*\(', code, re.M) or re.search(r'^\s*(import|from)\s+\w+', code, re.M):

        return 'python'

    # 检测 JavaScript/TypeScript

    if re.search(r'\b(function\s+\w+\s*\(|const\s+\w+\s*=)', code) or re.search(r'=>|console\.(log|error)', code):

        return 'javascript'

    # 检测 Bash

    if re.search(r'^#!.*\b(bash|sh)\b', code, re.M) or re.search(r'\b(if|then|fi|for|in|do|done)\b', code):

        return 'bash'

    # 默认文本格式

    return 'text'

def format_markdown(content):

    """格式化 Markdown 内容"""

    # 为无标签代码块补全语言

    fence_pattern = r'(?ms)^([ \t]{0,3})```([^\n]*)\n(.*?)(\n\1```)\s*$'

    def add_lang(match):

        indent, info, body, closing = match.groups()

        if not info.strip():

            lang = detect_language(body)

            return f"{indent}```{lang}\n{body}{closing}\n"

        return match.group(0)

    content = re.sub(fence_pattern, add_lang, content)

    # 清理多余空行(仅清理代码块外的内容)

    content = re.sub(r'\n{3,}', '\n\n', content)

    return content.rstrip() + '\n'

if __name__ == "__main__":

    try:

        # 读取 Claude 传递的 JSON 数据

        input_data = json.load(sys.stdin)

        file_path = input_data.get('tool_input', {}).get('file_path', '')

        # 仅处理 .md/.mdx 文件

        if not file_path.endswith(('.md', '.mdx')):

            sys.exit(0)

        # 读取并格式化文件

        if os.path.exists(file_path):

            with open(file_path, 'r', encoding='utf-8') as f:

                content = f.read()

            formatted_content = format_markdown(content)

            # 仅在内容变化时写入

            if formatted_content != content:

                with open(file_path, 'w', encoding='utf-8') as f:

                    f.write(formatted_content)

                print(f"已格式化 Markdown 文件:{file_path}")

    except Exception as e:

        print(f"格式化失败:{e}", file=sys.stderr)

        sys.exit(1)

第三步:赋予脚本执行权限 ​

bash
chmod +x .claude/hooks/markdown_formatter.py

示例 3:Claude 等待输入时发送桌面通知 ​

功能:当 Claude 需要用户输入时,自动弹出桌面提醒(适用于 Linux/macOS)

json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "", // 匹配所有通知事件
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code 提示' '请你输入指令或确认权限'"
          }
        ]
      }
    ]
  }
}

示例 4:禁止修改敏感文件 ​

功能:阻止 Claude 编辑 .env、package-lock.json 等敏感文件

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 -c \"import json, sys; data=json.load(sys.stdin); path=data.get('tool_input',{}).get('file_path',''); sys.exit(2 if any(p in path for p in ['.env', 'package-lock.json', '.git/']) else 0)\""
          }
        ]
      }
    ]
  }
}

说明:脚本返回状态码 2 时,Claude Code 会拦截此次工具调用,从而阻止文件修改。


Claude Code 钩子参考手册 ​

配置文件路径 ​

配置级别文件路径生效范围
用户级~/.claude/settings.json所有项目
项目级.claude/settings.json当前项目
本地项目级(不提交).claude/settings.local.json当前项目,不纳入版本控制
托管策略级管理员指定路径企业/团队统一管控

核心配置结构 ​

Hooks 按事件+匹配器组织,支持 command(执行 Shell 命令)和 prompt(调用 LLM 决策)两种类型。

json
{
  "hooks": {
    "【钩子事件名】": [
      {
        "matcher": "【工具匹配规则】", // 部分事件可省略
        "hooks": [
          {
            "type": "command/prompt",
            "command": "【Shell 命令】", // type=command 时必填
            "prompt": "【LLM 提示词】",  // type=prompt 时必填
            "timeout": 30 // 可选,超时时间(秒)
          }
        ]
      }
    ]
  }
}

匹配器规则(仅适用于工具类事件) ​

匹配规则示例说明
精确匹配Write仅匹配 Write 工具
多工具匹配EditWrite
前缀匹配Notebook.*匹配所有以 Notebook 开头的工具
全匹配* / 空字符串匹配所有工具

特殊配置技巧 ​

场景配置方法示例
引用项目内脚本使用环境变量 $CLAUDE_PROJECT_DIR"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-style.sh"
插件 Hooks插件内配置 hooks/hooks.json,用 ${CLAUDE_PLUGIN_ROOT} 引用插件文件"command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh"
组件级 Hooks(Skill/Agent)在组件 frontmatter 中定义,作用域仅限组件生命周期见下方扩展配置表格

扩展配置(Skill/Agent/斜杠命令) ​

扩展配置允许直接在 Skill、Agent 或自定义斜杠命令的定义中内嵌 Hooks 配置,这类 Hooks 仅在对应组件被激活并运行时生效,组件执行完成后会自动清理,不会影响全局会话。

支持的钩子事件 ​

仅支持 PreToolUse、PostToolUse、Stop 三类事件,与全局 Hooks 功能一致,但作用域仅限当前 Skill/斜杠命令的生命周期。

特有配置项 ​

  • once: true(可选):设置为 true 时,该 Hooks 在整个会话中仅运行一次,首次成功执行后会自动移除,避免重复触发。

完整配置示例 ​

yaml
---
# Skill/斜杠命令的基础信息
name: secure-operations
description: 执行Shell命令前先做安全校验的工具
# Hooks 配置段
hooks:
  PreToolUse:
    # 匹配器:仅拦截Bash工具调用
    - matcher: "Bash"
      hooks:
        - type: "command"
          # 要执行的安全校验脚本
          command: "./scripts/security-check.sh"
          # 会话内仅执行一次
          once: true
          # 超时时间(秒),避免脚本卡死
          timeout: 15
---

Agent 中的 Hooks 配置 ​

支持的钩子事件 ​

同样仅支持 PreToolUse、PostToolUse、Stop 三类事件,作用域仅限该子 Agent 的任务执行周期。

特有配置项 ​

无额外专属配置项,不支持 once: true(Agent 每次执行任务时,Hooks 都会触发)。

完整配置示例 ​

yaml
---
# Agent 的基础信息
name: code-reviewer
description: 自动审查代码修改并运行代码检查的子代理
# Hooks 配置段
hooks:
  PostToolUse:
    # 匹配器:拦截Edit(编辑)或Write(写入)工具
    - matcher: "Edit|Write"
      hooks:
        - type: "command"
          # 代码检查脚本,执行lint校验
          command: "./scripts/run-linter.sh"
          # 超时时间(秒)
          timeout: 30
---

注意事项:

  1. 组件内 Hooks 的匹配器规则与全局 Hooks 完全一致:支持精确匹配(如 "Write")、多工具匹配(如 "Edit|Write")、通配匹配("*"),且区分大小写;
  2. 组件内 Hooks 与全局 Hooks 会并行执行:若全局和组件内同时配置了针对同一事件的 Hooks,触发时两类 Hooks 会一起运行,互不冲突;
  3. 配置格式要求:组件内 Hooks 需写在 frontmatter(--- 包裹的区域)中,遵循 YAML 语法,缩进错误会导致配置失效;
  4. 脚本路径建议:优先使用相对路径(如 ./scripts/xxx.sh),或借助 $CLAUDE_PROJECT_DIR 环境变量指定绝对路径,确保组件在任意目录下都能找到脚本。

钩子事件--工具类事件(支持匹配器) ​

事件名触发时机常见匹配器核心作用
PreToolUse工具调用前Bash/Edit/Write/Read拦截工具执行、修改入参、自动批准/拒绝权限
PermissionRequest弹出权限请求对话框时同 PreToolUse自动处理权限申请,无需用户手动确认
PostToolUse工具调用成功后同 PreToolUse执行后置操作(如代码格式化、日志记录)
NotificationClaude 发送通知时permission_prompt/idle_prompt/auth_success自定义通知方式(如桌面弹窗、邮件提醒)
PreCompact执行上下文压缩操作前manual(手动触发)/auto(自动触发)自定义压缩规则、备份重要上下文

钩子事件--会话/任务类事件(无匹配器) ​

事件名触发时机核心作用
UserPromptSubmit用户提交提示后、Claude 处理前验证提示合法性、补充上下文信息
Stop主 Agent 完成响应时(用户中断不触发)智能判断是否需要继续执行任务
SubagentStop子 Agent 任务完成时评估子任务结果,决定是否终止
SessionStart启动/恢复会话时初始化环境、加载项目配置、设置持久化环境变量
SessionEnd会话结束时清理临时文件、记录会话日志、保存工作状态

钩子类型对比 ​

Claude Code 支持两种钩子类型,满足不同场景需求。

特性command 类型(命令钩子)prompt 类型(提示词钩子)
执行方式运行 Shell 命令/脚本调用 LLM(默认 Haiku 模型)做智能决策
决策逻辑基于代码逻辑的确定性判断基于上下文的灵活语义判断
配置难度需要编写脚本,门槛较高只需写提示词,简单易上手
响应速度快(本地执行)较慢(需 API 调用)
适用场景代码格式化、日志记录、权限拦截等固定规则任务完成度评估、复杂意图判断等灵活场景
核心配置command + timeoutprompt + timeout(可引用 $ARGUMENTS 占位符)

输入与输出 -- 钩子输入(stdin 传入 JSON) ​

所有钩子都会收到通用字段,部分事件附带特定字段。

字段类型通用字段说明
基础信息session_id会话唯一标识
transcript_path对话记录文件路径
cwd钩子执行时的当前工作目录
permission_mode当前权限模式(default/plan/acceptEdits 等)
hook_event_name当前触发的钩子事件名

各事件特有字段示例

事件名特有字段示例
PreToolUsetool_name/tool_input{"tool_name":"Write","tool_input":{"file_path":"/test.txt"}}
UserPromptSubmitprompt{"prompt":"帮我写一个排序函数"}
SessionEndreason{"reason":"clear/logout/other"}

钩子输出(两种方式) ​

方式1:退出代码(简单场景) ​

通过退出代码传递执行状态,stdout/stderr 用于反馈信息。

退出代码含义行为说明
0执行成功stdout 可返回 JSON 做高级控制;部分事件(如 UserPromptSubmit)会将 stdout 加入上下文
2阻止操作仅使用 stderr 作为错误消息反馈给 Claude,阻止当前事件继续执行
其他非零值非阻塞错误stderr 仅在详细模式(ctrl+o)显示,不影响事件执行

退出代码 2 在各事件中的行为

事件名触发行为
PreToolUse阻止工具调用,向 Claude 展示 stderr
UserPromptSubmit阻止提示处理,擦除用户输入
Stop阻止 Claude 停止,强制继续工作
PostToolUse/Notification仅展示 stderr,不影响已完成操作

方式2:JSON 输出(高级场景) ​

退出代码为 0 时,可通过 stdout 返回 JSON 实现精细化控制,核心字段如下:

通用 JSON 字段作用
continue: true/false是否允许事件继续执行(false 优先于其他规则)
stopReasoncontinue=false 时,展示给用户的原因
systemMessage向用户显示的警告信息

事件特有 JSON 字段示例

事件名特有字段示例
PreToolUsepermissionDecision(allow/deny/ask){"hookSpecificOutput":{"permissionDecision":"allow","updatedInput":{"file_path":"/new.txt"}}}
UserPromptSubmitdecision: block/undefined{"decision":"block","reason":"提示包含敏感信息"}
PostToolUseadditionalContext{"hookSpecificOutput":{"additionalContext":"文件已格式化完成"}}

MCP 工具的 Hooks 配置 ​

MCP 工具可与 Hooks 无缝集成,通过特定命名规则匹配。

MCP 工具命名规则 ​

bash
mcp__<服务器名>__<工具名>

示例:mcp__github__search_repositories、mcp__filesystem__read_file

匹配示例 ​

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__memory__.*", // 匹配 memory 服务器的所有工具
        "hooks": [{"type": "command", "command": "echo '内存操作日志' >> log.txt"}]
      },
      {
        "matcher": "mcp__.*__write.*", // 匹配所有服务器的写操作工具
        "hooks": [{"type": "command", "command": "./validate-write.py"}]
      }
    ]
  }
}

安全与调试 ​

安全最佳实践 ​

安全要点具体操作
输入校验严格校验 tool_input 中的文件路径、命令参数,防止路径遍历(如 ../)
变量引用Shell 命令中使用 "$VAR" 而非 $VAR,避免参数注入
权限最小化钩子脚本仅赋予必要权限,避免使用 sudo 等高危命令
敏感文件排除拦截对 .env、.git、密钥文件的操作
命令审查注册钩子前,手动执行命令验证逻辑,确认无恶意行为

调试技巧 ​

问题类型排查步骤
钩子不生效1. 执行 /hooks 命令检查配置是否注册
2. 验证 JSON 语法是否正确
3. 检查匹配器规则是否与工具名一致(区分大小写)
命令执行失败1. 手动运行钩子命令,确认是否可正常执行
2. 检查脚本是否有可执行权限(chmod +x script.sh)
3. 使用绝对路径调用脚本,避免环境变量问题
查看详细日志启动 Claude Code 时添加 --debug 参数,查看钩子执行全过程

参考文档:如需查看钩子的完整功能说明,可查阅官方 钩子参考文档。

AI 思考中...

Claude Code 输出样式

Claude Code CLI 参考手册

基于 VitePress 构建,部署于 GitHub Pages