返回 AI编程

Hooks 钩子系统详解

Hooks 钩子系统详解

Hooks 是 Claude Code 中的事件驱动自动化机制,允许在特定事件触发时自动执行自定义脚本,用于自定义工作流、拦截危险操作、自动格式化代码等场景。

一、什么是 Hooks?

核心概念

Hooks 是在特定事件触发时自动执行的脚本,具有以下特点:

  • 事件驱动:在特定事件发生时自动触发
  • 自动化:可以自动执行预定义的操作
  • 拦截能力:可以阻止危险操作
  • 灵活配置:支持阻塞和非阻塞模式

核心价值

┌───────────────────────────┐
│                      事件触发流程                             │
│                                                             │
│   ┌─────────┐    ┌─────────────┐       │
│   │ 事件触发 │ → │ Hook 拦截    │ → │ 执行自定义脚本   │    │
│   └─────────┘    └─────────────┘      │
│                      ↓                                      │
│              ┌───────────────┐                               │
│              │ 返回结果      │                               │
│              │ 继续/阻止操作 │                               │
│              └───────────────┘                               │
└─────────────────────────────┘

二、Hook 事件类型

| 事件类型 | 触发时机 | 典型用途 |
|----------|----------|----------|
| user-prompt-submit | 用户提交提示词前 | 验证、修改提示词 |
| tool-use | 工具使用前 | 权限检查、参数验证 |
| after-tool-use | 工具使用后 | 日志记录、结果处理 |
| permission-request | 权限请求时 | 拦截危险操作 |
| notification | 通知时 | 发送告警、更新状态 |
| task-complete | 任务完成时 | 发送通知、更新状态 |

三、配置方式

方式一:通过 /hooks 命令

# 在 Claude Code 中
/hooks

方式二:通过配置文件

~/.claude/settings.json 或项目 .claude/settings.json 中配置:

{
  "hooks": {
    "user-prompt-submit-hook": {
      "command": "npm run validate-prompt",
      "enabled": true
    },
    "tool-use-hook": {
      "command": "~/.claude/hooks/check-permission.sh",
      "enabled": true,
      "blocking": true
    },
    "after-tool-use-hook": {
      "command": "echo 'Tool used: {{toolName}}' >> ~/.claude/hooks.log",
      "enabled": true
    },
    "permission-request-hook": {
      "command": "~/.claude/hooks/check-dangerous.sh",
      "enabled": true,
      "blocking": true
    }
  }
}

配置参数说明

| 参数 | 说明 | 必填 |
|------|------|------|
| command | 要执行的命令 | 是 |
| enabled | 是否启用 | 否(默认 true) |
| blocking | 是否阻塞主流程 | 否(默认 false) |

四、Hook 实战示例

示例 1:拦截危险命令

创建 ~/.claude/hooks/check-dangerous.sh

#!/bin/bash
# ~/.claude/hooks/check-dangerous.sh

# 读取工具调用信息
TOOL_NAME=$(jq -r '.toolName' <<< "$CLAUDE_HOOK_INPUT")

# 危险操作列表
DANGEROUS_TOOLS=("rm" "delete" "format" "shutdown" "reboot")

if [[ " ${DANGEROUS_TOOLS[@]} " =~ " ${TOOL_NAME} " ]]; then
  echo "⚠️  警告:即将执行危险操作 - $TOOL_NAME"
  echo "请确认是否继续? (yes/no)"
  read -r confirmation
  if [[ "$confirmation" != "yes" ]]; then
    exit 1  # 阻止操作
  fi
fi

exit 0

示例 2:自动格式化代码

{
  "hooks": {
    "after-write-hook": {
      "command": "if [[ {{filePath}} == *.js ]]; then prettier --write {{filePath}}; fi",
      "enabled": true,
      "blocking": false
    }
  }
}

示例 3:发送通知

{
  "hooks": {
    "task-complete-hook": {
      "command": "notify-send 'Claude Code' '任务已完成'",
      "enabled": true
    }
  }
}

示例 4:日志记录

{
  "hooks": {
    "after-tool-use-hook": {
      "command": "echo '$(date): {{toolName}} - {{filePath}}' >> ~/.claude/hooks.log",
      "enabled": true,
      "blocking": false
    }
  }
}

五、实战案例:消灭 CI 格式报错

来自 Claude Code 创始人的实战经验,使用 Hook 彻底解决 CI 中的格式问题:

配置

{
  "hooks": {
    "after-tool-use-hook": {
      "command": "bun run format || true",
      "enabled": true,
      "blocking": false
    }
  }
}

