Claude Code Hooks 使用示例:让你的 AI 助手更智能

82 次阅读

Claude Code Hooks 使用示例:让你的 AI 助手更智能

你是否遇到过这样的情况:Claude Code 在执行某些操作时,你希望它能自动做一些检查,或者在某些关键时刻给你一些提醒?比如,当它要写入文件时,你希望自动运行代码格式化;当它要执行 Bash 命令时,你希望先验证一下命令是否安全。

Claude Code Hooks 就是这样一个功能,它让你可以在 Claude Code 执行特定操作时,自动运行自定义脚本或逻辑。今天,我就来带你看看如何配置和使用 Hooks,并通过几个实际例子让你快速上手。

什么是 Hooks?

简单来说,Hooks 就像是你给 Claude Code 设置的"触发器"。当某个事件发生时(比如工具调用前、工具调用后、用户提交提示时等),你可以让系统自动执行一段代码或脚本。

想象一下,这就像你在家里安装了一个智能门铃:当有人按门铃时(事件触发),它会自动拍照并发送到你的手机(执行自定义逻辑)。Hooks 的工作原理也类似,只不过触发的是 Claude Code 的各种操作。

如何配置 Hooks?

Hooks 的配置非常简单,你只需要在设置文件中添加相应的配置即可。Claude Code 会在以下几个位置查找配置:

  • ~/.claude/settings.json - 用户级别的设置(所有项目都会生效)
  • .claude/settings.json - 项目级别的设置(只对当前项目生效)
  • .claude/settings.local.json - 本地项目设置(不会被提交到版本控制)

基本配置结构

让我们先看一个最简单的配置示例:

json
{
  "hooks": {
    "EventName": [{
      "matcher": "ToolPattern",
      "hooks": [{
        "type": "command",
        "command": "your-command-here"
      }]
    }]
  }
}

这个结构看起来有点复杂,让我解释一下:

  • EventName:这是你要监听的事件类型,比如 PreToolUse(工具使用前)、PostToolUse(工具使用后)等
  • matcher:这是用来匹配工具名称的模式。比如 Write 只匹配 Write 工具,Edit|Write 可以匹配 Edit 或 Write 工具
  • type:Hook 的类型,可以是 command(执行 bash 命令)或 prompt(使用 LLM 评估)
  • command:要执行的命令或脚本路径

实际示例:文件写入后自动格式化

让我们从一个实用的例子开始。假设你希望每次 Claude Code 写入或编辑文件后,自动运行代码格式化工具。

第一步:创建格式化脚本

首先,我们在项目中创建一个脚本文件。我建议把它放在 .claude/hooks/ 目录下:

bash
#!/bin/bash
# .claude/hooks/format-code.sh

# 获取工具输入(通过 stdin 接收 JSON)
input=$(cat)

# 提取文件路径(这里简化处理,实际应该解析 JSON)
file_path=$(echo "$input" | grep -o '"file_path":"[^"]*"' | cut -d'"' -f4)

# 如果文件存在且是代码文件,则格式化
if [ -f "$file_path" ]; then
    case "$file_path" in
        *.js|*.jsx|*.ts|*.tsx)
            npx prettier --write "$file_path" 2>/dev/null || true
            ;;
        *.py)
            black "$file_path" 2>/dev/null || true
            ;;
        *.go)
            gofmt -w "$file_path" 2>/dev/null || true
            ;;
    esac
fi

exit 0

记得给脚本添加执行权限:

bash
chmod +x .claude/hooks/format-code.sh

第二步:配置 Hook

然后在 .claude/settings.json 中添加配置:

json
{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Write|Edit",
      "hooks": [{
        "type": "command",
        "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-code.sh",
        "timeout": 30
      }]
    }]
  }
}

这里有几个关键点:

  1. matcher: Write|Edit 表示匹配 Write 或 Edit 工具
  2. command: 使用 $CLAUDE_PROJECT_DIR 环境变量来引用项目根目录,这样无论当前目录在哪里都能正确执行
  3. timeout: 设置超时时间为 30 秒,防止脚本执行时间过长

现在,每次 Claude Code 写入或编辑文件后,都会自动运行格式化脚本。是不是很方便?

示例二:Bash 命令安全检查

另一个常见的需求是:在执行 Bash 命令前,先检查一下命令是否安全。比如,你可能希望阻止使用 rm -rf 这样的危险命令。

创建安全检查脚本

创建一个 Python 脚本来检查命令:

