Skip to main content
Glama
zhimadelvdou

CodeBuddy Agent Bridge

by zhimadelvdou

CodeBuddy Agent Bridge · 0.5.1

让 Codex 通过 MCP stdio 接入一个持久控制器,异步管理中国版 CodeBuddy Code:启动、读取进度、同会话追问、运行中改向、权限应答、中断、恢复和关闭。每个 worker 是官方 CLI 的真实子进程;长任务不会被一个同步工具调用占住。

这是一份可运行、可检查的参考实现。协议锁定 @tencent-ai/codebuddy-code@2.161.0,不是 Tencent 或 OpenAI 官方连接器。早期版本曾通过真实中国版 CLI 会话及 MCP → 共享文件 daemon → 真实 CLI 探测;各版本的验证范围单独列在 验证记录。目标 Codex 原生 supervisor/UI 与完整生产验收仍须在目标机器完成。

0.5.1:中文工作目录与 Python unittest

启用 commandProfiles 时,allowedRoots / workspace / cwd 支持规范中文与 Unicode 字面目录,无需改名、移动或符号链接别名;含 ASCII 空格的命令路径 token 使用单引号。新增经固定真实绝对解释器路径调用的有限 python3 -m unittest、点分用例/相对测试文件以及 discover 参数支持。仍按完整原始命令和 worker cwd 精确匹配;未知参数、追加参数、越界、shell 展开/链式操作和通配符不自动批准。详见 0.5.1 完整契约。

仍为 21 个 MCP 工具,无新增依赖、计时功能或自动部署;文件 grants、capabilities/summary/recover 契约不变。未改动或重启已知本地 0.3.0 / 15-schema 部署。验证与限制见 本版验证记录。

Related MCP server: claude-session

0.5.0:按任务选择精确命令授权

仍为 21 个 MCP 工具。操作者可显式配置 commandProfiles:[{id,category,workspace,command}],默认为空;category 仅支持 test、build、git-query。这些是审查过的工作目录与完整命令,不是 shell 前缀、通配符或类别级放行。详细语法和边界见 0.5.0 命令 profile。

  • spawn / resume 可用 permissionProfileIds:["project_test"] 为新进程选择已获授权的精确命令;省略时无命令 grant。恢复相同 SID 不继承旧 grant;recover 替代进程仍清空全部 grant

  • 同一空闲进程的 send 省略 permissionProfileIds 会保留现有 grant;显式数组替换全部命令 grant,[] 清空命令 grant,均不清除文件范围 grant。改选要求没有已知活跃后台任务

  • 首次人工批准匹配的 pending 请求时,可用 rememberCommandProfileId 记住配置内的精确命令;不能与 rememberSession 同用,也不能用于拒绝或中断应答

  • capabilities 展示操作者 profile 上限;status、capabilities.worker 展示当前 commandProfileIds,查看和撤销仍用既有 grant 工具

allowSessionGrants 只控制既有文件范围授权,与命令 profile 独立。默认示例保持 commandProfiles:[]、只读工具和 allowSessionGrants:false;另附需操作者审查后才能使用的 profile 配置模板。配置、选择 ID 和模型文字不能证明适用的人类批准;敏感数据、系统设置、破坏性或其他高风险动作不能靠 test / build / git-query 标签授权。测试和构建会执行受信任的项目代码及依赖,可能产生任意效果;精确匹配不是沙箱,宿主政策始终优先。本次只做离线验证,结果见 验证记录。

以下版本小节保留历史;0.4.0 中“不支持 shell 范围授权”专指 rememberSession 文件范围机制,0.5.0 的独立命令 profile 见上。

0.4.0:会话范围授权、能力快照、轻量轮询和显式恢复

0.4.0 当时共 21 个 MCP 工具;该版新增 codebuddy_capabilities、codebuddy_permission_grants、codebuddy_revoke_permission_grant 和 codebuddy_recover。其余扩展保持默认行为兼容,未增加计时/耗时统计功能。完整参数、示例、错误和安全限制见 0.4.0 会话控制。

  • 进程内范围授权:codebuddy_respond_permission 可带 rememberSession:{tool,operation,path,recursive}。操作者必须先显式启用 allowSessionGrants:true(默认 false);可信 supervisor 还须取得用户对当前请求和未来相同工具/操作/路径范围的明确批准。匹配的后续、到达 bridge 的许可请求才会自动应答。默认不开启;不写 CLI permission rules,不使用原生 --allowedTools,不跨进程、resume/recover 或 daemon 重启继承。支持精确文件工具的已知输入;shell、未知工具/字段/结构、跨界或可疑路径不自动放行

  • 能力快照:codebuddy_capabilities({agentId?}) 分开返回脱敏的操作者上限、单 worker 解析后配置,以及 CLI init 已观察到的工具目录证据和时间。policyRevision 只是这些 bridge 策略字段的版本指纹;完整 CLI 许可规则与宿主批准政策均为 unknown。目录可见性不是操作授权

  • 轻量轮询:status/list/wait 可选 view:"summary";wait 可选 includeEvents:false。省略时仍为 detail 和带事件。summary 返回 ID、状态、计数及中断/恢复证据,省略 prompt、工具输入和长事件;省略事件不消费事件游标,后续仍可 read,需处理 ring 的 gap。不会续租或改变等待完成条件

  • 显式恢复:codebuddy_recover({agentId,recoveryId,expectedTurnId,mode,prompt,model?}) 必须给出完整 ID、显式 same_session 或 fresh,以及 supervisor 根据已确认进度新写的 prompt。关闭旧进程并观察到旧 leader 退出后才创建替代 worker;保留工作目录、worker 配置和选定模型,清空旧范围授权。相同参数重试复用同一恢复记录/新 agentId 或同一失败;不自动重放旧 prompt,不保证 exactly-once,创建成功也不等于启动或任务完成

