主题
Gemini CLI 钩子
钩子是 Gemini CLI 在代理循环的特定点执行的脚本或程序,允许你在不修改 CLI 源代码的情况下拦截和自定义行为。
参见编写钩子指南获取创建第一个钩子的教程和完整示例。
参见钩子参考获取 I/O 模式的技术规范。
参见最佳实践获取安全、性能和调试指南。
什么是钩子?
使用钩子,你可以:
- 添加上下文: 在模型处理请求之前注入相关信息
- 验证操作: 审查并阻止潜在危险的操作
- 执行策略: 实施安全和合规要求
- 记录交互: 跟踪工具使用和模型响应
- 优化行为: 动态调整工具选择或模型参数
钩子作为代理循环的一部分同步运行——当钩子事件触发时,Gemini CLI 会等待所有匹配的钩子完成后再继续。
核心概念
钩子事件
钩子由 Gemini CLI 生命周期中的特定事件触发。下表列出了所有可用的钩子事件:
| 事件 | 触发时机 | 常见用例 |
|---|---|---|
SessionStart | 会话开始时 | 初始化资源、加载上下文 |
SessionEnd | 会话结束时 | 清理、保存状态 |
BeforeAgent | 用户提交提示后、规划前 | 添加上下文、验证提示 |
AfterAgent | 代理循环结束时 | 审查输出、强制继续 |
BeforeModel | 发送请求到 LLM 之前 | 修改提示、添加指令 |
AfterModel | 收到 LLM 响应后 | 过滤响应、记录交互 |
BeforeToolSelection | LLM 选择工具之前(在 BeforeModel 之后) | 过滤可用工具、优化选择 |
BeforeTool | 工具执行之前 | 验证参数、阻止危险操作 |
AfterTool | 工具执行之后 | 处理结果、运行测试 |
PreCompress | 上下文压缩之前 | 保存状态、通知用户 |
Notification | 通知发生时(如权限请求) | 自动批准、记录决策 |
钩子类型
Gemini CLI 目前支持运行 shell 命令或脚本的命令钩子:
json
{
"type": "command",
"command": "$GEMINI_PROJECT_DIR/.gemini/hooks/my-hook.sh",
"timeout": 30000
}注意: 插件钩子(npm 包)计划在未来版本中发布。
匹配器
对于工具相关事件(BeforeTool、AfterTool),你可以过滤哪些工具触发钩子:
json
{
"hooks": {
"BeforeTool": [
{
"matcher": "write_file|replace",
"hooks": [
/* 写操作的钩子 */
]
}
]
}
}匹配器模式:
- 精确匹配:
"read_file"只匹配read_file - 正则表达式:
"write_.*|replace"匹配write_file、replace - 通配符:
"*"或""匹配所有工具
会话事件匹配器:
- SessionStart:
startup、resume、clear - SessionEnd:
exit、clear、logout、prompt_input_exit - PreCompress:
manual、auto - Notification:
ToolPermission
钩子输入/输出契约
命令钩子通信
钩子通过以下方式通信:
- 输入: stdin 上的 JSON
- 输出: 退出码 + stdout/stderr
退出码
- 0: 成功 - stdout 显示给用户(或对某些事件注入为上下文)
- 2: 阻塞错误 - stderr 显示给代理/用户,操作可能被阻止
- 其他: 非阻塞警告 - 记录但继续执行
通用输入字段
每个钩子都会收到这些基本字段:
json
{
"session_id": "abc123",
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/path/to/project",
"hook_event_name": "BeforeTool",
"timestamp": "2025-12-01T10:30:00Z"
// ... 事件特定字段
}事件特定字段
BeforeTool
输入:
json
{
"tool_name": "write_file",
"tool_input": {
"file_path": "/path/to/file.ts",
"content": "..."
}
}输出(stdout 上的 JSON):
json
{
"decision": "allow|deny|ask|block",
"reason": "显示给代理的解释",
"systemMessage": "显示给用户的消息"
}或简单的退出码:
- 退出 0 = 允许(stdout 显示给用户)
- 退出 2 = 拒绝(stderr 显示给代理)
AfterTool
输入:
json
{
"tool_name": "read_file",
"tool_input": { "file_path": "..." },
"tool_response": "文件内容..."
}输出:
json
{
"decision": "allow|deny",
"hookSpecificOutput": {
"hookEventName": "AfterTool",
"additionalContext": "给代理的额外上下文"
}
}BeforeAgent
输入:
json
{
"prompt": "修复认证 bug"
}输出:
json
{
"decision": "allow|deny",
"hookSpecificOutput": {
"hookEventName": "BeforeAgent",
"additionalContext": "最近的项目决策:..."
}
}BeforeModel
输入:
json
{
"llm_request": {
"model": "gemini-2.0-flash-exp",
"messages": [{ "role": "user", "content": "你好" }],
"config": { "temperature": 0.7 },
"toolConfig": {
"functionCallingConfig": {
"mode": "AUTO",
"allowedFunctionNames": ["read_file", "write_file"]
}
}
}
}输出:
json
{
"decision": "allow",
"hookSpecificOutput": {
"hookEventName": "BeforeModel",
"llm_request": {
"messages": [
{ "role": "system", "content": "额外指令..." },
{ "role": "user", "content": "你好" }
]
}
}
}AfterModel
输入:
json
{
"llm_request": {
"model": "gemini-2.0-flash-exp",
"messages": [
/* ... */
],
"config": {
/* ... */
},
"toolConfig": {
/* ... */
}
},
"llm_response": {
"text": "string",
"candidates": [
{
"content": {
"role": "model",
"parts": ["内容部分数组"]
},
"finishReason": "STOP"
}
]
}
}输出:
json
{
"hookSpecificOutput": {
"hookEventName": "AfterModel",
"llm_response": {
"candidate": {
/* 修改后的响应 */
}
}
}
}BeforeToolSelection
输入:
json
{
"llm_request": {
"model": "gemini-2.0-flash-exp",
"messages": [
/* ... */
],
"toolConfig": {
"functionCallingConfig": {
"mode": "AUTO",
"allowedFunctionNames": [
/* 100+ 工具 */
]
}
}
}
}输出:
json
{
"hookSpecificOutput": {
"hookEventName": "BeforeToolSelection",
"toolConfig": {
"functionCallingConfig": {
"mode": "ANY",
"allowedFunctionNames": ["read_file", "write_file", "replace"]
}
}
}
}或简单输出(逗号分隔的工具名称将模式设置为 ANY):
bash
echo "read_file,write_file,replace"SessionStart
输入:
json
{
"source": "startup|resume|clear"
}输出:
json
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "已加载 5 个项目记忆"
}
}SessionEnd
输入:
json
{
"reason": "exit|clear|logout|prompt_input_exit|other"
}不期望结构化输出(但 stdout/stderr 会被记录)。
PreCompress
输入:
json
{
"trigger": "manual|auto"
}输出:
json
{
"systemMessage": "压缩开始..."
}Notification
输入:
json
{
"notification_type": "ToolPermission",
"message": "string",
"details": {
/* 通知详情 */
}
}输出:
json
{
"systemMessage": "通知已记录"
}配置
钩子定义在 settings.json 文件中使用 hooks 对象配置。配置可以在多个级别指定,具有定义的优先级规则。
配置层级
钩子配置按以下执行顺序应用(数字越小越先运行):
- 项目设置: 项目目录中的
.gemini/settings.json(最高优先级) - 用户设置:
~/.gemini/settings.json - 系统设置:
/etc/gemini-cli/settings.json - 扩展: 已安装扩展定义的内部钩子(最低优先级)
去重和覆盖
如果在不同配置层级发现具有相同名称和命令的多个钩子,Gemini CLI 会对它们进行去重。来自更高优先级层级(如项目)的钩子将被保留,其他的将被忽略。
在每个级别内,钩子按配置中声明的顺序运行。
配置模式
json
{
"hooks": {
"EventName": [
{
"matcher": "pattern",
"hooks": [
{
"name": "hook-identifier",
"type": "command",
"command": "./path/to/script.sh",
"description": "这个钩子做什么",
"timeout": 30000
}
]
}
]
}
}配置属性:
name(字符串,推荐):钩子的唯一标识符,用于/hooks enable/disable命令。如果省略,将使用command路径作为标识符。type(字符串,必需):钩子类型 - 目前只支持"command"command(字符串,必需):要执行的脚本或命令的路径description(字符串,可选):在/hooks panel中显示的人类可读描述timeout(数字,可选):超时时间(毫秒)(默认:60000)matcher(字符串,可选):过滤钩子何时运行的模式(仅事件匹配器)
环境变量
钩子可以访问:
GEMINI_PROJECT_DIR:项目根目录GEMINI_SESSION_ID:当前会话 IDGEMINI_API_KEY:Gemini API 密钥(如果已配置)- 父进程的所有其他环境变量
管理钩子
查看已注册的钩子
使用 /hooks panel 命令查看所有已注册的钩子:
bash
/hooks panel此命令显示:
- 按事件组织的所有活动钩子
- 钩子来源(用户、项目、系统)
- 钩子类型(命令或插件)
- 执行状态和最近输出
启用和禁用钩子
你可以使用命令临时启用或禁用单个钩子:
bash
/hooks enable hook-name
/hooks disable hook-name这些命令允许你在不编辑配置文件的情况下控制钩子执行。钩子名称应与钩子配置中的 name 字段匹配。通过这些命令所做的更改会持久化到你的全局用户设置(~/.gemini/settings.json)。
禁用钩子配置
要永久禁用钩子,将它们添加到 settings.json 中的 hooks.disabled 数组:
json
{
"hooks": {
"disabled": ["secret-scanner", "auto-test"]
}
}注意: hooks.disabled 数组使用 UNION 合并策略。来自所有配置级别(用户、项目、系统)的禁用钩子会被合并和去重,这意味着在任何级别禁用的钩子都会保持禁用状态。
从 Claude Code 迁移
如果你有为 Claude Code 配置的钩子,可以迁移它们:
bash
gemini hooks migrate --from-claude此命令:
- 读取
.claude/settings.json - 转换事件名称(
PreToolUse→BeforeTool等) - 翻译工具名称(
Bash→run_shell_command、replace→replace) - 更新匹配器模式
- 写入
.gemini/settings.json
事件名称映射
| Claude Code | Gemini CLI |
|---|---|
PreToolUse | BeforeTool |
PostToolUse | AfterTool |
UserPromptSubmit | BeforeAgent |
Stop | AfterAgent |
Notification | Notification |
SessionStart | SessionStart |
SessionEnd | SessionEnd |
PreCompact | PreCompress |
工具名称映射
| Claude Code | Gemini CLI |
|---|---|
Bash | run_shell_command |
Edit | replace |
Read | read_file |
Write | write_file |
Glob | glob |
Grep | search_file_content |
LS | list_directory |
工具和事件匹配器参考
匹配器可用的工具名称
以下内置工具可用于 BeforeTool 和 AfterTool 钩子匹配器:
文件操作
read_file- 读取单个文件read_many_files- 一次读取多个文件write_file- 创建或覆盖文件replace- 使用查找/替换编辑文件内容
文件系统
list_directory- 列出目录内容glob- 查找匹配模式的文件search_file_content- 在文件内容中搜索
执行
run_shell_command- 执行 shell 命令
Web 和外部
google_web_search- 带 grounding 的 Google 搜索web_fetch- 获取网页内容
代理功能
write_todos- 管理 TODO 项目save_memory- 将信息保存到记忆delegate_to_agent- 将任务委托给子代理
示例匹配器
json
{
"matcher": "write_file|replace" // 文件编辑工具
}json
{
"matcher": "read_.*" // 所有读取操作
}json
{
"matcher": "run_shell_command" // 仅 shell 命令
}json
{
"matcher": "*" // 所有工具
}事件特定匹配器
SessionStart 事件匹配器
startup- 全新会话启动resume- 恢复之前的会话clear- 会话已清除
SessionEnd 事件匹配器
exit- 正常退出clear- 会话已清除logout- 用户已登出prompt_input_exit- 从提示输入退出other- 其他原因
PreCompress 事件匹配器
manual- 手动触发的压缩auto- 自动触发的压缩
Notification 事件匹配器
ToolPermission- 工具权限通知