当前位置: 首页 > news >正文

codex cli 源码教程 | 第一篇:Codex CLI 不只是一个 CLI

Codex CLI 表面上是一个终端命令:在项目目录执行codex,输入任务,然后等待它阅读代码、执行命令并修改文件。

如果只把它理解成“给大模型套了一层命令行界面”,后续阅读源码会很快遇到困难。这个仓库实际实现的是一套本地 Agent Runtime:它既要连接模型,也要管理会话、上下文、工具、权限、沙箱、扩展、持久化和多个客户端。

本篇先不深入某个函数,而是建立一张全局地图。后续每篇课程都会沿着这张地图进入一个具体模块。

本篇目标

阅读完成后,你应该能够:

  1. 解释 Codex CLI 的产品边界,而不只把它看作终端 UI。
  2. 说清 CLI、TUI、App Server、Core 和 Tool System 的职责。
  3. 理解 Thread、Turn、Item 三个核心协议对象。
  4. 描述一条用户指令从输入到最终回复的完整路径。
  5. 知道接下来应该按什么顺序阅读源码。

1. Codex CLI 到底是什么

仓库根目录的 README.md 给出了最简洁的定义:Codex CLI 是一个运行在本地计算机上的编码智能体。

这里有三个关键词。

1.1 编码智能体

Codex 不只生成文本。它可以根据模型返回的工具调用执行实际操作,例如:

  • 搜索和读取代码。
  • 执行 Shell 命令。
  • 修改工作区文件。
  • 查看本地图片。
  • 调用 MCP 工具。
  • 发起 Web Search。
  • 创建子智能体并分派任务。
  • 运行测试并继续分析结果。

因此,一次用户请求通常不是一次模型调用,而是“模型推理、工具执行、结果回填、继续推理”的循环。

1.2 运行在本地

模型推理可以发生在远端服务,但 Codex 的 Agent Runtime 运行在用户环境中。工作区文件、终端进程、项目指令和本地工具都由这个 Runtime 管理。

这带来两个直接要求:

  1. Runtime 必须理解本地操作系统、Shell、路径和进程。
  2. Runtime 必须为文件修改、命令执行和网络访问建立安全边界。

所以仓库中既有模型客户端,也有沙箱、审批、网络策略和跨平台执行代码。

1.3 不只有命令行客户端

同一套能力需要服务于不同入口:

使用方式入口典型用途
交互终端codex人工参与的持续编码会话
无交互执行codex exec脚本、CI 和自动化任务
自动审查codex review针对代码变更执行 Review
IDE 或桌面端codex app-serverVS Code、图形客户端
MCP 集成codex mcp-server将 Codex 暴露给其他 Agent
TypeScript SDKsdk/typescriptNode.js 工作流集成
Python SDKsdk/pythonPython 应用和自动化集成

这些入口不会分别实现一套 Agent。它们最终会收敛到相同的会话、协议和执行核心。

2. 从“命令行工具”转向“Agent Runtime”

可以先用一张简化图理解整个系统:

TUI / Exec / IDE / SDK | v App Server | v ThreadManager / Session | +----+----+ | | v v ModelClient ToolRouter | v Approval / Sandbox | v Rollout / SQLite State

这张图省略了大量细节,但已经揭示了最重要的事实:

  • CLI 主要负责解析参数和选择运行模式。
  • App Server 提供统一的会话协议。
  • Core 管理 Agent 的运行状态。
  • Model Client 负责与模型服务通信。
  • Tool Router 负责将模型请求映射到本地能力。
  • Approval 和 Sandbox 控制工具能否以及如何执行。
  • Rollout 和 SQLite 负责恢复会话与查询状态。

接下来逐层拆解。

3. 第一层:发布与进程入口

用户通过 npm 安装@openai/codex时,得到的 JavaScript 并不是 Agent 的主要实现。

codex-cli/bin/codex.js 主要完成以下工作:

  1. 根据操作系统和 CPU 架构确定 Target Triple。
  2. 找到对应平台包中的原生codex二进制。
  3. 启动 Rust 二进制并继承标准输入输出。
  4. SIGINTSIGTERMSIGHUP转发给子进程。
  5. 保持父子进程退出码和信号语义一致。