交付此源码、示例或功能说明不构成用户批准,也不会修改正在运行的操作者配置或代为启用授权。宿主权限政策始终适用;范围检查不是 OS 沙箱,不能消除文件系统竞态。恢复不会回滚已产生的效果,也不能证明脱离进程组的子进程已停止。

以下 0.3.x 小节保留版本历史,工具数量和测试结果只对应当时版本。

0.3.2:模型积分倍率展示

codebuddy_models({agentId}) 在各模型中新增 credits:string|null,读取 CLI 2.161.0 的 get_available_models 原始条目中同 ID 的 credits 展示字符串(例如 "1x"、"0.5x")。不会返回原始目录或 provider/账号配置;未知、Auto 缺值或非法值为 null,不猜测倍率,不转换成每次请求费用。17 个工具及既有账号/登录守卫不变。

每次调用都会询问现有就绪 worker,但 CLI 的 getInitializeMetadata 会缓存目录,只有 credits 变化时可能不刷新。返回的 source、observedAt 与 cacheNotice 明确记录来源和此限制;observedAt 是 bridge 观察时间,不是价格生效/更新时间,不保证即时计费准确或按请求固定扣费。完整字段约束见 模型倍率协议。本版通过离线 fixture 和源码证据验证;真实在线倍率查询尚未验证,没有为此执行生成或登录操作。

0.3.1:账号查询与人工登录入口

WebUI 常驻显示 daemon 当前 CLI 的脱敏账号快照;新增 codebuddy_account 和 codebuddy_login,总计 17 个 MCP 工具。默认只读,登录须操作者配置和显式人工批准。已有账号时短路,不退出、不换号;没有账号时才生成短期官方登录链接,交给人完成。查询不是凭据有效期验证。详见 账号接口与验证边界 和 监控启用步骤。

这是向后兼容、默认关闭的新入口,按请求使用补丁版本 0.3.1;既有工具参数和 turn/recovery 语义不变。登录真实闭环未进行授权验收,不能以离线 fixture 代替。

0.3.0:按 2026-10-03 本地反馈补强

本次输入报告的离线子集为 39/39;12 个工具的 42 次调用包括负例,不能解读为全功能通过。报告中的 steer → interrupt → send 出现旧任务继续运行;独立 interrupt → send 对照通过,但不是同一序列复测,根因仍未知。0.3.0 提供保守隔离与可观察性,不声称修复 CLI/模型根因。

中断后必须重建进程

任何关联终态为 interrupted 或 interrupted_or_unknown 时,worker 进入 quarantined,保留 recoveryRequired。send 返回 RECOVERY_REQUIRED,不会把新 prompt 发进可能仍在执行旧任务的进程。已发送的变更控制超时、写入不确定或 ACK 不合法也会保持隔离;迟到 ACK 不会解除隔离。仍可读取、等待、检查后台任务和关闭。

恢复步骤:核对终态/副作用与后台任务,使用 0.4.0 的显式 recover,或沿用显式 close 后以完整 SID resume 新进程/创建新会话。恢复 prompt 必须由监督者按已确认进度重新决定,不自动重放不确定请求。close+resume 隔离旧进程,不证明持久历史中的旧意图已消失,也不回滚已经执行的工具或外部效果。

turn 守卫

codebuddy_steer({agentId,prompt,expectedTurnId?}) 和 codebuddy_interrupt({agentId,reason?,expectedTurnId?}) 都支持完整 turn UUID。推荐总是传入刚读取的 turn.id;操作者可设 strictTurnGuards:true 强制要求。过期为 STALE_TURN,无活动轮为 NO_ACTIVE_TURN,严格模式省略为 TURN_GUARD_REQUIRED。守卫先于续租,再在真正的队列写入点同步复核;过期控制不发 CLI 字节,也不影响替代轮。

这保证 bridge 的本地排队边界。CLI 的 interrupt 原生协议没有 expected_request_id;字节发出后 CLI 内部仍存在无法由 bridge 原子锁定的时序。steer 同时携带原生 expected_request_id。不能把本地守卫说成跨进程事务。

单 worker 启动配置

spawn/resume 新增可选 tools:string[]、permissionMode:"default"|"plan"、settingSources:("user"|"project"|"local")[]。省略仍为操作者 tools、default、none;空 settingSources:[] 显式渲染 --setting-sources none。tools:[] 关闭内置工具。

