文章内容
一、项目概述
AgentPlanFlow 是一个面向多智能体协作编程的桌面工作台。它把 Codex(OpenAI)、Claude Code(Anthropic)和 Hermes(Nous Research)组织在同一个原生桌面窗口里,让不同智能体可以围绕同一工作目录运行、协作、委托任务,并共享执行上下文。
它并不是简单地把几个终端拼在一起。AgentPlanFlow 在桌面侧负责窗口、终端、进程和跨面板控制,在服务侧提供模型 API 代理、请求记录、控制台输出和 Trace 事件管理。这样一来,用户既可以直接操作每个智能体,也可以让 Hermes 拆解任务后,把子任务委托给 Codex 或 Claude,再把结果带回编排流程。
AgentPlanFlow 还集成了 Codex App / Codex Desktop。桌面层会启动 codex-desktop,再通过 X11 窗口定位与同步方案,把 Codex App 视觉嵌入到 GTK 工作台左侧区域。用户可以在 Codex App 中保留完整的图形化交互体验,同时继续使用 Codex CLI 面板参与 Hermes 的自动委托链路。
各面板的职责如下:
| 面板 | 运行对象 | 主要职责 |
|---|---|---|
| Codex App | OpenAI Codex Desktop | 图形化 Codex 交互入口,视觉嵌入 GTK 工作台 |
| Codex | OpenAI Codex CLI | 代码生成、修复和局部实现,可被 Hermes 委托 |
| Claude Code | Anthropic Claude CLI | 代码审查、重构建议和复杂推理 |
| Hermes | Nous Research Hermes CLI | 任务拆解与编排,可通过 ask_codex / ask_claude 委托子任务 |
| Trace | 内置 Trace / Console 面板 | 展示代理请求、控制台输出和任务事件 |
这个设计的核心目标,是把不同智能体的优势放进同一个开发工作流:Codex 偏向出图,Claude 偏向审查和解释,Hermes 则负责拆解、调度和串联任务。

二、技术栈
| 层次 | 技术选型 | 工程结构 |
|---|---|---|
| 桌面 GUI | Python 3 + GTK3 + VTE | index.py、app/ |
| Codex 桌面嵌入 | X11 窗口嵌入与同步 | app/embed/ |
| 跨面板控制 | PTY + Unix Domain Socket + JSON | app/control_server.py、service/hermes/bridge/ |
| API 代理服务 | Rust + Tokio + Axum | service/proxy/ |
| Web 仪表盘 | Rust + Axum + SSE | service/proxy/crates/web_app/ |
| 终端仪表盘 | Rust + Ratatui | service/proxy/crates/tui_app/ |
| Python 绑定 | PyO3 | service/proxy/crates/python_api/ |
| 容器化 | Docker + Compose | docker/ |
核心依赖关系可以概括为:
index.py是 GTK3 桌面应用入口,负责创建窗口、读取配置、启动 Codex、Claude、Hermes 和 Trace 面板。CodexEmbedder负责启动并管理 Codex App,把codex-desktop作为独立 X11 顶层窗口固定到 GTK 嵌入区。- Codex、Claude、Hermes 分别运行在独立 PTY 中,保留各自原生 CLI 的认证、会话和交互体验。
- Hermes 通过 Bridge Plugin(
agentplanflow-bridge)访问本机 Unix Socket,把任务发送到 Codex 或 Claude 面板。 - Rust Proxy Service 提供 OpenAI / Anthropic 风格的兼容路由,并把请求、响应和控制台输出推送到观测层。
三、系统架构
3.1 整体架构图
下图展示了 AgentPlanFlow 从桌面窗口到上游模型服务的整体链路。