也就是说,npm 包更接近“跨平台分发启动器”。真正的命令解析和业务逻辑从 codex-rs/cli/src/main.rs 开始。

Rust 入口使用 Clap 定义MultitoolCli,再由cli_main根据子命令分发:

  • 无子命令:进入交互式 TUI。
  • exec:进入无交互执行。
  • review:转换为 Exec 的 Review 模式。
  • app-server:启动 JSON-RPC 服务。
  • mcp-server:启动 MCP Server。
  • 其他子命令:处理登录、插件、沙箱、云任务和诊断等能力。

这一层的核心职责是“选择产品形态”,而不是执行 Agent 推理。

4. 第二层:客户端与用户交互

4.1 TUI

codex-rs/tui基于 Ratatui 实现交互式终端。它负责:

  • 输入编辑和快捷键。
  • 会话列表与恢复。
  • Agent 消息和 Reasoning 的流式展示。
  • 命令输出和文件 Diff 渲染。
  • 审批问题和用户输入。
  • Token 使用量、状态和错误提示。

TUI 看起来离 Core 很近,但它没有自行管理完整的 Agent 会话。默认情况下,它会启动一个进程内 App Server,再通过 App Server Client 发起 Thread 和 Turn 请求。

相关入口位于:

  • codex-rs/tui/src/lib.rs
  • start_embedded_app_server
  • AppServerSession
  • codex_tui::run_main

4.2 Exec

codex-rs/exec面向无交互场景。它关注的不是界面,而是稳定输出:

  • 默认模式下,标准输出只保留最终消息。
  • JSON 模式下,标准输出必须是合法 JSONL。
  • 日志、警告和诊断信息写入标准错误。

Exec 同样通过InProcessAppServerClient发起 Thread 和 Turn。因此,TUI 与 Exec 的差异主要在客户端交互和事件消费方式,而不是 Agent 核心。

4.3 SDK

两套 SDK 展示了两种不同的集成方式:

  • TypeScript SDK 启动codex exec --experimental-json,消费 JSONL 事件。
  • Python SDK 启动codex app-server --listen stdio://,使用类型化 JSON-RPC。

这说明 Codex 对外既提供“任务执行流”,也提供“完整会话服务”。

5. 第三层:App Server 统一协议

codex-rs/app-server/README.md 将 App Server 定义为丰富客户端使用 Codex 的接口,例如 VS Code 扩展。

App Server 支持多种传输:

  • stdio。
  • WebSocket。
  • Unix Socket。
  • 进程内 Channel。

传输形式不同,但承载的是同一组 JSON-RPC 消息。每个连接首先执行initialize握手,之后才能创建 Thread 或发起 Turn。

App Server 的价值不只是“把 Core 包成接口”,它还解决了以下问题:

  • 为 TUI、IDE、SDK 提供一致的协议。
  • 管理连接初始化与能力协商。
  • 将内部事件转换成稳定的客户端通知。
  • 维护 Thread 订阅和客户端状态。
  • 使用有界队列提供背压。
  • 隔离慢速网络写入与请求处理。
  • 支持内嵌、本地守护进程和远程服务。

理解 App Server 是阅读当前 Codex 架构的关键。很多看似属于 TUI 或 Exec 的功能,实际上已经通过 App Server 协议实现。

6. Thread、Turn、Item 三个核心对象

App Server 使用三个对象描述一次持续的 Agent 交互。

6.1 Thread

Thread 表示一段可以持续、恢复和分叉的会话。

它包含:

  • 唯一 Thread ID。
  • 当前模型和工作目录。
  • Sandbox 与 Approval 配置。
  • 多个 Turn。
  • 持久化路径和会话元数据。
  • 当前运行状态。

Thread 可以被创建、恢复、分叉、归档或删除。

6.2 Turn

Turn 表示一次用户任务。

通常从一条用户输入开始,在以下情况之一结束:

  • Agent 生成最终消息。
  • 用户主动中断。
  • 执行失败。
  • 达到限制。

一个 Turn 内部可能包含多轮模型请求。只要模型仍在请求工具,Core 就会继续执行工具并发起后续采样。

6.3 Item

Item 是 Turn 中可持久化、可流式传输的最小语义单元,例如:

  • 用户消息。
  • Agent 消息。
  • Reasoning。
  • Shell 命令。
  • 文件修改。
  • MCP Tool Call。
  • Web Search。
  • Token 使用量和错误。

Item 不只是 UI 展示对象。它同时承担协议事件、会话历史和恢复依据等职责。

6.4 Session 是什么

阅读 Core 时还会遇到 Session。

可以暂时这样区分:

  • Thread 是对外暴露的会话资源。
  • Session 是 Core 内部承载 Thread 运行状态和服务依赖的执行对象。
  • Turn 是 Session 上的一次任务。
  • Item 是 Turn 产生的结构化内容。

后续课程会进一步解释CodexThreadCodexSession的对象关系。

7. 第四层:Core Agent 引擎

codex-rs/core是 Agent 运行时的核心,但它并不是一个单文件状态机。

主要职责包括:

  • 创建和恢复 Thread。
  • 接收用户操作并输出事件。
  • 维护会话历史和上下文。
  • 构建模型请求。
  • 消费流式模型响应。
  • 调度工具调用。
  • 管理取消、重试和错误。
  • 自动压缩过长上下文。
  • 加载AGENTS.md、Skills、插件和 MCP。
  • 记录 Rollout 和遥测数据。

7.1 ThreadManager

codex-rs/core/src/thread_manager.rs 中的ThreadManager负责创建 Thread 并维护内存中的活动实例。

它持有大量共享依赖:

  • Auth Manager。
  • Models Manager。
  • Environment Manager。
  • Skills Service。
  • Plugins Manager。
  • MCP Manager。
  • Thread Store。
  • Agent Graph Store。

这表明 Thread 不是一个简单的消息数组,而是多种运行时能力的组合边界。

7.2 CodexThread

codex-rs/core/src/codex_thread.rs 中的CodexThread是调用方与 Core 交互的主要入口。

它提供的方法包括:

  • submit:提交操作。
  • next_event:读取事件。
  • steer_input:向运行中的 Turn 追加输入。
  • shutdown_and_wait:停止并等待会话退出。
  • try_start_turn_if_idle:空闲时启动自动任务。
  • fork、Rollout 和背景终端相关能力。

7.3 Session Loop

Session 创建后会启动一个异步 Submission Loop。它持续接收Op,并根据操作类型执行:

  • 启动用户 Turn。
  • 中断当前任务。
  • 更新设置。
  • 执行 Review。
  • 压缩上下文。
  • 关闭 Session。

调用方通过另一条事件通道接收执行进度。由此形成双向异步通信:

Client -- Submission/Op --> Session Client <-- Event --------- Session

8. 第五层:模型与工具循环

真正体现 Agent 特征的代码位于 codex-rs/core/src/session/turn.rs。

run_turn的注释直接描述了核心算法:

  1. 将当前会话历史和用户输入构造成 Prompt。
  2. 请求模型。
  3. 如果模型返回工具调用,执行工具。
  4. 将工具输出记录到历史。
  5. 再次请求模型。
  6. 如果模型只返回最终消息,结束 Turn。

这个循环还需要处理:

  • Turn 开始前的上下文压缩。
  • Skills 与插件注入。
  • Hooks。
  • 用户在运行期间追加的输入。
  • 并行工具调用。
  • 流式消息增量。
  • 模型请求重试。
  • Token 使用量。
  • 用户取消。

因此,run_turn可以看作 Codex Agent Runtime 的主循环。

8.1 ModelClient

codex-rs/core/src/client.rs 中的ModelClient负责模型通信。

它支持:

  • Responses API。
  • SSE 流式响应。
  • WebSocket 会话。
  • Provider 认证。
  • 重试和连接恢复。
  • 请求级遥测。

仓库内置 OpenAI、Amazon Bedrock、Ollama 和 LM Studio 等 Provider,也允许用户配置兼容服务。

8.2 ToolRouter

工具系统主要位于codex-rs/core/src/tools

其中:

  • spec_plan.rs决定当前 Turn 应该有哪些工具。
  • registry.rs保存工具名到执行器的映射。
  • router.rs解析模型返回的 Tool Call。
  • parallel.rs管理工具调用的并行执行和结果顺序。
  • handlers包含具体工具实现。

