Bridge between IM platforms and AI coding CLIs — one topic, one CLI session with live streaming
163 stars | TypeScript | MIT | 2026-03 | Node.js >= 22
飞书话题群 + AI 编程 CLI 的桥接层。Daemon 监听飞书消息,为每个新话题自动启动独立 CLI 进程,提供实时流式卡片和可交互 Web 终端。
核心定位
不做 SDK wrapper,直接桥接 CLI 进程。
botmux 不重新实现 Agent 能力,而是直接桥接已有的 AI 编程 CLI(Claude Code、Codex、Cursor、Gemini、OpenCode、Antigravity)。记忆、上下文管理、工具调用、权限体系——这些能力 CLI 本身都在快速迭代,botmux 选择站在这个进化之上,而不是平行重造一套。CLI 的每次升级,botmux 零适配自动受益。
整体架构
飞书消息 → Daemon (2503行) → Worker Pool → Worker进程(每会话独立)
↓
CliAdapter (8种CLI适配器)
↓
Backend (pty / tmux)
↓
IdleDetector → BridgeTurnQueue
↓
飞书流式卡片 / Web终端(xterm.js)
三层进程模型:
- PM2 — 管理 daemon 生命周期,开机自启
- Daemon (
daemon.ts, 2503行) — 处理飞书事件、路由消息、管理会话、调度 Workflow - Worker (
worker.ts) — 每个会话独立进程,持有 PTY + WebSocket 服务器
源码结构
src/
├── adapters/
│ ├── backend/ # pty-backend, tmux-backend, tmux-pipe-backend
│ └── cli/ # 8种CLI适配器 + registry + shared-hints
├── core/ # session-manager, worker-pool, scheduler, command-handler
├── dashboard/ # Web管控面 (esbuild打包的前端 + IPC后端)
├── im/lark/ # 飞书SDK封装:card-builder, event-dispatcher, identity-cache
├── services/ # bridge-turn-queue, bridge-rotation-policy, session-store等
├── skills/ # Skill定义 + 安装器
├── utils/ # idle-detector, terminal-renderer, screenshot-renderer
└── workflows/ # 完整工作流引擎 (orchestrator, events, hostExecutors)
180个测试文件,核心模块均有单元测试。
核心技术深度分析
1. BridgeTurnQueue — 异步流归因状态机
最复杂的模块,解决的核心问题:飞书消息和 CLI 的 JSONL transcript 是两个异步流,需要精确对应”哪条飞书消息触发了哪段 assistant 输出”。
纯状态机设计(无 IO,测试友好):
mark(turnId, fingerprint) → 飞书消息到来时打标记
ingest(events) → 消费 JSONL transcript,用 fingerprint 匹配 user event 启动 turn
drainEmittable() → 弹出已有 assistant 文本的 turn,发回飞书
边界情况处理:
| 场景 | 处理方式 |
|---|---|
| HOL-block drop | 前一 turn 无 assistant 文本但新 user event 来了 → 直接丢弃(Claude 单线程不会回来) |
| Local terminal input | 用户直接在 tmux 里打字,fingerprint 不匹配 → 合成 isLocal turn,飞书显示”🖥️ 终端本地对话” |
| Headless turn | daemon 重启导致 collecting 指针丢失,assistant 文本孤立 → 合成 headless turn 避免静默丢弃 |
| Type-ahead | Claude Code 支持 supportsTypeAhead,通过 attachment(queued_command) 事件触发 turn start |
2. Session ID Rotation 三层追踪
Claude Code 在 /clear、--resume、进程重启时会轮换 session ID(对应不同 JSONL 文件)。bridge-rotation-policy.ts 实现三层策略:
- Pid resolver(主路径) — 读
~/.claude/sessions/<pid>.json获取当前 session ID- 盲区:Claude Code 2.1.123 只在进程启动时写一次,
/clear不刷新
- 盲区:Claude Code 2.1.123 只在进程启动时写一次,
- Fingerprint fallback(补充) — 扫描目录下所有 JSONL,找包含消息 fingerprint 的文件
- 解决
/clear场景
- 解决
- Quiet rotation(兜底) — 按 mtime 启发式选最活跃的 JSONL
- 仅在前两者都无法判断时启用,多 pane 场景下容易误选兄弟 pane
竞态处理:stalePidStateSessionId 记录”已被 fingerprint 覆盖的旧 sid”,阻止 pid resolver 把 watcher 拉回去。
3. CliAdapter 接口
src/adapters/cli/types.ts 定义的核心抽象,支持 8 种 CLI:claude-code、aiden、coco、codex、cursor、gemini、opencode、antigravity。
关键设计:writeInput 可返回 { submitted: boolean, recheck?: () => boolean } — 允许 adapter 在写入后异步验证(通过读 JSONL 确认 user event 出现),失败时提供 recheck 闭包供 worker 延迟重试(处理 hook 慢、磁盘忙等情况)。
interface CliAdapter {
buildArgs(opts) // 构建启动参数
writeInput(pty, content) // 写入用户消息(可验证是否成功)
buildResumeCommand(opts) // 生成用户可粘贴的本地恢复命令
completionPattern? // CLI 完成标记正则
readyPattern? // CLI 就绪标记正则(抑制过早的 idle 检测)
supportsTypeAhead? // 是否支持 Claude Code 的 type-ahead
injectsSessionContext? // 是否通过 --append-system-prompt 注入上下文
skillsDir? // Skill 目录路径
}4. IdleDetector — 双策略空闲检测
检测 CLI 何时”空闲可接受输入”:
- Strategy 1: completionPattern — CLI 特定完成标记正则(如 Claude Code 的
✢符号),匹配后 500ms 确认 - Strategy 2: Quiescence — PTY 静默 2s + 最近 3s 内无 spinner 字符(
·✢✳✶✻✽⠋⠙⠹...)
readyPattern 用于抑制过早的 idle 判断(如 CoCo 的 ⏵⏵ 状态栏出现前不算就绪)。
5. Workflow 引擎
src/workflows/ 是一个完整的持久化工作流引擎,参考 Temporal/Durable Execution 思路:
核心设计:
- Event sourcing — 所有状态变更写入 NDJSON 事件日志,状态通过 replay 重建
- 纯决策层 —
orchestrator.ts是纯函数,输入 Snapshot + WorkflowDefinition,输出OrchestratorAction[],不做任何 IO - 幂等性 —
events/idempotency.ts保证同一 effect 不重复执行 - Human Gate — 节点可声明
humanGate.stage='before',要求人工审批后才执行 - 冷恢复 —
cold-attach.ts+resume.ts支持 daemon 重启后从磁盘恢复 in-flight runs
安全强制:side-effect executor(feishu-send、feishu-reply、botmux-schedule)默认强制要求 humanGate 或显式 unsafeAllowUngated: true,在 schema 解析时就拦截,不依赖运行时约定。
节点类型:
subagent— 启动 bot worker,传入 prompt,收集 output JSONhostExecutor— 调用注册的 executor(飞书发消息、定时任务等)
WorkflowDefinition 用 Zod 做 schema 验证,parseWorkflowDefinition 额外做图校验(DAG 无环、deps 引用合法、至少一个 root node)。
6. TmuxBackend — 进程常驻核心
pty-under-tmux 架构:
node-pty 进程 → tmux new-session/attach-session
kill() 只 detach(pty viewer 退出,tmux session 存活)
destroySession() 才真正 kill tmux session
会话命名:bmx-<sessionId.slice(0,8)>
Adopt 模式:adoptedPaneTarget 记录真实 pane 地址(如 0:2.0),所有 pane 级 tmux 命令必须显式寻址,避免误操作兄弟 pane。
与 OpenClaw 对比
| 特性 | botmux | OpenClaw |
|---|---|---|
| 底层架构 | 直接桥接完整 CLI 进程 | 基于 Agent SDK 重新构建 |
| CLI 能力 | 完整运行时(hooks/memory/plan mode/Skill//命令) | SDK API 子集 |
| CLI 升级 | 零适配自动受益 | 需跟进 SDK 版本变更 |
| 记忆/上下文 | 直接复用 CLI 内建记忆系统 | 需自建记忆系统 |
| 多 CLI 支持 | 8 种 CLI 一键切换 | 绑定单一 SDK |
| Web 终端 | 可交互完整终端,移动端快捷键工具栏 | 通常仅 Web 聊天界面 |
| 多机器人协作 | 多 bot 同群 @mention 路由,独立进程隔离 | 通常单机器人 |
| 复杂度代价 | Bridge 层极复杂(JSONL 追踪 + rotation + fingerprint) | 直接 API 回调,无此复杂度 |
| 适用场景 | 想用完整 CLI 能力的个人/小团队 | 需要深度定制 Agent 行为的产品 |
功能特性
实时流式卡片
- 终端输出实时渲染为 Markdown,自动过滤 TUI 装饰
- 状态指示:🟡 启动中 → 🔵 工作中 → 🟢 就绪
- 操作按钮:打开终端、获取操作链接、重启 CLI、关闭会话
Web 终端(可交互)
- 只读链接展示在群话题流式卡片上
- 可操作链接通过私聊按需获取(一次一密)
- 移动端悬浮快捷键工具栏(Esc、Ctrl+C、Tab、方向键等)
Tmux 会话常驻
- 核心收益:Daemon 重启不中断 CLI,
botmux restart时 worker 退出但 tmux session 保持运行 botmux list交互式列出所有活跃会话并 attach
多机器人协作
- 同一群聊中通过 @mention 路由消息
@<bot1> @<bot2> /t xxx让每个 bot 各自独立开新话题/introduce让各 bot 互相登记 open_id,支持跨 bot 协作
会话接入(Adopt)
/adopt将已在 tmux 中运行的 CLI 进程无缝接入 botmux- 共享模式:iTerm2 和飞书双向同步
- 一键接管:点击「🔄 接管」转为标准 botmux 会话
定时任务
- 斜杠命令:
/schedule 每日17:50 帮我看看AI圈有什么新闻 - 支持中文自然语言、duration、cron 表达式、ISO 时间戳
- 到点在原话题内续消息,不另开 thread
会话内 Skill(给 CLI agent 用)
通过 --append-system-prompt 注入,不依赖 MCP 协议,对所有 8 种 CLI 通用:
botmux send— 向当前话题发消息(文本/图片/文件/@mention)botmux history— 读取当前会话历史消息botmux quoted <message_id>— 读取被引用的消息botmux bots list— 查询当前群聊的机器人及 open_idbotmux schedule— 增删改查定时任务
安装与配置
npm install -g botmux
botmux setup # 交互式配置(扫码建应用或手动粘 AppID/Secret)
botmux start
botmux autostart enable # macOS launchd / Linux user systemd,无需 sudobots.json 核心字段
[{
"larkAppId": "cli_xxx",
"larkAppSecret": "secret",
"name": "claude-main",
"cliId": "claude-code",
"workingDir": "~/projects",
"allowedUsers": ["alice@company.com"]
}]cliId 可选:claude-code、aiden、coco、codex、cursor、gemini、opencode、antigravity
值得借鉴的设计
- BridgeTurnQueue 纯状态机 — 复杂异步归因逻辑封装成纯函数,测试无需 mock IO
- writeInput 验证机制 — 写入后异步确认 + recheck 闭包,比 sleep 等待更可靠
- Workflow humanGate 强制 — schema 层面要求 side-effect 节点必须有人工审批
- stalePidStateSessionId 竞态处理 — 两个异步信号源(pid resolver + fingerprint)之间的优先级协调
- pty-under-tmux 架构 — 用 node-pty 包裹 tmux,kill 只 detach 不销毁,实现进程常驻
局限性
- 仅支持飞书:目前仅支持飞书 (feishu.cn) 租户,Lark 国际版不支持
- Bridge 层复杂度高:JSONL 追踪 + session rotation + fingerprint 匹配,这是”直接桥接 CLI”必须付出的代价
- Idle 检测依赖 PTY 输出特征:CLI 更新 UI 风格可能导致误判
- 早期项目:163 stars,2026-03 创建,API 可能变动
相关页面
- openclaw — 同类方案:基于 Agent SDK 构建的 IM 平台 AI 网关
- claude-plugins-official — Claude Code Plugin 生态
- superpowers — AI 编程 Agent 开发方法论,含 botmux-schedule Skill
人工增加
## Oncall模式
- `/oncall bind <path>` — 绑定当前群到某个项目目录,发起人自动成为 owner
- `/oncall unbind` — 解绑(仅 owner)
- `/oncall status` — 查看当前绑定
## 会话能「搬家」:/relay 接力
Adopt 是把本机 tmux 里的进程接进飞书;
Relay 是把一个已经在 botmux 里跑的会话从 A 群搬到 B 群。