PreToolUse / PostToolUse / PostToolUseFailure)、会话与子代理(SessionStart / SessionEnd / Stop / SubagentStart / SubagentStop / StopFailure)、用户交互(UserPromptSubmit / Notification / PermissionRequest / PermissionDenied / Elicitation / ElicitationResult)、上下文(PreCompact / PostCompact / InstructionsLoaded / ConfigChange)、任务与团队(TaskCreated / TaskCompleted / TeammateIdle)、文件与环境(FileChanged / CwdChanged / WorktreeCreate / WorktreeRemove)以及启动/维护(Setup)。完整事件清单见插件参考的事件表。session_id、会话转录文件、当前工作目录等上下文信息。/hooks 面板进行图形化配置,所有外部修改需在面板审核后生效,保障安全。作用域 | 文件路径 | 说明 |
用户级 | ~/.codebuddy/settings.json | 适用于所有项目 |
项目级 | <项目根>/.codebuddy/settings.json | 对项目成员共享的配置 |
项目本地 | <项目根>/.codebuddy/settings.local.json | 本地未提交配置 |
企业策略 | 集成发布的策略文件 | 受企业统一管理 |
{"hooks": {"EventName": [{"matcher": "ToolPattern","hooks": [{"type": "command","command": "your-command-here"}]}]}}
Write 会匹配任何包含 "Write" 的工具名(如 Write、NotebookWrite)^Write$ 仅匹配 Write 工具Edit|Write 或 Web.** 字符"""command" 用于 shell 命令,或 "prompt" 用于基于 LLM 的评估"command")要执行的 shell 命令(可以使用 $CODEBUDDY_PROJECT_DIR 环境变量)。在 macOS/Linux 上使用用户默认 shell($SHELL)执行,在 Windows 上强制使用 Git Bash 执行(不支持 cmd.exe 或 PowerShell),因此命令需兼容 bash 语法"prompt")发送给 LLM 进行评估的提示词(仅支持 Stop、UserPromptSubmit、PreToolUse 事件){"hooks": {"UserPromptSubmit": [{"hooks": [{"type": "command","command": "python3 /path/to/prompt-validator.py"}]}]}}
CODEBUDDY_PROJECT_DIR(仅在 CodeBuddy Code 生成 hook 命令时可用)来引用存储在项目中的脚本:{"hooks": {"PostToolUse": [{"matcher": "Write|Edit","hooks": [{"type": "command","command": "\\"$CODEBUDDY_PROJECT_DIR\\"/.codebuddy/hooks/check-style.sh"}]}]}}
python3 来调用,而不是直接执行 .py 文件。因为在 Windows 上即使脚本包含 shebang 行(#!/usr/bin/env python3),Git Bash 也不一定能正确识别:"command": "python3 \\"$CODEBUDDY_PROJECT_DIR\\"/.codebuddy/hooks/my_hook.py"
hooks/hooks.json 文件中定义,或在 hooks 字段提供的自定义路径的文件中定义${CODEBUDDY_PLUGIN_ROOT} 环境变量来引用插件文件{"description": "Automatic code formatting","hooks": {"PostToolUse": [{"matcher": "Write|Edit","hooks": [{"type": "command","command": "${CODEBUDDY_PLUGIN_ROOT}/scripts/format.sh","timeout": 30}]}]}}
type: "command"),CodeBuddy Code 还支持基于提示词的 hooks(type: "prompt"),使用 LLM 来评估是否允许或阻止某个操作。Stop、UserPromptSubmit 和 PreToolUse 三种事件。/goal <condition> 即可让 CodeBuddy 持续工作直到条件满足,无需手写 hook 配置。如果您的判定逻辑可以靠条件文本表达,优先用 /goal;只有需要更复杂的 prompt 编排或跨多事件协作时才回到本节自己写 prompt hook。lite 槽位的小模型,按 model provider 分别映射)事件 | 用途 |
Stop | 智能决定 CodeBuddy 是否应继续工作 |
UserPromptSubmit | 使用 LLM 协助验证用户提示 |
PreToolUse | 做出上下文感知的权限决策 |
特性 | Command Hooks | Prompt Hooks |
执行方式 | 运行 bash 脚本 | 查询 LLM |
决策逻辑 | 您在代码中实现 | LLM 评估上下文 |
设置复杂性 | 需要脚本文件 | 只需配置提示词 |
上下文感知 | 受脚本逻辑限制 | 自然语言理解 |
性能 | 快速(本地执行) | 较慢(API 调用) |
适用场景 | 确定性规则 | 上下文感知决策 |
{"hooks": {"Stop": [{"hooks": [{"type": "prompt","prompt": "Evaluate if CodeBuddy should stop: $ARGUMENTS. Check if all tasks are complete."}]}]}}
"prompt"$ARGUMENTS 作为 hook 输入 JSON 的占位符,会被直接替换$ARGUMENTS,输入 JSON 会以 \\n\\nARGUMENTS:\\n{JSON} 格式追加到提示词末尾ok: false 时,是否让 Agent 继续工作而不是停止。设为 true 时行为类似 /goal:reason 会注入对话历史,Agent 继续循环直到条件满足。仅对 Stop/SubagentStop 事件有意义。默认为 false(Agent 停止){"ok": true | false,"reason": "Explanation for the decision", // 当 ok 为 false 时必需"impossible": false // 可选,仅 Stop 事件下生效}
ok:true 允许操作,false 阻止操作reason:当 ok 为 false 时必需,显示给 CodeBuddy 的解释impossible:可选布尔值,仅 Stop hook 下有意义。{ok: false, impossible: true} 表示评估器判断"在当前会话里这个目标根本不可能完成"(条件自相矛盾、依赖资源不可用、模型已穷尽合理尝试)。CodeBuddy 不再继续循环,UI 显示"无法达成"终态。普通 {ok: false} 仍按"未达成、继续工作"处理。Stop hook 返回 {ok: false} 时,reason 文本不是简单地"显示给 CodeBuddy",它会以 isMeta=true 的内部 user message 形式注入到对话 history 中,让主模型在下一轮看到评估器的视角,从而精准补做欠缺的部分。这是 prompt-based Stop hook 能驱动多轮迭代收敛的核心机制(/goal 命令底层就是依赖这条链路)。{"hooks": {"Stop": [{"hooks": [{"type": "prompt","prompt": "You are evaluating whether CodeBuddy should stop working. Context: $ARGUMENTS\\n\\nAnalyze the conversation and determine if:\\n1. All user-requested tasks are complete\\n2. Any errors need to be addressed\\n3. Follow-up work is needed\\n\\nRespond with JSON: {\\"ok\\": true} to allow stopping, or {\\"ok\\": false, \\"reason\\": \\"your explanation\\"} to continue working.","timeout": 30}]}]}}
continueOnBlock: true,prompt Stop hook 可以在条件不满足时驱动 Agent 继续工作,类似 /goal 的效果:{"hooks": {"Stop": [{"hooks": [{"type": "prompt","prompt": "Check if all tests pass and code is properly formatted. Context: $ARGUMENTS\\n\\nIf tests pass and code is clean, return {\\"ok\\": true}.\\nIf not, return {\\"ok\\": false, \\"reason\\": \\"describe what still needs to be fixed\\"}.","continueOnBlock": true,"timeout": 30}]}]}}
continueOnBlock 为 true 时:ok: true → Agent 正常停止ok: false → reason 注入对话历史,Agent 继续工作直到条件满足ok: false, impossible: true → Agent 停止,显示"目标不可达成"continueOnBlock 为 false(默认)时:ok: false → Agent 停止,不会继续循环{"hooks": {"UserPromptSubmit": [{"hooks": [{"type": "prompt","prompt": "Evaluate if this user prompt is safe and appropriate. Input: $ARGUMENTS\\n\\nCheck if:\\n- The prompt contains sensitive information (passwords, secrets)\\n- The request is clear and actionable\\n- Any security concerns exist\\n\\nReturn: {\\"ok\\": true} to allow, or {\\"ok\\": false, \\"reason\\": \\"explanation\\"} to block."}]}]}}
{"hooks": {"PreToolUse": [{"matcher": "Bash","hooks": [{"type": "prompt","prompt": "Evaluate if this bash command should be allowed. Input: $ARGUMENTS\\n\\nCheck if:\\n- The command is safe and non-destructive\\n- It doesn't access sensitive files or directories\\n- It aligns with the user's stated goals\\n\\nReturn: {\\"ok\\": true} to allow, or {\\"ok\\": false, \\"reason\\": \\"explanation\\"} to deny."}]}]}}
事件 | 触发时机 | matcher 字段 | 典型场景 |
PreToolUse | 工具执行前 | 支持(工具名) | 校验命令、二次审批、日志记录 |
PostToolUse | 工具成功执行后 | 支持 | 自动格式化、补充上下文、压缩/替换工具结果 |
Notification | 权限请求或 60 秒无输入提醒 | 部分支持 | 桌面提示、IM 通知 |
UserPromptSubmit | 用户提交消息时<br/>注:不包括内部命令 | 不支持 | 内容审查、上下文注入 |
Stop | 主代理响应结束时 | 不支持 | 要求继续执行、追加提醒 |
SubagentStop | 子代理(TaskTool)结束时 | 不支持 | 子任务继续执行或补充说明 |
PreCompact | 执行上下文压缩前 | 支持( manual/auto) | 保留关键信息、防止压缩 |
SessionStart | 会话创建或恢复时 | 支持( startup/resume/clear/compact) | 环境初始化、变量注入 |
SessionEnd | 会话结束时 | 支持( clear/logout/prompt_input_exit/other) | 清理资源、持久化日志 |
Task - 子代理任务Bash - Shell 命令Glob - 文件模式匹配Grep - 内容搜索Read - 文件读取Edit - 文件编辑Write - 文件写入WebFetch, WebSearch - Web 操作permission_prompt - 来自 CodeBuddy Code 的权限请求idle_prompt - 当 CodeBuddy 等待用户输入时(空闲时间超过 60 秒后)auth_success - 身份验证成功通知elicitation_dialog - 当 CodeBuddy Code 需要 MCP 工具引导的输入时(暂未支持){"hooks": {"Notification": [{"matcher": "permission_prompt","hooks": [{"type": "command","command": "/path/to/permission-alert.sh"}]},{"matcher": "idle_prompt","hooks": [{"type": "command","command": "/path/to/idle-notification.sh"}]}]}}
/goal <condition> 一行即可注册一个让 CodeBuddy 持续工作到条件满足为止的 Stop hook,并自动处理三态评估(达成 / 未达成继续 / 不可达成)、turn 计数、token 统计、/resume 自动恢复等细节。需要会话级"持续工作直到 X"时优先考虑 /goal,不必手写 hook 配置。manual - 从 /compact 调用auto - 从自动压缩调用(由于上下文窗口已满)startup - 从启动调用resume - 从 --resume、--continue 或 /resume 调用clear - 从 /clear 调用compact - 从自动或手动压缩调用clear - 使用 /clear 命令清除会话logout - 用户注销prompt_input_exit - 用户在提示词输入可见时退出other - 其他退出原因(包括正常退出){// 公共字段"session_id": "string","transcript_path": "string", // 对话 JSON 的路径"cwd": "string", // 调用 hook 时的当前工作目录"permission_mode": "string", // 当前权限模式: "default"、"plan"、"acceptEdits" 或 "bypassPermissions"// 事件特定字段"hook_event_name": "string"// ...}
{"session_id": "abc123","transcript_path": "/Users/.../.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl","cwd": "/Users/...","permission_mode": "default","hook_event_name": "PreToolUse","tool_name": "Write","tool_input": {"file_path": "/path/to/file.txt","content": "file content"}}
{"session_id": "abc123","transcript_path": "/Users/.../.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl","cwd": "/Users/...","permission_mode": "default","hook_event_name": "PostToolUse","tool_name": "Write","tool_input": {"file_path": "/path/to/file.txt","content": "file content"},"tool_response": {"filePath": "/path/to/file.txt","success": true}}
{"session_id": "abc123","transcript_path": "/Users/.../.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl","cwd": "/Users/...","permission_mode": "default","hook_event_name": "Notification","message": "CodeBuddy needs your permission to use Bash","notification_type": "permission_prompt"}
{"session_id": "abc123","transcript_path": "/Users/.../.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl","cwd": "/Users/...","permission_mode": "default","hook_event_name": "UserPromptSubmit","prompt": "Write a function to calculate the factorial of a number"}
stop_hook_active 为 true。{"session_id": "abc123","transcript_path": "/Users/xxx/.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl","permission_mode": "default","hook_event_name": "Stop","stop_hook_active": true}
custom_instructions 来自用户传入 /compact 的内容。对于自动触发,custom_instructions 为空。{"session_id": "abc123","transcript_path": "/Users/xxx/.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl","permission_mode": "default","hook_event_name": "PreCompact","trigger": "manual","custom_instructions": ""}
{"session_id": "abc123","transcript_path": "/Users/xxx/.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl","permission_mode": "default","hook_event_name": "SessionStart","source": "startup"}
{"session_id": "abc123","transcript_path": "/Users/xxx/.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl","cwd": "/Users/...","permission_mode": "default","hook_event_name": "SessionEnd","reason": "other"}
reason/stopReason 字段或纯文本)> stderr。即 stderr 仅作为 fallback,只有当 stdout 没有输出任何内容时才会传递给 CodeBuddy。因此调试日志可以安全地写入 stderr,不会污染给 Agent 的反馈消息。Hook 事件 | 行为 |
PreToolUse | 阻止工具调用,向 CodeBuddy 显示消息 |
PostToolUse | 向 CodeBuddy 显示消息(工具已运行,用于补充上下文);可用 updatedToolOutput 替换工具结果 |
Notification | N/A,仅向用户显示消息 |
UserPromptSubmit | 阻止提示词处理,清除提示词,仅向用户显示消息 |
Stop | 阻止停止,向 CodeBuddy 显示消息并继续对话 |
SubagentStop | 阻止停止,向 CodeBuddy 子代理显示消息并继续执行 |
PreCompact | 阻止压缩操作,仅向用户显示消息 |
SessionStart | N/A,仅向用户显示消息 |
SessionEnd | N/A,仅向用户显示消息 |
{"continue": true, // CodeBuddy 在 hook 执行后是否继续(默认: true)"stopReason": "string", // 当 continue 为 false 时显示给 CodeBuddy 的消息"reason": "string", // stopReason 的别名,两者等效"suppressOutput": true, // 在 transcript 模式中隐藏 stdout(默认: false)"systemMessage": "string" // 显示给用户的可选警告消息(不传给 Agent)}
stopReason / reason:传递给 CodeBuddy Agent 的消息,用于解释为什么阻止操作systemMessage:仅显示给用户的警告信息,不会传给 Agent{"hookSpecificOutput": {"hookEventName": "PreToolUse","permissionDecision": "allow" | "deny" | "ask","permissionDecisionReason": "显示在权限对话框中的原因说明","modifiedInput": {"field_to_modify": "new value"}}}
"allow" 绕过权限系统,直接执行工具"deny" 阻止工具调用执行,permissionDecisionReason 会传递给 Agent"ask" 要求用户在 UI 中确认工具调用,permissionDecisionReason 会显示在确认对话框中modifiedInput 允许您在执行前修改工具的输入参数(部分字段覆盖)additionalContext);updatedToolOutput)。{"hookSpecificOutput": {"hookEventName": "PostToolUse","additionalContext": "补充给 CodeBuddy 的额外信息,如代码规范检查结果"}}
{"hookSpecificOutput": {"hookEventName": "PostToolUse","updatedToolOutput": "精简后的工具输出"}}
updatedToolOutput 对所有工具生效(内置工具与 MCP 工具均可)。additionalContext 的区别:additionalContext 是追加(结果只会变长),updatedToolOutput 是替换(结果可以变短)。updatedToolOutput 替换,再把 additionalContext 追加到替换后的内容上。updatedToolOutput 若为数组则原样作为 MCP content 数组,否则包装为单个文本块。decision: "block" 字段已废弃。由于工具已执行完成,此时无法真正"阻止"操作。{"continue": false, // 设为 false 阻止提示词处理"reason": "阻止原因(仅显示给用户)","hookSpecificOutput": {"hookEventName": "UserPromptSubmit","additionalContext": "注入给 CodeBuddy 的额外上下文"}}
decision: "block" 字段已废弃,请使用 continue: false。{"continue": false, // 设为 false 阻止停止,让 Agent 继续工作"reason": "告诉 Agent 为什么需要继续工作的原因"}
decision: "block" 字段已废弃,请使用 continue: false。{"hookSpecificOutput": {"hookEventName": "SessionStart","additionalContext": "My additional context here"}}
mcp__<server>__<tool> 模式,例如:mcp__memory__create_entities - Memory 服务器的创建实体工具mcp__filesystem__read_file - Filesystem 服务器的读取文件工具mcp__github__search_repositories - GitHub 服务器的搜索工具{"hooks": {"PreToolUse": [{"matcher": "mcp__memory__.*","hooks": [{"type": "command","command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"}]},{"matcher": "mcp__.*__write.*","hooks": [{"type": "command","command": "python3 /home/user/scripts/validate-mcp-write.py"}]}]}}
"$VAR" 而不是 $VAR.."$CODEBUDDY_PROJECT_DIR").env、.git/、密钥等/hooks 菜单中审查才能应用更改$SHELL 环境变量,通常为 bash 或 zsh),回退到 /bin/shCODEBUDDY_CODE_GIT_BASH_PATH 环境变量指定 bash.exe 路径CODEBUDDY_CODE_SHELL 环境变量覆盖默认 shell(仅支持 POSIX shell:bash、zsh、sh)CODEBUDDY_PROJECT_DIR 环境变量包含项目根目录的绝对路径--debug)/hooks 查看您的 hook 是否已注册codebuddy --debug 查看 hook 执行详情\\"codebuddy --debug 查看详细的 hook 执行codebuddy --debug 查看 hook 执行详情:[DEBUG] Executing hooks for PostToolUse:Write[DEBUG] Getting matching hook commands for PostToolUse with query: Write[DEBUG] Found 1 hook matchers in settings[DEBUG] Matched 1 hooks for query "Write"[DEBUG] Found 1 hook commands to execute[DEBUG] Executing hook command: <Your command> with timeout 60000ms[DEBUG] Hook command completed with status 0: <Your stdout>
~/.codebuddy/settings.json 中全局配置 hooks 外,还可以直接在自定义 Agent 的 .md 文件或 Skill 的 SKILL.md 的 YAML frontmatter 里声明 hooks 字段。这种方式让 Hook 与 Agent / Skill 一起作为"原子单位"分发,scope 自动随 subagent 生命周期开闭,不污染主会话。hooks 字段结构和 settings.json 完全一致——按事件名分组,每个事件下若干个 {matcher?, hooks[]} 配置;hook type 支持 command / prompt / agent / http 四种:---name: my-reviewerdescription: Code reviewer with pre-tool-use guardhooks:PreToolUse:- matcher: Bashhooks:- type: commandcommand: ./guard.shonce: trueSubagentStop:- hooks:- type: commandcommand: echo "reviewer finished"- type: httpurl: https://example.com/notifymethod: POST---
context: fork 时支持 frontmatter hooks(注入路径无清晰生命周期边界,不接入);自定义 Agent 总是支持。ScopedHookRegistry,subagent 退出时自动注销。Hooks 仅对该 subagent 自身的工具调用 / 生命周期事件生效。Stop → SubagentStop 重写:在 frontmatter 中写 Stop 事件会被自动重写为 SubagentStop——subagent 完成时不会触发主会话的 Stop,写 Stop 是想表达"subagent 自己结束"的语义。settings.json / 插件 hooks/hooks.json 会叠加(不覆盖),全部并行触发。allowUntrustedFrontmatterHooks)来源 | 默认是否注册 |
Product 内置 Agent / Skill | ✔ 自动放行 |
.codebuddy/agents/*.md(用户/项目本地 Agent) | ✖ 默认拒绝 |
.codebuddy/skills/SKILL.md(用户/项目本地 Skill) | ✖ 默认拒绝 |
插件市场分发的 Agent / Skill | ✖ 默认拒绝 |
插件 hooks/hooks.json(不是 frontmatter) | ✔ 不受闸门约束 |
~/.codebuddy/settings.json 设置:{"allowUntrustedFrontmatterHooks": true}
[AgentTask] Frontmatter hooks from skill 'xxx' skipped(source not admin-trusted; enable `allowUntrustedFrontmatterHooks` in settings to allow)
event 'YYY' invalid: <详细原因> 便于定位。unknown event 'XXX'),不会让整个 frontmatter 报废。Malformed YAML frontmatter in '<path>'。CODEBUDDY_DEBUG=1 启动后可以看到 [ScopedHookRegistry] registered N hook config(s) for scope '<sessionId>' (...) 这样的注册日志,确认 hooks 是否就位。文档反馈