第九章:钩子与自动化工作流

钩子系统架构

钩子(Hooks)是 Claude Code 的自动化扩展机制,它允许你在特定事件发生时自动执行自定义脚本。如果把 Claude Code 比作一个操作系统,那么钩子就是它的 "自动化脚本引擎"——你可以编写脚本在特定时机自动触发,从而实现工作流的自动化。

钩子系统采用事件驱动的架构,整体分为三个层次:

  1. 事件源:Claude Code 运行过程中的各类事件(工具调用、消息收发等)
  2. 钩子注册表:定义在 settings.json 中的钩子配置,指定事件与脚本的映射关系
  3. 执行引擎:负责在事件发生时调用对应的钩子脚本,并处理返回值

钩子脚本可以是任意的可执行脚本(Shell、Node.js、Python 等),Claude Code 不限制脚本语言。脚本通过标准输入接收事件数据,通过标准输出返回处理结果。

支持的事件类型

钩子系统支持两大类事件:前置钩子(Pre-hooks)和后置钩子(Post-hooks)。每种事件在触发时机和执行语义上有所不同:

Tool-use 事件(工具调用前)

在 Claude Code 调用任何工具之前触发。前置钩子可以拦截、修改或拒绝工具调用。例如,你可以用这个钩子实现权限控制,阻止危险命令的执行。

Tool-result 事件(工具调用后)

在工具执行完毕并返回结果后触发。后置钩子可以检查、过滤或增强工具的执行结果。例如,自动格式化命令的输出,或者记录工具调用日志。

Message 事件(消息收发)

在发送或接收消息时触发。你可以利用这个钩子实现消息内容的预处理,比如自动翻译、敏感信息脱敏等。

Session 事件(会话生命周期)

在会话开始或结束时触发。适合用于初始化工作环境、清理临时资源、记录会话统计信息等。

事件类型触发时机用途示例
tool-use工具调用前命令白名单校验、参数修正
tool-result工具返回后结果格式化、日志记录
message消息收发时内容翻译、敏感信息过滤
session会话开始/结束环境初始化、清理工作

编写钩子脚本

钩子脚本本质上是一个从标准输入(stdin)读取事件数据、通过标准输出(stdout)返回结果的可执行程序。事件数据以 JSON 格式传递。

以下是一个前置钩子脚本示例,用于阻止在生产环境中执行危险命令:

#!/bin/bash
# pre-tool-check.sh - 命令安全校验钩子

read input
event=$(echo "$input" | jq -r '.event')
tool=$(echo "$input" | jq -r '.toolName')

if [ "$event" = "tool-use" ] && [ "$tool" = "Bash" ]; then
  command=$(echo "$input" | jq -r '.args.command')

  # 检查是否包含危险命令
  if echo "$command" | grep -qE "rm -rf|drop table|shutdown"; then
    echo '{"status": "rejected", "reason": "检测到危险命令,已阻止执行"}'
    exit 0
  fi
fi

# 允许执行
echo '{"status": "allowed"}'

以下是一个后置钩子脚本示例,用于记录所有工具调用日志:

#!/usr/bin/env node
// post-tool-logger.js - 工具调用日志记录

const chunks = [];
process.stdin.on("data", (chunk) => chunks.push(chunk));
process.stdin.on("end", () => {
  const event = JSON.parse(chunks.join(""));
  const log = {
    timestamp: new Date().toISOString(),
    tool: event.toolName,
    status: event.result?.status || "unknown",
    duration: event.duration,
  };

  // 写入日志文件
  const fs = require("fs");
  fs.appendFileSync(
    ".claude/tool-audit.log",
    JSON.stringify(log) + "\n"
  );

  // 原样传递结果
  process.stdout.write(JSON.stringify({ status: "pass_through" }));
});

自动化工作流设计模式

结合不同类型的事件钩子,你可以设计出复杂的自动化工作流。以下是几种常见的设计模式:

审计模式:在 tool-result 事件上注册日志记录钩子,记录所有操作行为。适合合规性要求高的项目。

防护模式:在 tool-use 事件上注册安全检查钩子,拦截危险操作。适合生产环境或共享开发环境。

增强模式:在 tool-result 事件上注册结果增强钩子,自动格式化或补充工具输出。适合提升日常开发效率。

初始化模式:在 session 事件上注册初始化钩子,自动配置开发环境。适合有特定环境要求的团队项目。

钩子配置(settings.json 中注册)

.claude/settings.json 中注册钩子,指定事件类型和对应的脚本路径:

{
  "hooks": {
    "pre": {
      "tool-use": {
        "security-check": {
          "command": "bash .claude/hooks/pre-tool-check.sh"
        }
      }
    },
    "post": {
      "tool-result": {
        "audit-log": {
          "command": "node .claude/hooks/post-tool-logger.js"
        }
      },
      "session": {
        "session-cleanup": {
          "command": "bash .claude/hooks/session-end.sh"
        }
      }
    }
  }
}

配置中的 key(如 security-checkaudit-log)是钩子的标识名,方便管理和调试。同一事件类型下可以注册多个钩子,它们会按照配置顺序依次执行。

实战:git commit 前自动运行 lint

一个非常实用的自动化场景是:在 Claude Code 执行 git commit 之前自动运行代码检查,确保提交的代码符合规范。

步骤 1:创建 pre-commit 钩子脚本

#!/bin/bash
# .claude/hooks/pre-commit-lint.sh

read input

# 检查是否为 git commit 操作
event=$(echo "$input" | jq -r '.event')
tool=$(echo "$input" | jq -r '.toolName')
command=$(echo "$input" | jq -r '.args.command // ""')

if [ "$event" = "tool-use" ] && [ "$tool" = "Bash" ] && echo "$command" | grep -q "git commit"; then
  echo "检测到 git commit 操作,正在运行代码检查..." >&2

  # 运行 lint
  if npm run lint 2>&1; then
    echo "代码检查通过,允许提交" >&2
    echo '{"status": "allowed"}'
  else
    echo "代码检查未通过,提交已阻止" >&2
    echo '{"status": "rejected", "reason": "Lint 检查未通过,请先修复代码风格问题"}'
  fi
else
  echo '{"status": "allowed"}'
fi

步骤 2:注册钩子

{
  "hooks": {
    "pre": {
      "tool-use": {
        "pre-commit-lint": {
          "command": "bash .claude/hooks/pre-commit-lint.sh"
        }
      }
    }
  }
}

步骤 3:验证效果

现在当你在 Claude Code 中说 "提交代码" 时,Claude Code 在执�� git commit 之前会自动触发钩子脚本运行 npm run lint:

  • 如果 lint 通过:git commit 正常执行
  • 如果 lint 失败:git commit 被阻止,你会收到提示信息

钩子系统是 Claude Code 实现自动化工作流的关键基础设施。通过合理设计钩子,你可以将重复性的人工检查转变为自动化的质量门禁,让 Claude Code 在提升开发效率的同时,也成为代码质量的守护者。