Claude Code Hooks 教程:自动化你的 AI 编程工作流

学习如何使用 Claude Code hooks 自动化任务、强制编码规范并创建强大的自定义工作流。完整教程包含 PreToolUse、PostToolUse 和 Notification hooks 的实用示例。

ClaudeCode.Guide Team
hooks自动化教程工作流高级

Claude Code Hooks 教程:自动化你的 AI 编程工作流

Hooks 是 Claude Code 中最强大的功能之一,允许你自动化任务、强制编码规范并创建自定义工作流。本教程从基础设置到高级用例,全面覆盖 hooks 的使用方法。

什么是 Claude Code Hooks?

Hooks 是在 Claude Code 操作过程中特定时刻自动执行的 shell 命令。它们能让你:

  • 自动化重复任务 - 自动运行格式化器、代码检查器或测试
  • 强制项目规范 - 阻止某些操作或要求特定模式
  • 扩展功能 - 与外部工具和服务集成
  • 创建护栏 - 在破坏性操作前添加安全检查

Hooks 类型概览

Claude Code 支持四种类型的 hooks:

Hook 类型运行时机用途
PreToolUse工具执行前验证、审批、阻止
PostToolUse工具完成后格式化、通知、日志
NotificationClaude 发送通知时提醒、集成、日志
StopClaude 完成任务时清理、验证、报告

设置 Hooks

Hooks 在 .claude/settings.json 文件中配置:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit",
        "command": "echo '即将编辑: $CLAUDE_FILE_PATH'"
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "npx prettier --write $CLAUDE_FILE_PATH"
      }
    ]
  }
}

配置位置

Hooks 可以在以下位置定义:

  1. 项目级别:项目根目录的 .claude/settings.json
  2. 用户级别~/.claude/settings.json 用于全局 hooks
  3. CLAUDE.md:内联 hook 定义(功能有限)

PreToolUse Hooks

PreToolUse hooks 在 Claude 执行工具之前运行。它们可以:

  • 记录即将发生的操作
  • 通过返回非零退出码阻止操作
  • 根据条件修改行为

基础示例:记录所有编辑

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit",
        "command": "echo \"[$(date)] 编辑: $CLAUDE_FILE_PATH\" >> ~/.claude/edit.log"
      }
    ]
  }
}

阻止危险操作

防止编辑关键文件:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit",
        "command": "if [[ \"$CLAUDE_FILE_PATH\" == *\".env\"* ]]; then echo '不能编辑 .env 文件!' && exit 1; fi"
      }
    ]
  }
}

对破坏性命令要求确认

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "if [[ \"$CLAUDE_COMMAND\" == *\"rm -rf\"* ]]; then echo '已阻止: 不允许 rm -rf' && exit 1; fi"
      }
    ]
  }
}

模式匹配

matcher 字段支持:

  • 精确匹配"Edit""Bash""Write"
  • 通配符"*" 匹配所有工具
  • 正则表达式"/Edit|Write/" 匹配 Edit 或 Write

PostToolUse Hooks

PostToolUse hooks 在工具成功完成后运行。适用于:

  • 自动格式化代码
  • 运行代码检查器
  • 更新文档
  • 发送通知

编辑后自动格式化

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
      },
      {
        "matcher": "Write",
        "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
      }
    ]
  }
}

JavaScript 更改后运行 ESLint

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "if [[ \"$CLAUDE_FILE_PATH\" == *.js ]] || [[ \"$CLAUDE_FILE_PATH\" == *.ts ]]; then npx eslint --fix \"$CLAUDE_FILE_PATH\"; fi"
      }
    ]
  }
}

自动运行测试

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "if [[ \"$CLAUDE_FILE_PATH\" == *\"test\"* ]]; then npm test -- --findRelatedTests \"$CLAUDE_FILE_PATH\"; fi"
      }
    ]
  }
}

Notification Hooks

Notification hooks 在 Claude 发送通知(任务完成、错误等)时触发。

桌面通知(macOS)

{
  "hooks": {
    "Notification": [
      {
        "matcher": "*",
        "command": "osascript -e 'display notification \"$CLAUDE_MESSAGE\" with title \"Claude Code\"'"
      }
    ]
  }
}

桌面通知(Linux)

{
  "hooks": {
    "Notification": [
      {
        "matcher": "*",
        "command": "notify-send 'Claude Code' \"$CLAUDE_MESSAGE\""
      }
    ]
  }
}

Slack 集成

{
  "hooks": {
    "Notification": [
      {
        "matcher": "*",
        "command": "curl -X POST -H 'Content-type: application/json' --data '{\"text\":\"Claude Code: '$CLAUDE_MESSAGE'\"}' $SLACK_WEBHOOK_URL"
      }
    ]
  }
}

微信/钉钉集成

{
  "hooks": {
    "Notification": [
      {
        "matcher": "*",
        "command": "curl -X POST -H 'Content-type: application/json' --data '{\"msgtype\":\"text\",\"text\":{\"content\":\"Claude Code: '$CLAUDE_MESSAGE'\"}}' $DINGTALK_WEBHOOK_URL"
      }
    ]
  }
}

Stop Hooks

Stop hooks 在 Claude 完成任务或对话轮次时运行。

生成摘要报告