操作者 tools 是上限,单 worker 只能取其子集,超界拒绝 CONFIG_DENIED。allowedPermissionModes 默认 ["default","plan"],allowedSettingSources 默认 [];单次请求必须在这两项上限内。禁止 acceptEdits/bypassPermissions/dontAsk/auto,禁止任意 CLI flag、环境、MCP 配置或 provider 设置。非空 setting source 会加载已有规则、hooks、commands 等,只有操作者审查后才应开放;上限不构成 OS 沙箱。每个 worker 保存独立 workerConfig,许可 allow 再检查该 worker 收窄后的 tools。

cliToolCatalog 只是 CLI init 广播的工具目录,不表示实际允许执行;真正的桥接启动请求上限见 workerConfig.tools。CLI 工具目录和模型文本都不能充当操作授权。

模型工具(共 15 个 MCP 工具)

  • codebuddy_models({agentId}):向就绪 worker 调原生 get_available_models,只返回有界名称、ID、说明、credits 展示值及 disabled/configured 可用性标记;不返回 rawModels/provider/账号设置

  • codebuddy_model_status({agentId}):分别返回 requestedModel、confirmedModel、证据来源、matchesRequest 和 uncertain。启动参数不等于 CLI 确认;UI 也分栏显示

  • codebuddy_set_model({agentId,model,expectedSessionId,expectedModel?}):只有已确认完整 SID、无前台 turn/许可/已知活跃后台任务/待定变更才允许;先核对 CLI 目录(可能缓存),未知/disabled/configured:false 拒绝且不回退。预留本地锁阻止并发 send;写入前再次核对。ACK 必须返回完全相同 SID 和 model 才确认。超时或不匹配显式不确定并隔离,不自动重试

spawn/resume 显式给出 model 时,在首个 prompt 之前核对 CLI 目录(可能缓存);initialize 明确解析到别的模型也会失败,不静默回退。不要使用未列入目录的别名。未指定 model 时沿用 CLI 默认,并单独显示确认情况。

模型目录来自该 CLI 当前账号/运行环境,可能随服务变化,不在 bridge 硬编码供应商列表。CLI 不支持、未认证或返回未知 schema 都明确报错,不能以 fixture 通过替代真实模型验证。

关联与未实现项

turn、prompt、控制请求/超时事件包含 turnId 与 conversation request ID;prompt_written 仅表示管道写入,不表示接受。陈旧/replay/隔离后的输出记录为 unmatched 事件,不结算下一轮。无 request ID 的普通事件标为 unattributed,不伪造可靠关联。已知后台 task 的迟到非 replay 状态仍单独追踪。

本版没有 codebuddy_history。现有 read 仍只读取受限 event ring,gap 必须显式处理;不扫描整个 CLI 历史目录、不导出 thinking/凭据。安全的按 SID 补查、跨 daemon 持久游标/保留策略需单独设计。通用 spawn 创建幂等 key、重启 reattach 也未实现(0.4.0 仅为显式 recover 提供受限内存幂等);不凭短 SID/PID 认领未知进程,不自动重放不确定 spawn。

角色、票据、Coder/Reviewer 和双审查继续属于上层 Skill,不进入 MCP 业务协议。

先看清边界

  • 需要 Node.js 22+、macOS 或 Linux。控制器拒绝原生 Windows;WSL/Linux 仍需自行验收。默认仅开放 Read、Glob、Grep,不会写项目或执行任意 shell。

  • allowedRoots 只校验启动目录的真实路径,不是 OS 沙箱。CLI 会继承运行账号可用的系统权限、必要环境与本地认证。提示中的 inputs/ 只读、产物放 outputs/ 是工作约定,不能代替挂载权限、专用用户、容器或其他 OS 隔离。

  • 默认使用 --permission-mode default、--setting-sources none,始终使用严格空 MCP 配置;单 worker 可在操作者上限内收窄配置。不使用权限绕过开关;默认不自动批准工具,只有获得明确授权的进程内文件范围 grant 或已配置且选定的精确命令 profile 才会自动应答匹配请求。它没有声称屏蔽 CodeBuddy 所有可能的上下文/本地数据来源。

  • interrupt 取消当前 turn 并尽量保留会话;close 终止持有的进程组。两者都不回滚已产生的文件或外部效果。

  • wait 超时或取消、Codex 原生 supervisor 停止、一个 turn 完成,均不代表外部 CodeBuddy 或它的后台任务已停止。

  • 推荐模式使用共享私有文件 IPC daemon(另提供 Unix-socket 选项):多个 MCP proxy 和原生 supervisor 连接同一 daemon,可以控制同一组 agentId。daemon 重启后 registry 消失;独立 daemon 之间不共享。简化的 standalone 模式则每个 MCP 连接独占控制器。CodeBuddy 本地历史另外保存,可用 sessionId 创建新进程恢复。

  • daemon 是同一用户的本地受信任控制服务,没有 TCP 监听、没有多租户隔离。能访问同一 spool/socket 的本地进程可控制其中所有 worker;不要暴露运行目录、改变为宽松权限或共享给其他用户。

目录

