本教程面向已有Claude Code基础使用经验的开发者,系统讲解Hooks机制——从理解事件模型、配置schema,到编写生产级钩子脚本、调试排错、团队共享。学完后你将具备用Hooks构建确定性工作流的能力,让Claude Code在每次工具调用、文件编辑、会话启停时自动执行你定义的逻辑,彻底告别重复提醒AI的窘境。
适用人群:已安装Claude Code并完成至少一个项目的开发者,熟悉JSON配置和基础Shell脚本。
| 项目 | 要求 |
|---|---|
| Claude Code | v1.0.20+(Hooks在早期版本中引入,建议最新版) |
| Shell环境 | Bash/Zsh,支持标准输入输出 |
| 编辑器 | 任意(VS Code推荐) |
| 基础知识 | JSON配置、Shell脚本、正则表达式 |
验证Claude Code版本:
claude --version
Hooks是用户定义的Shell命令、LLM提示或子Agent,在Claude Code生命周期的特定节点自动执行。它们提供确定性控制——不依赖AI"记住"规则,而是通过系统级机制强制执行。
核心价值:
- 自动格式化:每次文件编辑后自动运行Prettier/ESLint
- 安全防护:拦截危险命令(rm -rf、修改.env)
- 上下文注入:会话启动或压缩后自动注入项目规范
- 工作流自动化:编辑后自动运行测试、Git操作
- 通知集成:任务完成后发送Slack/邮件通知
Claude Code定义了多种Hook事件类型,每种在不同的生命周期节点触发:
┌─────────────────────────────────────────────────────────────┐
│ Claude Code 生命周期 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 会话开始 ──→ [SessionStart] ──→ 对话循环 ──→ 会话结束 │
│ ↑ ↓ │
│ 注入上下文/规范 [Stop] 通知用户 │
│ │
│ ┌──────────── 对话循环内部 ────────────┐ │
│ │ │ │
│ │ AI生成工具调用 │ │
│ │ ↓ │ │
│ │ [PreToolUse] ──→ 执行工具 ──→ [PostToolUse] │
│ │ 拦截/验证 ↓ 格式化/通知 │
│ │ (Write/Edit/Bash/...) │
│ │ │ │
│ │ 上下文压缩 │ │
│ │ ↓ │ │
│ │ [Compaction] ──→ 注入关键上下文 │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
| 事件 | 触发时机 | 典型用途 |
|---|---|---|
PreToolUse |
工具调用之前 | 拦截危险操作、验证输入 |
PostToolUse |
工具调用之后 | 自动格式化、运行测试 |
Notification |
Claude停止生成时 | 发送通知、触发后续流程 |
Stop |
会话结束 | 清理临时文件、汇总报告 |
SubagentStop |
子Agent完成时 | 聚合子任务结果 |
Hooks可在三个层级配置,优先级从高到低:
.claude/settings.json)—— 团队共享,进入版本控制~/.claude/settings.json)—— 个人偏好Hooks配置在settings.json的hooks字段中:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "your-script.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx prettier --write $CLAUDE_FILE_PATH"
}
]
}
]
}
}
顶层分组(Hook Group):
{
"matcher": "工具名匹配模式", // 正则表达式,匹配工具名
"hooks": [ // 该匹配下要执行的钩子列表
{ "type": "command", "command": "..." },
{ "type": "prompt", "prompt": "..." }
]
}
Matcher字段:
- 精确匹配:"Bash" —— 只匹配Bash工具
- 正则匹配:"Write|Edit" —— 匹配Write或Edit
- 通配所有:".*" 或省略matcher —— 匹配所有工具
Hook类型:
- "command" —— 执行Shell命令
- "prompt" —— 向AI注入提示文本(不执行Shell)
- "subagent" —— 启动子Agent执行任务
Hooks执行时可访问关键环境变量:
| 变量 | 含义 | 示例 |
|---|---|---|
$CLAUDE_TOOL_NAME |
当前工具名 | Bash, Write, Edit |
$CLAUDE_TOOL_INPUT |
工具输入(JSON字符串) | {"command":"ls"} |
$CLAUDE_FILE_PATH |
涉及的文件路径 | /src/app.ts |
对于PostToolUse,还可以通过stdin获取工具输出结果。
| 退出码 | 含义 | 对Claude的影响 |
|---|---|---|
0 |
成功 | 正常继续 |
2 |
阻止+反馈 | 阻止工具执行,将stdout作为反馈返回Claude |
| 其他非零 | 错误 | 记录错误但继续执行(取决于配置) |
退出码2是实现安全防护的核心——它阻止操作并给Claude一个理由。
最经典的Hook用例:每次Claude编辑文件后自动运行Prettier。
步骤1:在项目根目录创建.claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
}
]
}
]
}
}
步骤2:验证配置生效:
# 启动Claude Code,让AI编辑任意文件
claude
# > 请帮我修改 src/app.ts,把标题改成 "Hello Hooks"
预期结果:Claude编辑文件后,你会看到Prettier自动运行,文件被格式化。Claude的输出中会显示Hook执行信息。
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Hook未触发 | matcher写错 | 检查工具名大小写(Write不是write) |
| 命令报错 | 文件路径含空格 | 用双引号包裹$CLAUDE_FILE_PATH |
| 格式化卡住 | Prettier缺少配置 | 确保项目有.prettierrc |
| 所有文件都格式化 | 缺少忽略规则 | 添加.prettierignore |
这是PreToolUse最强大的能力——在执行前拦截。
创建脚本.claude/hooks/block-dangerous.sh:
#!/bin/bash
# 从stdin读取工具输入JSON
INPUT=$(cat)
# 检查是否包含危险命令模式
COMMAND=$(echo "$INPUT" | jq -r '.command // empty')
DANGEROUS_PATTERNS=(
"rm -rf /"
"rm -rf ~"
"DROP TABLE"
"DROP DATABASE"
"git push --force"
"git reset --hard"
"dd if="
":(){:|:&};:"
"chmod -R 777 /"
"mkfs"
)
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if echo "$COMMAND" | grep -qi "$pattern"; then
echo "⛔ 安全防护:检测到危险命令模式 '$pattern'。此操作已被阻止。如果确需执行,请手动在终端操作。"
exit 2
fi
done
exit 0
在settings.json中配置:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/block-dangerous.sh"
}
]
}
]
}
}
赋予执行权限:
chmod +x .claude/hooks/block-dangerous.sh
阻止Claude修改关键配置文件:
#!/bin/bash
# .claude/hooks/protect-files.sh
INPUT=$(cat)
# 提取文件路径
FILE_PATH=$(echo "$INPUT" | jq -r '.file_path // .filePath // empty')
PROTECTED_FILES=(
".env"
".env.production"
"credentials.json"
"service-account-key.json"
"deploy-keys.pem"
)
PROTECTED_PATTERNS=(
"\.env$"
"\.env\."
"secret"
"credential"
"private.?key"
)
for protected in "${PROTECTED_FILES[@]}"; do
if [[ "$FILE_PATH" == *"$protected"* ]]; then
echo "🔒 文件保护:'$FILE_PATH' 是受保护文件,禁止修改。如需编辑,请手动操作。"
exit 2
fi
done
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if echo "$FILE_PATH" | grep -qiE "$pattern"; then
echo "🔒 文件保护:'$FILE_PATH' 匹配敏感文件模式,禁止修改。"
exit 2
fi
done
exit 0
配置:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/protect-files.sh"
}
]
}
]
}
}
将所有安全规则整合为一个完整的settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/block-dangerous.sh"
}
]
},
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/protect-files.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
}
]
}
]
}
}
会话启动时自动注入项目规范,无需写入CLAUDE.md:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/block-dangerous.sh"
}
]
}
]
}
}
SessionStart的prompt类型Hook:
{
"hooks": {
"PreToolUse": [
{
"matcher": "",
"hooks": [
{
"type": "prompt",
"prompt": "项目使用 React 18 + TypeScript + Vite。路由使用 react-router v6。状态管理用 Zustand。CSS 使用 Tailwind。测试框架 Vitest + Testing Library。所有组件使用函数式组件和 Hooks。"
}
]
}
]
}
}
注意:SessionStart作为特殊事件,推荐使用prompt类型注入上下文。实际配置中,prompt类型hooks直接向Claude的上下文窗口追加文本,不执行Shell命令。
当对话上下文被压缩(compaction)时,关键信息可能丢失。通过Compaction Hook重新注入:
{
"hooks": {
"PreToolUse": [
{
"matcher": "",
"hooks": [
{
"type": "prompt",
"prompt": "[上下文恢复] 当前项目架构:前端 React 18 + Vite,后端 Node.js + Express,数据库 PostgreSQL。API遵循RESTful规范,使用JWT认证。请继续保持这一技术栈的编码风格。"
}
]
}
]
}
}
更高级的用法:根据当前Git分支动态注入不同规范:
#!/bin/bash
# .claude/hooks/dynamic-context.sh
BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
case "$BRANCH" in
"main"|"master")
echo "⚠️ 当前在主分支。所有修改必须:1) 先创建feature分支 2) 通过PR合并 3) 通过CI检查。禁止直接push到main。"
;;
"develop"*)
echo "📌 当前在开发分支。请确保:1) 编写单元测试 2) 遵循Conventional Commits规范 3) 代码覆盖率不低于80%。"
;;
"feature/"*)
echo "🔧 功能开发中。完成后请:1) 运行完整测试套件 2) 更新相关文档 3) 创建PR到develop分支。"
;;
"hotfix/"*)
echo "🚨 紧急修复!请:1) 最小化改动范围 2) 添加回归测试 3) 同时修复main和develop。"
;;
esac
Claude完成任务后自动发送通知(通过Notification事件):
#!/bin/bash
# .claude/hooks/notify.sh
# 获取通知内容
MESSAGE=$(cat)
# macOS通知
if [[ "$OSTYPE" == "darwin"* ]]; then
osascript -e "display notification \"Claude Code任务完成\" with title \"Claude Code\" sound name \"Glass\""
fi
# Linux通知
if command -v notify-send &>/dev/null; then
notify-send "Claude Code" "任务完成" --icon=utilities-terminal
fi
# 可选:发送到Slack
# curl -X POST -H 'Content-type: application/json' \
# --data "{\"text\":\"✅ Claude Code任务完成: $(date)\"}" \
# "$SLACK_WEBHOOK_URL"
编辑后自动暂存和提交:
#!/bin/bash
# .claude/hooks/auto-git.sh
# PostToolUse - 在文件编辑后自动git add
FILE_PATH="$CLAUDE_FILE_PATH"
if [[ -z "$FILE_PATH" ]] || [[ ! -f "$FILE_PATH" ]]; then
exit 0
fi
# 排除不需要自动暂存的文件
IGNORE_PATTERNS=("*.lock" "*.log" ".env*" "dist/" "node_modules/")
for pattern in "${IGNORE_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == $pattern ]]; then
exit 0
fi
done
git add "$FILE_PATH" 2>/dev/null
exit 0
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "FILE=\"$CLAUDE_FILE_PATH\"; if [[ \"$FILE\" == *.test.* ]] || [[ \"$FILE\" == *.spec.* ]]; then npx vitest run \"$FILE\" 2>&1 | tail -5; elif [[ \"$FILE\" == src/**/*.ts ]] && [[ \"$FILE\" != *.d.ts ]]; then CORRESPONDING_TEST=\"${FILE%.ts}.test.ts\"; if [[ -f \"$CORRESPONDING_TEST\" ]]; then npx vitest run \"$CORRESPONDING_TEST\" 2>&1 | tail -5; fi; fi"
}
]
}
]
}
}
Prompt类型Hook不执行Shell命令,而是直接向Claude注入文本指令。适合注入编码规范、项目上下文:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "prompt",
"prompt": "编码规范检查提醒:请确保新代码遵循以下规则——1) 使用const而非let,除非需要重新赋值 2) 优先使用可选链(?.)和空值合并(??) 3) 函数不超过30行 4) 组件文件不超过200行。"
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "prompt",
"prompt": "执行Shell命令前请注意:本项目使用pnpm作为包管理器,不要使用npm或yarn。Docker命令需要加--user参数。"
}
]
}
]
}
}
同一个matcher下可配置多个hooks,它们按顺序执行:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
},
{
"type": "command",
"command": "npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
},
{
"type": "command",
"command": "echo \"[$(date)] Formatted: $CLAUDE_FILE_PATH\" >> .claude/format-log.txt"
}
]
}
]
}
}
执行顺序:Prettier格式化 → ESLint修复 → 记录日志。如果其中任何一个返回退出码2,后续hooks不再执行。
#!/bin/bash
# .claude/hooks/smart-format.sh
# 根据文件扩展名选择格式化工具
FILE_PATH="$CLAUDE_FILE_PATH"
if [[ -z "$FILE_PATH" ]] || [[ ! -f "$FILE_PATH" ]]; then
exit 0
fi
EXT="${FILE_PATH##*.}"
case "$EXT" in
ts|tsx|js|jsx|json|css|md)
npx prettier --write "$FILE_PATH" 2>/dev/null
;;
py)
python -m black "$FILE_PATH" 2>/dev/null
python -m isort "$FILE_PATH" 2>/dev/null
;;
go)
gofmt -w "$FILE_PATH" 2>/dev/null
;;
rs)
rustfmt "$FILE_PATH" 2>/dev/null
;;
java)
google-java-format -i "$FILE_PATH" 2>/dev/null
;;
*)
# 未知文件类型,不做格式化
;;
esac
exit 0
启用Hooks调试日志:
# 在Shell中设置环境变量
export CLAUDE_HOOK_DEBUG=1
# 或在.claude/settings.json中
{
"env": {
"CLAUDE_HOOK_DEBUG": "1"
}
}
问题1:Hook未触发
# 检查配置文件是否正确
cat .claude/settings.json | jq '.hooks'
# 验证JSON格式
jq . .claude/settings.json
检查清单:
- [ ] 文件路径正确(.claude/settings.json)
- [ ] JSON格式有效
- [ ] matcher拼写正确(区分大小写)
- [ ] hooks数组格式正确
- [ ] Shell脚本有执行权限
问题2:Hook执行报错
# 手动测试Hook脚本
echo '{"command":"ls -la"}' | bash .claude/hooks/block-dangerous.sh
echo $?
# 应输出 0 或 2
# 检查脚本的Shell兼容性
shellcheck .claude/hooks/block-dangerous.sh
问题3:格式化循环
如果Prettier或ESLint的修改触发了新的Write/Edit事件,可能导致循环。解决方案:
#!/bin/bash
# .claude/hooks/safe-format.sh
FILE="$CLAUDE_FILE_PATH"
# 防重复标记
MARKER=".claude/.formatting-$(echo "$FILE" | md5sum | cut -d' ' -f1)"
if [[ -f "$MARKER" ]]; then
rm "$MARKER"
exit 0
fi
touch "$MARKER"
npx prettier --write "$FILE" 2>/dev/null || true
为所有Hooks建立统一日志:
#!/bin/bash
# .claude/hooks/logger.sh —— 在每个Hook脚本中source此文件
LOG_FILE=".claude/hooks.log"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
log_hook() {
local level="$1"
local message="$2"
echo "[$TIMESTAMP] [$level] $message" >> "$LOG_FILE"
}
log_hook "INFO" "Hook executed: $0, Tool: $CLAUDE_TOOL_NAME, File: $CLAUDE_FILE_PATH"
在各个Hook脚本中使用:
#!/bin/bash
source .claude/hooks/logger.sh
log_hook "INFO" "Starting format check for $CLAUDE_FILE_PATH"
# ... 实际逻辑 ...
log_hook "INFO" "Format check completed"
project-root/
├── .claude/
│ ├── settings.json # Hooks配置入口
│ ├── hooks/
│ │ ├── README.md # Hooks说明文档
│ │ ├── block-dangerous.sh
│ │ ├── protect-files.sh
│ │ ├── smart-format.sh
│ │ ├── auto-test.sh
│ │ ├── notify.sh
│ │ └── logger.sh # 共享日志模块
│ └── hooks.log # 运行日志(gitignore)
├── .gitignore
└── ...
.gitignore中添加:
.claude/hooks.log
.claude/.formatting-*
将项目Hooks纳入版本控制,确保团队一致性:
# 初始化
git add .claude/settings.json .claude/hooks/
git commit -m "feat: add Claude Code hooks for project safety and automation"
团队成员拉取后自动生效,无需额外配置。
为Hooks编写测试,确保可靠性:
#!/bin/bash
# .claude/hooks/test-hooks.sh
set -e
PASS=0
FAIL=0
assert_exit_code() {
local test_name="$1"
local expected="$2"
local actual="$3"
if [[ "$actual" == "$expected" ]]; then
echo "✅ PASS: $test_name"
((PASS++))
else
echo "❌ FAIL: $test_name (expected=$expected, actual=$actual)"
((FAIL++))
fi
}
# 测试1:安全命令应通过
echo '{"command":"ls -la src/"}' | bash .claude/hooks/block-dangerous.sh
assert_exit_code "Safe command passes" "0" "$?"
# 测试2:rm -rf应被阻止
echo '{"command":"rm -rf /"}' | bash .claude/hooks/block-dangerous.sh
assert_exit_code "rm -rf blocked" "2" "$?"
# 测试3:DROP TABLE应被阻止
echo '{"command":"echo \"DROP TABLE users;\""}' | bash .claude/hooks/block-dangerous.sh
assert_exit_code "DROP TABLE blocked" "2" "$?"
# 测试4:保护.env文件
echo '{"file_path":"./.env"}' | bash .claude/hooks/protect-files.sh
assert_exit_code ".env protected" "2" "$?"
# 测试5:普通文件可编辑
echo '{"file_path":"./src/app.ts"}' | bash .claude/hooks/protect-files.sh
assert_exit_code "Normal file allowed" "0" "$?"
echo ""
echo "═══════════════════════════"
echo " Results: $PASS passed, $FAIL failed"
echo "═══════════════════════════"
[[ $FAIL -eq 0 ]] || exit 1
运行测试:
bash .claude/hooks/test-hooks.sh
预期输出:
✅ PASS: Safe command passes
✅ PASS: rm -rf blocked
✅ PASS: DROP TABLE blocked
✅ PASS: .env protected
✅ PASS: Normal file allowed
═══════════════════════════
Results: 5 passed, 0 failed
═══════════════════════════
一个React + Node.js + PostgreSQL全栈项目,需要: 1. 自动格式化(Prettier + ESLint) 2. 安全防护(阻止危险命令、保护敏感文件) 3. 编辑后自动测试 4. Git分支规范注入 5. 任务完成通知
.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/block-dangerous.sh"
},
{
"type": "prompt",
"prompt": "本项目使用pnpm,不要使用npm或yarn。Docker命令需加--user $(id -u):$(id -g)。"
}
]
},
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/protect-files.sh"
},
{
"type": "prompt",
"prompt": "编码规范:TypeScript严格模式,React函数式组件,Zustand状态管理,Tailwind CSS。每个组件不超过200行,函数不超过30行。"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/smart-format.sh"
},
{
"type": "command",
"command": "bash .claude/hooks/auto-test.sh"
},
{
"type": "command",
"command": "bash .claude/hooks/auto-git.sh"
}
]
}
],
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/notify.sh"
}
]
}
]
}
}
flowchart TB
A[Claude Code 会话启动] --> B{工具调用?}
B -->|Bash命令| C[PreToolUse: Bash]
C --> C1[安全检查脚本]
C --> C2[pnpm规范提示]
C1 -->|exit 0| D[执行Bash命令]
C1 -->|exit 2 阻止| E[返回错误给Claude]
B -->|Write/Edit文件| F[PreToolUse: Write/Edit]
F --> F1[敏感文件保护检查]
F --> F2[编码规范注入]
F1 -->|exit 0| G[执行文件编辑]
F1 -->|exit 2 阻止| E
D --> H[PostToolUse]
G --> H
H --> H1[智能格式化]
H1 --> H2[自动运行测试]
H2 --> H3[自动Git暂存]
H3 --> I[Claude继续响应]
I --> J{会话结束?}
J -->|是| K[Notification Hook]
K --> K1[发送桌面通知]
K --> L[会话结束]
J -->|否| B
style C1 fill:#ff6b6b,color:#fff
style F1 fill:#ff6b6b,color:#fff
style E fill:#ffd93d,color:#333
style K1 fill:#6bcb77,color:#fff
部署前逐项验证:
# 1. JSON格式检查
jq . .claude/settings.json && echo "✅ JSON valid"
# 2. 所有脚本可执行
for f in .claude/hooks/*.sh; do
test -x "$f" && echo "✅ $f" || echo "❌ $f (chmod +x needed)"
done
# 3. 依赖检查
command -v jq >/dev/null && echo "✅ jq" || echo "❌ jq missing"
command -v npx >/dev/null && echo "✅ npx" || echo "❌ npx missing"
# 4. 运行Hooks测试
bash .claude/hooks/test-hooks.sh
# 5. 端到端验证
echo "启动Claude Code并执行以下测试:"
echo " a) 让Claude编辑一个.ts文件 → 应自动格式化"
echo " b) 让Claude运行'rm -rf /' → 应被阻止"
echo " c) 让Claude编辑.env → 应被保护"
| 原则 | 说明 |
|---|---|
| 快速执行 | Hook应<500ms完成,避免阻塞Claude |
| 异步非阻塞 | 耗时操作(测试、通知)考虑后台执行 |
| 失败优雅 | 用\|\| true确保Hook失败不中断主流程 |
| 条件判断前置 | 先检查文件类型再执行具体操作 |
对于耗时操作(运行完整测试套件、发送通知),使用后台执行:
#!/bin/bash
# .claude/hooks/async-test.sh
FILE="$CLAUDE_FILE_PATH"
# 快速检查是否有对应测试
if [[ "$FILE" != *.ts ]] && [[ "$FILE" != *.tsx ]]; then
exit 0
fi
TEST_FILE="${FILE%.ts}.test.ts"
[[ ! -f "$TEST_FILE" ]] && TEST_FILE="${FILE%.ts}.spec.ts"
[[ ! -f "$TEST_FILE" ]] && exit 0
# 后台运行测试,结果写入日志
(
RESULT=$(npx vitest run "$TEST_FILE" 2>&1)
echo "[$(date)] Test $TEST_FILE: $RESULT" >> .claude/hooks/test-results.log
) &
# 立即返回,不阻塞Claude
exit 0
┌──────────────────────────────────────┐
│ 企业级(管理员配置) │ ← 安全策略、合规要求
│ 所有项目强制执行 │
├──────────────────────────────────────┤
│ 用户级(~/.claude/settings.json)│ ← 个人偏好(主题、通知)
│ 跨项目统一 │
├──────────────────────────────────────┤
│ 项目级(.claude/settings.json) │ ← 项目特定规则
│ 团队共享,进入版本控制 │
└──────────────────────────────────────┘
建议分配: - 企业级:阻止危险命令、保护敏感文件(强制) - 用户级:个人通知偏好、个人格式化工具 - 项目级:项目特定格式化规则、测试策略、编码规范注入
Hooks和CLAUDE.md各有分工,理解它们的关系能更好地组织项目规范:
| 维度 | CLAUDE.md | Hooks |
|---|---|---|
| 本质 | AI读取的文本指令 | 系统执行的代码/脚本 |
| 确定性 | AI可能忽略 | 100%执行 |
| 适用场景 | 编码风格、架构决策 | 安全防护、自动化流程 |
| 可维护性 | Markdown,易读 | Shell脚本,需测试 |
| 执行时机 | 会话启动时加载 | 每次工具调用时触发 |
最佳实践: - CLAUDE.md:记录"应该做什么"(编码规范、架构说明) - Hooks:执行"必须做什么"(安全检查、自动格式化) - 两者互补:CLAUDE.md告诉AI项目背景,Hooks确保AI不犯低级错误
训练营适用性评估:
| 训练营类型 | 适用性 | 预计时长 | 说明 |
|---|---|---|---|
| Claude Code初级营 | ⭐⭐ | 2小时 | 建议只讲第1-3章(概念+第一个Hook) |
| Claude Code进阶营 | ⭐⭐⭐⭐⭐ | 4-6小时 | 全部章节,重点第4-7章 |
| 企业AI工程化营 | ⭐⭐⭐⭐⭐ | 6-8小时 | 全部章节+团队协作+CI/CD集成 |
| DevOps自动化营 | ⭐⭐⭐⭐ | 3-4小时 | 重点第6、8、9章 |
| 安全工程营 | ⭐⭐⭐ | 2-3小时 | 重点第4、8章(安全防护+测试框架) |
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