架构可以分为四层:
- 桌面窗口层 Desktop:GTK3 + VTE 承载 Codex App、Codex CLI、Claude Code、Hermes 和 Trace。Codex App 通过 X11 视觉嵌入固定在桌面工作台中,其他智能体则以 PTY 终端面板运行。
- 服务应用层 Service App(Python):负责 PTY 进程管理、Unix Socket 控制服务和面板输出采集,是桌面窗口和智能体 CLI 之间的协调层。
- 代理服务层 Proxy Service(Rust):负责 API 代理、请求记录、Trace 事件、Web / TUI 仪表盘,以及 Python API 绑定。
- 上游 LLM 服务:真正处理模型请求的服务端,可以是不同模型提供方或兼容 OpenAI / Anthropic 协议的服务。
主要数据流有两条:
- 任务委托流:用户把任务交给 Hermes,Hermes 通过
ask_codex或ask_claude发起委托;请求经 Unix Socket 到达 Control Server,再写入对应 PTY 面板,最终把终端输出作为结果返回。 - 模型代理流:Codex CLI、Claude Code 或其他客户端发起模型请求;Proxy API Server 接收后路由到上游 LLM 服务,并把请求摘要、响应预览和 Trace 事件交给 Manager Service。
Codex App 是一个独立的图形化入口。它由 AgentPlanFlow 统一启动、定位、隐藏和恢复,但不直接参与 Hermes 的 PTY 委托返回链路。
3.2 Rust Proxy Service 内部模块结构

Cargo.toml :
# service/proxy/Cargo.toml[workspace]members = [ ".", "crates/trace/lib", "crates/clients", "crates/clients/common", "crates/clients/deepseek", "crates/clients/minmax", "crates/plan", "crates/http-proxy", "crates/api_server", "crates/manager", "crates/python_api", "crates/tui_app", "crates/web_app",]Proxy Service 由两类模块组成:
- 核心服务:
main是程序入口;api_server负责 API 代理,默认监听127.0.0.1:3001;manager负责 Console / Trace 管理,默认监听127.0.0.1:3002;web_app提供 Web 仪表盘,默认监听127.0.0.1:3000。 - 支撑模块:
plan承担任务拆解和协作相关能力;clients封装上游模型客户端;trace提供追踪基础设施;python_api通过 PyO3 暴露 Python 扩展;tui_app提供终端仪表盘;vendor放置外部协议和执行策略相关依赖。
api_server、manager 和 web_app 构成了运行时的服务闭环:API Server 处理模型请求,Manager 聚合可观测数据,Web / TUI / Trace 面板再把这些数据展示出来。
四、核心工作流程
4.1 应用启动流程
下图展示从执行入口到桌面面板可用的启动过程。

# index.py:4629-4672(精简)def main() -> int: args = parse_args() app_config = load_app_config() # ... 加载配置、解析 CWD maybe_reexec_with_system_python() # ① 检查 GTK 环境 gtk = load_gtk() # ② 加载 GTK/VTE 绑定 builder = AppBuilder(gtk) terminal_pane_cls = build_terminal_pane_class(...) main_window_cls = builder.main_window_class(terminal_pane_cls) terminal_app_cls = builder.terminal_app_class(main_window_cls) app = terminal_app_cls( # ③ 构建 GTK Application codex_runtime.resolve_cli_command(args.codex_cmd), claude_runtime.resolve_cli_command(args.claude_cmd), hermes_runtime.resolve_cli_command(args.hermes_cmd), args.proxy_cmd, cwd, ... ) return app.run(sys.argv) # ④ 进入 GTK 主循环启动流程分为 6 步:
- 检查 GTK 环境:
maybe_reexec_with_system_python()检查 PyGObject、GTK3 和 VTE 是否可用,必要时切换到系统 Python 重新执行。 - 加载配置文件:读取
config.yaml、model_config.yaml、api_key_config.yaml等配置,准备工作目录、模型和代理参数。 - 构建桌面窗口:创建 GTK3 主窗口,并组织 Codex App 嵌入区、Codex、Claude、Hermes、Trace 和状态栏布局。
- 启动面板进程:在独立 PTY 中启动 Codex、Claude、Hermes 等 CLI;同时启动
codex-desktop,等待其 X11 窗口被捕获后同步到嵌入区。
# app/embed/codex_embed.py:1-14"""Visually-embedded codex-desktop window via X11 position synchronisation.We tried real XReparentWindow into a host widget, but Chromium's top-levelwindows can't survive being reparented to a non-root parent — Electron detectsit and quits. Instead we keep codex-desktop as its own top-level X window and:* strip its decorations (_MOTIF_WM_HINTS)* mark it as _NET_WM_STATE_SKIP_TASKBAR / SKIP_PAGER / ABOVE* set WM_TRANSIENT_FOR to our main window so the WM treats it as a child* keep it positioned over the EventBox host area in screen coordinates"""实际做法是去掉窗口装饰、标记跳过任务栏、设置 WM_TRANSIENT_FOR 让它跟随主窗口,然后用屏幕坐标持续同步位置。
- 启动控制服务:创建
cache/control.sock,监听来自 Hermes Bridge Plugin 的跨面板请求。 - 进入交互状态:窗口恢复布局,Hermes 面板获得焦点,用户可以开始输入任务。
这条启动链路的关键点是先准备桌面运行环境,再启动智能体面板,最后开放跨面板控制。这样可以保证 Hermes 开始编排任务时,Codex / Claude 面板和本地 Socket 服务都已经就绪。
4.2 跨智能体协作流程
Hermes 将子任务委托给 Codex 或 Claude 的链路。

