botmux 可以在关键生命周期事件发生时异步调用外部命令。命令失败、超时或不存在只会写日志,不阻塞 botmux 主流程(fire-and-forget)。

配置位置

按优先级从高到低:

  1. BOTMUX_HOOKS_JSON 环境变量(直接传 JSON 数组)
  2. BOTMUX_HOOKS_FILE 指定的文件路径
  3. 默认 ~/.botmux/data/hooks.json

环境变量机制见 env。

配置字段

[
  {
    "event": "session.requires_attention",
    "command": "/absolute/path/to/your-hook --flag value",
    "timeoutMs": 5000,
    "filter": { "chatId": "oc_xxx" },
    "redact": { "fullContentEvents": ["session.requires_attention"] }
  }
]
字段类型说明
eventstring必填。订阅的事件名(见下表)
commandstring必填。外部可执行命令;支持参数,但不经 shell 执行(不能用管道/重定向)
timeoutMsnumber可选。默认 5000;超时先 SIGTERM,再兜底 SIGKILL
filter.chatIdstring|string[]可选。只匹配指定飞书群 / 话题所在 chat
filter.senderOpenIdstring|string[]可选。只匹配指定发送者 open_id
redact.fullContentEventsstring[]可选。默认截断长文本;列入 allowlist 的事件透传全文

支持事件

事件触发时机
topic.new收到新话题 / @mention
thread.reply收到已有话题回复
outbound.sendbotmux 发送普通消息成功
outbound.replybotmux 回复话题消息成功
schedule.fired定时任务执行完成(见 schedule)
session.startworker / adopt worker 启动成功
session.exitworker 退出、崩溃或会话被关闭(daemon shutdown 默认静音)
session.idlesession 进入或离开 idle,按 session + 状态 10s 去重
session.requires_attentionTUI prompt 或 worker user_notify 需要用户处理

会话生命周期概念见 session-model。

Payload

所有 payload 通过 stdin 写入 hook 命令,同时设置环境变量 BOTMUX_HOOK_EVENT。每份 payload 都包含 event、emittedAt;事件上下文可含 sessionId、chatId、chatType、larkAppId、scope、anchor、title、cliId、workingDir、hasHistory、spawnedAt、lastMessageAt。

各事件额外字段:

事件额外字段
topic.newmessageId、senderOpenId、senderType、msgType、content
thread.replymessageId、rootId、parentId、senderOpenId、senderType、msgType、content
outbound.sendmessageId、msgType、uuid、content
outbound.replymessageId、replyId、msgType、replyInThread、uuid、content
schedule.firedid、name、schedule、status、error、rootMessageId、runAt
session.startreason、pid、adoptedFrom
session.exitreason、code(worker 退出路径;dashboard_close 为 null)
session.idleprevState、newState、transition、source
session.requires_attentionreason、description、optionsCount、optionsPreview、multiSelect、message

默认把 content、message、description、finalOutput、lastScreenContent 截断到 600 字符,并补充 xxxLength / xxxTruncated;只有 redact.fullContentEvents 内的事件透传全文。

快速验证与实践

仓库内置 examples/hooks/ 示例脚本,复制即用:echo-to-log.sh(把 payload 写入本地日志,配好 hooks.json 后 tail -f /tmp/botmux-hook.log 即可验证)、osascript-notify.sh(macOS 通知中心)、http-webhook.sh(HTTP webhook)。

用 session.start hook 自动更新 Skills:botmux 原生集成 agentbuddy 作为 skill 来源(botmux skills install <agentbuddy命令> 安装、botmux skills update <name> 更新)。配合 session.start hook 可在每次新会话启动时自动检查更新,等效于 Claude Code settings.json 的 SessionStart Hook:

[
  {
    "event": "session.start",
    "command": "botmux skills update my-skill-name",
    "timeoutMs": 60000
  }
]

注意事项:

  • botmux skills update 只接受单个 skill 名称,不支持 * 或正则;更新全部需脚本循环(botmux skills list | cut -f1 | while read ... 逐个 update)。
  • 想直接跑 npx agentbuddy update(更新用户全局 skills 而非 botmux 管理的 skills)时,受 hook 执行环境限制(shell: false 不支持管道/重定向;环境变量被清洗,只保留 PATH/HOME/TMPDIR/SHELL/USER 等基础项),建议写成包装脚本(私有 npm 源在脚本内自行 export npm_config_registry)。
  • 默认 timeoutMs 5000ms 对涉及网络请求的更新不够,必须显式加大(建议 60s+);超时后先 SIGTERM 再 SIGKILL 整个进程组。
  • hook 异步执行,不阻塞会话启动;skill 更新完成后需新会话才生效。
  • 可用 filter 限定只对特定 chatId / senderOpenId 生效,避免所有会话都跑更新。
  • 推荐优先使用 botmux skills update:它经过 botmux 的 telemetry 清理(clearAgentbuddyTelemetry),更新的是 botmux 注入的 skill 版本,与 botmux skill 生命周期一致。Skill 系统见 skill-cli。

写自己的 hook

hook 命令可以是任意 executable:bash / Python / Node / Go 二进制、公司内部 CLI、HTTP 转发器都行。命令 exit 0 视为成功;非 0 / 超时 / 找不到命令只写 botmux 日志,不会影响收发消息、定时任务或 session 生命周期。