在 Claude Code 中配置 Hook 是构建生产级自动化工作流的关键。本文将基于 Claude HowTo 教程指南中的 8 个实战脚本,手把手教你实现代码自动格式化、安全扫描拦截、用户提示验证、上下文 token 追踪、会话学习进度记录及依赖漏洞检查,让你的 AI 编程助手更安全、更高效。
8 个 Hook 脚本实战:自动格式化、安全扫描、提示验证与上下文追踪
Claude Code 的 Hook 系统允许你在特定事件发生时自动执行脚本,从而实现自动化验证、格式化、安全检查和日志记录。本文将基于 Claude HowTo 教程指南中的 8 个实战脚本,深入解析其核心设计与配置方法,帮助你快速将这些生产就绪的模板应用到自己的项目中。
1. pre-tool-check.sh:双层安全检查与审计日志
这个脚本在 PreToolUse:Bash 事件触发时运行,用于拦截或警告潜在的危险命令。它的核心设计是双层安全检查。
工作原理与配置: 脚本首先读取来自 stdin 的 JSON 输入,提取将要执行的 Bash 命令。然后进行两层模式匹配:
- Blocked patterns:如
rm -rf /、dd if=/dev/zero、mkfs.等。这些命令被无条件阻断,脚本以exit 2退出,Claude Code 会将 stderr 的内容(即阻断原因)反馈给 Claude。 - Warning patterns:如
git push --force、chmod -R 777、DROP TABLE等。这些命令被识别为高风险,但允许执行。脚本会记录一条警告到审计日志,并以exit 0退出。
关键机制——审计日志:
由于 Claude Code 在 exit 0 时会静默丢弃 stderr,脚本将所有决策(BLOCK/WARN/ALLOW)写入一个独立的审计日志文件 $CLAUDE_PROJECT_DIR/.claude/hooks/audit.log。这是监控警告级别事件的唯一可靠方法。
# 审计日志记录函数
log_decision() {
echo "$(date -u +%FT%TZ) [$1] $COMMAND" >> "$LOG_FILE"
}
要启用此脚本,将其复制到 ~/.claude/hooks/ 目录,并在你的 Claude Code 设置文件中配置:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/pre-tool-check.sh"
}
]
}
]
}
}
2. security-scan.sh:多模式密钥与凭据检测
该脚本在 PostToolUse:Write 事件触发后运行,扫描新写入或修改的文件,检测硬编码的密钥、密码和私钥,发出非阻塞警告。
多模式检测规则:
脚本定义了多组 grep 模式,覆盖常见形式:
- 密码:检测
"password": "value"或password = 'value'格式。 - API 密钥:检测
"api_key": "value"、"apikey": "value"、"access_token": "value"。 - 私钥:检测
BEGIN.*PRIVATE KEY头。 - AWS 密钥:检测符合
AKIA[0-9A-Z]{16}格式的字符串。
外部工具集成:
如果环境中安装了 semgrep 或 trufflehog,脚本会调用它们进行更深入的扫描,并将 stdout 静默以避免污染 JSON 输出。
输出格式:
当发现任何问题时,脚本会按照 Claude Code 的 PostToolUse 协议,输出一个包含 additionalContext 字段的 JSON 对象,将安全警告反馈给 Claude。
printf '{"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": "Security scan found issues in %s:\\n%sPlease review and use environment variables instead."}}' "$SAFE_PATH" "$SAFE_ISSUES"
3. format-code.sh:多语言代码自动格式化
在 PostToolUse:Write 或 PostToolUse:Edit 事件后,此脚本自动调用对应语言的格式化工具,确保 Claude 生成的代码风格统一。
多语言格式化器检测: 脚本通过文件扩展名判断语言,并检查相应格式化工具是否可用,实现无侵入式集成:
case "$FILE_PATH" in
*.js|*.jsx|*.ts|*.tsx)
command -v prettier &> /dev/null && prettier --write "$FILE_PATH"
;;
*.py)
command -v black &> /dev/null && black "$FILE_PATH"
;;
*.go)
command -v gofmt &> /dev/null && gofmt -w "$FILE_PATH"
;;
*.rs)
command -v rustfmt &> /dev/null && rustfmt "$FILE_PATH"
;;
*.java)
command -v google-java-format &> /dev/null && google-java-format -i "$FILE_PATH"
;;
esac
它支持 JavaScript/TypeScript(prettier)、Python(black)、Go(gofmt)、Rust(rustfmt)和 Java(google-java-format),只要本地安装了这些工具,就会在文件保存后自动执行。
4. validate-prompt.sh:用户提示安全验证
当用户提交提示时,UserPromptSubmit 事件触发此脚本。它会在 Claude 处理提示前进行验证,可阻断危险操作。
危险操作拦截: 脚本定义了一个危险操作列表,并逐一匹配用户提示:
DANGEROUS_PATTERNS=(
"rm -rf /"
"delete database"
"drop database"
...
)
一旦匹配,脚本将输出一个包含 "decision": "block" 和原因的 JSON,阻止 Claude 执行该提示。
生产部署审批流程:
对于 deploy 或 push 到 production 的提示,脚本会检查项目中是否存在 .deployment-approved 文件。若不存在,则阻断请求并提示创建审批文件,实现了一个简易的审批门控。
5. context-tracker.py:双 Hook 模式下的上下文消耗追踪
这是一个巧妙的 Python 脚本,通过成对使用 UserPromptSubmit 和 Stop 事件来计算每次请求的 token 消耗增量。
双 Hook 协同工作原理:
- UserPromptSubmit:在用户提示被处理前,读取当前会话的 transcript 文件,估算当前的 token 总数,并保存到临时文件。
- Stop:在 Claude 响应完成后,再次估算 token 总数,减去之前保存的值,得到本次请求的 token 增量,并计算上下文使用百分比和剩余量。
两种 Token 计数方法:
- 字符估算(默认):基于每 4 个字符约等于 1 个 token 的经验法则,零依赖,准确率约 80-90%。
- tiktoken(可选):使用
tiktoken库和p50k_base编码,准确率约 90-95%,需要安装额外依赖。
关键实现细节:
- 使用
session_id作为临时文件名的一部分,隔离不同会话的状态。 - 通过读取
transcript_path获取上下文内容,该文件记录了用户和 Claude 的对话历史。 - 将报告输出到 stderr,避免干扰 Hook 的正常 JSON 输出。
配置此脚本需要在设置中同时为 UserPromptSubmit 和 Stop 事件添加相同的命令:
{
"hooks": {
"UserPromptSubmit": [{
"hooks": [{"type": "command", "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/context-tracker.py\""}]
}],
"Stop": [{
"hooks": [{"type": "command", "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/context-tracker.py\""}]
}]
}
}
6. session-end.sh:交互式学习进度追踪
此脚本挂载在 SessionEnd 事件上,在 Claude Code 会话终止时触发,用于记录你本次会话学习了哪些模块。
交互式设计与关键模式:
- 会话结束触发:使用
SessionEnd而非Stop,确保只在会话彻底结束时记录一次。 - 终端输入:由于 Hook 的 stdin 被 JSON 输入占用,脚本使用
read -r INPUT </dev/tty直接从终端读取用户输入。 - 进度持久化:学习进度保存在用户主目录的
~/.claude-howto-progress.json文件中,位于仓库之外,避免被git pull覆盖。 - 防护性守卫:脚本开头检查
CLAUDE_PROJECT_DIR或PWD是否包含claude-howto,防止在无关项目中误触发。
安装后,在会话结束时,脚本会提示你输入本次学习的模块编号(如 06,07),并将记录追加到进度文件中,为你的学习旅程留下足迹。
7. dependency-check.sh:多包管理器漏洞扫描
当 PostToolUse:Write 事件写入依赖清单文件(如 package.json、requirements.txt、go.mod)时,此脚本会自动触发,扫描已知的安全漏洞。
多包管理器支持与 trivy 兜底: 脚本通过文件名判断包管理器类型,并调用对应的审计工具:
- Node.js:调用
npm audit,并用 Python 解析 JSON 输出,仅报告 high 和 critical 级别的漏洞。 - Python:优先使用
pip-audit,回退到safety。 - Go:使用
govulncheck。 - Rust:使用
cargo audit。 - Ruby:使用
bundler-audit。 - 通用回退:如果安装了
trivy,会使用它进行一次通用的文件系统扫描,查找 HIGH/CRITICAL 问题。
设计特点:
- 仅警告不阻断:脚本始终以
exit 0退出,将发现的漏洞以建议形式反馈给用户,不会阻止工作流。 - 清晰的摘要输出:扫描完成后,会明确告知是“通过”还是“检测到漏洞”。
8. log-bash.sh:Bash 命令日志记录
这是一个轻量级的审计脚本,在 PostToolUse:Bash 事件后运行,将所有执行的 Bash 命令记录到日志文件中。
实现逻辑:
COMMAND=$(echo "$INPUT" | sed -n 's/.*"command"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
LOGFILE="$HOME/.claude/bash-commands.log"
echo "[$TIMESTAMP] $COMMAND" >> "$LOGFILE"
脚本从输入 JSON 中提取命令,加上时间戳,追加到 ~/.claude/bash-commands.log 文件。这对于审计 Claude 自动执行的所有 shell 命令非常有用,尤其是在调试或审查自动化任务时。
如何应用这些脚本
- 复制脚本:将需要的脚本从
06-hooks/目录复制到你的项目.claude/hooks/或用户级~/.claude/hooks/目录。 - 赋予执行权限:
chmod +x .claude/hooks/your-script.sh。 - 配置 settings.json:在项目的
.claude/settings.json或用户级~/.claude/settings.json中,根据配置模板添加相应的 Hook 事件配置。 - 测试:启动新的 Claude Code 会话,触发对应的操作(如写入文件、提交提示、结束会话),观察脚本是否按预期工作。
FAQ
Q: 如何调试 Hook 脚本?
A: 可以在脚本中添加 set -x 开启调试输出,或在脚本中打印日志到 stderr(echo "debug info" >&2)。Claude Code 在详细模式下会显示 stderr 输出。对于 exit 0 的脚本,将调试信息写入独立文件(如审计日志)是更可靠的方式。
Q: Hook 脚本出错或阻断了正常操作怎么办?
A: 首先检查脚本的 stderr 输出(Claude Code 会显示)。如果是 pre-tool-check.sh 这类安全脚本误判,可以暂时注释掉对应模式或调整正则表达式。如果问题紧急,可以通过在设置文件中将 "disableAllHooks": true 来临时禁用所有 Hook,然后排查问题。