工作原理

  1. 每次 Claude 使用 WriteEdit 工具后自动触发
  2. 运行格式化命令(这里是 bun run format
  3. || true 确保即使格式化失败也不阻塞流程
  4. Claude 已经写得很规范,但这最后 10% 的自动化处理能彻底解决格式问题

效果

  • ✅ CI 中不再有格式报错
  • ✅ 代码风格始终一致
  • ✅ 无需手动运行格式化
  • ✅ Git diff 更清晰

六、Hook 模板

通用 Hook 模板

#!/bin/bash
# Hook 名称:xxx
# 用途:xxx
# 触发事件:xxx

# 获取环境变量
TOOL_NAME=${CLAUDE_TOOL_NAME:-""}
FILE_PATH=${CLAUDE_FILE_PATH:-""}
USER_INPUT=${CLAUDE_USER_INPUT:-""}

# 业务逻辑
if [ 条件 ]; then
    # 执行操作
    echo "执行的操作"
fi

# 返回结果
exit 0  # 允许操作继续
# 或
exit 1  # 阻止操作

复杂 Hook 示例

#!/bin/bash
# 复杂的权限检查 Hook

# 读取完整输入
INPUT=$(cat)

# 解析参数
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
FILE_PATH=$(echo "$INPUT" | jq -r '.filePath')
USER_ID=$(echo "$INPUT" | jq -r '.userId')

# 危险操作检查
DANGEROUS_PATTERN=("rm" "format" "delete" "shutdown")

for pattern in "${DANGEROUS_PATTERN[@]}"; do
    if [[ "$TOOL_NAME" == *"$pattern"* ]]; then
        # 记录危险操作
        echo "危险操作检测: $TOOL_NAME on $FILE_PATH"
        
        # 发送告警
        curl -X POST "https://hooks.slack.com/services/xxx" \
             -d "{\"text\":\"危险操作: $USER_ID 执行了 $TOOL_NAME\"}"
        
        exit 1  # 阻止操作
    fi
done

exit 0

七、最佳实践

1. 最小权限原则

{
  "hooks": {
    "tool-use-hook": {
      "command": "~/.claude/hooks/lightweight-check.sh",
      "enabled": true,
      "blocking": true
    }
  }
}

避免使用重量级的检查脚本,尽量保持轻量快速。

2. 非阻塞优先

{
  "hooks": {
    "after-tool-use-hook": {
      "command": "~/.claude/hooks/log.sh",
      "enabled": true,
      "blocking": false
    }
  }
}

除非必要,否则使用非阻塞模式,不影响主流程。

3. 错误处理

#!/bin/bash
# 带有错误处理的 Hook

set -e  # 遇到错误立即退出

# 主逻辑
if [ "$TOOL_NAME" == "write" ]; then
    # 执行操作
    echo "Write operation detected"
fi

exit 0

4. 调试技巧

#!/bin/bash
# 调试模式 Hook

# 开启调试
set -x

# 主逻辑
echo "Tool: $TOOL_NAME"
echo "File: $FILE_PATH"

exit 0

八、常见问题

问题 1:Hook 不触发

可能原因:

  1. Hook 未在配置中启用
  2. 命令路径错误
  3. 脚本没有执行权限

解决方案:

# 检查配置文件
cat ~/.claude/settings.json | grep hooks

# 检查脚本权限
ls -la ~/.claude/hooks/

# 手动测试脚本
~/.claude/hooks/check-dangerous.sh

问题 2:Hook 阻塞主流程

可能原因:

  1. blocking 设置为 true
  2. 脚本执行时间过长

解决方案:

{
  "hooks": {
    "tool-use-hook": {
      "command": "~/.claude/hooks/slow-check.sh",
      "enabled": true,
      "blocking": false
    }
  }
}

问题 3:权限不足

错误信息:

Permission denied: xxx.sh

解决方案:

# 添加执行权限
chmod +x ~/.claude/hooks/*.sh

九、进阶技巧

1. 条件 Hook

{
  "hooks": {
    "tool-use-hook": {
      "command": "~/.claude/hooks/conditional.sh",
      "enabled": true,
      "blocking": true,
      "conditions": {
        "tools": ["write", "edit"],
        "paths": ["src/**/*.ts"]
      }
    }
  }
}

2. 链式 Hook

#!/bin/bash
# 主 Hook 触发其他 Hook

# 执行前置检查
~/.claude/hooks/pre-check.sh

# 执行主操作
if [ "$TOOL_NAME" == "write" ]; then
    ~/.claude/hooks/format.sh
fi

# 执行后置处理
~/.claude/hooks/post-process.sh

3. 环境变量传递

#!/bin/bash
# 读取 Claude Code 环境变量

echo "当前工具: $CLAUDE_TOOL_NAME"
echo "当前文件: $CLAUDE_FILE_PATH"
echo "用户输入: $CLAUDE_USER_INPUT"

# 使用环境变量进行逻辑判断
if [ "$CLAUDE_TOOL_NAME" == "bash" ]; then
    echo "检测到 bash 命令执行"
fi

十、总结

通过本指南,你已经了解了:

  1. ✅ Hooks 的核心概念和工作原理
  2. ✅ Hook 事件类型和触发时机
  3. ✅ Hook 的配置方式
  4. ✅ 实用的 Hook 实战示例
  5. ✅ Hook 的最佳实践

Hooks 是 Claude Code 强大的自动化机制,合理使用 Hooks 可以大大提高开发效率和安全性。

参考资源