BOTBUS / DOCS

接入你自己的 agent

BotBus 让你在手机和手表上查看、控制电脑上的 agent。除了内置深度适配的六个,任何实现了 ACP(Agent Client Protocol)的 agent 都能接进来:新建任务、续聊、审批、中断、看对话记录,都和内置的一样在手机上完成。

需要电脑上的 BotBus Mac 版 1.1 或更新。agent 要和 BotBus 装在同一台电脑上。

01给使用者

装好 agent,手机上就能看到

大多数情况下你什么都不用做。下面说明 BotBus 怎么找到 agent,以及找不到时去哪里看原因。

注册表里的 agent:装了就出现

电脑上装了 ACP 官方注册表里的 agent,BotBus 会自动认出来,不用配置。常见的这几家在手机和手表上显示自己的图标:

  • Gemini CLI
  • goose
  • OpenCode
  • Qwen Code
  • Kimi CLI
  • Cursor
  • GitHub Copilot
  • Cline
  • Mistral Vibe
  • Kilo
  • 以及注册表里的其他 agent
  • 发现到的 agent 默认启用。不想让它出现在手机上,在电脑的 BotBus 设置 →「本机 Agent」里关掉它;手表的设备页也能开关。
  • BotBus 内置一份注册表快照,随 BotBus 更新。刚进注册表的 agent 要等 BotBus 的下一版。
  • 其他注册表 agent 和自己写清单的 agent 显示默认的 >_ 图标。

公司或自己的 agent

不在注册表里的 agent,只要实现了 ACP,也能接进来。向它的开发者要一份清单文件(很多 agent 的安装程序会自动放好),放进这个文件夹:

清单文件夹
~/.botbus/agents/<id>.json

放进去就生效,不用重启 BotBus。删掉文件,agent 也就从手机上消失。

没看到你的 agent?

  • 清单写错了BotBus 设置的「通用」页会多出一节「这些 ACP 清单没有生效」,逐个列出文件和原因(例如“文件名必须是 my-agent.json”)。旁边有「打开清单文件夹」和「重新检测」。
  • 在终端里查运行 botbus agent list,会列出 BotBus 找到的 agent、来源、开关状态,以及没生效的清单和原因。botbus 在 /Applications/BotBus.app/Contents/Helpers/ 里。
  • 第一次启动就失败注册表里的 agent 如果第一次连接就失败(起不来、不是 ACP、版本不对),BotBus 会把它藏起来,直到它重新安装或更新、或 BotBus 重启。
  • 显示“请在电脑上登录”这个 agent 需要先登录。在电脑上按它自己的方式登录一次就好,手机上不能登录。
  • 被停用了检查 BotBus 设置 →「本机 Agent」里它的开关。停用的 agent 在手机上显示为“没有启用”。
  • 电脑上开的会话看不到实时进度在 agent 自己的终端或 IDE 里开的会话,只有 agent 实现了 BotBus 的反向扩展才会实时出现;否则最多在列表里看到标题和时间。

02给开发者

把你的 agent 接进 BotBus

BotBus 电脑端用 ACP v1 驱动本机的 agent。你只需要实现 ACP;配对、凭据和手机之间的连接都由 BotBus 处理。另有一个很小的「反向扩展」,让你自己界面里开的会话也实时出现在手机上。

三种接入方式

进 ACP 官方注册表放清单文件反向扩展
你要做的提交到 ACP 注册表安装程序写 ~/.botbus/agents/<id>.json在前两种之一的基础上,进程主动连 ~/.botbus/run/acp.sock
自动发现是,按可执行文件名在本机找;随 BotBus 下一版生效是,放好即生效,不用重启常驻型的清单可以不写 command
手机新建、续聊、审批、中断、看记录是,BotBus 按需拉起子进程是按握手里声明的能力
你自己界面里开的会话支持 session/list 时列出,只有标题、目录、时间同左实时:状态、消息、审批
  • 内置的六个 agent 优先;注册表里对应它们的适配器(claude-acp、codex-acp、pi-acp)会被跳过。同一个 id,清单优先于注册表。
  • 注册表条目要本机真装了才算:在 PATH 和常见全局目录(Homebrew、npm / pnpm / bun / volta 的全局 bin、~/.local/bin 等)里找。npm 分发的,可执行文件的真实路径还必须落在 node_modules/<包名>/ 下。
  • 注册表 agent 的第一次握手就是验证,失败会被隐藏;initialize 超时和要求登录不算失败。清单 agent 失败照常显示并报错。

清单文件

放在 ~/.botbus/agents/<id>.json。BotBus 监视这个目录,增删改都即时生效。安装程序请直接把文件写进已有目录,不要先删整个目录再换一个进来。