src/config.mjs                  操作者配置和目录校验
src/protocol.mjs                NDJSON、线协议信封与输出脱敏
src/controller.mjs              持久进程、turn、权限、租期和事件管理
src/server.mjs                  MCP stdio 与 21 个工具
src/session-grants.mjs          进程内文件范围授权与匹配校验
src/command-profiles.mjs        精确命令 profile 校验和进程范围匹配
src/daemon.mjs                  同用户共享 Unix-socket 控制器
src/daemon-client.mjs           MCP proxy 到 daemon 的 RPC
src/file-daemon.mjs             可选:私有目录文件 IPC daemon
src/file-ipc.mjs                原子文件 RPC 与心跳
examples/bridge.config.json     控制器配置(命令 profile 默认空)
examples/bridge.command-profiles.config.json 需审查的精确命令模板
examples/codex.config.toml       推荐:连接共享 daemon 的 MCP 配置
examples/codex.standalone.config.toml 单连接独占控制器配置
examples/codex.file-spool.config.toml 显式文件 IPC 配置
examples/codex.unix-socket.config.toml 可选 Unix-socket 配置
examples/codex-mcp.plugin.json   Codex 插件 .mcp.json 格式示例
examples/codebuddy-supervisor.toml   可选 Codex 原生监督角色
examples/codebuddy-supervise/SKILL.md 可选、新编写的监督 skill
src/monitor.mjs                 可选:本机只读 HTTP 监控服务
src/monitor-diff.mjs            可选:有界、可信本地 Git HEAD 比较
web/                            任务列表、事件、对话和中断确认 UI
docs/monitor.md                 监控启动、安全边界和浏览器验收
docs/protocol.md                协议、状态、错误和测试边界
docs/session-controls-v0.4.0.md  会话授权、能力、summary 与显式恢复
docs/command-profiles-v0.5.0.md  命令 profile 语法、选择和安全边界
docs/testing.md                 脱敏验证矩阵与未验证项

1. 安装并锁定官方 CLI

把桥接项目放在一个可信目录。以下 /ABSOLUTE/PATH/... 全部是需要替换的绝对路径占位符,不指向任何预设云机器。

cd /ABSOLUTE/PATH/codebuddy-agent-bridge
npm ci
npm run check

# 将官方 CLI 装到独立目录,不把它复制进桥接源码。
npm install --prefix /ABSOLUTE/PATH/codebuddy-runtime --save-exact @tencent-ai/codebuddy-code@2.161.0
/ABSOLUTE/PATH/codebuddy-runtime/node_modules/.bin/codebuddy --version
# 必须恰好输出 2.161.0

官方 npm 包与安装方法见 CodeBuddy 快速入门。桥接端第一次启动 worker 会自行核对版本;其他版本返回 VERSION_MISMATCH,不会猜测兼容性。升级时应先复核类型和行为、跑测试,再有意更新版本钉选。

2. 在运行 MCP 的账号下完成中国版登录

由用户在自己的终端启动官方 CLI,选择 Log in via Chinese Site,在官方登录界面完成认证:

export CODEBUDDY_INTERNET_ENVIRONMENT=internal
cd /ABSOLUTE/PATH/codebuddy-workspaces
/ABSOLUTE/PATH/codebuddy-runtime/node_modules/.bin/codebuddy

中国版使用 CODEBUDDY_INTERNET_ENVIRONMENT=internal;ioa 是另外的企业环境。见 官方环境变量参考。持有控制器的 daemon(或 standalone MCP)和该次登录应使用相同的运行账号及 HOME,否则本地认证/历史不一定可见。推荐先手动登录;0.3.1 起另有默认关闭的人工登录入口,见 账号接口。桥接不读取认证文件或导出凭据。

不要把密码、API key、token 写进本仓库、prompt、日志或示例配置。优先沿用官方 CLI 登录保存的会话。若自行采用官方文档支持的环境认证,需由操作者通过宿主的安全秘密机制注入,并在 Codex 的 env_vars 和桥接的 envPassthrough 两层仅允许必要的变量名;不要把秘密值提交到 TOML/JSON。

3. 配置限定工作目录

先创建自己的工作目录,例如每个任务独立一个子目录:

mkdir -p /ABSOLUTE/PATH/codebuddy-workspaces/demo/inputs
mkdir -p /ABSOLUTE/PATH/codebuddy-workspaces/demo/outputs
cp examples/bridge.config.json bridge.config.json

编辑 bridge.config.json,至少替换:

  • cliPath:上面安装得到的可执行文件绝对路径

  • allowedRoots:自己管理的工作目录根路径;必须已存在

  • envPassthrough:保留 CODEBUDDY_INTERNET_ENVIRONMENT,使中国版环境进入 CLI 子进程

配置在控制器启动时读取;改动需要先清理现有 worker,再重启 daemon 或 standalone MCP。不要把不受信任任务目录当成配置文件来源。

默认同时最多 4 个未关闭 worker;idle 也占名额。最多保留 64 条 worker 记录,满后淘汰旧的已关闭记录。默认每个 worker 保留 256 个事件,单条事件 64 KiB、单行协议 1 MiB、prompt 128 KiB,租期 30 分钟。全部字段与边界见 协议说明。allowSessionGrants 默认 false,只控制文件范围;commandProfiles 默认空,需操作者逐项审查精确命令、workspace 和项目代码后显式配置。配置本身不代替适用的任务授权与宿主批准政策。

默认只读工具不能生成 outputs/ 文件。需要编辑时,由操作者审查后把 tools 改成确切需要的工具,如 Read,Glob,Grep,Write,Edit,然后重启;执行命令还需显式加入 Bash。工具可用性不等于操作已获授权。尤其不要给任意任务无差别开放全部工具,或误以为这些配置带来目录读写隔离。

4. 启动共享文件 daemon,再接入 Codex

推荐结构:Codex 根代理 / 可选原生 supervisor → 各自 MCP stdio proxy → 同一个私有 spool → 一个 daemon → CodeBuddy workers。本构建环境已用官方 MCP SDK、两个独立 proxy 进程和 fixture CLI 验证跨连接接管。真实 CodeBuddy 的模型测试属于另外一层,详见验收章节。

先在自己的受信任终端启动 daemon。spool 放在项目源码之外的私有运行目录,不要放在将打包、提交或同步的仓库中。它必须是真实绝对路径、当前 UID 所有、权限 0700,不能通过符号链接解析到别处:

install -d -m 700 /ABSOLUTE/PATH/cb-bridge/spool
export CODEBUDDY_BRIDGE_CONFIG=/ABSOLUTE/PATH/codebuddy-agent-bridge/bridge.config.json
export CODEBUDDY_BRIDGE_SPOOL=/ABSOLUTE/PATH/cb-bridge/spool
export CODEBUDDY_INTERNET_ENVIRONMENT=internal
/ABSOLUTE/PATH/TO/node /ABSOLUTE/PATH/codebuddy-agent-bridge/src/file-daemon.mjs
# 保持这个终端进程运行;启动成功会在 stderr 显示 daemon PID。

daemon 用私有原子 JSON 文件交换请求/响应,不开网络端口,消息文件为 0600。prompt 和结果会短暂落盘;正常断连清理已识别客户端目录,崩溃可能留下内容和锁。不要把 spool 当日志、秘密仓库或交付物。程序每 25 ms 轮询、每秒心跳,超过 5 秒无心跳视为断连;详情见 文件 IPC。

然后把 examples/codex.config.toml 合并进现有 ~/.codex/config.toml 或受信任项目 .codex/config.toml,不要覆盖原配置:

[mcp_servers.codebuddy_bridge]
command = "/ABSOLUTE/PATH/TO/node"
args = ["/ABSOLUTE/PATH/codebuddy-agent-bridge/src/server.mjs"]
startup_timeout_sec = 30
tool_timeout_sec = 45

[mcp_servers.codebuddy_bridge.env]
CODEBUDDY_BRIDGE_SPOOL = "/ABSOLUTE/PATH/cb-bridge/spool"

用 command -v node 找到实际 Node 可执行路径。Root 和所有 supervisor 都必须使用同一个 spool 绝对路径。中国版/认证/代理等 CLI 环境在 daemon 启动时提供;只把它们写到 proxy 环境不会转发到已运行的 daemon。

重新连接/重启 Codex 会话后,用 codex mcp list 检查注册,再检查 codebuddy_spawn 等工具是否可见。模型侧可能带 mcp__codebuddy_bridge__ 前缀,以宿主实际工具名称为准。仅出现在列表不证明已登录或真实模型调用成功。

JSON 示例 examples/codex-mcp.plugin.json 是 Codex 插件 .mcp.json 的 mcpServers 格式片段,不是 config.toml 替代文件,也不是可直接安装的完整插件。只有已有插件封装时才走此路线。语法来源:Codex MCP、插件封装。

daemon 没有自动安装服务或开机启动。长期运行可由操作者审查后接入本机服务管理器。锁冲突时拒绝启动;恢复前必须确认原 owner 已停止并审查残留,不能盲删 daemon.lock 或重放未知是否已经执行的请求。

可选:Unix-socket IPC

普通 POSIX 主机可选择 socket 传输;本构建环境 bind 被内核 EPERM 拒绝,未实测该传输的跨进程集成,不要把它当已通过的部署路径。它与文件 daemon 是独立实例,不能混用 registry,不会自动切换。

install -d -m 700 /ABSOLUTE/PATH/cb-bridge/run
export CODEBUDDY_BRIDGE_CONFIG=/ABSOLUTE/PATH/codebuddy-agent-bridge/bridge.config.json
export CODEBUDDY_BRIDGE_SOCKET=/ABSOLUTE/PATH/cb-bridge/run/bridge.sock
export CODEBUDDY_INTERNET_ENVIRONMENT=internal
/ABSOLUTE/PATH/TO/node /ABSOLUTE/PATH/codebuddy-agent-bridge/src/daemon.mjs

Codex 改用 examples/codex.unix-socket.config.toml。双方使用同一 CODEBUDDY_BRIDGE_SOCKET,不设置 spool;两个同时设置会报错。socket 路径 <=100 UTF-8 字节,父目录是当前 UID 所有的真实私有 0700 目录;socket 为 0600。已有 socket 不自动覆盖,确认旧 owner 已结束且路径确为残留后才手动清理。没有 TCP 备用监听。

简化选项:standalone

不需要多线程接管时,可使用 examples/codex.standalone.config.toml,不给 server 设置 CODEBUDDY_BRIDGE_SOCKET 或 CODEBUDDY_BRIDGE_SPOOL,改为提供 CODEBUDDY_BRIDGE_CONFIG 和中国版环境。此时一个 MCP 进程持有一个独立控制器,stdio 断开会清理它自己的 worker;另一 MCP 连接无法访问这些 agentId。配置不会合并:设置 socket 或 spool 时 server 走对应 proxy,两个都不设才走 standalone。

不论哪种模式,stdout 只用于 MCP 报文。不要每次工具调用临时启动新控制器。

企业代理和 CA

桥接默认不继承整个宿主环境。如果官方 CLI 需要企业代理或 CA,可由操作者按实际网络要求,把必要变量加入 envPassthrough,并在 daemon 启动环境设置:NODE_EXTRA_CA_CERTS、SSL_CERT_FILE、HTTPS_PROXY、HTTP_PROXY、ALL_PROXY、NO_PROXY。只传需要的项;代理 URL 若含秘密,不要记录或提交。不要用关闭 TLS 校验来修复认证或网络问题。

5. 第一个安全任务

在 Codex 中可以这样要求:

使用 codebuddy_bridge,在 /ABSOLUTE/PATH/codebuddy-workspaces/demo 启动一个只读 CodeBuddy worker。检查 inputs 中的普通测试文本并总结,不访问秘密或执行命令。保留 agentId 和 cursor,等到当前 turn 有确定结果后读取输出,最后关闭 worker。

其工具调用流程如下;WORKER_UUID 用实际返回值替换,不是 sessionId:

codebuddy_spawn({"cwd":"/ABSOLUTE/PATH/codebuddy-workspaces/demo","prompt":"只读检查 inputs 中的测试文本并总结","name":"demo"})
  → 立即返回 agentId,state 通常为 starting
codebuddy_wait({"agentId":"WORKER_UUID","until":"settled","timeoutMs":20000})
  → 若 timedOut:true,继续观察,不重新 spawn
codebuddy_read({"agentId":"WORKER_UUID","after":0,"limit":100})
  → 提取结果,记录 nextCursor;hasMore:true 时继续分页
codebuddy_status({"agentId":"WORKER_UUID"})
  → 核对 lastTurn.status 和 backgroundTasks
codebuddy_close({"agentId":"WORKER_UUID","reason":"结果已取得"})
  → 核对 closed/failed、exit 及 cleanup_error

wait(until:"turn_complete") 只等当前轮;wait(until:"settled") 还要求所有已知后台 task 为终态。两者也可能因进程失败或关闭返回,必须看状态;idle 也可能是失败后的空闲;中断后本版进入 quarantined。lastTurn.status="succeeded" 与输出/产物验收一起构成成功证据。interrupted_or_unknown 或 turn_completed.data.resultMayBeStale=true 的内容不能当成可靠的新结果。

连续对话和改向

  • idle:codebuddy_send({agentId,prompt}) 在现有进程/会话开启下一轮

  • 当前 turn 仍运行:codebuddy_steer({agentId,prompt,expectedTurnId});查看 response.steered,可能为 false

  • send 不会悄悄排队:运行中返回 BUSY

  • steer/interrupt 的 CONTROL_TIMEOUT 表示结果不确定;先读取状态/后续事件,不自动重发。CONTROL_PENDING/CONTROL_UNCERTAIN/RECOVERY_REQUIRED 会阻止新 send;已发送变更控制的不确定结果要求显式 recover,或 close 后显式恢复

  • daemon/standalone 控制器已重启或 worker 已关闭:用已确认 sessionId、原工作目录及新 prompt 调 codebuddy_resume,得到新 agentId。它依赖官方 CLI 本地历史和认证,不会接管已有未知 PID

权限请求

state="waiting_approval" 时,从 pendingPermissions 或事件获取精确的 requestId、工具名、输入和目标。展示给用户并按宿主权限政策处理。只有这次具体操作确已获授权,才调用:

codebuddy_respond_permission({"agentId":"WORKER_UUID","requestId":"EXACT_REQUEST_ID","allow":true,"reason":"用户已明确批准此工具、输入和目标"})

拒绝时 allow:false;要在拒绝时请求中断可加 interrupt:true,不能和 allow:true 同用。应答返回 sent:true, acknowledged:false 仅说明已写入管道;需要继续观察。过期请求返回 STALE_PERMISSION,不能把先前许可移用到新请求。此工具没有身份验证器来自动证明人类授权,监督者仍须保留授权依据。若用户明确批准后续相同工具的文件范围,可在操作者启用后附上 rememberSession;若需记住配置内的精确命令,则使用互斥的 rememberCommandProfileId,并核对当前完整原始请求匹配该 profile;详见 命令授权规则。否则保持本次一次性应答。查看和撤销范围分别用 codebuddy_permission_grants / codebuddy_revoke_permission_grant,详见 范围授权规则。未实现自动全放行或持久 permission rules。

