From 0e1081b64afc5dd0517d4ef9de811296263e1cb6 Mon Sep 17 00:00:00 2001 From: hei Date: Wed, 8 Jul 2026 07:33:49 +0800 Subject: [PATCH] WOR-119: add claude_codex_bridge architecture analysis --- README.md | 6 +- ...e-codex-bridge-architecture-analysis.zh.md | 383 ++++++++++++++++++ 2 files changed, 388 insertions(+), 1 deletion(-) create mode 100644 docs/claude-codex-bridge-architecture-analysis.zh.md diff --git a/README.md b/README.md index 6f047455c..f4d6eb5c5 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ **中文** | [English](readme_en.md) | [日本語](readme_ja.md) | [Français](readme_fr.md) | [Deutsch](readme_de.md) | [العربية](readme_ar.md) | [Español](readme_es.md) | [Português](readme_pt.md) | [한국어](readme_ko.md) | [Русский](readme_ru.md) -[快速开始](#quick-start) · [Mobile App](#mobile-app) · [Rich 模式](#rich-mode) · [配置团队](#configure-agents) · [使用文档](docs/manuals/user-guide/) · [开发文档](docs/manuals/developer-guide/) +[快速开始](#quick-start) · [Mobile App](#mobile-app) · [Rich 模式](#rich-mode) · [配置团队](#configure-agents) · [使用文档](docs/manuals/user-guide/) · [开发文档](docs/manuals/developer-guide/) · [架构分析](docs/claude-codex-bridge-architecture-analysis.zh.md)

CCB 可见多 Agent CLI 工作台 @@ -230,6 +230,10 @@ CCB 支持 [Agent Roles Spec](https://github.com/SeemSeam/agent-roles-spec): `.ccb/ccb_memory.md` 是项目级共享记忆文档,适合记录团队协作规则、项目约束、长期上下文和 agent 交接约定。把跨 agent 的稳定信息放在这里,比把同一段说明复制到多个 provider 私有记忆里更可靠。 +如果你想先快速理解 CCB 当前的系统形态,而不是从源码入口逐层追踪,可以先看这篇架构分析: + +- [深入分析 claude_codex_bridge](docs/claude-codex-bridge-architecture-analysis.zh.md) + ## 联系方式 diff --git a/docs/claude-codex-bridge-architecture-analysis.zh.md b/docs/claude-codex-bridge-architecture-analysis.zh.md new file mode 100644 index 000000000..0d78ebf3b --- /dev/null +++ b/docs/claude-codex-bridge-architecture-analysis.zh.md @@ -0,0 +1,383 @@ +# 深入分析 claude_codex_bridge:它不是“给 Claude 和 Codex 搭个桥”,而是在做一个可见的多 Agent 操作系统 + +`claude_codex_bridge`,现在更常直接以 `CCB` 的名字出现,看上去像一个“把 Claude、Codex、Gemini 等 CLI 串起来”的工具。但真正读完代码以后,会发现它的野心比“桥接”大很多。 + +它本质上想做的,不是把多个模型命令行塞进一个 tmux 布局,而是把“多 Agent 协作”从一堆临时脚本、会话历史和人为调度,收敛成一个项目级、可恢复、可监督、可接管的运行时系统。 + +这篇文章基于仓库 `c6983bb24f676e015011c1767e633b4f0054d206`(`release: prepare 8.0.19`,2026-07-07)以及项目 README、架构文档、测试和 DeepWiki 页面做分析。需要先说明一点:DeepWiki 页面抓取到的索引时间是 `2026-05-18`,比当前 checkout 旧,所以它适合作为结构参考,不应替代当前源码。 + +## 先说结论:CCB 的核心价值不在“多模型”,而在“多 Agent 的可运维性” + +很多多 Agent 工具的第一层卖点是: + +- 同时调用多个模型 +- 让一个 agent 去 ask 另一个 agent +- 把协作过程放进终端或者 Web UI + +这些点 CCB 都有,但它真正有辨识度的是另外三件事: + +1. 它把每个 agent 都当成一个长期存在的运行单元,而不是一次性的 prompt 调用。 +2. 它把 agent 间通信建模成可持久化、可恢复的邮箱事件,而不是 stdout/stderr 级别的拼接。 +3. 它非常强调项目级 daemon、provider state 隔离、tmux pane 恢复和生命周期监督,也就是说,它把“AI 协作系统的运维问题”当成一等公民。 + +如果只看 README,你会以为这是一个“可见的多 Agent TUI 工作台”。如果深入 `lib/`、`docs/` 和 `test/`,更准确的描述是: + +> CCB 是一个以项目为边界、以 daemon 为控制平面、以 mailbox 为通信内核、以 provider 隔离为安全边界的多 Agent 运行时。 + +## 从入口看:Node 只是壳,Python 才是主系统 + +`package.json` 暴露了四个命令: + +- `ccb` +- `ask` +- `autonew` +- `ctx-transfer` + +但 npm 这层很薄。`bin/ccb.js` 只是转发到 `ccb-npm-runner`,真正主逻辑在 Python。`ask.py` 直接把控制权交给 `lib/ask_cli/main.py`,而 `ccb` 的入口最终会走到 `lib/cli/entrypoint_runtime.py`,再进入 `lib/cli/phase2.py`。 + +这条链路很关键,因为它解释了 CCB 的“产品表面”和“系统内核”是分离的: + +- npm 包负责安装、跨平台分发和命令暴露 +- Python runtime 负责项目发现、命令分派、daemon 通讯、provider 调度和状态存储 + +这不是一个“Node 工具套 Python 脚本”的随意拼装,反而更像是: + +- Node 负责分发层 +- Python 负责控制平面 + +这也解释了为什么仓库里测试主体几乎都围绕 Python 模块展开。 + +## 真正的主干:`ccb -> cli/phase2 -> ccbd -> provider_execution -> completion/storage` + +仓库自己的 `docs/current-project-structure.md` 已经把当前运行时主干说得很直白: + +```text +ccb + -> lib/cli/* + -> lib/ccbd/* + -> lib/provider_execution/* + -> lib/completion/* + -> lib/storage/* + lib/project/* + lib/workspace/* +``` + +这里最值得注意的是 `ccbd`。 + +`ccbd` 不是一个附属后台服务,而是当前架构里的“权威控制平面”。`lib/ccbd/app.py` 定义的 `CcbdApp` 暴露了几类核心职责: + +- 启动项目 runtime +- 维护 service graph +- 负责 heartbeat +- 执行 project stop +- 处理 shutdown / remount / recovery + +`lib/ccbd/main.py` 则把它作为项目级 daemon 长期跑起来。 + +换句话说,CCB 的中心不是某个 agent,也不是某个 provider,而是“某个项目目录下唯一权威的 daemon”。这和很多 agent 工具的思路不同。 + +很多工具的中心对象是: + +- 一次会话 +- 一个任务 +- 一个 prompt 请求 + +而 CCB 的中心对象是: + +- 一个带 `.ccb/` anchor 的项目 + +这会直接影响系统的一切设计:配置怎么解析、agent 怎么挂载、tmux pane 怎么恢复、session 状态写到哪、kill 命令清理到什么边界。 + +## 它为什么执着于项目级 daemon + +读 `docs/ccbd-startup-supervision-contract.md` 能看出,作者对“控制平面漂移”非常敏感。 + +文档核心在反复强调几件事: + +- 一个 `.ccb` anchor 只允许一个权威 `ccbd` +- lifecycle、lease、socket ownership 各自承担不同层级的 authority +- tmux pane、provider session file、runtime residue 只能作为 evidence,不能反过来重定义 authority + +这套措辞很像分布式系统或者容器编排系统里的语言:`authority`、`evidence`、`residue`、`desired agents`。 + +这不是修辞问题,而是 CCB 在试图解决一个现实难题: + +> 当一个多 Agent 项目运行几小时甚至几天后,系统里会出现 daemon 重启、pane 死亡、provider 会话残留、runtime 文件损坏、用户手动接管等情况。此时谁说了算? + +CCB 的答案不是“哪个进程还活着谁说了算”,也不是“重新扫一遍 tmux 状态”。它的答案是: + +- 配置定义想要的状态 +- daemon 定义当前权威控制平面 +- tmux 和 provider 只是证据层 + +这个边界如果守不住,多 agent 系统迟早会退化成脚本拼接。 + +## 它最有意思的部分:把 agent 通信做成邮箱内核 + +如果只看 README,你可能以为 `/ask reviewer review xxx` 只是某个快捷命令。但读 `docs/agent-mailbox-kernel-design.md`、`lib/mailbox_kernel/service.py` 和 `lib/message_bureau/facade.py` 会发现,CCB 已经不把通信当“发条消息”看了。 + +它在做的是 mailbox kernel。 + +核心思想可以压缩成四条: + +1. 每个 agent 都有自己的 inbox。 +2. 一个 agent 的入站事件必须串行消费。 +3. reply 不是直接打回 caller,而是先落盘,再回流成新的 inbound event。 +4. provider 层只提供事实,不做 retry、wait、aggregation 这类策略。 + +这意味着 CCB 不是在实现一个“聊天系统”,而是在实现一个“可执行事件队列系统”。 + +它和普通消息系统的最大差别在于,收件人不是人,而是有 runtime、有 provider backend、有 workspace 的 agent。于是“消息投递成功”不等于“任务被处理”,真正重要的是: + +- 谁 claim 了这个事件 +- 是否进入 delivering +- reply 有没有变成 caller 的新 inbound event +- 某次 retry 是否生成了新的 lineage + +这套模型有一个很大的好处:系统恢复时不会只剩聊天记录,而是还保留任务处理链本身。 + +## `ask` 的意义:不是 CLI 糖,而是统一提交入口 + +`ask` 命令在 CCB 里是一个兼容入口,但不是边角料。 + +`lib/ask_cli/main.py` 会把 `ask` 规范化成 `ccb ask`,最后还是走 `phase2` 分发。`lib/cli/ask_sender.py` 则做了一件很关键的事:推断 sender。 + +它会优先从 runtime 环境、session actor、workspace actor 里推断“当前是谁在发问”,最后才退回 `USER_ACTOR`。 + +这说明在 CCB 里,`ask` 不是“用户对 agent 说句话”这么简单,它实际上是在构造一条具有身份语义的 submission。谁是 caller,会决定后续 reply 路由、消息归档和 callback chain。 + +而测试 `test/test_v2_phase2_ask.py` 也能看出,提交任务后系统已经默认按异步 accepted job 模型来渲染结果,而不是同步阻塞等待 provider 输出。 + +也就是说,`ask` 本身就是控制平面的任务提交接口,而不是 provider shell 的代理。 + +## provider 抽象不是口号,隔离才是关键实现 + +README 里最吸睛的是 provider 名单:Codex、Claude、Gemini、Kimi、MiMo、Qwen、Cursor、Copilot、OpenCode、Droid 等。 + +但真正让这件事成立的,不是 provider 数量,而是 provider isolation。 + +`lib/provider_profiles/materializer.py` 是整个项目非常重要的一个切面。它做的事情不是“填几个环境变量”,而是: + +- 为每个 agent 和 provider 生成独立 runtime/state 目录 +- 根据 provider 类型 materialize 独立 profile +- 控制 API、auth、skills、plugins、memory 的继承策略 +- 为 Codex/Claude 这类 provider 处理更严格的 home 隔离 + +尤其值得注意的是 Codex 和 Claude 的隔离契约文档: + +- `docs/codex-session-isolation-contract.md` +- `docs/claude-session-isolation-contract.md` + +这两份文档传达了同一个观点: + +> `work_dir` 不是会话身份,provider home 才是隔离边界。 + +对 Codex,系统明确要求: + +- 显式设置 `CODEX_HOME` +- 显式设置 `CODEX_SESSION_ROOT` +- `CODEX_SESSION_ROOT` 必须在 `CODEX_HOME/sessions` +- 不能依赖全局 `~/.codex` + +对 Claude,系统则通过私有 `HOME` 投影来隔离: + +- 独立 `.claude/projects` +- 独立 `.claude/session-env` +- 独立 auth/config/skills/commands/memory projection + +这背后有很现实的工程判断: + +- 如果多个 agent 共用 provider home,所谓“多 agent”最后只是同一个账号状态在互相污染 +- 如果 session identity 依赖工作目录,恢复时一定会混乱 +- 如果不把 source home 和 managed home 分开,继承配置会和运行时 authority 打架 + +这也是为什么 CCB 虽然外表像 TUI 工具,内部却有很重的“沙箱化 provider runtime”色彩。 + +## 它并不只是协作,还在做 memory projection + +仓库里有一份很显眼的文档:`docs/memory-first-agent-architecture.md`。这不是随便写的理念文,而是真实影响实现的设计方向。 + +`lib/project_memory/materializer.py` 已经把这个方向落到工程上: + +- 确保项目 memory 目录存在 +- 收集 shared memory、agent private memory 和可继承源 +- 渲染成 runtime memory bundle +- 用 hash 比较决定是否重写 + +换句话说,CCB 对 memory 的理解不是“把对话历史存一下”,而是: + +- 项目级共享记忆 +- agent 级私有记忆 +- provider 原生格式投影 + +以 Codex 为例,生成的是托管 `AGENTS.md` bundle;对 Claude,则生成托管 `CLAUDE.md` bundle。 + +这一步很关键,因为它把“记忆”从应用层附加功能,拉到了 provider 启动前的 materialization 阶段。也就是说,对 CCB 来说,memory 不是补充品,而是 provider runtime 的一部分。 + +## tmux 在这里不是 UI,而是 runtime substrate + +很多人看到 CCB 会先注意它的终端布局。实际上它使用 tmux,并不是因为 tmux 看起来黑客味更重,而是因为它需要一个能承载这些能力的宿主层: + +- 多 pane 可见 +- 可直接人工接管 +- 可保持长期存活 +- 可与 daemon 状态对照 +- 可做 pane health / recovery / relabel / remount + +因此,tmux 在 CCB 里更像是 runtime substrate,而不是展示层。 + +这也解释了为何 `docs/ccbd-startup-supervision-contract.md` 会专门强调: + +- CCB 要用隔离的 tmux config +- 不能受用户全局 tmux 插件和 hooks 污染 +- pane 状态只能作为 evidence,不是 authority + +换个角度看,CCB 是把 tmux 从“UI 工具”提升成“agent 运行托盘”。 + +## 代码结构透露了作者在和复杂度长期作战 + +如果你看 `lib/` 的目录数量,会很快发现一个事实:这个项目已经很大,而且作者清楚这一点。 + +从 `docs/current-project-structure.md` 能看出,当前阶段的一个重要工作就是不断把扁平文件拆成 runtime 子模块、facade 和 service layer。例如: + +- `cli/*` 逐步拆到 `*_runtime/` +- `ccbd/*` 拆到 start/stop/reload/supervision 多层 +- provider 逻辑拆成 `provider_core`、`provider_backends`、`provider_execution` + +这类重构通常发生在一个项目已经经历过“功能长出来太快”的阶段之后。 + +我对这个结构的判断是: + +- 优点是边界意识很强,作者知道哪些层应该只是 facade,哪些层是真权威 +- 风险是命名空间会快速膨胀,新读者进入成本很高 + +换句话说,CCB 现在已经不是“小而美”的脚本项目,而是进入“系统工程化但仍保持快速演化”的区间了。 + +## 测试规模说明它不是 Demo,而是长期维护中的基础设施 + +这个仓库一个非常有说服力的信号是测试数量。 + +`test/` 目录下可以看到大量围绕这些主题的测试: + +- `ccbd` 生命周期与 supervision +- phase2 ask 提交 +- mailbox kernel +- message bureau +- Codex/Claude session binding +- provider execution polling +- runtime attach / reload / restore +- tmux namespace / pane / input / logs + +这说明作者不是只在做“能跑起来”的 happy path,而是在处理: + +- 崩溃恢复 +- session 绑定 +- 证据与 authority 冲突 +- daemon 重启后的状态继续 + +对这种系统来说,测试不是锦上添花,而是唯一能压住复杂度的工具。没有这些测试,任何一次 provider 升级、tmux 行为变化或路径迁移都会把系统打回脆弱状态。 + +## 它最难也最值钱的部分:把 provider 当作“不可靠但可治理的执行器” + +如果把整个项目抽象一下,CCB 的世界观大概是这样的: + +- CLI provider 不同、能力不同、日志格式不同、恢复语义不同 +- 这些 provider 不值得被信任为系统 authority +- 但它们可以被包装成统一的 execution backend + +因此 provider 层只负责: + +- 启动 +- 报告原始进展 +- 产出 completion evidence +- 暴露健康事实 + +而 retry、queue、wait-all、fan-in、callback chain、reply routing 这些更高阶能力,都尽量留在 provider 之外。 + +这其实是一个很对的方向。因为真正稳定的多 Agent 协作,不能建立在“每个 provider 都有同样 API”这个假设上,而应该建立在: + +- provider 是可替换执行器 +- 系统自己掌握通信、状态和恢复 + +从这个意义上说,CCB 和很多“多模型聚合器”的区别非常大。后者重点是统一调用;前者重点是统一运行时治理。 + +## 这个项目的真正难点,不是功能,而是边界 + +读完以后,我觉得 CCB 最难的地方不在多 provider,也不在 tmux,而在下面这些边界始终要对齐: + +- 项目 authority 和 runtime evidence 的边界 +- provider home 和 source home 的边界 +- 聊天记录、任务消息、reply event 的边界 +- UI 可见性和后台自治的边界 +- memory projection 和 provider 原生记忆机制的边界 + +一旦边界松动,系统会立即退化: + +- 没有 authority,恢复就会乱 +- 没有隔离,agent 会互相污染 +- 没有 durable mailbox,协作链就不可追踪 +- 没有 daemon,所有行为都只能绑在前台终端生命周期上 + +所以 CCB 真正的工程含量,不在“加了多少 provider”,而在它持续把这些边界写成 contract,并尽量在代码里守住。 + +## 我对 CCB 的整体判断 + +如果用一句话概括: + +> `claude_codex_bridge` 正在从“多 Agent CLI 工具”进化成“项目级 Agent runtime”。 + +它当前最强的地方有三点: + +- 架构上明确把 daemon、mailbox、provider isolation、memory projection 当成核心 +- 文档和测试都在围绕非 happy path 场景收敛 +- 对 authority / evidence / residue 的区分非常成熟 + +它当前最明显的代价也有三点: + +- 代码体量已经很大,学习曲线陡 +- 目录重构仍在进行,外部读者会感到命名和层级很多 +- provider 适配和兼容契约会持续吞噬维护成本 + +但如果目标真的是“让多 Agent 协作在真实项目里稳定跑起来,而不是演示一段漂亮 workflow”,这些代价基本都躲不开。 + +## 最后总结 + +CCB 的名字里有 `bridge`,但它现在做的早就不只是“桥”。 + +它在做的是: + +- 用 `ccbd` 建项目级控制平面 +- 用 mailbox kernel 管 agent 间消息和 reply 回流 +- 用 provider home/session isolation 把不同 CLI 执行器装进受控边界 +- 用 memory projection 把项目知识编织进运行时 +- 用 tmux 把 agent 运行、可见性和人工接管统一到一个宿主层 + +如果把它只理解成“Claude + Codex 的终端协作工具”,会低估很多。 + +更准确的理解是: + +它在尝试给 AI coding agents 搭一层真正能长期运行、能恢复、能运维、能接管的底座。 + +而这,恰恰是今天大多数多 Agent 项目最缺的部分。 + +## 参考材料 + +- 仓库:`https://github.com/SeemSeam/claude_codex_bridge` +- DeepWiki:`https://deepwiki.com/SeemSeam/claude_codex_bridge` +- 重点源码与文档: + - `README.md` + - `package.json` + - `lib/cli/entrypoint_runtime.py` + - `lib/cli/phase2.py` + - `lib/ccbd/app.py` + - `lib/ccbd/main.py` + - `lib/ask_cli/main.py` + - `lib/cli/ask_sender.py` + - `lib/mailbox_kernel/service.py` + - `lib/message_bureau/facade.py` + - `lib/project_memory/materializer.py` + - `lib/provider_profiles/materializer.py` + - `docs/current-project-structure.md` + - `docs/agent-mailbox-kernel-design.md` + - `docs/ccbd-startup-supervision-contract.md` + - `docs/codex-session-isolation-contract.md` + - `docs/claude-session-isolation-contract.md` + - `docs/memory-first-agent-architecture.md`