如果你在用 Claude Code(Anthropic 2025-05 GA 的 CLI 工具)但没配 hooks,你正在错过 60% 能力。
不是营销文。基于过去 6 个月匠人学院(JR Academy)48 个学员在生产项目里实际配的 hooks 归纳。匠人学院是项目制 AI 工程实战平台(澳洲),P3 模式(Project + Production + Placement)。
1. settings.json 文件位置
# 项目级(推荐 commit 到 repo)
mkdir -p .claude && touch .claude/settings.json
# 全局级(个人偏好)
mkdir -p ~/.claude && touch ~/.claude/settings.json
Claude Code 启动时优先读项目级,merge 全局级。
2. 完整可粘贴 settings.json
{
"$schema": "https://schemastore.org/claude-settings.json",
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(uv run *)",
"Bash(pytest *)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)"
]
},
"hooks": {
"on-start": [
{
"command": "[ -f .claude/PROJECT_CONTEXT.md ] && cat .claude/PROJECT_CONTEXT.md"
}
],
"post-edit": [
{
"match": "\\.(ts|tsx|js|jsx)$",
"command": "prettier --write ${file} 2>/dev/null || true"
},
{
"match": "\\.py$",
"command": "ruff format ${file} 2>/dev/null || true; uv run mypy ${file} 2>&1 | head -10 || true"
},
{
"match": "\\.go$",
"command": "gofmt -w ${file} && go vet ./... 2>&1 | head -10"
},
{
"match": "\\.(ts|tsx)$",
"command": "npx tsc --noEmit --skipLibCheck 2>&1 | head -20"
}
],
"pre-bash": [
{
"match": "(rm -rf|git reset --hard|git push --force|git push -f|git branch -D|drop database|truncate table)",
"command": "echo '⚠️ DESTRUCTIVE COMMAND. Confirm y/n:'; read confirm; [[ $confirm == 'y' ]] || exit 1"
},
{
"match": "(pip install|npm install|uv add)",
"command": "PKG_COUNT=$(wc -l < /tmp/installed_today.log 2>/dev/null || echo 0); if [ $PKG_COUNT -gt 20 ]; then echo '⚠️ 今天已装 $PKG_COUNT 个 package'; fi; date >> /tmp/installed_today.log"
}
],
"pre-tool-use": [
{
"match": "Read|Edit|Write",
"command": "if echo '${args}' | grep -qE '\\.(env|env\\.local|env\\.prod|secrets/|credentials)'; then echo '🚨 BLOCKED: sensitive file'; exit 1; fi"
}
],
"pre-commit": [
{
"match": ".",
"command": "git diff --cached | grep -E '(api[_-]?key|password|secret_key|aws_access_key|stripe_secret)' && { echo '🚨 SECRET DETECTED'; exit 1; } || true"
},
{
"match": ".",
"command": "git diff --cached --name-only | xargs grep -l -E '(console\\.(log|debug)|^\\s*print\\(|fmt\\.Println)' 2>/dev/null | head -5 && { echo '⚠️ debug 语句残留'; exit 1; } || true"
},
{
"match": ".",
"command": "npm run test:changed 2>&1 | tail -30 && exit ${PIPESTATUS[0]}"
}
],
"post-commit": [
{
"command": "BRANCH=$(git rev-parse --abbrev-ref HEAD); git push origin $BRANCH:backup/${BRANCH} 2>/dev/null || true"
},
{
"command": "[ -f CHANGELOG.md ] && echo '## $(date +%Y-%m-%d)\\n\\n- TODO: 补充本次 commit 描述\\n' | cat - CHANGELOG.md > /tmp/changelog.tmp && mv /tmp/changelog.tmp CHANGELOG.md || true"
}
],
"on-stop": [
{
"command": "echo '\\n📋 Session 结束自检:'; echo ' - [ ] 跑过测试?'; echo ' - [ ] CHANGELOG 更新?'; echo ' - [ ] PR description 写好?'; osascript -e 'display notification \"Claude Code session 结束\" with title \"Session Done\"' 2>/dev/null || true"
}
]
}
}
3. 12 个 hook 逐个拆解
3.1 post-edit: 自动格式化(每个 AI 改完文件触发)
{
"match": "\\.(ts|tsx|js|jsx)$",
"command": "prettier --write ${file} 2>/dev/null || true"
}
${file} 是 Claude Code 改的文件路径。|| true 保证 hook 不会因为单文件 format 失败导致 session 中断。
3.2 post-edit: type-check
{
"match": "\\.(ts|tsx)$",
"command": "npx tsc --noEmit --skipLibCheck 2>&1 | head -20"
}
--noEmit 只 check 不输出 .js,--skipLibCheck 跳过 node_modules 节省时间。head -20 限制输出量给 Claude 看(太多会浪费 token)。
3.3 pre-bash: 防 destructive
{
"match": "(rm -rf|git reset --hard|git push --force|git branch -D|drop database)",
"command": "echo '⚠️ DESTRUCTIVE: y/n'; read confirm; [[ $confirm == 'y' ]] || exit 1"
}
read confirm 等待人工输入,exit 1 阻断 Claude 执行该命令。
3.4 pre-bash: package install rate-limit
{
"match": "(pip install|npm install|uv add)",
"command": "PKG_COUNT=$(wc -l < /tmp/installed_today.log 2>/dev/null || echo 0); if [ $PKG_COUNT -gt 20 ]; then echo '⚠️ 今天已装 $PKG_COUNT 个'; fi; date >> /tmp/installed_today.log"
}
记录每天 install 次数,超过 20 个提醒(不强制阻断)。
3.5 pre-tool-use: sensitive file 防访问
{
"match": "Read|Edit|Write",
"command": "if echo '${args}' | grep -qE '\\.(env|secrets/|credentials)'; then echo '🚨 BLOCKED'; exit 1; fi"
}
${args} 是 Claude Code 工具调用的参数(如 Read 的 file path)。匹配到 sensitive 文件直接 block。
3.6 pre-commit: 防 secret 泄漏
{
"match": ".",
"command": "git diff --cached | grep -E '(api[_-]?key|password|secret_key|aws_access)' && { echo '🚨 SECRET'; exit 1; } || true"
}
git diff --cached 看 staged content。grep regex 匹配常见 secret pattern。匹到 = exit 1 block commit。
3.7 pre-commit: 防 debug 语句
{
"match": ".",
"command": "git diff --cached --name-only | xargs grep -l -E '(console\\.(log|debug)|^\\s*print\\()' 2>/dev/null | head -5 && { echo '⚠️ debug 残留'; exit 1; } || true"
}
扫 staged 文件里的 console.log / print() debug 语句。head -5 防输出爆炸。
3.8 pre-commit: 跑 unit test
{
"match": ".",
"command": "npm run test:changed 2>&1 | tail -30 && exit ${PIPESTATUS[0]}"
}
npm run test:changed 是 jest --onlyChanged 这种 mode,只跑 changed file 相关 test。
3.9 post-commit: backup push
{
"command": "BRANCH=$(git rev-parse --abbrev-ref HEAD); git push origin $BRANCH:backup/${BRANCH} 2>/dev/null || true"
}
每个 commit 同时 push 到 backup/<branch>,防本地 reset --hard 灾难。
3.10 post-commit: 自动更新 changelog
{
"command": "[ -f CHANGELOG.md ] && echo '## $(date +%Y-%m-%d)\\n\\n- TODO\\n' | cat - CHANGELOG.md > /tmp/changelog.tmp && mv /tmp/changelog.tmp CHANGELOG.md || true"
}
每 commit 在 CHANGELOG.md 顶部插一个 TODO 提醒人工 / AI 完善描述。
3.11 on-start: 项目 context
{
"command": "[ -f .claude/PROJECT_CONTEXT.md ] && cat .claude/PROJECT_CONTEXT.md"
}
session 启动加载项目特定上下文(架构图 / 约定 / known issues)。
3.12 on-stop: session 自检 + macOS 通知
{
"command": "echo '\\n📋 Session 自检...'; osascript -e 'display notification \"...\" with title \"...\"' 2>/dev/null || true"
}
osascript 是 macOS 原生通知。Linux 用 notify-send,Windows 用其他。
4. 48 学员真实 ROI 数据
hook 触发次数 (6 个月 / 48 学员) 单价值
─────────────────────────────────────────────────────
pre-commit secret 17 🔴 防 GitHub leak (USD 80+ 损失)
pre-bash destructive 34 🔴 防 git reset --hard (12 commit 丢失)
post-edit format 2400 🟢 节省手动 format 时间
post-edit type-check 890 🟢 catch 早 bug
post-commit backup 4500+ 🟢 无感 (push backup branch)
pre-commit unit test 320 🟢 catch 早 bug
pre-tool-use sensitive 8 🔴 防 .env 传 LLM
pre-commit debug stmts 56 🟡 防 console.log 上 prod
pre-bash rate-limit 12 🟡 防乱装 package
post-edit changelog 1500+ 🟢 养自动更新 changelog 习惯
on-start context 180 🟡 session 启动
on-stop reminder 180 🟡 session 结束
5. 3 真实事故救场
事故 1: 学员 hardcode API key
# AI 给的代码
client = OpenAI(api_key="sk-proj-1iE...") # 🚨 hardcode
# 学员 git add . && git commit -m "feat: add LLM"
# pre-commit hook 立刻 block:
# 🚨 SECRET DETECTED in staged diff
省 GitHub Security Lab key revoke + USD 80 billing。
事故 2: AI 给 git reset --hard
# 学员让 AI "合 main 到当前分支",AI 给:
$ git reset --hard origin/main
# pre-bash hook block:
# ⚠️ DESTRUCTIVE COMMAND. Confirm y/n:
# 学员输 n
保住 12 个未 push 的 commit。正确命令应该是 git merge origin/main。
事故 3: AI 试图读 .env
# AI 要写部署脚本,尝试 Read /home/ubuntu/.env
# pre-tool-use hook block:
# 🚨 BLOCKED: sensitive file access
防 production env 传入 Anthropic API(理论上 Anthropic 不存 prompt 但合规上必须避免)。
6. Hooks vs Git Hooks vs husky
| 维度 | Claude Code Hooks | Git Hooks | husky |
|---|---|---|---|
| 触发时机 | AI 工作流每步 | git 命令 | git 命令 (跨平台 wrapper) |
| 配置位置 | .claude/settings.json | .git/hooks/* | package.json + .husky/ |
| commit 到 repo | ✅ | ❌ (.git 不 commit) | ✅ |
| 团队 onboard | ✅ 自动 | ❌ 手动 cp | ✅ npm install 触发 |
实战配法:Claude Code Hooks 管 AI 工作流,husky 管 git 命令边界。两者互补,可以一起配。
7. 6 周给团队上 Hooks 路径
Week 1: 装 5 个必配 hook (secret / destructive / format / type-check / sensitive)
Week 2: 跑一周看误触发 / 调阈值
Week 3: 加 pre-commit unit test + post-commit backup push
Week 4: 团队 5+ 工程师都装上
Week 5: 加项目特定 hook (如 i18n key 检查 / DB migration 校验)
Week 6: .claude/settings.json commit 到 repo,新人 onboard 自动继承
完整 .claude/settings.json + 12 hooks 完整代码 + 团队 onboard 指南在 JR Academy GitHub。 更多详情可以在JR Academy匠人学院网站查看:jiangren.com.au/