以"先让 Codex 生成代码,再让 Claude 审查"为例,协作过程如下:
- Hermes 理解用户任务,决定调用
ask_codex或ask_claude。 - Bridge Plugin(
agentplanflow-bridge)把委托内容封装成本地 JSON 请求。 - 请求通过 Unix Domain Socket 发送给 Control Server。
- Control Server 执行
run_prompt动作,把 prompt 写入目标面板的 PTY stdin。
Control Server 的 _run_prompt 方法实现如下:
# app/control_server.py:132-167(精简)def _run_prompt(self, request: dict[str, Any]) -> dict[str, Any]: pane_label = str(request.get("pane") or "Codex") prompt = str(request.get("prompt") or "") idle_timeout = max(0.5, float(request.get("idle_timeout") or 2.0)) timeout = max(idle_timeout, float(request.get("timeout") or 90.0)) pane = self._invoke_main(self._owner.get_pane_by_label, pane_label) # ... 检查 pane 是否存在、进程是否在运行 # 用 bracketed-paste 包装 prompt,防止多行内容被 TUI 拆散 wrapped = "\x1b[200~" + prompt + "\x1b[201~" self._invoke_main(pane.send_text, wrapped, submit=False, focus=True) if submit: time.sleep(0.1) # 等 paste end marker 生效 self._invoke_main(pane.submit_enter)- Codex 或 Claude 在原 CLI 会话中执行任务,并持续向 PTY stdout 输出结果。
- Control Server 读取终端输出,并通过输出变化和 idle timeout 判断任务是否完成:
# app/control_server.py:187-202(精简)started_at = time.monotonic()saw_change = Falsewhile time.monotonic() - started_at < timeout: latest_state = self._invoke_main(pane.activity_state) revision = int(latest_state.get("revision") or 0) if revision > effective_baseline: saw_change = True if saw_change: last_activity = float(latest_state.get("last_activity_monotonic") or started_at) if time.monotonic() - last_activity >= idle_timeout: break # 终端输出停止 idle_timeout 秒,判定任务完成 time.sleep(0.2)- 任务结果沿 Socket 返回给 Bridge Plugin,再回到 Hermes 的上下文中。
- Hermes 根据返回结果继续拆解任务、调用另一个智能体,或把最终结论交还给用户。
这条链路的特点是低侵入。AgentPlanFlow 不要求 Codex 或 Claude 暴露额外 API,而是复用已有 CLI 的认证、会话、模型配置和交互界面。代价是任务完成判断依赖终端输出和 idle timeout,因此长时间流式输出、强交互确认或输出格式变化,都需要更谨慎地配置超时和结果抓取策略。
4.3 API 请求代理流程
下图展示模型请求经过 Proxy Service 的转发过程。

