8.4 实战案例集

案例一:保护敏感文件
.env 文件、package-lock.json、数据库迁移文件——这些你永远不想让 AI 随手改掉。
思路: 用 PreToolUse 拦截 Edit 和 Write,检查目标文件路径,如果命中黑名单就 exit 2 阻止。
第一步:创建保护脚本
mkdir -p .claude/hooks
cat > .claude/hooks/protect-files.sh << 'EOF'
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# 如果没有 file_path(比如不是文件操作工具),直接放行
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# 受保护的文件模式
PROTECTED_PATTERNS=(
".env"
".env.local"
".env.production"
"package-lock.json"
"yarn.lock"
".git/"
"db/migrations/"
)
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "🔒 Blocked: '$FILE_PATH' matches protected pattern '$pattern'" >&2
echo "If you need to modify this file, please do it manually." >&2
exit 2
fi
done
exit 0
EOF
chmod +x .claude/hooks/protect-files.sh第二步:注册 Hook
在 .claude/settings.json 里添加:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}$CLAUDE_PROJECT_DIR 是 Claude Code 自动设置的环境变量,指向项目根目录。
效果: 当 Claude Code 尝试修改 .env 文件时,会被阻止,并收到一条解释——然后它会想别的办法,或者告诉你"这个操作需要你手动做"。
案例二:上下文压缩后重注入关键信息
长会话里,上下文压缩(compaction)会把对话历史摘要化,细节会丢失。如果你有一些"无论如何 Claude 都必须知道"的信息,可以用 SessionStart Hook 在压缩后重新注入。
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "cat .claude/critical-context.md"
}
]
}
]
}
}Hook 脚本输出到 stdout 的内容,会被自动注入到 Claude Code 的上下文里。
创建 .claude/critical-context.md:
# 关键上下文(压缩后恢复)
## 当前任务
正在重构支付模块,目标是把 Stripe 和 PayPal 分离成独立的 Strategy 类。
## 绝对不能做的
- 不要修改 PaymentService 的公共接口(有 15 个调用方)
- 不要改 src/types/payment.ts 里的类型定义(等重构完再统一更新)
## 当前进度
- [x] 创建了 PaymentStrategy 接口
- [x] 实现了 StripeStrategy
- [ ] 还没实现 PayPalStrategy
- [ ] 还没更新 PaymentService 使用新的 Strategy压缩发生后,这些关键信息会立刻重新出现在上下文里,Claude Code 不会"忘记"任务状态。
案例三:审计日志
记录 Claude Code 的每次文件改动——什么时候改了哪个文件,原始内容是什么。
cat > .claude/hooks/audit-log.sh << 'EOF'
#!/bin/bash
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // "N/A"')
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
# 追加到审计日志
echo "[$TIMESTAMP] $TOOL -> $FILE" >> .claude/audit.log
exit 0
EOF
chmod +x .claude/hooks/audit-log.sh{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/audit-log.sh"
}
]
}
]
}
}.claude/audit.log 会记录:
[2026-03-15 20:30:12] Edit -> src/services/PaymentService.ts
[2026-03-15 20:30:45] Bash -> N/A
[2026-03-15 20:31:03] Write -> src/services/StripeStrategy.ts把 audit.log 加进 .gitignore,不进版本控制。
案例四:提交前自动跑 Lint
在 Claude Code 执行 git commit 之前,强制跑 lint。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash -c 'CMD=$(echo \"$1\" | jq -r \".tool_input.command\"); if [[ \"$CMD\" == git\\ commit* ]]; then npm run lint || (echo \"Lint failed. Fix errors before committing.\" >&2; exit 2); fi' -- "
}
]
}
]
}
}这个 Hook 检查 Bash 工具要执行的命令,如果是 git commit 开头的,就先跑 lint,失败了就阻止提交。
💡 复杂的逻辑建议写成独立的 shell 脚本,而不是把所有命令塞在一行 JSON 里,可读性差很多。
案例五:完成任务后通知 Slack
Claude Code 完成一段工作在等你的时候,自动往 Slack 发条消息:
cat > ~/.claude/hooks/slack-notify.sh << 'EOF'
#!/bin/bash
# 需要设置 SLACK_WEBHOOK_URL 环境变量
if [ -z "$SLACK_WEBHOOK_URL" ]; then
exit 0
fi
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H 'Content-type: application/json' \
-d "{\"text\": \"🤖 Claude Code needs your attention in: $(pwd)\"}" \
> /dev/null
exit 0
EOF
chmod +x ~/.claude/hooks/slack-notify.sh{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/slack-notify.sh"
}
]
}
]
}
}在 ~/.zshrc 里设置环境变量:
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/xxx/yyy/zzz"脚本放哪里最好
| 位置 | 适合什么 |
|---|---|
.claude/hooks/ | 项目级,进版本控制,团队共享 |
~/.claude/hooks/ | 用户级,个人所有项目使用 |
脚本文件记得加执行权限:
chmod +x .claude/hooks/your-hook.sh这是最常见的"Hook 不执行"原因之一,下一节会详细讲调试方法。