工具列表不是固定常量。它会受到以下因素影响:

  • 模型能力。
  • Feature Flag。
  • 当前执行环境。
  • MCP Server。
  • 插件和动态工具。
  • Code Mode。
  • 当前是否为 Review 或 Guardian 会话。

9. 第六层:安全与执行环境

Agent 能执行命令并修改文件,因此“能不能执行”和“在哪里执行”必须在模型之外判断。

Codex 主要通过三层机制控制风险。

9.1 Approval Policy

Approval Policy 决定何时向用户发起审批,例如:

  • 从不请求审批。
  • 模型按需请求。
  • 不可信操作需要审批。
  • 分别控制命令、规则、Skill 和权限请求。

9.2 Exec Policy

Exec Policy 根据命令和规则产生决策:

  • 允许。
  • 拒绝。
  • 请求审批。

它不会因为模型“认为安全”就跳过本地策略。

9.3 Sandbox

codex-rs/sandboxing/src 提供跨平台沙箱抽象:

  • macOS:Seatbelt。
  • Linux:Bubblewrap 和 Landlock。
  • Windows:受限 Token 与文件系统策略。

Sandbox 进一步限制:

  • 可读目录。
  • 可写目录。
  • 网络访问。
  • 进程能力。

审批与沙箱不是互相替代的。审批表达用户是否授权某项操作,沙箱负责限制操作实际能影响的范围。

10. 持久化:为什么同时需要 JSONL 和 SQLite

Codex 会话需要支持恢复、搜索、分叉、归档和审计。

仓库使用两类持久化数据。

10.1 Rollout JSONL

codex-rs/rollout将会话事件追加写入 Rollout 文件。默认路径类似:

~/.codex/sessions/YYYY/MM/DD/rollout-时间-线程ID.jsonl

JSONL 适合:

  • 按发生顺序记录事件。
  • 追加写入。
  • 恢复完整历史。
  • 保留协议演进所需的信息。

10.2 SQLite State

codex-rs/state使用 SQLite 保存结构化状态和索引,例如:

  • Thread Metadata。
  • Rollout 路径。
  • Git 信息。
  • 记忆处理状态。
  • Thread Goal。
  • Agent Spawn Graph。
  • Agent Job。
  • 远程控制信息。
  • 结构化日志。

SQLite 适合分页、筛选、排序和快速查询。JSONL 保存事实流,SQLite 提供可查询视图,两者通过回填和对账机制保持关联。

11. 仓库地图

理解职责后,再看目录会清晰很多。

路径主要职责
codex-rs/cli命令定义、参数解析、运行模式分发
codex-rs/tui交互式终端客户端
codex-rs/exec无交互执行与 JSONL 输出
codex-rs/app-serverJSON-RPC 服务与连接管理
codex-rs/app-server-protocolApp Server 请求、响应和通知类型
codex-rs/coreSession、Turn、上下文和工具调度
codex-rs/protocolCore 操作、事件、审批和配置类型
codex-rs/model-provider模型提供方运行时抽象
codex-rs/codex-mcpMCP 连接与工具管理
codex-rs/sandboxing跨平台沙箱选择与策略转换
codex-rs/rollout会话事件持久化
codex-rs/stateSQLite 状态、日志和迁移
codex-rs/skillspluginhooks扩展机制
sdk/typescriptTypeScript SDK
sdk/pythonPython SDK
codex-clinpm 原生二进制启动器
scripts构建、打包、格式化和发布脚本

codex-rs/Cargo.toml中的 Workspace Members 是更完整的模块索引。不要尝试第一次就逐个阅读所有 crate,先沿一条请求链建立主干。

12. 一条用户请求的完整旅程

现在可以把前面的模块串起来。

假设用户在终端执行:

codex"解释这个项目的架构"

请求大致经历以下步骤:

  1. npm 启动器找到当前平台的 Rust 二进制。
  2. cli/src/main.rs解析参数,发现没有子命令。
  3. CLI 调用codex_tui::run_main
  4. TUI 默认启动进程内 App Server。
  5. TUI 发送thread/start,App Server 创建 Core Thread。
  6. 用户输入被转换为turn/start
  7. Core Session 接收操作并进入run_turn
  8. ModelClient向模型发送包含上下文和工具定义的请求。
  9. 如果模型请求工具,ToolRouter在审批和沙箱约束下执行。
  10. 工具结果写入历史并再次发送给模型。
  11. 最终 Agent Message 以流式事件返回 App Server。
  12. TUI 将事件渲染到终端,同时 Rollout 和状态索引被更新。