代理链路如下:
- Codex CLI、Claude Code 或其他客户端发起 HTTP 模型请求。
- Proxy API Server(Rust Axum,默认端口
3001)接收请求。
Proxy Service 的入口在 service/proxy/src/main.rs:
// service/proxy/src/main.rs:55-84(精简)#[tokio::main]async fn main() -> Result<()> { let cli = Cli::parse(); let file_config = FileConfig::load_from(&app_root().join("config.yaml"))?; trace::set_enabled(file_config.resolve_trace_enabled()); match cli.command { Some(Command::Serve { api_bind, web_bind, workspace, .. }) => { let runtime = build_runtime(&file_config, api_bind, web_bind, workspace, base_url, model, api_key)?; ensure_runtime_ports_free(&runtime)?; // 端口占用检测 if tui { run_runtime_with_tui(runtime).await } else { run_runtime_servers(runtime).await // 启动 API + Manager + Web } } // ... }}- API Server 根据路径进入 OpenAI 风格或 Anthropic 风格的兼容处理逻辑,例如
/v2/chat/completions、/v1/*和/anthropic/v1/messages。 - Proxy Service 根据模型配置选择对应的上游客户端,并转发请求。
- 上游 LLM 服务返回普通响应或 SSE 流式响应。
- 响应沿原请求路径返回给调用方。
- Manager Service 同步记录请求摘要、响应预览、Trace 事件和 Console 输出,供 Web 仪表盘、TUI 仪表盘和 Trace 面板查看。
这层代理的职责不只是"转发请求",而且将模型适配、协议兼容和运行观测集中聚合到一个 Rust 服务。
五、Q&A
5.1 为什么选择桌面应用,而不是纯 Web 应用?
- 保留原生 CLI 体验:Codex、Claude 和 Hermes 仍以各自熟悉的终端形态运行,用户可以随时查看、输入和干预。
- 复用本地开发环境:工作目录、认证状态、终端配置和模型选择都可以跟随本机环境,不需要重新搬到浏览器沙箱中。
- 支持 Codex App 嵌入:在 X11 环境下,Codex Desktop 可以被嵌入到 GTK 工作台中,形成更统一的桌面体验。
- 本地控制链路更短:跨面板委托通过 Unix Socket 和 PTY 完成,适合单机桌面场景。
5.2 为什么同时保留 Codex App 和 Codex CLI?
Codex App 和 Codex CLI 在 AgentPlanFlow 中承担的是两种互补入口。
- Codex App 更适合用户主动探索、调整和继续对话,保留 Codex Desktop 自身的产品化体验。
- Codex CLI 面板 更适合被 Hermes 自动委托,因为它运行在可控 PTY 中,Control Server 可以写入 prompt、读取 stdout,并捕获任务结果。
- 嵌入方式低侵入:AgentPlanFlow 不改造 Codex App 内部实现,只负责启动、定位、隐藏和尺寸同步,因此 Codex App 可以继续按原应用方式升级和运行。
- 工作流边界清晰:人工探索走 Codex App,自动化子任务和跨面板结果回传走 Codex CLI PTY。
因此,两者并不是重复建设。Codex App 提供更完整的人工交互体验,Codex CLI 提供更适合编排的机器可控通道。
六、总结
整体来看,AgentPlanFlow 更像是一个本地多 Agent 编程实验平台。将智能体协作从"多个终端之间手动切换"推进到"统一桌面中的可编排工作流":
- 多智能体协作:Codex 负责实现,Claude 负责审查,Hermes 负责任务拆解和编排。
- Codex App 嵌入:在 GTK 工作台内提供图形化 Codex 入口,同时保留 Codex CLI 作为可委托的自动化通道。
- 低侵入集成:通过 PTY 和 Unix Socket 复用已有 CLI 会话,而不是强制接入专用 API。
- 可观测工作流:通过 Manager、Trace、Console、Web 和 TUI 视图观察请求与任务执行过程。
- 本地桌面体验:GTK3、VTE 和 Codex 桌面嵌入让多个智能体集中在一个窗口中工作。
- 可扩展代理层:Rust Proxy Service 为模型兼容、请求记录和后续多模型适配提供基础。
本文由 AgentPlanFlow 生成