Claude Code Hooks 完全指南:打造自动化工作流与飞书通知集成
- Claude Code Hooks 完全指南:打造自动化工作流与飞书通知集成
Claude Code Hooks 完全指南:打造自动化工作流与飞书通知集成
🚀 本文将带你深入了解 Claude Code 的 Hook 机制,通过一个完整的飞书通知集成案例,教你如何打造属于自己的自动化工作流。
📖 目录
什么是 Claude Code Hooks
Claude Code Hooks 是一种事件驱动的自动化机制,它允许你在特定事件发生时自动执行自定义脚本或命令。这个机制类似于 Git Hooks,但专门为 AI 编程助手场景设计。
🎯 核心价值
- 📝 自动化记录:自动保存每次提问和回答,构建个人知识库
- 📢 实时通知:任务完成后自动推送通知到 Slack、飞书、钉钉等平台
- 🔄 流程自动化:触发测试、部署、备份等后续操作
- 📊 数据分析:统计使用频率、问题类型、响应时间等指标
- 🔗 工具集成:与现有工作流无缝对接
💡 应用场景
- 团队协作:任务完成后自动通知团队成员
- 项目管理:自动更新任务状态、记录工时
- 知识管理:构建问答历史库,便于回顾和分享
- 质量保证:代码生成后自动运行测试
- 合规审计:记录所有 AI 交互历史
Hook 类型详解
Claude Code 提供了丰富的 Hook 事件,覆盖整个交互生命周期:
Hook 名称 | 触发时机 | 典型用途 | 可用数据 |
---|---|---|---|
UserPromptSubmit |
用户提交问题时 | 保存提问、发送开始通知、初始化环境 | 用户输入文本、项目信息 |
Stop |
用户点击 Stop 或任务完成 | 发送完成通知、清理资源、生成报告 | 执行状态、耗时 |
ToolUse |
AI 调用工具时 | 记录工具使用、权限控制 | 工具名称、参数 |
ApiRequestStart |
API 请求开始时 | 计费预警、流量控制 | 请求内容、Token 数 |
ApiRequestFinish |
API 请求结束时 | 性能分析、错误追踪、成本统计 | 响应内容、耗时、费用 |
🔍 Hook 执行流程
graph LR
A[用户提问] --> B[UserPromptSubmit]
B --> C[Claude 处理]
C --> D{是否调用工具}
D -->|是| E[ToolUse]
E --> C
D -->|否| F[生成响应]
F --> G[用户操作]
G -->|点击Stop| H[Stop Hook]
G -->|继续对话| A
快速开始:配置你的第一个 Hook
Step 1: 找到配置文件
# macOS/Linux
~/.claude/settings.json
# Windows
%USERPROFILE%\.claude\settings.json
Step 2: 编写简单的 Hook
创建一个最简单的通知 Hook:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo 'Task completed!' | tee -a ~/.claude/tasks.log"
}
]
}
]
}
}
Step 3: 测试验证
- 重启 Claude Code(确保配置生效)
- 执行任意任务
- 点击 Stop 按钮
- 检查日志文件:
cat ~/.claude/tasks.log
恭喜!你已经成功配置了第一个 Hook 🎉
实战案例:飞书通知集成
让我们通过一个完整的案例,实现从用户提问到飞书通知的全流程自动化。
📐 系统架构
┌─────────────────────┐
│ 用户提交问题 │
└──────────┬──────────┘
│
▼
┌──────────────────────────────────┐
│ UserPromptSubmit Hook │
│ • 保存问题内容 │
│ • 记录时间戳 │
│ • 获取项目信息 │
└──────────┬───────────────────────┘
│
▼
┌─────────────────────┐
│ Claude 处理问题 │
│ • 理解需求 │
│ • 生成代码 │
│ • 执行操作 │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ 用户点击 Stop │
└──────────┬──────────┘
│
▼
┌──────────────────────────────────┐
│ Stop Hook │
│ • 读取保存的问题 │
│ • 构造通知内容 │
│ • 发送到飞书 │
│ • 记录发送日志 │
└──────────────────────────────────┘
│
▼
┌─────────────────────┐
│ 飞书收到通知 │
│ • 项目名称 │
│ • 问题内容 │
│ • 完成时间 │
└─────────────────────┘
Step 1: 配置 Hook 系统
编辑 ~/.claude/settings.json
:
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "bash -c 'cd /your/project/path && if [ -f .claude/scripts/save-prompt.sh ]; then bash .claude/scripts/save-prompt.sh; fi'"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "bash -c 'cd /your/project/path && if [ -f .claude/scripts/feishu-notify.sh ]; then bash .claude/scripts/feishu-notify.sh; fi'"
}
]
}
]
}
}
⚠️ 重要提示:请将
/your/project/path
替换为你的实际项目路径
Step 2: 创建问题保存脚本
创建 .claude/scripts/save-prompt.sh
:
#!/bin/bash
# ===========================================
# Claude Code UserPromptSubmit Hook
# 功能:保存用户提问,为后续通知提供数据
# ===========================================
set -e
# 配置
LOG_DIR="${HOME}/.claude/prompts"
TIMESTAMP=$(date '+%Y%m%d_%H%M%S')
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
PROJECT_NAME=$(basename "$PROJECT_DIR")
# 确保日志目录存在
mkdir -p "$LOG_DIR"
# 构造保存文件路径
PROMPT_FILE="${LOG_DIR}/${PROJECT_NAME}_${TIMESTAMP}.txt"
# 保存问题详情
{
echo "==================================="
echo "Time: $(date '+%Y-%m-%d %H:%M:%S')"
echo "Project: $PROJECT_NAME"
echo "Path: $PROJECT_DIR"
echo "Session: ${CLAUDE_SESSION_ID:-unknown}"
echo "==================================="
echo ""
cat # 从 stdin 读取用户输入
} > "$PROMPT_FILE"
# 记录操作日志
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Prompt saved: $PROMPT_FILE" >> "${HOME}/.claude/hook.log"
exit 0
Step 3: 创建飞书通知脚本
创建 .claude/scripts/feishu-notify.sh
:
#!/bin/bash
# ===========================================
# Claude Code Stop Hook - 飞书通知
# 功能:任务完成后发送飞书通知
# ===========================================
set -e
# 配置
LOG_FILE="${HOME}/.claude/feishu-notify.log"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
PROJECT_NAME=$(basename "$PROJECT_DIR")
# 飞书 Webhook URL(需要替换为你的实际 webhook)
FEISHU_WEBHOOK="${FEISHU_WEBHOOK_URL:-https://www.feishu.cn/flow/api/trigger-webhook/YOUR_TOKEN}"
# 日志记录函数
log() {
echo "[$TIMESTAMP] $1" >> "$LOG_FILE"
}
log "Stop hook triggered for project: $PROJECT_NAME"
# 获取最新的用户问题
PROMPT_DIR="${HOME}/.claude/prompts"
LATEST_PROMPT_FILE=$(ls -t "${PROMPT_DIR}/${PROJECT_NAME}"_*.txt 2>/dev/null | head -1)
if [ -f "$LATEST_PROMPT_FILE" ]; then
log "Found prompt file: $LATEST_PROMPT_FILE"
# 提取 JSON 数据
JSON_LINE=$(grep -E '^\{.*\}$' "$LATEST_PROMPT_FILE" 2>/dev/null || echo "{}")
# 使用合适的工具解析 JSON
if command -v jq &> /dev/null; then
# 优先使用 jq(最可靠)
USER_QUESTION=$(echo "$JSON_LINE" | jq -r '.prompt // "Claude Code 任务完成"' | \
sed 's/<[^>]*>//g' | head -c 200)
elif command -v python3 &> /dev/null; then
# 降级到 Python
USER_QUESTION=$(echo "$JSON_LINE" | python3 -c "
import sys, json
try:
data = json.load(sys.stdin)
print(data.get('prompt', 'Claude Code 任务完成')[:200])
except:
print('Claude Code 任务完成')
" | sed 's/<[^>]*>//g')
else
# 最后使用 sed(可能不够可靠)
USER_QUESTION="Claude Code 任务完成"
fi
else
log "No prompt file found, using default message"
USER_QUESTION="Claude Code 任务完成"
fi
# 构造飞书消息
if command -v jq &> /dev/null; then
# 使用 jq 构造 JSON(自动处理转义)
JSON_DATA=$(jq -n \
--arg project "$PROJECT_NAME" \
--arg time "$TIMESTAMP" \
--arg question "$USER_QUESTION" \
'{
msg_type: "text",
content: {
project_name: $project,
finish_time: $time,
question: $question
}
}')
else
# 手动构造 JSON(注意转义)
USER_QUESTION_ESCAPED=$(echo "$USER_QUESTION" | \
sed 's/\\/\\\\/g' | \
sed 's/"/\\"/g' | \
sed 's/\t/ /g' | \
tr -d '\n\r')
JSON_DATA=$(cat <<EOF
{
"msg_type": "text",
"content": {
"project_name": "${PROJECT_NAME}",
"finish_time": "${TIMESTAMP}",
"question": "${USER_QUESTION_ESCAPED}"
}
}
EOF
)
fi
log "Sending notification with data: $JSON_DATA"
# 发送飞书通知
if [ -n "$FEISHU_WEBHOOK" ] && [ "$FEISHU_WEBHOOK" != *"YOUR_TOKEN"* ]; then
RESPONSE=$(curl -s -X POST "$FEISHU_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "$JSON_DATA" 2>&1)
log "API Response: $RESPONSE"
# 检查响应
if echo "$RESPONSE" | grep -q "success\|ok\|200"; then
log "✅ Notification sent successfully"
echo "✅ 飞书通知已发送:$PROJECT_NAME - $USER_QUESTION"
else
log "⚠️ Notification may have failed: $RESPONSE"
echo "⚠️ 飞书通知可能失败,请检查日志:$LOG_FILE"
fi
else
log "❌ FEISHU_WEBHOOK not configured properly"
echo "❌ 请配置飞书 Webhook URL"
fi
exit 0
Step 4: 配置飞书工作流
- 创建工作流
- 登录飞书,进入「工作台」→「工作流」
- 点击「创建工作流」
- 选择「自定义触发器」
- 配置 Webhook 触发器
- 添加「Webhook」触发器
- 配置输入参数:
project_name (文本) - 项目名称 finish_time (文本) - 完成时间 question (文本) - 问题内容
- 设计通知流程
- 添加「发送消息」节点
- 配置消息模板:
🤖 Claude Code 任务完成通知 📁 项目: ❓ 问题: ⏰ 时间:
- 获取 Webhook URL
- 保存工作流
- 复制 Webhook URL
- 替换脚本中的
YOUR_TOKEN
Step 5: 设置权限和测试
# 设置执行权限
chmod +x .claude/scripts/save-prompt.sh
chmod +x .claude/scripts/feishu-notify.sh
# 测试保存功能
echo '{"prompt": "测试问题"}' | bash .claude/scripts/save-prompt.sh
# 测试通知功能
bash .claude/scripts/feishu-notify.sh
# 查看日志
tail -f ~/.claude/feishu-notify.log
🎯 效果展示
当你在 Claude Code 中完成任务后,飞书会收到这样的通知:
🤖 Claude Code 任务完成通知
📁 项目:my-awesome-project
❓ 问题:帮我实现一个 Redis 缓存管理器
⏰ 时间:2025-10-21 15:30:45
点击查看详情 →
调试与故障排查
🔍 常见问题与解决方案
问题 1:Hook 没有被触发
症状:配置了 Hook 但没有任何反应
排查步骤:
- 验证配置文件语法
# 使用 jq 验证 JSON 格式 cat ~/.claude/settings.json | jq .
- 检查脚本路径和权限
# 确认脚本存在 ls -la .claude/scripts/ # 确认有执行权限 chmod +x .claude/scripts/*.sh
- 启用调试日志
# 在脚本开头添加 set -x # 打印每条命令 exec 2>> ~/.claude/debug.log # 重定向错误输出
- 手动测试脚本
# 直接运行脚本测试 bash -x .claude/scripts/feishu-notify.sh
问题 2:环境变量为空
症状:CLAUDE_PROJECT_DIR
等环境变量获取不到值
解决方案:
# 使用绝对路径(推荐)
"command": "bash -c 'cd /absolute/path/to/project && bash .claude/scripts/hook.sh'"
# 或使用默认值
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
问题 3:JSON 格式错误
症状:飞书返回格式错误或无响应
解决方案:
- 验证 JSON 格式
echo "$JSON_DATA" | jq .
- 正确转义特殊字符
# 转义顺序很重要 TEXT=$(echo "$TEXT" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g')
- 使用工具构造 JSON
# 推荐:使用 jq JSON=$(jq -n --arg key "$value" '{key: $key}')
问题 4:通知发送失败
症状:脚本执行但飞书没收到通知
调试技巧:
# 1. 打印完整的 curl 命令
echo "curl -X POST '$WEBHOOK' -H 'Content-Type: application/json' -d '$JSON_DATA'" >> debug.log
# 2. 保存响应详情
RESPONSE=$(curl -v -X POST "$WEBHOOK" -d "$JSON_DATA" 2>&1)
echo "Full response: $RESPONSE" >> debug.log
# 3. 测试 Webhook 连通性
curl -X POST "$WEBHOOK" -d '{"msg_type":"text","content":{"text":"test"}}'
📊 调试检查清单
- 配置文件格式正确(JSON 语法)
- 脚本文件存在且有执行权限
- 路径使用绝对路径或正确的相对路径
- 环境变量正确获取或有默认值
- JSON 数据格式符合 API 要求
- Webhook URL 正确且未过期
- 网络连接正常(可以访问外部 API)
- 日志文件有写入权限
最佳实践
1. 📁 项目结构规范
your-project/
├── .claude/
│ ├── hooks.json # 项目级 Hook 配置
│ ├── scripts/ # Hook 脚本目录
│ │ ├── save-prompt.sh
│ │ ├── notify.sh
│ │ └── test.sh
│ └── logs/ # 日志目录
│ ├── prompts/
│ └── notifications/
2. 🔒 安全性建议
敏感信息管理:
# ❌ 不要硬编码
WEBHOOK="https://example.com/webhook/secret_token_123"
# ✅ 使用环境变量
WEBHOOK="${FEISHU_WEBHOOK_URL}"
# ✅ 或使用配置文件(添加到 .gitignore)
source ~/.claude/secrets.env
权限控制:
# 限制脚本权限
chmod 700 .claude/scripts/*.sh # 仅所有者可执行
# 限制日志权限
chmod 600 ~/.claude/logs/* # 仅所有者可读写
3. 🚀 性能优化
异步执行:
# 避免阻塞主流程
{
# 耗时操作
sleep 2
curl -X POST "$WEBHOOK" -d "$DATA"
} & # 后台执行
缓存机制:
# 缓存常用数据
CACHE_FILE="$HOME/.claude/cache/project_info.json"
if [ -f "$CACHE_FILE" ] && [ $(($(date +%s) - $(stat -f %m "$CACHE_FILE"))) -lt 3600 ]; then
# 使用缓存(1小时内)
PROJECT_INFO=$(cat "$CACHE_FILE")
else
# 重新获取并缓存
PROJECT_INFO=$(get_project_info)
echo "$PROJECT_INFO" > "$CACHE_FILE"
fi
4. 📝 日志管理
结构化日志:
# 统一日志格式
log() {
local level=$1
shift
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" >> "$LOG_FILE"
}
log INFO "Starting hook execution"
log ERROR "Failed to send notification: $error"
log DEBUG "JSON data: $JSON_DATA"
日志轮转:
# 自动清理旧日志
MAX_LOG_SIZE=10485760 # 10MB
if [ -f "$LOG_FILE" ] && [ $(stat -f %z "$LOG_FILE") -gt $MAX_LOG_SIZE ]; then
mv "$LOG_FILE" "${LOG_FILE}.$(date +%Y%m%d)"
gzip "${LOG_FILE}.$(date +%Y%m%d)"
fi
5. 🔄 错误恢复
重试机制:
# 自动重试
MAX_RETRIES=3
RETRY_DELAY=5
for i in $(seq 1 $MAX_RETRIES); do
if curl -X POST "$WEBHOOK" -d "$DATA"; then
log INFO "Notification sent successfully"
break
else
log WARN "Attempt $i failed, retrying in ${RETRY_DELAY}s..."
sleep $RETRY_DELAY
fi
done
降级处理:
# 主通道失败时使用备用通道
if ! send_to_feishu; then
log WARN "Feishu failed, trying email..."
send_email_notification
fi
进阶技巧
1. 🎯 智能路由
根据不同条件路由到不同处理器:
#!/bin/bash
# 根据项目类型选择通知渠道
case "$PROJECT_NAME" in
*-frontend)
notify_frontend_team
;;
*-backend)
notify_backend_team
;;
*-urgent)
notify_all_channels
;;
*)
notify_default_channel
;;
esac
# 根据时间选择通知级别
HOUR=$(date +%H)
if [ $HOUR -ge 22 ] || [ $HOUR -le 6 ]; then
# 夜间静默模式
log INFO "Night mode: notification saved for tomorrow"
queue_for_tomorrow
else
send_immediate_notification
fi
2. 📊 数据分析
收集和分析使用数据:
#!/bin/bash
# 记录使用统计
STATS_DB="$HOME/.claude/stats.db"
# 使用 SQLite 存储(如果可用)
if command -v sqlite3 &> /dev/null; then
sqlite3 "$STATS_DB" <<EOF
CREATE TABLE IF NOT EXISTS usage_stats (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
project TEXT,
question TEXT,
duration INTEGER,
tokens_used INTEGER
);
INSERT INTO usage_stats (project, question, duration, tokens_used)
VALUES ('$PROJECT_NAME', '$QUESTION', $DURATION, $TOKENS);
EOF
# 生成周报
if [ "$(date +%u)" -eq 1 ]; then # 周一
WEEKLY_STATS=$(sqlite3 "$STATS_DB" <<EOF
SELECT
COUNT(*) as total_queries,
AVG(duration) as avg_duration,
SUM(tokens_used) as total_tokens,
GROUP_CONCAT(DISTINCT project) as projects
FROM usage_stats
WHERE timestamp >= datetime('now', '-7 days');
EOF
)
send_weekly_report "$WEEKLY_STATS"
fi
fi
3. 🔗 工具链集成
与其他开发工具集成:
#!/bin/bash
# Git 集成
if [ -d .git ]; then
CURRENT_BRANCH=$(git branch --show-current)
LAST_COMMIT=$(git log -1 --pretty=format:"%h - %s")
# 自动提交 AI 生成的代码
if [ "$AUTO_COMMIT" = "true" ]; then
git add -A
git commit -m "AI: $USER_QUESTION"
log INFO "Auto-committed changes"
fi
fi
# Docker 集成
if [ -f docker-compose.yml ]; then
# 重新构建和部署
docker-compose down
docker-compose build
docker-compose up -d
log INFO "Docker services redeployed"
fi
# 测试集成
if [ -f package.json ]; then
npm test && log INFO "Tests passed" || log ERROR "Tests failed"
fi
4. 🤖 AI 增强
利用 AI 能力增强 Hook:
#!/bin/bash
# 使用 AI 分析问题类型
analyze_question() {
local question=$1
# 调用本地 LLM 或 API
local category=$(echo "$question" | \
curl -s -X POST "http://localhost:11434/api/generate" \
-d "{\"model\": \"llama2\", \"prompt\": \"Categorize: $question\"}" | \
jq -r .response)
echo "$category"
}
# 智能通知
CATEGORY=$(analyze_question "$USER_QUESTION")
case "$CATEGORY" in
"bug-fix")
notify_qa_team
create_jira_ticket
;;
"feature")
notify_product_team
update_roadmap
;;
"optimization")
run_benchmark
notify_if_improved
;;
esac
5. 🌍 多环境支持
支持开发、测试、生产环境:
#!/bin/bash
# 检测环境
detect_environment() {
if [ -f .env.production ]; then
echo "production"
elif [ -f .env.staging ]; then
echo "staging"
else
echo "development"
fi
}
ENV=$(detect_environment)
# 加载环境配置
source ".env.$ENV"
# 环境特定行为
case "$ENV" in
production)
WEBHOOK="$PROD_WEBHOOK"
NOTIFY_LEVEL="error"
AUTO_DEPLOY=false
;;
staging)
WEBHOOK="$STAGE_WEBHOOK"
NOTIFY_LEVEL="warning"
AUTO_DEPLOY=true
;;
development)
WEBHOOK="$DEV_WEBHOOK"
NOTIFY_LEVEL="debug"
AUTO_DEPLOY=false
;;
esac
log INFO "Running in $ENV environment"
总结
通过本文的学习,你已经掌握了 Claude Code Hooks 的核心概念和实战技巧:
✅ 你学到了什么
- 基础知识
- Hook 的工作原理和事件类型
- 配置文件的编写方法
- 脚本的基本结构
- 实战技能
- 完整的飞书通知集成方案
- JSON 数据的处理和转义
- 错误排查和调试方法
- 高级技巧
- 安全性和性能优化
- 多环境和多渠道支持
- 与其他工具的集成
🎯 下一步行动
- 立即尝试:从最简单的日志记录 Hook 开始
- 逐步完善:根据实际需求添加更多功能
- 分享经验:将你的 Hook 配置分享给团队
- 持续优化:根据使用反馈不断改进
💡 核心要点回顾
- 🔧 使用绝对路径避免环境变量问题
- 🛡️ 保护敏感信息,使用环境变量
- 📝 记录详细日志,便于调试
- 🔄 实现错误重试和降级机制
- 🚀 异步执行避免阻塞主流程
参考资源
💬 有问题或建议?欢迎在评论区交流!如果这篇文章对你有帮助,请分享给更多人 🚀