首页
看点啥
插画图片
首页 看点啥 一文详解Claude Code中Hooks的用法

一文详解Claude Code中Hooks的用法

2026-07-23 0

Claude Code 每次调用工具、等待输入、结束会话,都会触发对应的生命周期事件。你可以在这些事件上挂脚本,拿到上下文 JSON,决定 Claude 要不要继续执行。

Hooks 是什么

Claude 要调用工具时,Claude Code 把当时的状态打包成 JSON,通过 stdin 传给你配置的脚本,等脚本退出再继续。

整个流程:

有哪些 Hook 事件

事件触发时机能否阻断
SessionStart会话开始
UserPromptSubmit用户提交了一条消息
PreToolUseClaude 调用工具之前
PostToolUse工具调用完成之后
NotificationClaude 需要提醒用户时
StopClaude 完成一轮回复,等待用户
SessionEnd会话结束

七个事件覆盖一次完整会话的全过程:

PreToolUse 是最关键的事件。退出码决定行为:0 继续执行,2 阻断工具调用,其他非 0 记录错误但不阻断。

怎么配置

打开 ~/.claude/settings.json,加入 hooks 字段:

{
  "hooks": {
    "PreToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 /path/to/my_hook.py"
          }
        ]
      }
    ],
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 /path/to/notify.py"
          }
        ]
      }
    ]
  }
}

每个事件可以配多个脚本,按顺序执行。脚本可以是任何可执行文件,Python、Shell、Node 都行。

脚本收到什么数据

Claude Code 把 JSON 写入脚本的 stdin,不同事件的字段不同。

PreToolUse 示例:

{
  "session_id": "abc-123",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
    "command": "rm -rf /tmp/test"
  },
"cwd": "/Users/you/myproject",
"tty": "/dev/ttys001"
}

Notification 示例:

{
  "session_id": "abc-123",
  "hook_event_name": "Notification",
  "message": "任务完成,等待你的下一步指令",
  "cwd": "/Users/you/myproject"
}

Stop 示例:

{
  "session_id": "abc-123",
  "hook_event_name": "Stop",
  "cwd": "/Users/you/myproject"
}

脚本还能通过 stdout 影响 Claude

stdin 是 Claude Code 传给脚本的数据,stdout 方向相反:脚本输出 JSON 到 stdout,Claude Code 读取并按内容决策。

PreToolUse:用 stdout 阻断或放行

脚本可以在 stdout 输出一个 JSON 对象,decision 字段控制行为:

import json, sys

data = json.load(sys.stdin)

if data.get("tool_name") == "Bash":
    command = data.get("tool_input", {}).get("command", "")
    if"rm -rf"in command:
        # 通过 stdout JSON 阻断
        print(json.dumps({
            "decision": "block",
            "reason": "禁止执行 rm -rf"
        }))
        sys.exit(0)  # stdout 已表达意图,退出码可以是 0

sys.exit(0)

decision 值为 "block" 时阻断,"approve" 时强制放行(跳过权限提示)。

向 Claude 注入上下文

stdout JSON 还支持 additionalContext 字段,内容会直接注入到 Claude 的上下文里,Claude 读完再决定下一步。适合在工具调用前后补充环境信息:

print(json.dumps({
    "additionalContext": "当前磁盘剩余空间 2GB,请谨慎执行大文件操作"
}))
sys.exit(0)

动手写第一个 Hook

示例 1:记录 Claude 调用过的所有命令

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

data = json.load(sys.stdin)

if data.get("tool_name") == "Bash":
    command = data.get("tool_input", {}).get("command", "")
    with open("/tmp/claude_commands.log", "a") as f:
        f.write(f"{datetime.now()} | {command}n")

sys.exit(0)  # 退出码 0,Claude 继续执行

挂在 PostToolUse 上,Claude 每跑完一条 Bash 命令,日志文件就多一行。

示例 2:阻止删除操作

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

data = json.load(sys.stdin)

if data.get("tool_name") == "Bash":
    command = data.get("tool_input", {}).get("command", "")
    if "rm -rf" in command:
        print("拦截:禁止执行 rm -rf", file=sys.stderr)
        sys.exit(2)  # 退出码 2,Claude 放弃这次工具调用

sys.exit(0)

退出码 2 是 PreToolUse 的阻断信号。Claude 读到 stderr,把它当作拒绝原因展示给用户,然后停止这次工具调用。退出码 1 或其他非 0 值只会记录错误,Claude 仍会继续执行。

示例 3:任务完成时发系统通知

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

data = json.load(sys.stdin)

subprocess.run([
    "osascript", "-e",
    f'display notification "Claude 完成了,去看看吧" with title "Claude Code"'
])

sys.exit(0)

把这个脚本挂在 Stop 或 Notification 上。Claude 停下来等你回复时,Mac 右上角就会弹出通知。

示例 4:针对特定工具设置 matcher

如果只想监听某类工具,加 matcher 字段:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 /path/to/bash_guard.py"
          }
        ]
      }
    ]
  }
}

加了 matcher,只有 Bash 工具触发时脚本才跑,EditRead 等其他工具不走这里。

脚本拿到数据后能做什么

写日志:把 Claude 的所有工具调用记下来,方便复盘

发通知:Claude 等待输入时,通过系统通知或微信、钉钉提醒你

阻断危险操作:检测到高风险命令,退出码 2 阻止执行

转发事件:把 JSON 发到本地 socket,驱动自定义 UI 或状态面板

记录耗时:PreToolUse 记开始时间,PostToolUse 记结束时间,统计每类工具的耗时分布

进阶:用 Hooks 驱动自定义 UI

Hook 脚本除了做判断和记录,还可以把事件转发到本地 socket,让一个常驻进程处理所有状态变化。

转发脚本只需几行:

#!/usr/bin/env python3
import json, socket, sys
data = sys.stdin.read()
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect("/tmp/my_app.sock")
sock.sendall((data + "n").encode())
response = sock.recv(1024).decode().strip()
sock.close()
# 常驻进程返回 "block" 时阻断工具调用(必须用退出码 2)
sys.exit(2if response == "block"else0)

常驻进程在 socket 上监听,收到 PreToolUse 弹出确认窗口,用户点通过就回 ok,点拒绝就回 block,hook 脚本根据返回值决定退出码。这样就能在 Claude 执行过程中插入任意交互界面,不限于终端。

上手步骤

  1. 创建你的脚本文件,给执行权限:chmod +x my_hook.py
  2. 编辑 ~/.claude/settings.json,加入 hooks 配置
  3. 启动一个新的 Claude Code 会话(已有会话需要重启才能加载新配置)
  4. 触发相关操作,看脚本是否被调用

调试时在脚本里加 print(json.dumps(data, indent=2), file=sys.stderr) 把收到的完整数据打出来,Claude Code 会把 stderr 输出显示在终端。

一个脚本、一个退出码,就能接入 Claude Code 的整个执行流程。你的脚本负责判断逻辑,Claude Code 负责触发和等待,各管各的。

到此这篇关于一文详解Claude Code中Hooks的使用的文章就介绍到这了,更多相关Claude Code Hooks使用内容请搜索以前的文章或继续浏览下面的相关文章,希望大家以后多多支持!

喜欢(0)

上一篇

Codex 终端常用命令与使用场景总结

Codex 终端常用命令与使用场景总结

下一篇

最强音乐生成工具 Suno AI 的若干使用技巧

最强音乐生成工具 Suno AI 的若干使用技巧
猜你喜欢