6. 停止、租期和失联处理

正常取消

  1. 根代理必须保留所有 worker 的 agentId 及所属控制器,不只保留原生 supervisor 的 ID

  2. 对运行中的 worker 调 codebuddy_interrupt 并传 expectedTurnId;ACK 只是控制请求应答

  3. 用 read/wait 等待对应 turn 的终态,并检查 backgroundTasks;中断不保证后台工作都停止

  4. 用户要求停止一切、控制不确定、启动尚未完成或不再需要会话时,调用 codebuddy_close

  5. 检查关闭结果和 cleanup 错误。需要继续时显式 recover,或 close+resume;隔离 worker 不接受 send。不要只说“原生 agent 已停止”而遗漏外部进程

close 对拥有的 POSIX 进程组先发 SIGTERM,默认 1500 ms 后尝试 SIGKILL;同组后代也在目标内。后代如果自行 setsid/脱离该组,桥接无法保证捕获。关闭返回反映已执行清理尝试,不是对系统中所有后代存活情况的绝对证明。

租期

默认 leaseMs=1800000(30 分钟)。send、steer、interrupt、权限应答及显式 keepalive 会触发续租;read、status、list、wait 不续租。某些写操作即便随后因状态校验失败也可能已经续租,不能把租期用作精确计费限额。

长任务仍获授权且有人监督时,在 leaseExpiresAt 前主动 codebuddy_keepalive。一直只读状态会让任务到期自动关闭。无人接管时不要让一个独立心跳永远续租;租期是遗留进程兜底,不是持久任务调度器。

MCP 失联和原生子代理

推荐的 daemon 模式中,单个 MCP proxy 的 EOF、关闭或断连只断开它的控制连接,并取消该连接的等待;worker 继续由 daemon 持有,其他 proxy 可以接管。要停任务应明确 interrupt/close,或让租期到期;要停整个 daemon,由操作者对已确认的 daemon PID 发 SIGTERM,或在 daemon 前台终端按 Ctrl+C,触发全部 worker 清理。

standalone 模式中,MCP 的正常 stdin EOF、transport close、SIGINT/SIGTERM 会清理自身 worker。真正持有控制器的 daemon/standalone MCP 被 SIGKILL、宿主崩溃或断电时无法运行 JavaScript 清理;严格要求应另用 OS 级进程/容器监管并自行验收。

停止 Codex 原生 wrapper 不等于关闭它曾创建的外部 worker。官方 Codex Interrupt 和 SessionEnd hooks 不覆盖子代理的同类停止场景,不要用它们声称万无一失的退出清理;见 Hooks 文档。本项目没有安装这些 hooks。

7. 可选 supervisor 和 skill

根代理可以直接使用 MCP,不一定需要额外 Codex 子代理。需要原生监督角色时,可把 examples/codebuddy-supervisor.toml 放进受信任项目 .codex/agents/。它仍运行 Codex 模型、消耗正常 Codex 用量,仅监督 CodeBuddy;不会把 CodeBuddy 的外部模型注册到 Codex 原生子代理列表,也不会消除双模型成本。当前角色语法见 Codex Subagents。

推荐 daemon 模式消除了“不同 MCP 连接各有独立 registry”的问题:Root 与 supervisor 指向同一 socket(选文件 IPC 时同一 spool),并用 codebuddy_list / status 验证相同 worker 可见。根代理仍须保存所有 agentId,因为停止原生 supervisor 不触发外部停止。不要为 supervisor 配置另一个 socket/spool 或再启一个独立 daemon。采用 standalone 时,根代理应自己创建/控制 worker,supervisor 只协助分析;否则 root 的另一连接会 NOT_FOUND。

examples/codebuddy-supervise/SKILL.md 是随本项目新写的可选操作指南,可审查后安装到自己的 Codex skills 目录。它不会自动安装或启动 MCP,不依赖某个预先存在的“任务助手初始化”技能。

8. 可选本地监控页

无需再运行一个模型代理。另开终端,指向 Codex 已使用的同一个文件 daemon:

cd /ABSOLUTE/PATH/codebuddy-agent-bridge
export CODEBUDDY_BRIDGE_SPOOL=/ABSOLUTE/PATH/cb-bridge/spool
npm run monitor
# 在同一台电脑浏览器打开 http://127.0.0.1:4317

默认只读:看多任务列表、实际活动时间线、Prompt / 回复、许可等待、后台 task 与租期。纯浏览不启动任务、不续租,关页也不会停止 worker。未知/缺口/截断和失联状态都会明确标记;不是完整审计日志。

需要时由操作者显式开启:

npm run monitor -- --allow-interrupt --git-diff

人工中断需要弹窗确认并由 daemon 原子核对当前 turn;ACK 不等于终态。文件差异按按钮读取一次,是可信本地仓库的当前跟踪文件与 HEAD 比较,不是任务开始基线或该 worker 的专属改动。未跟踪/秘密路径/无基线等不展示。监控只绑定 127.0.0.1,没有公开部署和远程鉴权,不适合不互信的多用户主机。