其中第 8 到第 10 步可以重复多次。

这也是后续课程反复使用的主调用链:

CLI -> Client -> App Server -> Thread -> Turn -> Model -> Tool -> Model -> Event -> Client

13. 这个架构有哪些重要取舍

13.1 协议优先

TUI、Exec、IDE 和 SDK 不直接共享 UI 代码,而是共享 Thread、Turn、Item 协议。新增客户端时,不需要重新实现 Agent 核心。

13.2 安全策略位于 Runtime

模型只能请求操作,不能决定最终权限。执行策略、审批和沙箱在本地 Runtime 中独立判断。

13.3 工具按上下文动态组装

Codex 不会把所有工具无条件暴露给模型。Tool Plan 根据模型、Feature、环境和扩展生成当前 Turn 的工具集合,减少无效能力和命名冲突。

13.4 事件流既服务 UI,也服务恢复

流式事件不仅用于实时显示,还会进入会话历史和持久化体系。这使中断、恢复、分叉和审计拥有统一事实来源。

13.5 大 Core 正在被主动约束

根目录 AGENTS.md 明确提醒开发者不要继续无条件扩张codex-core。新增概念应优先寻找现有独立 crate,必要时创建新的职责边界。

这是阅读和修改仓库时非常重要的工程约束:能够放进 Core,不代表应该放进 Core。

14. 初学者常见误区

误区一:npm 包就是 Codex 的主体

npm 包主要负责分发和启动。Agent 主体是 Rust 工作区中的原生二进制和各个 crate。

误区二:App Server 是远端模型服务

App Server 是 Codex 的客户端协议层。它可以本地运行,也可以通过远程传输访问,但它不等同于模型推理后端。

误区三:一次 Turn 等于一次模型请求

一次 Turn 可能包含多次模型采样。每次工具调用通常都会触发后续模型请求。

误区四:TUI 直接调用 Core

当前架构中,TUI 默认通过进程内 App Server 驱动 Thread 和 Turn。App Server 是统一边界,不只是给 IDE 使用的附加服务。

误区五:审批后就不需要沙箱

审批和沙箱解决不同问题。审批确认意图,沙箱限制影响范围。

误区六:所有新功能都应加入codex-core

项目规范明确要求控制 Core 体积。模型 Provider、状态、插件、协议和工具基础设施已经拆分成独立 crate。

15. 建议的源码阅读方法

大型仓库最有效的阅读方式不是从lib.rs开始逐文件展开,而是沿一个行为搜索入口。

第一轮可以只执行以下搜索:

rg-n"fn main|async fn cli_main"codex-rs/cli/src/main.rs rg-n"start_embedded_app_server|run_main"codex-rs/tui/src/lib.rs rg-n"start_thread_with_options"codex-rs/core/src/thread_manager.rs rg-n"async fn run_turn"codex-rs/core/src/session/turn.rs

阅读时为每个函数记录三件事:

  1. 输入从哪里来。
  2. 状态由谁持有。
  3. 输出发送给谁。

不要在第一轮追踪所有错误分支和 Feature Flag。先找到主路径,再逐步补充安全、重试和兼容逻辑。

16. 动手练习

练习一:绘制产品入口图

Subcommand枚举出发,将所有子命令按以下类别分组:

  • Agent 交互。
  • 服务端。
  • 鉴权和配置。
  • 扩展管理。
  • 调试和诊断。

要求每个类别至少标记一个最终调用的 crate。

练习二:验证统一 App Server

分别在以下文件中寻找InProcessAppServerClient

  • codex-rs/tui/src/lib.rs
  • codex-rs/exec/src/lib.rs

回答:

  1. 两个客户端如何启动 App Server?
  2. 它们如何构造 Thread 参数?
  3. 它们消费事件的方式有什么差异?

练习三:建立个人仓库地图