~/.botbus/agents/my-agent.jsonJSON
{
  "id": "my-agent",
  "name": "My Agent",
  "command": "/usr/local/bin/my-agent",
  "args": ["--acp"],
  "env": { "MY_AGENT_LOG": "warn" }
}
字段规则
id必填。[a-z0-9-],1–32 个字符,等于文件名。不能用保留 id:codex claude hermes pi openclaw dsh acp claude-acp codex-acp pi-acp
name必填,非空,超过 40 字截断。手机和菜单里显示它
command可选。绝对路径(可以用 ~,必须可执行),或 PATH / 常见安装目录里能找到的名字。不写 = 只能经反向扩展接入
args可选,字符串数组
env可选,字符串到字符串,合并在 BotBus 自己的环境之上。可执行文件所在目录会补到 PATH 最前(node 脚本需要)

子进程的工作目录是用户主目录,会话目录经 session/new 的 cwd 给出。清单暂不支持自定义图标。

BotBus 用到的 ACP

手机上的操作

手机上ACP说明
新建任务initialize → session/new → session/prompt按需拉起。session/new 一返回,手机就能看到这个任务
续聊session/prompt;会话不在进程里时先 session/load不支持 loadSession、或这一轮还在跑时失败
审批回复 session/request_permission见下方「审批」
中断session/cancel挂起的审批同时回成 cancelled
带图的消息image 内容块(base64)没声明 promptCapabilities.image 时直接失败,不悄悄只发文字
看对话记录收集到的 session/update内存里没有时用 session/load 重放
看未提交的改动不经过 ACPBotBus 在 cwd 里只读 git

子进程空闲 10 分钟后关掉;崩溃后不自动重启,下一条命令来时再拉起。

能力

  • initialize:BotBus 发 protocolVersion: 1,你回的也必须正好是 1;10 秒没回算超时。BotBus 不提供 fs 和 terminal,工具由 agent 自己执行,BotBus 只看和批。
  • promptCapabilities.image:声明了才能从手机发图。
  • agentCapabilities.loadSession:续聊不在当前进程里的会话、查看历史对话都要靠它。
  • sessionCapabilities.list:让手机看到电脑上已有的会话(只有标题、目录、时间,只列 7 天内更新过的)。进程在跑时每 60 秒刷新,不在跑时每 10 分钟短暂拉起一次。
BotBus → agentinitialize
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
  "protocolVersion":1,
  "clientCapabilities":{"fs":{"readTextFile":false,"writeTextFile":false},"terminal":false},
  "clientInfo":{"name":"botbus","version":"1.0"}}}

审批

  • 手机点允许时选 allow_once,没有才用 allow_always;拒绝时先 reject_once,其次 reject_always。都没有就失败。
  • 工具类型 execute 显示为命令,edit / delete / move 显示为改文件,其余显示为一般权限。
  • 审批请求里的 toolCall 往往只有 toolCallId,请先发对应的 tool_call 通知,手机上才有标题可看。

把产物分享回手机

从手机发起的 session/new 与 session/load 会在 mcpServers 里带一个 botbus stdio server。照常启动它,agent 就能把截图、文件、链接和本机预览分享到手机上,不用做任何适配。

mcpServers[0]JSON
{
  "name": "botbus",
  "command": "/Applications/BotBus.app/Contents/Helpers/botbus",
  "args": ["mcp"],
  "env": [
    { "name": "BOTBUS_CLI", "value": "…" },
    { "name": "BOTBUS_TASK_TOKEN", "value": "…" },
    { "name": "BOTBUS_TOOLS_URL", "value": "http://127.0.0.1:…" }
  ]
}

登录

initialize 返回了 authMethods、调用时又报 auth_required(-32000)的,手机上显示“请在电脑上登录 <name>”。BotBus 不从手机上登录。

状态

手机上条件
运行中session/prompt 还没返回(反向连接:_botbus/turn started 之后)
待审批有挂起的 session/request_permission
完成stopReason = end_turn
已中断stopReason = cancelled;反向连接断开时正在跑的一轮
失败refusal、max_tokens、max_turn_requests、JSON-RPC 报错、进程崩溃

标题优先取 session_info_update,其次 session/list,最后取首条 prompt 前 80 字。思考过程不显示。

反向扩展 v1

用来让你自己的终端或 IDE 里开的会话实时出现在手机上。连接方向反过来,角色不变:你的进程仍是 ACP 的 agent,BotBus 仍是 client。

  • socket:~/.botbus/run/acp.sock。开始会话时检查它在不在:在就连,不在(BotBus 没运行)就什么都不做。
  • JSON-RPC 2.0,每行一条(UTF-8,\n 结尾,和 ACP stdio 一样),单行上限 16 MiB。
  • 只有同一用户的进程连得上:目录 0700、socket 0600,BotBus 还会核对对端 uid。不需要 task token。

握手

_botbus/hello→ 发出 / ← 收到
→ {"jsonrpc":"2.0","id":1,"method":"_botbus/hello",
   "params":{"id":"my-agent","version":1,"pid":4321,
             "capabilities":{"prompt":true,"cancel":true,"newSession":false}}}
← {"jsonrpc":"2.0","id":1,"result":{"accepted":true}}
← {"jsonrpc":"2.0","id":1,"result":{"accepted":false,"reason":"用户在 BotBus 里停用了这个 agent"}}

