
编写完代码后,通常还有一大堆琐事等着:跑 Lint、执行测试、检查类型、扫描安全漏洞、确认格式规范…… 手动执行这些步骤不仅耗时,而且极易被忽略。尤其是在赶工时,一句“下次再说”可能就让 Bug 溜进了生产环境。
Claude Code 的 Hook 系统 正是为解决此痛点而生。它允许你在代码编写、文件保存、提交前后等关键节点,自动触发预设的检查脚本。无论是类型检查、Lint、安全扫描还是格式化审计,全部实现自动化。你再也不用记着去运行这些命令,即便想跳过,系统也会自动拦截。这不仅关乎效率,更是一种代码质量的文化。在 云栈社区 的技术讨论中,自动化流程的构建也是提升研发效能的热门话题。
本文将从 Hook 的原理入手,逐步讲解脚本的具体实现,并延伸至 CI/CD 集成与企业级审计方案,所有代码均可直接复用。
Hook 是什么?如何工作?
Claude Code Hook 是用户在工作流程特定节点执行的自定义脚本。其概念类似于 Git Hook,但专门为 Claude 的 AI 编码工作流进行了优化。
执行流程 大致如下:Claude 任务开始 → Pre Hook 执行 → 若通过则继续任务,失败则中断 → 任务完成 → Post Hook 执行 → 若通过则完成,失败则回滚或发出警告。
Hook 通过 退出码 来控制 Claude 的行为:
exit 0 # 成功(继续任务)
exit 1 # 失败(中断任务)
exit 2 # 警告(继续但显示警告)
目录结构 通常如下所示:
.claude/
└── hooks/
├── pre-file-write.sh # 文件保存前执行
├── post-file-write.py # 文件保存后执行
├── pre-commit.sh # 提交前执行
├── post-commit.py # 提交后执行
└── code-review.js # 自定义审查 Hook
Claude 会以 JSON 格式向 Hook 脚本传递上下文信息:
{
"file_path": "src/components/Button.tsx",
"operation": "write",
"content": "...",
"metadata": {
"timestamp": "2025-10-29T10:30:00Z",
"user": "developer@example.com"
}
}
第一个 Hook:保护敏感文件
让我们从最简单的 Hook 开始——防止 AI 意外修改 .env 或包含 credentials 字样的敏感文件:
#!/bin/bash
# .claude/hooks/pre-file-write.sh
input=$(cat)
file_path=$(echo "$input" | jq -r '.file_path')
echo "Checking file: $file_path"
# 保护敏感文件
if [[ "$file_path" == *".env"* ]] || [[ "$file_path" == *"credentials"* ]]; then
echo "Error: Cannot modify sensitive files"
exit 1
fi
exit 0
创建脚本后,别忘了为其添加执行权限:
chmod +x .claude/hooks/*.sh
chmod +x .claude/hooks/*.py
编码规则自动验证
TypeScript 类型检查
#!/bin/bash
# .claude/hooks/typescript-check.sh
input=$(cat)
file_path=$(echo "$input" | jq -r '.file_path')
# 仅检查 TypeScript 文件
if [[ "$file_path" != *.ts ]] && [[ "$file_path" != *.tsx ]]; then
exit 0
fi
echo "Running TypeScript type check..."
npx tsc --noEmit "$file_path" 2>&1 | tee /tmp/tsc-output.txt
if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "❌ Type check failed"
cat /tmp/tsc-output.txt
exit 1
fi
echo "✅ Type check passed"
exit 0
ESLint 检查(Python 版)
#!/usr/bin/env python3
# .claude/hooks/eslint-check.py
import sys
import json
import subprocess
def main():
input_data = json.loads(sys.stdin.read())
file_path = input_data.get('file_path', '')
if not (file_path.endswith('.js') or file_path.endswith('.ts') or
file_path.endswith('.jsx') or file_path.endswith('.tsx')):
sys.exit(0)
print(f"Running ESLint on {file_path}...")
result = subprocess.run(
['npx', 'eslint', file_path, '--format', 'json'],
capture_output=True, text=True
)
if result.returncode != 0:
lint_results = json.loads(result.stdout)
for file_result in lint_results:
for message in file_result.get('messages', []):
severity = 'Error' if message['severity'] == 2 else 'Warning'
print(f"{severity}: {message['message']} "
f"(line {message['line']}, col {message['column']})")
sys.exit(1)
print("✅ ESLint passed")
sys.exit(0)
if __name__ == '__main__':
main()
保存后自动格式化
#!/bin/bash
# .claude/hooks/post-file-write.sh
input=$(cat)
file_path=$(echo "$input" | jq -r '.file_path')
if [[ "$file_path" =~ \.(js|ts|jsx|tsx|json|css|scss)$ ]]; then
echo "Auto-formatting $file_path with Prettier..."
npx prettier --write "$file_path"
if [ $? -eq 0 ]; then
echo "✅ Formatted successfully"
else
echo "⚠️ Formatting failed, but continuing..."
fi
fi
exit 0
综合代码审查 Hook
我们可以创建一个功能更强大的 Hook,在一个脚本中集成安全扫描、类型检查、Lint、测试覆盖和文档检查:
#!/bin/bash
# .claude/hooks/comprehensive-review.sh
set -e
input=$(cat)
file_path=$(echo "$input" | jq -r '.file_path')
echo "🔍 Starting comprehensive code review for $file_path"
# 1. 安全扫描
echo "🔒 Security scan..."
if command -v semgrep &> /dev/null; then
semgrep --config=auto "$file_path" --quiet
fi
# 2. 类型检查
echo "📝 Type checking..."
if [[ "$file_path" =~ \.(ts|tsx)$ ]]; then
npx tsc --noEmit "$file_path"
fi
# 3. Linting
echo "✨ Linting..."
if [[ "$file_path" =~ \.(js|ts|jsx|tsx)$ ]]; then
npx eslint "$file_path"
fi
# 4. 测试覆盖率
echo "🧪 Test coverage..."
test_file="${file_path/src/tests}"
test_file="${test_file/.ts/.test.ts}"
if [ ! -f "$test_file" ]; then
echo "⚠️ Warning: No test file found at $test_file"
fi
# 5. 文档检查
echo "📚 Documentation check..."
if [[ "$file_path" =~ \.(ts|tsx|js|jsx)$ ]]; then
if ! grep -q "/\*\*" "$file_path"; then
echo "⚠️ Warning: No JSDoc comments found"
fi
fi
echo "✅ Code review completed successfully"
exit 0
SOX/SOC2 审计追踪
对于合规要求较高的企业级项目,每次代码变更都需要留下清晰的审计痕迹。这个Hook将自动记录变更信息:
#!/usr/bin/env python3
# .claude/hooks/audit-trail.py
import sys, json, hashlib, os
from datetime import datetime
AUDIT_LOG = '.claude/audit/trail.jsonl'
def main():
input_data = json.loads(sys.stdin.read())
os.makedirs(os.path.dirname(AUDIT_LOG), exist_ok=True)
audit_entry = {
'timestamp': datetime.utcnow().isoformat(),
'operation': input_data.get('operation', 'unknown'),
'file_path': input_data.get('file_path', ''),
'user': os.environ.get('USER', 'unknown'),
'content_hash': hashlib.sha256(
input_data.get('content', '').encode()
).hexdigest(),
'metadata': input_data.get('metadata', {})
}
with open(AUDIT_LOG, 'a') as f:
f.write(json.dumps(audit_entry) + '\n')
print(f"✅ Audit trail recorded: {audit_entry['timestamp']}")
sys.exit(0)
if __name__ == '__main__':
main()
每次 AI 对代码进行修改后,该脚本会自动在 JSONL 格式的文件中记录时间戳、操作类型、文件路径、内容哈希值和操作者等信息,为后续的合规审计提供完整依据。
CI/CD 集成
GitHub Actions 集成
将这些审查 Hook 无缝集成到你的 CI/CD 流程中,可以确保代码质量门禁在自动化流水线中得到严格执行。这是很多专业团队在 运维/DevOps 实践中采用的方法。
# .github/workflows/claude-hooks.yml
name: Claude Code Hooks
on:
pull_request:
types: [opened, synchronized]
jobs:
run-hooks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Make hooks executable
run: chmod +x .claude/hooks/*.sh
- name: Run code review hook
run: |
for file in $(git diff --name-only origin/main); do
if [ -f ".claude/hooks/code-review.sh" ]; then
echo "{\"file_path\": \"$file\"}" | .claude/hooks/code-review.sh
fi
done
Telegram 通知
#!/usr/bin/env python3
# .claude/hooks/telegram-notify.py
import sys, json, os, requests
def send_telegram_message(message):
bot_token = os.environ.get('TELEGRAM_BOT_TOKEN')
chat_id = os.environ.get('TELEGRAM_CHAT_ID')
if not bot_token or not chat_id:
return
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
requests.post(url, json={'chat_id': chat_id, 'text': message,
'parse_mode': 'Markdown'}, timeout=5)
def main():
input_data = json.loads(sys.stdin.read())
file_path = input_data.get('file_path', 'unknown')
message = f"🔍 *Code Review Completed*\n📁 File: `{file_path}`\n✅ All checks passed"
send_telegram_message(message)
sys.exit(0)
if __name__ == '__main__':
main()
渐进式引入策略
一次性启用所有阻塞性 Hook 可能会严重干扰现有的工作流。更明智的做法是分阶段、渐进式地引入:
阶段 1:非破坏性监控(第 1~2 周)
这个阶段 Hook 只提供信息反馈,绝不阻塞操作,让团队习惯它的存在。
# 只提供信息,永远 exit 0
echo "ℹ️ Code formatting applied"
echo "ℹ️ Audit trail recorded"
exit 0
阶段 2:警告级别(第 3~4 周)
发现问题时会给出警告,但允许操作继续,让开发者开始关注并修复问题。
# 发现问题但不阻塞,exit 2
npx eslint "$file_path" || echo "⚠️ Linting issues found"
exit 2
阶段 3:阻塞性检查(第 5 周起)
在团队充分适应后,将关键检查(如类型安全)升级为阻塞级别,从根本上杜绝问题代码入库。
# 检查不过直接中断,exit 1
npx tsc --noEmit "$file_path"
if [ $? -ne 0 ]; then
echo "❌ Type check failed - blocking operation"
exit 1
fi
exit 0
性能优化技巧
并行执行
将多个独立的检查任务并行执行,可以显著减少总体等待时间。
# 设置超时 5 秒,并行跑
TIMEOUT=5
(
timeout $TIMEOUT npx eslint "$file_path" &
timeout $TIMEOUT npx prettier --check "$file_path" &
wait
) 2>/dev/null
使用缓存避免重复检查
对内容未变化的文件跳过重复检查,利用缓存提升效率。
content_hash=$(echo "$content" | sha256sum | cut -d' ' -f1)
cache_file=".claude/cache/$content_hash"
if [ -f "$cache_file" ]; then
echo "✅ Using cached result"
exit 0
fi
# 执行实际检查...
echo "passed" > "$cache_file"
条件执行:按文件类型分流
根据文件类型调用不同的专用检查脚本,实现精准分流。
case "$file_path" in
*.ts|*.tsx) .claude/hooks/typescript-check.sh <<< "$input" ;;
*.py) .claude/hooks/python-check.sh <<< "$input" ;;
*.md) .claude/hooks/markdown-lint.sh <<< "$input" ;;
*) echo "No specific checks for this file type" ;;
esac
安全注意事项
在编写 Hook 脚本时,必须考虑安全性,防止恶意输入或操作。
# 1. 验证 JSON 输入
if ! echo "$input" | jq empty 2>/dev/null; then
echo "Error: Invalid JSON input"
exit 1
fi
# 2. 防止路径注入攻击
if [[ "$file_path" =~ \.\. ]]; then
echo "Error: Path traversal detected"
exit 1
fi
# 3. 安全处理临时文件
temp_file=$(mktemp)
trap "rm -f $temp_file" EXIT
Claude Code 简介
Claude Code 是 Anthropic 推出的终端 AI 编程助手。其 Hook 系统是核心能力之一,让你能够在 AI 编码工作流的各个节点插入自定义逻辑,从而实现代码审查、测试、安全扫描等流程的完全自动化。
除了 Hook,Claude Code 还支持 MCP 服务器扩展、自定义斜杠命令、并行代理和子代理系统等功能。使用需要订阅 Anthropic 官方套餐。
| 套餐 |
月费 |
说明 |
| Claude Pro |
$20/月 |
日常使用足够 |
| Claude Max |
$200/月 |
完整功能,包含 Agent Teams、Extended Thinking |
官方订阅需要海外信用卡和支付环境。对于国内开发者,也可以考虑使用一些提供 Claude API 中转服务的平台来降低使用门槛。
常见问题
Q: Hook 脚本可以用什么语言编写?
A: 任何能够从标准输入读取 JSON、并能通过退出码返回结果的编程语言都可以使用。Bash、Python、Node.js、Go 都是不错的选择。文中示例主要使用了 Bash 和 Python,你可以选择自己最熟悉的语言。
Q: Hook 会不会拖慢开发速度?
A: 如果设计不当,确实可能影响效率。解决方案有三个:一是将多个检查并行执行;二是利用内容哈希缓存避免对未变更内容进行重复检查;三是为每个检查设置合理的超时时间。文中的“性能优化技巧”部分提供了具体代码。此外,强烈推荐采用“渐进式引入”策略。
Q: Hook 和 Git Hook 有什么区别?
A: 核心概念相似,但 Claude Code Hook 专门针对 AI 编码工作流设计。它的触发点不仅限于 Git 提交,还包括文件保存前后、AI 任务开始与结束等。更重要的是,Claude 会以结构化的 JSON 格式向脚本传递丰富的上下文信息(文件路径、内容、元数据等),这比传统 Git Hook 的信息量要大得多。
Q: 可以在 CI/CD 流水线中复用这些 Hook 吗?
A: 完全可以。文中提供了完整的 GitHub Actions YAML 配置示例。其思路是遍历拉取请求中所有变更的文件,然后将每个文件的信息依次喂给相同的 Hook 脚本执行。这确保了本地开发环境和 CI/CD 流水线使用完全相同的质量检查标准。
总结
通过 Claude Code 的 Hook 系统,我们可以将AI编程从随意的“提示词对话”升级为严谨的“工程化流程”。它不仅仅是自动化了几个命令,更是将代码质量保障内嵌到了开发工作流的每一个环节。
从保护敏感文件的基础检查,到集成安全扫描、代码风格、测试覆盖的全面审查,再到满足企业合规要求的审计追踪,Hook 提供了极高的灵活性和强大的能力。结合渐进式引入策略和性能优化技巧,这套系统可以平滑地融入现有团队,在不显著增加开发负担的前提下,持续守护代码质量。如果你对这类自动化脚本开发与集成感兴趣,也可以在 开源实战 板块找到更多灵感。