Verboo Code 的 hooks:如何在工具调用前后自动运行命令
返回博客
文章verboo codetutorialdev toolshow to

Verboo Code 的 hooks:如何在工具调用前后自动运行命令

Mafra2026年9月25日阅读约 4 分钟

Verboo Code 允许你接入一条 shell 命令,甚至是一次模型检查,让它在会话中每次发生特定事情时自动运行,不需要写插件,也不用指望代理会记得去做。这就是hook,整套配置都写在你的 settings.json 里。

Verboo Code 里的 hook 是什么?

hook 是 CLI 在特定事件发生时自动触发的命令,比如在调用某个工具之前、之后,或者会话开始的时候。你在 settings.json 中配置它,不需要插件,也不用记得手动运行任何东西。

Verboo Code 一共有27 种 hook 事件。日常最常用的几种:

事件何时触发
PreToolUse任意工具执行之前
PostToolUse工具执行结束之后
PostToolUseFailure工具执行失败时
UserPromptSubmit你发送一条消息时
SessionStart打开、恢复或清空会话时
Stop代理即将结束这次回答之前

hook 应该写在哪个文件里?

根据你想要的生效范围,写在以下三个文件之一:

  • ~/.claude/settings.json:对你个人生效,跨所有项目
  • .claude/settings.json:只对这个项目生效,并会被提交进版本库,整个团队都会继承
  • .claude/settings.local.json:只对这个项目生效,只对你个人,不进版本库

结构始终一样:一个 hooks 键,里面是事件名,一个可选的 matcher 用来按工具名过滤,以及匹配时要运行的 hook 列表:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          { "type": "command", "command": "..." }
        ]
      }
    ]
  }
}

如何让代理在编辑完文件后自动格式化代码?

这是 hook 最常见的用法:每次 Verboo Code 写入或编辑文件后自动运行格式化工具,不需要额外开口。把这段加进 settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "file=$(cat | jq -r '.tool_input.file_path'); npx prettier --write \"$file\" 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}

matcher 会作为正则表达式去匹配工具名,所以 Write|Edit 能同时命中两者。命令通过 stdin 接收该事件的 JSON 数据,而不是通过环境变量。在 PostToolUse 里,这个 JSON 包含 tool_name、tool_input(传给工具的内容)、tool_response(工具返回的内容)、session_id 和 cwd。这就是为什么示例用 jq 读取 file_path,而不是假设一个固定的文件名。

为什么 PostToolUse 上的 hook 拦不住工具执行?因为 PostToolUse 是在工具已经执行完之后才触发的。已经发生的事情没法拦截,只能做出反应:提醒模型、记录日志、触发修复。真正能拦住工具的是 PreToolUse,它的退出码行为非常明确,直接从源码核实过:

事件exit 0exit 2其他退出码
PreToolUse正常继续取消这次调用,stderr 会返回给模型继续执行,但错误只显示给你看
PostToolUse正常继续把 stderr 显示给模型,但工具已经执行完了继续执行,错误只显示给你看

如果你需要阻止一次编辑发生,hook 必须写在 PreToolUse 上,并以 exit 2 结束。

如何让 hook 只对某一类命令生效,比如只对 git?

使用 if 字段,语法和你在 allow、deny 里用的权限规则一样,例如 Bash(git *)。它在 hook 进程被创建之前就完成过滤,不匹配的命令根本不会触发脚本。一个真实的例子:拦截直接推送到 main。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "if": "Bash(git *)",
            "command": "cmd=$(cat | jq -r '.tool_input.command'); if echo \"$cmd\" | grep -qE 'push.*(origin|upstream)[[:space:]]+main'; then echo '直接推送到 main 已被拦截,请开一个 PR。' >&2; exit 2; fi"
          }
        ]
      }
    ]
  }
}
Verboo Code 中 hook 的流程:在 settings.json 的 PostToolUse 里写入 hook,代理调用 Write,hook 自动运行并通过 stdin 接收 JSON,以及需要提前拦截时改用 PreToolUse 的分支。
已于 2026-09-25 在 verbeux-ai/code 源码中核实,src/utils/hooks.ts 与 src/schemas/hooks.ts。

hook 一定得是 shell 脚本吗?

不一定。一共有 4 种类型,各自的用途不同:

类型作用消耗 token?
command运行一条 shell 命令,bash 或 powershell不消耗
http把事件的 JSON 通过 POST 发到一个 URL不消耗
prompt用一个快速模型评估这次数据,回答是或否消耗
agent运行一个完整的验证代理,模型由你自己选消耗

举个例子,在 Stop 上配置一个 agent 类型的 hook,可以用来检查测试是否真的跑过并且通过了,而不是只相信主代理自己说完成了。

怎么查看当前会话里哪些 hook 是激活的?

运行 /hooks。它会按事件、再按 matcher 打开一个浏览界面,显示每个已配置的 hook 以及它的来源:用户配置、项目配置、本地配置、插件,还是会话本身。这个界面只能查看:要新建或修改 hook,你需要手动编辑 settings.json,或者直接让 Verboo Code 帮你改。旧的编辑界面只支持 command 类型的 hook,要在同一个菜单里同时支持全部 4 种类型,维护成本太高,所以现在官方的做法就是直接编辑配置文件。

prompt 和 agent 类型的 hook 每次触发都会调用一次模型,所以在按 token 计费的工具上,这是个需要节制使用的理由:每一次 PostToolUse、每一次 Stop、每一次检查都要花钱。在 Verboo Code 里,这类 hook 和会话里其他部分共用同一个不限量的 token 池,所以你可以在每一次 Stop 上都挂一个 agent 验证器,不用去算每次跑一遍要花多少钱。

喜欢这篇文章吗?
把知识分享给你的朋友。
// 继续阅读

相关文章