{
  "hooks": {
    "Stop": [
      {
        "matcher": "*",
        "command": "echo \"任务完成于 $(date)\" >> ~/.claude/completed.log"
      }
    ]
  }
}

完成时自动提交

{
  "hooks": {
    "Stop": [
      {
        "matcher": "*",
        "command": "if [ -n \"$(git status --porcelain)\" ]; then git add -A && git commit -m '自动提交: Claude Code 更改'; fi"
      }
    ]
  }
}

环境变量

Hooks 可以访问以下环境变量:

变量说明可用于
CLAUDE_FILE_PATH正在编辑的文件路径Edit, Write, Read
CLAUDE_TOOL_NAME当前工具名称所有 hooks
CLAUDE_COMMAND正在运行的 Bash 命令Bash 工具
CLAUDE_MESSAGE通知消息Notification hooks
CLAUDE_SESSION_ID当前会话 ID所有 hooks
CLAUDE_WORKING_DIR当前工作目录所有 hooks

高级 Hook 模式

基于文件类型的条件 Hooks

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "case \"$CLAUDE_FILE_PATH\" in *.py) black \"$CLAUDE_FILE_PATH\";; *.js|*.ts) npx prettier --write \"$CLAUDE_FILE_PATH\";; *.go) gofmt -w \"$CLAUDE_FILE_PATH\";; esac"
      }
    ]
  }
}

链接多个操作

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" && npx eslint --fix \"$CLAUDE_FILE_PATH\" && echo '已格式化和检查!'"
      }
    ]
  }
}

使用外部脚本

创建 hook 脚本 ~/.claude/hooks/post-edit.sh

#!/bin/bash
FILE="$CLAUDE_FILE_PATH"

# 根据扩展名格式化
case "${FILE##*.}" in
  py)
    black "$FILE"
    isort "$FILE"
    ;;
  js|ts|jsx|tsx)
    npx prettier --write "$FILE"
    npx eslint --fix "$FILE"
    ;;
  go)
    gofmt -w "$FILE"
    ;;
esac

# 记录编辑
echo "[$(date)] 已编辑: $FILE" >> ~/.claude/edits.log

在设置中引用它:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "~/.claude/hooks/post-edit.sh"
      }
    ]
  }
}

项目特定 Hooks

在项目的 .claude/settings.json 中:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "if [[ \"$CLAUDE_COMMAND\" == *\"npm publish\"* ]]; then echo '请先运行测试!' && npm test || exit 1; fi"
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "npm run lint:fix -- \"$CLAUDE_FILE_PATH\""
      }
    ],
    "Stop": [
      {
        "matcher": "*",
        "command": "npm run typecheck"
      }
    ]
  }
}

调试 Hooks

启用详细日志

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "*",
        "command": "echo \"[DEBUG] 工具: $CLAUDE_TOOL_NAME, 文件: $CLAUDE_FILE_PATH\" >> /tmp/claude-hooks.log"
      }
    ]
  }
}

手动测试 Hooks

# 模拟环境变量
export CLAUDE_FILE_PATH="/path/to/test.js"
export CLAUDE_TOOL_NAME="Edit"

# 运行你的 hook 命令
npx prettier --write "$CLAUDE_FILE_PATH"

常用 Hook 配方

1. 强制分支保护

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "BRANCH=$(git branch --show-current); if [[ \"$BRANCH\" == \"main\" || \"$BRANCH\" == \"master\" ]]; then echo '不能在受保护的分支上运行命令!' && exit 1; fi"
      }
    ]
  }
}

2. 自动更新测试

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "TEST_FILE=$(echo \"$CLAUDE_FILE_PATH\" | sed 's/\\.ts$/.test.ts/'); if [ -f \"$TEST_FILE\" ]; then echo \"记得更新: $TEST_FILE\"; fi"
      }
    ]
  }
}

3. 安全扫描

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "if grep -q 'password\\|secret\\|api_key' \"$CLAUDE_FILE_PATH\"; then echo '警告: 检测到可能的敏感数据!'; fi"
      }
    ]
  }
}

4. 文档提醒

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "command": "if [[ \"$CLAUDE_FILE_PATH\" == *\"/src/\"* ]]; then echo '如果这是公共 API,请记得更新文档!'; fi"
      }
    ]
  }
}

最佳实践

  1. 保持 hooks 快速 - 慢的 hooks 会拖慢整个工作流程
  2. 优雅处理错误 - 对非关键 hooks 使用 || true
  3. 正确使用退出码 - 在 PreToolUse 中返回非零值来阻止操作
  4. 记录重要事件 - 为团队项目创建审计跟踪
  5. 充分测试 hooks - 错误的 hooks 可能破坏你的工作流程
  6. 文档化项目 hooks - 帮助团队成员理解自定义行为

故障排除

Hook 未运行

  1. 检查 matcher 模式是否与工具名称完全匹配
  2. 验证命令语法是否正确
  3. 检查外部脚本的文件权限
  4. 查找 settings.json 中的拼写错误

Hook 阻止所有操作

  1. 检查 PreToolUse 的退出码
  2. 验证条件逻辑是否正确
  3. 手动测试命令

性能问题

  1. 将重型操作移到 PostToolUse 或 Stop hooks
  2. 尽可能使用异步操作
  3. 考虑使用后台进程:command &

相关资源


最后更新:2025 年 1 月