id 必须是 BotBus 已发现(清单或注册表)且没被停用的 agent;version 目前只认 1;capabilities 缺省的项当 false。

agent → BotBus

消息含义
_botbus/session{sessionId, cwd, title?}。先宣告,之后这个会话的消息 BotBus 才认;cwd 必填
session/update和 ACP 一样
_botbus/turn{sessionId, state, stopReason?}。没有 session/prompt 的返回可等,轮次 started / ended 要单独报
session/request_permission请求。同时在终端里照常问用户,谁先答用谁的
_botbus/permission_resolved{sessionId, toolCallId}。终端先答了,BotBus 撤掉手机上的审批
一轮对话每行一条
{"jsonrpc":"2.0","method":"_botbus/session","params":{"sessionId":"s-42","cwd":"/Users/me/proj","title":"修登录页"}}
{"jsonrpc":"2.0","method":"_botbus/turn","params":{"sessionId":"s-42","state":"started"}}
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"s-42","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"好的,我先看看"}}}}
{"jsonrpc":"2.0","id":7,"method":"session/request_permission","params":{"sessionId":"s-42","toolCall":{"toolCallId":"call-1"},"options":[{"optionId":"a1","name":"允许","kind":"allow_once"},{"optionId":"r1","name":"拒绝","kind":"reject_once"}]}}
{"jsonrpc":"2.0","method":"_botbus/permission_resolved","params":{"sessionId":"s-42","toolCallId":"call-1"}}
{"jsonrpc":"2.0","method":"_botbus/turn","params":{"sessionId":"s-42","state":"ended","stopReason":"end_turn"}}

BotBus → agent

声明的能力消息什么时候
promptsession/prompt手机续聊。请让消息出现在你的界面里,像用户在电脑上敲的;照常回 stopReason。没声明时手机提示“请在电脑上继续”
cancelsession/cancel手机点中断。没声明时提示“只能在电脑上中断”
newSessionsession/new + session/prompt手机新建任务,给常驻进程型 agent 用。没有 command 也没声明它的 agent 不出现在新建列表里

规则

  • 收到 accepted: true 再开始上报。握手前的通知会攒着(最多 100 条),只是尽力而为;握手前的请求一律回错误。10 秒内没握上手就断开。
  • 不要回显 BotBus 发给你的 prompt。用户在你自己界面里敲的可以转成 user_message_chunk 发来;BotBus 经 session/prompt 发的那句它已经记过了。
  • -32001 表示 BotBus 没有答案(会话不归这条连接、被新审批顶掉、这一轮已结束、终端先答了):继续等终端里的回答,不要当成用户取消。真正的取消回 {"outcome":{"outcome":"cancelled"}}。
  • 每条连接最多 50 个会话。另一条连接或 BotBus 自己的子进程正在驱动的会话不会被接管。
  • 用户停用 agent、删掉清单或 BotBus 退出时,BotBus 直接断开。断开后停止上报,下次开始会话时再连;正在跑的一轮记成已中断。

自查

botbus 在 BotBus.app/Contents/Helpers/botbus。下面两个子命令不需要 BotBus 在运行。

列出发现到的 agent不起进程
$ botbus agent list
gemini	Gemini CLI	注册表	已启用	/opt/homebrew/bin/gemini --acp
my-agent	My Agent	清单	已启用	/usr/local/bin/my-agent --acp
my-daemon	My Daemon	清单	已停用	(没有启动命令,只能经反向扩展接入)
✗ /Users/me/.botbus/agents/bad.json:文件名必须是 my-bad.json
真的跑一轮最多等 5 分钟
$ botbus agent check my-agent --prompt "hi"
ACP 协议版本: 1
loadSession: 是
图片: 否
session/list: 否
登录方式: 0 种
会话: 7f3c…
agent: 你好!
结束原因: end_turn
  • list 只读清单、注册表快照和开关设置;列表里有不等于能用,注册表 agent 可能在第一次握手后被隐藏。
  • check 拉起 agent 跑 initialize 并打印能力;加 --prompt 时在临时目录里跑一轮。它不注入 botbus MCP,审批一律回 cancelled。没有 command 的 agent 不能 check。退出码 0 成功、1 失败、2 用法错误。

已知限制

  • 只支持 macOS 电脑端,agent 必须跑在装着 BotBus 的那台电脑上。
  • ACP 没有“agent 在向用户提问”的信号,提问只会作为一条普通回复出现,不会显示“等待回复”。
  • 经 session/list 看到的会话只有静态信息;不实现它的 agent,只能看到 BotBus 拉起的和经反向扩展报的会话。
  • 反向连接断开时,正在跑的一轮记成已中断,即使 agent 那边其实还在跑。反向连接上的消息暂不带图。
  • 一台电脑最多同时接入 11 个 ACP agent,超出的按显示名排序后丢掉。
  • stderr 只在内存里留最后一小段,用来显示出错原因,不写日志。

更新于 2026-09-26