详情

首页手游攻略 一文完整指南Claude Code中Hooks的使用

一文完整指南Claude Code中Hooks的使用

佚名 2026-08-22 19:40:01

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

目录
  • Hooks 是什么
  • 有哪些 Hook 事件
  • 怎么设置
  • 脚本收到什么数据
  • 脚本还能借助 stdout 影响 Claude
  • 动手写第一个 Hook
    • 示例 1:记录 Claude 调用过的所有命令
    • 示例 2:阻止删除操作
    • 示例 3:任务完成时发系统通知
    • 示例 4:针对特定工具设置 matcher
  • 脚本拿到数据后能做什么
    • 进阶:用 Hooks 驱动自定义 UI
      • 上手步骤

        从实现思路看,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)

        把这个脚本挂在 StopNotification 上。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采用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章,希望大家以后多多兼容脚本之家!

        相关资讯
        点击查看更多
        游戏推荐
        推荐专题
        热门阅读
        推荐下载