新 daemon 才有 Prompt 提交事件及受 turn 保护的中断;连接旧 daemon 时保持只读。standalone MCP 的 controller 不能由该页面接管。完整运行选项、限制和验证方法见 监控指南。

本次已验证 Node HTTP 与共享文件 daemon 链路;云浏览器访问 loopback 被 ERR_BLOCKED_BY_CLIENT 拒绝,因此真实浏览器交互、响应式视觉和截图尚未验收。没有通过其他路由绕过,也不推断用户浏览器会遇到相同限制。

9. 验收与限制

先跑本地测试,不需要账户或模型额度:

npm run check
# 如需单独复跑独立审查测试
node --test --test-concurrency=1 tests/reviewer-adversarial.test.mjs

这类测试使用 fixture 模拟 CLI,覆盖会话复用、改向、中断 ACK 与终态分离、过期许可、控制超时、wait 取消、旧结果串轮、协议洪水/畸形输入、目录/符号链接越界、事件缺口、同进程组后代清理等。它们不能证明真实 CodeBuddy 模型、认证服务、所有后台工具或部署宿主都具有同样行为。

历史 0.2.0 npm run check 为 78 项:73 通过、0 失败、5 项 Unix-socket 集成因 EPERM 跳过;0.1.0 时 npm audit --omit=dev 报告 0 个已知漏洞,监控扩展没有新增 npm 依赖。后续版本结果见 验证矩阵;不能把这些历史结果当作 0.5.0 的验证。各版本新增接口须分别验收,本文不声称已通过真实 CLI/目标宿主闭环。历史证据分层如下:

  • 官方 2.161.0 包内类型/实现及文档已核对;还进行了真实 CLI 握手探测

  • 文件 daemon:用官方 MCP SDK 与两个独立 MCP proxy 进程进行端到端传输测试,worker 使用 fixture CLI;验证第一个连接 EOF 后任务保留,第二个连接可 list/status/steer/interrupt/wait/close

  • 真实中国版 CLI:已探测最小回答、同进程多轮上下文、steer、延后中断、关闭后 resume,以及 Read → Write 许可后核对文件字节/inputs 未变。极早中断可能缺少 terminal marker,因此桥接保守报告 interrupted_or_unknown 并标记 resultMayBeStale,不会冒充成功

  • Unix-socket 集成:内核 EPERM 阻止 bind,相关集成测试为 skip;没有 TCP 绕过

以上不等于“真实模型 + 文件 daemon + 用户目标 Codex 宿主 + 所有工具”的组合生产验收。仍需在部署目标逐项完成:

  • 在自己的账户/目标机器复跑中国版登录与最小只读提示词,得到可关联的成功 result

  • 同会话连续两轮、运行中 steer、interrupt 后拒绝 send(RECOVERY_REQUIRED),显式 close/resume 后再追问

  • 人工拒绝/允许一个明确许可,检查过期许可不能重用;另按 0.4.0 文档验证授权范围匹配、越界不匹配、撤销和恢复后清空

  • 关闭后用同 sessionId 恢复;测试历史缺失/认证失效

  • 明确启用后台工具时,分别观察 turn 与后台 task 的终态

  • 在目标 Codex 宿主验证 MCP 持久性、连接所有权、EOF/信号清理与租期

故障排查:

现象

下一步

VERSION_MISMATCH

核对 cliPath --version,重新安装钉选版本;不要跳过版本检查

WORKSPACE_DENIED

检查 cwd 的真实路径和 allowedRoots;不要用软链接绕过

NOT_FOUND

核对是否同一 file daemon/spool(或所选 daemon/socket);控制器重启后需用 sessionId 恢复历史

DAEMON_DISCONNECTED / RPC_TIMEOUT

先核对 daemon 是否仍在和任务现状;变更结果可能不确定,禁止自动重放

socket 权限错误/已存在

使用短的真实绝对路径与私有目录;先查清 socket owner,不自动放宽权限或删 socket

BUSY

先等当前 turn 完成,或用 steer;不要重复 spawn

waiting_approval

查看准确的 pendingPermissions 并处理授权;不要开 bypass

CONTROL_TIMEOUT

操作可能已经发生,先观察;仍不确定且需要停止则 close

gap:true

较早事件被淘汰;报告缺口,必要时调整 ringSize 后重启

30 分钟后自动关闭

检查租期;只读轮询没有续租

登录/网络错误

由用户在同账号同 HOME 的官方 CLI 复核中国站登录与网络;不要输出秘密

数据与许可

事件中已对常见秘密键、Bearer 文本、部分已知环境秘密及 thinking 类型块做最小化处理,但它不是完整的数据防泄漏系统。文件内容、CLI stderr、任意未知格式秘密仍可能进入输出。不要向任务提供秘密,不要把原始事件作为公共日志,不要把 CodeBuddy 输出当命令执行或授权依据。

桥接原创代码采用 MIT。npm 依赖与另装的 CodeBuddy CLI 各自保留原许可/服务条款;本项目不重新许可、不打包分发官方 CLI。

Related MCP Connectors

Related MCP Servers