python
#!/usr/bin/env python3
# .claude/hooks/validate-bash.py

import json
import re
import sys

# 定义危险命令模式
DANGEROUS_PATTERNS = [
    (r'\brm\s+-rf', '使用 rm -rf 可能删除重要文件,请谨慎操作'),
    (r'\bchmod\s+777', 'chmod 777 会降低文件安全性'),
    (r'\bdd\s+if=', 'dd 命令可能损坏磁盘,请确认后再执行'),
]

def validate_command(command: str) -> list[str]:
    """检查命令是否包含危险模式"""
    issues = []
    for pattern, message in DANGEROUS_PATTERNS:
        if re.search(pattern, command):
            issues.append(message)
    return issues

try:
    # 从 stdin 读取 JSON 输入
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"错误: JSON 输入无效: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")

# 只检查 Bash 命令
if tool_name != "Bash" or not command:
    sys.exit(0)  # 不是 Bash 命令,直接通过

# 验证命令
issues = validate_command(command)
if issues:
    # 发现问题,输出错误信息并阻止执行
    for message in issues:
        print(f"⚠️  {message}", file=sys.stderr)
    sys.exit(2)  # 退出代码 2 表示阻止执行

# 命令安全,允许执行
sys.exit(0)

配置 Hook

在设置文件中添加:

json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "command": "python3 \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/validate-bash.py",
        "timeout": 5
      }]
    }]
  }
}

现在,当 Claude Code 尝试执行 Bash 命令时,会先经过安全检查。如果检测到危险命令,会阻止执行并显示警告信息。

示例三:自动批准文档文件读取

有时候,你可能希望自动批准某些操作,而不需要每次都手动确认。比如,读取文档文件(.md、.txt 等)时,可以自动允许。

创建自动批准脚本

python
#!/usr/bin/env python3
# .claude/hooks/auto-approve-read.py

import json
import sys

try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"错误: JSON 输入无效: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})

# 只处理 Read 工具
if tool_name == "Read":
    file_path = tool_input.get("file_path", "")
    
    # 如果是文档文件,自动批准
    if file_path.endswith((".md", ".mdx", ".txt", ".json", ".yaml", ".yml")):
        output = {
            "hookSpecificOutput": {
                "hookEventName": "PreToolUse",
                "permissionDecision": "allow",
                "permissionDecisionReason": "文档文件自动批准"
            }
        }
        print(json.dumps(output))
        sys.exit(0)

# 其他情况,让正常流程继续
sys.exit(0)

配置 Hook

json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Read",
      "hooks": [{
        "type": "command",
        "command": "python3 \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/auto-approve-read.py"
      }]
    }]
  }
}

这样,当 Claude Code 读取文档文件时,会自动批准,不需要你每次都确认。

常用 Hook 事件类型

除了上面用到的 PreToolUsePostToolUse,Claude Code 还支持其他几种事件类型:

  • UserPromptSubmit:用户提交提示时触发,可以用来验证提示或添加上下文
  • Stop:Claude Code 完成响应时触发,可以用来检查任务是否真的完成
  • SessionStart:会话开始时触发,可以用来加载环境变量或安装依赖
  • SessionEnd:会话结束时触发,可以用来清理临时文件或保存状态

注意事项和安全建议

在使用 Hooks 时,有几个重要的安全注意事项:

  1. 验证输入:永远不要盲目信任输入数据,始终进行验证和清理
  2. 使用引号:在 shell 命令中使用变量时,记得加引号:"$VAR" 而不是 $VAR
  3. 路径检查:检查文件路径中是否包含 ..,防止路径遍历攻击
  4. 使用绝对路径:为脚本指定完整路径,使用 $CLAUDE_PROJECT_DIR 来引用项目文件
  5. 避免敏感文件:不要处理 .env.git/、密钥文件等敏感内容

总结

Claude Code Hooks 是一个非常强大的功能,它让你可以自定义 Claude Code 的行为,让它更符合你的工作流程。通过今天的几个例子,你应该已经了解了:

  • 如何配置 Hooks
  • 如何创建简单的 Hook 脚本
  • 如何使用不同的 Hook 事件类型
  • 如何通过 JSON 输出进行更复杂的控制

现在,你可以根据自己的需求,创建适合你的 Hooks 了。记住,从简单的开始,逐步完善,这样既能快速看到效果,又能避免一开始就陷入复杂的逻辑中。

感谢阅读,如果觉得有用欢迎分享
返回 AI使用笔记