只选择十个最关键的 crate,为每个 crate 写一句职责说明,并画出依赖方向。

建议至少包含:

  • cli
  • tui
  • exec
  • app-server
  • app-server-protocol
  • core
  • protocol
  • model-provider
  • sandboxing
  • state

练习四:跟踪一次 Turn

从 App Server 的turn/startRequest Processor 开始,一直跟踪到run_turn

记录经过的类型和函数,不需要阅读每个函数内部实现。最终产出一条可以在 IDE 中逐步跳转的调用链。

17. 本篇小结

Codex CLI 不是简单的“终端加大模型”,而是一套面向本地编码任务的 Agent Runtime。

它的核心结构可以概括为:

  1. CLI 选择运行模式。
  2. TUI、Exec、IDE 和 SDK 作为不同客户端。
  3. App Server 统一 Thread、Turn、Item 协议。
  4. Core 管理 Session、上下文和 Agent 循环。
  5. Model Client 与 Tool Router 交替完成推理和执行。
  6. Approval、Exec Policy 和 Sandbox 建立本地安全边界。
  7. Rollout 与 SQLite 支持持久化、恢复和查询。

掌握这张地图后,后续阅读就不再是面对数千个文件,而是沿着明确的数据流和控制流逐层深入。

下一篇将进入实际开发环境,介绍 Cargo、Just、Bazel 和 pnpm 在仓库中的分工,并建立可重复的构建、测试与日志观察流程。

http://www.jsqmd.com/news/1304923/

相关文章:

  • 深入理解 Linux 匿名管道:从进程间通信到内核级实现
  • 西门子840D/828D数控系统数据采集方案:OPC UA、NC变量与PLC通讯实战
  • 连锁酒店中央热水机组选什么牌子靠谱?:【芬尼】恒温续航 - 松梢月冷
  • Cursor Free VIP终极指南:5个简单步骤永久免费使用AI编程助手
  • C语言学习笔记(十)——指针基础与数组指针应用
  • 什么是三维数字沙盘?
  • 人害怕未知:本质是不知道下一步在哪里。
  • 豆包多轮意图漂移难题如何破局:从BERT-Whitening到动态对话图谱的5阶演进路径
  • 串口通信实战:从硬件连接到协议设计,打通电脑间数据传输
  • 进程间通信(IPC)核心机制解析与实战选型指南
  • 亲测合规\踩雷,体制内写稿效率翻倍
  • Verilog异或运算实战:格雷码、奇偶校验与奇数分频
  • 什么是 CSS?
  • 毕业论文终检前夕,如何快速搞定高重灾区与AI嫌疑句?
  • 一个人做多个公众号矩阵:如何优雅地规避平台的“一锅端”风险?
  • 2026年ES柜源头实力工厂甄选:五折柜/电控柜/控制柜/配电柜供应厂家全解析 - 优企名品
  • 【新闻】687个!本周艾为官网新增6个应用方案
  • 彻底解决Python文件读取UnicodeDecodeError:从编码原理到实战方案
  • 电机控制技术解析:从FOC到DTC,深入理解磁场定向与直接转矩控制
  • 醴陵市外墙漏水怎么处理_2026湖南东部湘东丘陵城市漏水维修流程教程与精选 - 雨婺虹房屋维修
  • 2026年聚醚消泡剂厂家实力排行榜,水性涂料/发酵/工业清洗专用聚醚消泡剂源头工厂精选推荐! - 优企名品
  • 如何在Obsidian中轻松管理电子表格?终极Excel插件完全指南
  • DedeCMS文件上传漏洞深度修复:从代码加固到服务器防线的三层防御方案
  • 8月更新:ChatGPT Pro、Plus 与 Codex 如何改变软件产品从想法到落地的速度(GPT-5.6与AI产品工程技术分享)
  • 告别“小助手”!乐享、擎天再升级,联想让AI“下场干活”
  • STM32CubeIDE调试失败:GDB服务器启动错误排查全攻略
  • Matlab txt数据导入与可视化:科研论文高效出图全流程指南
  • MP4Box.js:浏览器端MP4处理的革命性突破
  • 盗版设计软件的真实代价:数据安全、效率与法律风险全解析
  • PLC项目实战:从核心角色到技术栈的工业自动化实践指南