CodeBuddy Agent Bridge
by zhimadelvdou
README.md
# 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 探测;各版本的验证范围单独列在 [验证记录](docs/testing.md)。目标 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 完整契约](docs/command-profiles-v0.5.1.md)。
仍为 21 个 MCP 工具,无新增依赖、计时功能或自动部署;文件 grants、capabilities/summary/recover 契约不变。未改动或重启已知本地 0.3.0 / 15-schema 部署。验证与限制见 [本版验证记录](docs/testing.md)。
## 0.5.0:按任务选择精确命令授权
仍为 **21 个 MCP 工具**。操作者可显式配置 `commandProfiles:[{id,category,workspace,command}]`,默认为空;category 仅支持 `test`、`build`、`git-query`。这些是审查过的工作目录与完整命令,不是 shell 前缀、通配符或类别级放行。详细语法和边界见 [0.5.0 命令 profile](docs/command-profiles-v0.5.0.md)。
- `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 配置模板](examples/bridge.command-profiles.config.json)。配置、选择 ID 和模型文字不能证明适用的人类批准;敏感数据、系统设置、破坏性或其他高风险动作不能靠 `test` / `build` / `git-query` 标签授权。测试和构建会执行受信任的项目代码及依赖,可能产生任意效果;精确匹配不是沙箱,宿主政策始终优先。本次只做离线验证,结果见 [验证记录](docs/testing.md)。
以下版本小节保留历史;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 会话控制](docs/session-controls-v0.4.0.md)。
- **进程内范围授权**:`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 观察时间,不是价格生效/更新时间,不保证即时计费准确或按请求固定扣费。完整字段约束见 [模型倍率协议](docs/protocol.md#032-模型积分倍率展示)。本版通过离线 fixture 和源码证据验证;真实在线倍率查询尚未验证,没有为此执行生成或登录操作。
## 0.3.1:账号查询与人工登录入口
WebUI 常驻显示 daemon 当前 CLI 的脱敏账号快照;新增 `codebuddy_account` 和 `codebuddy_login`,总计 17 个 MCP 工具。默认只读,登录须操作者配置和显式人工批准。已有账号时短路,不退出、不换号;没有账号时才生成短期官方登录链接,交给人完成。查询不是凭据有效期验证。详见 [账号接口与验证边界](docs/accounts.md) 和 [监控启用步骤](docs/monitor.md)。
这是向后兼容、默认关闭的新入口,按请求使用补丁版本 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;不要暴露运行目录、改变为宽松权限或共享给其他用户。
## 目录
```text
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/...` 全部是需要替换的**绝对路径占位符**,不指向任何预设云机器。
```bash
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 快速入门](https://www.codebuddy.cn/docs/cli/quickstart)。桥接端第一次启动 worker 会自行核对版本;其他版本返回 `VERSION_MISMATCH`,不会猜测兼容性。升级时应先复核类型和行为、跑测试,再有意更新版本钉选。
## 2. 在运行 MCP 的账号下完成中国版登录
由用户在自己的终端启动官方 CLI,选择 `Log in via Chinese Site`,在官方登录界面完成认证:
```bash
export CODEBUDDY_INTERNET_ENVIRONMENT=internal
cd /ABSOLUTE/PATH/codebuddy-workspaces
/ABSOLUTE/PATH/codebuddy-runtime/node_modules/.bin/codebuddy
```
中国版使用 `CODEBUDDY_INTERNET_ENVIRONMENT=internal`;`ioa` 是另外的企业环境。见 [官方环境变量参考](https://www.codebuddy.cn/docs/cli/env-vars)。持有控制器的 daemon(或 standalone MCP)和该次登录应使用相同的运行账号及 `HOME`,否则本地认证/历史不一定可见。推荐先手动登录;0.3.1 起另有默认关闭的人工登录入口,见 [账号接口](docs/accounts.md)。桥接不读取认证文件或导出凭据。
不要把密码、API key、token 写进本仓库、prompt、日志或示例配置。优先沿用官方 CLI 登录保存的会话。若自行采用官方文档支持的环境认证,需由操作者通过宿主的安全秘密机制注入,并在 Codex 的 `env_vars` 和桥接的 `envPassthrough` 两层仅允许必要的变量名;不要把秘密值提交到 TOML/JSON。
## 3. 配置限定工作目录
先创建自己的工作目录,例如每个任务独立一个子目录:
```bash
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 分钟。全部字段与边界见 [协议说明](docs/protocol.md#配置)。`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,不能通过符号链接解析到别处:
```bash
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](docs/protocol.md#文件-ipc)。
然后把 [examples/codex.config.toml](examples/codex.config.toml) **合并**进现有 `~/.codex/config.toml` 或受信任项目 `.codex/config.toml`,不要覆盖原配置:
```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](https://developers.openai.com/codex/mcp)、[插件封装](https://developers.openai.com/plugins/build/plugins)。
daemon 没有自动安装服务或开机启动。长期运行可由操作者审查后接入本机服务管理器。锁冲突时拒绝启动;恢复前必须确认原 owner 已停止并审查残留,不能盲删 `daemon.lock` 或重放未知是否已经执行的请求。
### 可选:Unix-socket IPC
普通 POSIX 主机可选择 socket 传输;本构建环境 bind 被内核 EPERM 拒绝,**未实测该传输的跨进程集成**,不要把它当已通过的部署路径。它与文件 daemon 是独立实例,不能混用 registry,不会自动切换。
```bash
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:
```text
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`、工具名、输入和目标。展示给用户并按宿主权限政策处理。只有这次具体操作确已获授权,才调用:
```text
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;详见 [命令授权规则](docs/command-profiles-v0.5.0.md)。否则保持本次一次性应答。查看和撤销范围分别用 `codebuddy_permission_grants` / `codebuddy_revoke_permission_grant`,详见 [范围授权规则](docs/session-controls-v0.4.0.md#1-进程内文件范围授权)。未实现自动全放行或持久 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 文档](https://developers.openai.com/codex/hooks)。本项目没有安装这些 hooks。
## 7. 可选 supervisor 和 skill
根代理可以直接使用 MCP,不一定需要额外 Codex 子代理。需要原生监督角色时,可把 `examples/codebuddy-supervisor.toml` 放进受信任项目 `.codex/agents/`。它仍运行 Codex 模型、消耗正常 Codex 用量,仅监督 CodeBuddy;不会把 CodeBuddy 的外部模型注册到 Codex 原生子代理列表,也不会消除双模型成本。当前角色语法见 [Codex Subagents](https://learn.chatgpt.com/docs/agent-configuration/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**:
```bash
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。未知/缺口/截断和失联状态都会明确标记;不是完整审计日志。
需要时由操作者显式开启:
```bash
npm run monitor -- --allow-interrupt --git-diff
```
人工中断需要弹窗确认并由 daemon 原子核对当前 turn;ACK 不等于终态。文件差异按按钮读取一次,是可信本地仓库的当前跟踪文件与 HEAD 比较,**不是任务开始基线或该 worker 的专属改动**。未跟踪/秘密路径/无基线等不展示。监控只绑定 127.0.0.1,没有公开部署和远程鉴权,不适合不互信的多用户主机。
新 daemon 才有 Prompt 提交事件及受 turn 保护的中断;连接旧 daemon 时保持只读。standalone MCP 的 controller 不能由该页面接管。完整运行选项、限制和验证方法见 [监控指南](docs/monitor.md)。
本次已验证 Node HTTP 与共享文件 daemon 链路;云浏览器访问 loopback 被 `ERR_BLOCKED_BY_CLIENT` 拒绝,因此真实浏览器交互、响应式视觉和截图尚未验收。没有通过其他路由绕过,也不推断用户浏览器会遇到相同限制。
## 9. 验收与限制
先跑本地测试,不需要账户或模型额度:
```bash
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 依赖。后续版本结果见 [验证矩阵](docs/testing.md);不能把这些历史结果当作 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](LICENSE)。npm 依赖与另装的 CodeBuddy CLI 各自保留原许可/服务条款;本项目不重新许可、不打包分发官方 CLI。
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues