第 03 期 | Hooks 深度解析 — Caveman 的自动激活引擎
💡 进群学习加 wx: agentupdate
(申请发送: agentupdate)
(申请发送: agentupdate)
🎯 学习目标
学完本期你将掌握:
- Claude Code Hooks 的四个生命周期事件
- Caveman 三个 Hook 文件各自的职责与触发时机
- Flag File (
~/.claude/.caveman-active) 的桥接原理 - 如何自定义和扩展 Hook 配置
- 三大平台的 Hook 机制对比
📖 核心概念:Claude Code Hooks 机制
3.1 什么是 Hook?
Hook (钩子) 是 Claude Code 提供的 确定性回调机制。与 CLAUDE.md 中的指令不同(那只是"建议"),Hook 是 保证执行 的 Shell 命令或脚本。
graph LR
subgraph Comparison["指令 vs Hook"]
direction TB
A["📝 CLAUDE.md 指令
──────────────
• 建议性的
• Agent 可能忽略
• 无法保证执行"]
B["⚡ Hook 脚本
──────────────
• 确定性的
• 100% 会执行
• 独立于 Agent 的意志"]
end
A -.->|"可能被忽略"| C["Agent 行为"]
B -->|"必定执行"| C3.2 四个生命周期事件
Claude Code 的 Hook 系统提供了四个挂载点:
sequenceDiagram
participant U as 用户
participant CC as Claude Code
participant H as Hook 系统
Note over CC: 🟢 SessionStart
CC->>H: 触发 SessionStart hooks
H-->>CC: 注入启动上下文
loop 每次用户输入
U->>CC: 输入 prompt
Note over CC: 📝 UserPromptSubmit
CC->>H: 触发 UserPromptSubmit hooks
loop 每次工具调用
Note over CC: 🔧 PreToolUse
CC->>H: 触发 PreToolUse hooks
CC->>CC: 执行工具 (Read/Write/Bash...)
Note over CC: ✅ PostToolUse
CC->>H: 触发 PostToolUse hooks
end
CC->>U: 返回回答
end| 事件 | 触发时机 | 典型用途 |
|---|---|---|
SessionStart |
会话启动时 (仅一次) | 注入全局规则、初始化状态 |
UserPromptSubmit |
每次用户发送消息 | 检测命令、记录日志 |
PreToolUse |
工具调用前 | 安全检查、权限拦截 |
PostToolUse |
工具调用后 | 日志记录、自动格式化 |
📖 Caveman 的三个 Hook 文件
3.3 caveman-activate.js — SessionStart Hook
这是 Caveman 的"启动引擎"。每次 Claude Code 会话启动时自动执行。
职责:
- 写入
full到 Flag File~/.claude/.caveman-active - 将 Caveman 压缩规则作为隐藏上下文注入 (stdout → 系统上下文)
- 检测是否有自定义 statusLine,若无则发出配置建议
工作原理简述:
// caveman-activate.js 核心逻辑 (简化版)
const fs = require('fs');
const path = require('path');
// 1. 写入 flag file,标记 Caveman 已激活
const flagPath = path.join(process.env.HOME, '.claude', '.caveman-active');
fs.writeFileSync(flagPath, 'full');
// 2. 输出规则到 stdout (Claude Code 会将其作为隐藏系统上下文)
console.log(`
Terse like caveman. Technical substance exact. Only fluff die.
Drop: articles, filler (just/really/basically), pleasantries, hedging.
Fragments OK. Short synonyms. Code unchanged.
Pattern: [thing] [action] [reason]. [next step].
ACTIVE EVERY RESPONSE. No revert after many turns.
`);
// 3. 检查 statusLine 配置
const settingsPath = path.join(process.env.HOME, '.claude', 'settings.json');
if (fs.existsSync(settingsPath)) {
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
if (!settings.statusLine) {
console.log('[CAVEMAN] No statusLine configured. Say "setup caveman badge" to add it.');
}
}
💡 关键细节: SessionStart Hook 的 stdout 输出会被注入为隐藏系统上下文——Claude 能看到它,但用户看不到。这是 Caveman 能"无声激活"的关键。
3.4 caveman-mode-tracker.js — UserPromptSubmit Hook
这是 Caveman 的"模式跟踪器"。每次用户发送消息时都会执行。
职责:
- 检测用户消息是否包含
/caveman命令 - 解析命令参数,将新模式写入 Flag File
支持的模式:
/caveman → 写入 "full"
/caveman lite → 写入 "lite"
/caveman ultra → 写入 "ultra"
/caveman wenyan → 写入 "wenyan"
/caveman wenyan-lite → 写入 "wenyan-lite"
/caveman wenyan-ultra → 写入 "wenyan-ultra"
/caveman-commit → 写入 "commit"
/caveman-review → 写入 "review"
/caveman:compress → 写入 "compress"
核心逻辑:
// caveman-mode-tracker.js 核心逻辑 (简化版)
const fs = require('fs');
const path = require('path');
// 从 stdin 读取用户的消息
const userPrompt = process.argv[2] || '';
const flagPath = path.join(process.env.HOME, '.claude', '.caveman-active');
// 检测 /caveman 命令并更新 flag file
const match = userPrompt.match(/^\/(caveman(?:-\w+)?)\s*(\w*)/);
if (match) {
const command = match[1]; // "caveman" or "caveman-commit" etc.
const level = match[2]; // "lite", "ultra", "wenyan", etc.
let mode = 'full';
if (command === 'caveman-commit') mode = 'commit';
else if (command === 'caveman-review') mode = 'review';
else if (command === 'caveman:compress') mode = 'compress';
else if (level) mode = level;
fs.writeFileSync(flagPath, mode);
}
3.5 caveman-statusline.sh — 状态栏脚本
这是 Caveman 的"仪表盘"。它不是 Hook,而是一个被 Claude Code 的 statusLine 配置调用的独立脚本。
职责:
- 读取 Flag File 中的当前模式
- 输出带有 ANSI 颜色的徽章文本
#!/bin/bash
# caveman-statusline.sh
caveman_flag="$HOME/.claude/.caveman-active"
if [ -f "$caveman_flag" ]; then
mode=$(cat "$caveman_flag" 2>/dev/null)
if [ "$mode" = "full" ] || [ -z "$mode" ]; then
# 橙色 [CAVEMAN] 徽章
echo -e '\033[38;5;172m[CAVEMAN]\033[0m'
else
suffix=$(echo "$mode" | tr '[:lower:]' '[:upper:]')
# 橙色 [CAVEMAN:ULTRA] 等徽章
echo -e '\033[38;5;172m[CAVEMAN:'"${suffix}"']\033[0m'
fi
fi
徽章示例:
| 命令 | 状态栏显示 |
|---|---|
/caveman |
[CAVEMAN] |
/caveman ultra |
[CAVEMAN:ULTRA] |
/caveman wenyan |
[CAVEMAN:WENYAN] |
/caveman-commit |
[CAVEMAN:COMMIT] |
/caveman-review |
[CAVEMAN:REVIEW] |
📖 Flag File 桥接机制
三个 Hook 组件通过一个简单的文本文件协调状态:
graph LR
A["SessionStart Hook
caveman-activate.js"] -->|"写入 'full'"| F["~/.claude/.caveman-active"]
B["UserPromptSubmit Hook
caveman-mode-tracker.js"] -->|"写入新模式"| F
F -->|"读取模式"| C["Statusline Script
caveman-statusline.sh"]
C --> D["显示在状态栏
[CAVEMAN:ULTRA]"]
style F fill:#FFD700,stroke:#B8860B,color:#000这是一个经典的 文件即协议 设计模式:
- 没有进程间通信 (IPC)
- 没有 Socket 或 HTTP
- 只有一个纯文本文件
- 简单、可靠、零依赖
📖 手动配置 settings.json
如果你需要手动配置 Hook(而不是通过 Plugin 自动安装),需要编辑 ~/.claude/settings.json:
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"command": "node /path/to/caveman-activate.js"
}
],
"UserPromptSubmit": [
{
"matcher": "",
"command": "node /path/to/caveman-mode-tracker.js \"$PROMPT\""
}
]
},
"statusLine": {
"type": "command",
"command": "bash /path/to/caveman-statusline.sh"
}
}
⚠️ 将
/path/to/替换为实际路径。Plugin 安装时会自动处理路径。
如果你已有自定义 statusLine 脚本,将以下代码合并到你现有的脚本中:
# 在你的自定义 statusline 脚本中添加
caveman_text=""
caveman_flag="$HOME/.claude/.caveman-active"
if [ -f "$caveman_flag" ]; then
caveman_mode=$(cat "$caveman_flag" 2>/dev/null)
if [ "$caveman_mode" = "full" ] || [ -z "$caveman_mode" ]; then
caveman_text=$'\033[38;5;172m[CAVEMAN]\033[0m'
else
caveman_suffix=$(echo "$caveman_mode" | tr '[:lower:]' '[:upper:]')
caveman_text=$'\033[38;5;172m[CAVEMAN:'"${caveman_suffix}"$']\033[0m'
fi
fi
# 将 $caveman_text 追加到你的状态栏输出中
echo "$your_existing_status $caveman_text"
📊 三大平台 Hook 能力对比
| Hook 能力 | Claude Code | Antigravity | Gemini CLI |
|---|---|---|---|
| SessionStart | ✅ 原生支持 | ❌ 无 Hook 系统 | ⚠️ 通过 GEMINI.md 模拟 |
| UserPromptSubmit | ✅ 原生支持 | ❌ 不支持 | ❌ 不支持 |
| PreToolUse | ✅ 原生支持 | ❌ 不支持 | ❌ 不支持 |
| PostToolUse | ✅ 原生支持 | ❌ 不支持 | ❌ 不支持 |
| Flag File 状态追踪 | ✅ 完整支持 | ❌ 无需 (无 Hook) | ❌ 无需 |
| Statusline 徽章 | ✅ 原生支持 | ❌ 不支持 | ❌ 不支持 |
| 自动激活方式 | Hook → stdout 注入 | GEMINI.md 规则文件 | GEMINI.md 上下文文件 |
| 模式切换方式 | Hook 拦截 /caveman | 自然语言 | /caveman 命令 |
💡 结论: Claude Code 拥有最完善的 Hook 生态系统,这也是 Caveman 最初为它而设计的原因。Antigravity 和 Gemini CLI 虽无 Hook,但通过规则文件和上下文注入也能实现核心功能。
📝 本期要点回顾
- Hook ≠ 建议:Hook 是确定性执行的脚本,CLAUDE.md 是建议性指令
- Caveman 使用三个 Hook 协作:activate(启动注入) + mode-tracker(模式切换) + statusline(状态显示)
- Flag File (
~/.claude/.caveman-active) 是三者间的桥梁,存储当前模式 - SessionStart Hook 的 stdout 会作为隐藏系统上下文注入——用户看不到但 Claude 能看到
- Antigravity 和 Gemini CLI 无 Hook 系统,通过规则文件实现等效功能