# OpenAI Codex CLI 0.130.0 源码全貌参考

> **文档定位**：Codex CLI（OpenAI 官方）的 Rust 源码逐 crate 解构与架构差异分析，与
> [`claude-code-reference.md`](./claude-code-reference.md) / [`openclaude-reference.md`](./openclaude-reference.md) /
> [`openclaw-reference.md`](./openclaw-reference.md) 同序列，作为 FFAI Agent 内核架构选型的事实源之一。
>
> **不做什么**：不做"哪个最好"的排名，只做"在 X 维度上 Codex 选了 Y 路线、为什么、代价是什么"的事实记录。
> 横向对比矩阵在 [`agent-implementations-comparison.md`](./agent-implementations-comparison.md)。

---

## 元信息

| 项 | 值 |
|---|---|
| 上游 | https://github.com/openai/codex |
| 分析版本 | 0.130.0（release 2026-05-08） |
| Clone commit | `4f2918d` (2026-05-14) |
| Clone 时间 | 2026-05-15 |
| 仓库大小 | ~64 MiB（不含 target/） |
| 主要语言 | Rust 96.2%（少量 TS/Python/JS shim） |
| 顶层包管理 | Cargo (workspace) + Bazel + pnpm + Nix flake |
| 任务运行器 | `just`（justfile） |
| Codex-rs Workspace | ~98 crate |
| 主要 LoC（粗略） | codex-core 152K · tui 188K · app-server 38K · app-server-protocol 24K · windows-sandbox 15K · network-proxy 9K · login 7K |
| License | Apache 2.0 |

---

## 目录

- [总览：与 Claude Code 的范式差异](#总览与-claude-code-的范式差异)
  - [0.1 五个不寻常的设计决策](#01-五个不寻常的设计决策)
  - [0.2 整体架构图](#02-整体架构图)
  - [0.3 与 v0.1 FFAI 架构的对应关系](#03-与-v01-ffai-架构的对应关系)
  - [0.4 几个关键认知](#04-几个关键认知)
- [Part I：内核与协议层](#part-i内核与协议层)
  - [1. codex-core](#1-codex-core)
  - [2. core-api](#2-core-api)
  - [3. protocol](#3-protocol)
  - [4. app-server v1 vs v2 双协议](#4-app-server-v1-vs-v2-双协议)
  - [5. app-server 五件套](#5-app-server-五件套)
  - [6. thread-store / agent-graph-store / agent-identity](#6-thread-store--agent-graph-store--agent-identity)
  - [7. message-history / rollout / rollout-trace](#7-message-history--rollout--rollout-trace)
  - [8. model-provider 三件套](#8-model-provider-三件套)
  - [9. backend HTTP 层](#9-backend-http-层)
- [Part II：工具与执行 / 沙盒层](#part-ii工具与执行--沙盒层)
  - [10. tools crate + ToolExecutor trait](#10-tools-crate--toolexecutor-trait)
  - [11. apply-patch 自定义 DSL](#11-apply-patch-自定义-dsl)
  - [12. shell-command](#12-shell-command)
  - [13. shell-escalation](#13-shell-escalation)
  - [14. exec / exec-server 分离](#14-exec--exec-server-分离)
  - [15. execpolicy v2 / v1 双引擎](#15-execpolicy-v2--v1-双引擎)
  - [16. 文件系统四件套](#16-文件系统四件套)
  - [17. sandboxing 三平台实现](#17-sandboxing-三平台实现)
  - [18. process-hardening](#18-process-hardening)
  - [19. network-proxy](#19-network-proxy)
- [Part III：UI / 扩展 / 协作 / 云端](#part-iiiui--扩展--协作--云端)（见下半部分）
- [Part IV：Provider / 认证 / SDK / 构建系统](#part-ivprovider--认证--sdk--构建系统)（见下半部分）
- [Part V：横向对比与 FFAI 决策影响](#part-v横向对比与-ffai-决策影响)（见下半部分）

---

## 总览：与 Claude Code 的范式差异

### 0.1 五个不寻常的设计决策

Codex 不是"OpenAI 版的 Claude Code"。读 98 个 crate 后，最反直觉的五处选择：

**① Rust workspace ~98 crate vs CC 的单 TS package。**
Claude Code 是 sourcemap 还原后约 1332 个 .ts 文件、单一 npm 包；Codex 把同等业务面切成接近 100 个独立 crate。这不是单纯的"Rust 偏好细粒度 crate"，而是**显式架构纪律**——见下一条。

**② "resist adding code to codex-core" 写在 AGENTS.md 里。**
codex-core 已经膨胀到 152K LoC，仓库的 AGENTS.md（自己写给 AI 看的指令文件）反复警告：
> "**resist adding code to codex-core**! ... before adding to codex-core, consider whether there is an existing crate other than codex-core that is an appropriate place ... or it is time to introduce a new crate."

这种把"反 monolith"写成项目硬规则的做法，CC 和 OC 的代码库里都看不到。

**③ app-server 是 daemon-client 分离架构（v2 协议）。**
Codex 把"agent 引擎"独立成常驻 daemon（`app-server` + `app-server-daemon`），通过 JSON-RPC 2.0 over stdio/WebSocket/Unix-socket/remote-control **四种 transport** 跟前端解耦。CLI（`exec`）、TUI、IDE 客户端都是 daemon 的 client。
- v1 协议 = 248 LoC，标记弃用；v2 协议 = 12,392 LoC，按 thread/turn/item/mcp/permissions/config 分域
- TS SDK 通过 `ts-rs` 直接从 Rust 类型派生，零手写
- 这是 **LSP 风格**，CC（同进程 TS）/ OC（追加 gRPC）都没真正做到

**④ Plugin Marketplace + 内置 9 大 SaaS 允许列表。**
`core-plugins` (20.6K LoC) 不只是"插件加载器"，包含 marketplace 集成（"openai-curated"、"openai-bundled" 命名空间）+ 远程 plugin bundle 同步 + 内置工具建议允许列表，硬编码包含：
**GitHub, Notion, Slack, Gmail, Google Calendar, Figma, Linear, Canva, Microsoft Teams**。
这是企业 SaaS 集成"出厂即装"的清单，CC/OC 不存在类似设计。

**⑤ 显式 from-Claude-Code 迁移工具（`external-agent-migration` / `external-agent-sessions`）。**
源码里把 Claude Code 称为 "external-agent (predecessor)"，提供：
- `.mcp.json` / `hooks/` 配置 → Codex TOML 的转换函数
- session 历史导入：`detect_recent_sessions` → `summarize_session` → `prepare_pending_session_imports`，带 ledger 防重复

这是 OpenAI 在源码层面承认 CC 是先驱，并把"挖墙脚"做成产品功能。

---

### 0.2 整体架构图

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                            CLIENTS（多端入口）                              │
│                                                                              │
│  TUI            CLI (exec)         IDE 扩展         Python SDK    TS SDK    │
│  (ratatui      (JSONL events)    (HTTP poll/WS)    (spawn CLI    (ts-rs    │
│   188K LoC)    (4.9K LoC)                          + parse)      gen)      │
│      ▲              ▲                  ▲                ▲           ▲       │
└──────┼──────────────┼──────────────────┼────────────────┼───────────┼──────┘
       │              │                  │                │           │
       │  app-server-client (3.3K) ─── JSON-RPC 2.0 ──────┘           │
       └──────────────┴──────────────────┴────────────────────────────┘
                                     │
                       ┌─────────────┴───────────────┐
                       │   TRANSPORT（4 种并存）      │
                       │  stdio · WebSocket · UDS    │
                       │  · remote-control           │
                       │  app-server-transport(8.9K) │
                       └─────────────┬───────────────┘
                                     │
                       ┌─────────────▼───────────────┐
                       │      APP-SERVER DAEMON       │
                       │  app-server (38K) +          │
                       │  app-server-daemon (2.2K)    │
                       │  - lifecycle (start/stop)    │
                       │  - 自我升级                  │
                       │  - in-process 嵌入模式       │
                       └─────────────┬───────────────┘
                                     │
       ┌─────────────────────────────┼─────────────────────────────┐
       │                             │                             │
┌──────▼──────────┐         ┌────────▼─────────┐         ┌─────────▼────────┐
│ codex-core      │         │ TOOL EXECUTION    │         │ EXTENSION POINTS │
│ 152K LoC        │         │ tools (4.3K)      │         │ ext/extension-api│
│ ─ agent loop    │◀───────▶│ apply-patch (4.7K)│         │   (Contributor)  │
│   control.rs 47K│         │ shell-command     │         │ ext/guardian     │
│ ─ codex_delegate│         │   (5.9K, ts-bash) │         │ ext/memories     │
│   30K           │         │ shell-escalation  │         │ skills + plugins │
│ ─ exec_policy   │         │ exec-server (12K) │         │ hooks (8 events) │
│ ─ connectors    │         │ ─────────────     │         │ MCP 三件套       │
│ ─ permissions   │         │ SANDBOX 三平台    │         │ cloud-tasks      │
│ ─ mcp manager   │         │ ─ Linux: bwrap+   │         │ external-agent-* │
│ ─ config        │         │   landlock+seccomp│         │ realtime-webrtc  │
│                 │         │ ─ Win: AppCont+   │         │                  │
│ "RESIST adding  │         │   JobObj+ACL+     │         └──────────────────┘
│  code to core!" │         │   ConPTY (15K)    │
└─────────┬───────┘         │ ─ macOS: Seatbelt │
          │                 │ network-proxy     │
          │                 │ (MITM TLS 9.3K)   │
          │                 └─────────┬─────────┘
          │                           │
          ▼                           ▼
┌─────────────────────────────────────────────────────┐
│  PERSISTENCE & STATE                                │
│  thread-store · agent-graph-store · agent-identity  │
│  message-history · rollout · rollout-trace          │
│  memories · keyring-store · secrets                 │
└──────────────┬──────────────────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────────────────┐
│  PROVIDER LAYER                                     │
│  model-provider (trait) + model-provider-info       │
│  + models-manager                                   │
│  ├ ChatGPT / OpenAI Responses API                   │
│  ├ AWS Bedrock (aws-auth SigV4)                     │
│  ├ Ollama (gpt-oss:20b 默认)                        │
│  └ LM Studio (openai/gpt-oss-20b 默认)              │
└──────────────┬──────────────────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────────────────┐
│  OBSERVABILITY                                      │
│  otel → Statsig (ab.chatgpt.com/otlp)               │
│  analytics → app-server event bus                   │
│  feedback → Sentry SaaS                             │
└─────────────────────────────────────────────────────┘
```

### 0.3 与 v0.1 FFAI 架构的对应关系

| FFAI 关注点 | 来自 Codex 的可借鉴 | 不要照搬的原因 |
|---|---|---|
| 多端接入 | **app-server v2 + 4 种 transport** 直接对应 FFAI"Web UI + IDE poll + SDK"目标 | 4 种全保留太重，FFAI 只需 WebSocket（Web UI）+ HTTP（IDE）即可 |
| 工具系统 | `ToolExecutor<Invocation>` 异步泛型 trait（vs CC 的 Tool.ts 双布尔）表达力更强 | 但 `ToolExposure` 三态（Direct/Deferred/DirectModelOnly）需要根据 FFAI 多租户模型重新设计 |
| 扩展机制 | **Contributor 模式**（ToolContributor / TurnItemContributor / ThreadLifecycleContributor / ApprovalReviewContributor）比 CC hooks 更类型安全 | Rust trait-based，移植到 TypeScript 后表达力会下降，需要权衡 |
| 沙盒 | Linux bwrap+landlock+seccomp 三件套（FFAI 多租户必需 Docker 之外的次级隔离） | 但 Windows 15K LoC 的 ACL 工程量 FFAI 很难复制；macOS/Win 不是 FFAI 主战场 |
| 持久化 | `agent-graph-store` 把 parent-child 边显式存储 → FFAI 多 agent 必需 | rollout-trace 的 reducer 模式过于工程化，初期不需要 |
| 多 Provider | model-provider trait + model-provider-info 注册表 双层 | 简化为单层即可，FFAI 不需要本地 Ollama/LM Studio |
| 认证 | login + keyring-store 的 OS 原生 keyring 抽象 | FFAI 是 Web 服务，凭据走 vault/KMS，不走 OS keyring |
| Telemetry | OTEL 是工业标准，照搬 | 但 endpoint 不接 Statsig，自托管 OTel collector |
| Plugin Marketplace | "出厂即装 9 大 SaaS"思路对企业版有价值 | 实现成本高，v1 先把 plugin 加载机制做好，marketplace 留 v2 |

### 0.4 几个关键认知

- **Rust ≠ 性能至上选择**：Codex 选 Rust 主要是**类型安全 + 沙盒原语 + Tokio 异步生态**，不是为了 LLM 调用快几毫秒。整个 agent 的吞吐瓶颈在远端 LLM。
- **"反 monolith" 不是空话**：源码层面表现为 ~98 crate + AGENTS.md 写明禁令 + 工具系统/扩展机制都做成"双层"（identity crate + framework crate）。
- **多版本 RPC 协议是合规策略**：v1 (248 LoC) / v2 (12K LoC) 并存说明 OpenAI 至少做过一次大重构，且必须保留旧客户端。FFAI 早期没这个负担。
- **OS sandbox 不能省**：bwrap + landlock + seccomp + AppContainer + Seatbelt 这套不是"防恶意 LLM"，是**防工具误操作伤害**——多租户 FFAI 同样需要（Docker 是第一道，OS sandbox 是第二道）。
- **AGENTS.md 是项目级 agent 指令文件**：跟 CLAUDE.md 同位的概念，OpenAI 用 `agents.md` 命名，对应 docs/agents_md.md。FFAI 已经在用同套约定。

---

## Part I：内核与协议层

### 1. codex-core

| | |
|---|---|
| 路径 | `codex-rs/core/` |
| LoC | **152,279**（最大 crate） |
| 入口 | `src/lib.rs` |
| 关键依赖 | core-api · protocol · app-server-protocol · rollout · rollout-trace · app-server-transport · thread-store · model-provider · models-manager · mcp · state · hooks · config · login |

**职责**：主线程运行时，agent 循环执行，TUI/CLI 枢纽，配置与权限管理。

**核心导出**：`CodexThread` / `ThreadManager` / `StartThreadOptions` / `McpManager` / `Config` / `Permissions`

**关键子模块（按 LoC 排序）**：
- `client.rs` (86K) — 主 client 入口
- `agent/control.rs` (47K) — **agent loop 主体**：message dispatch、Op execution 状态机
- `exec_policy.rs` (37K) — 权限评估
- `codex_delegate.rs` (30K) — input → Op 转化
- `connectors.rs` (24K) — 工具执行
- 其余 17+ 子模块：mcp / compact / goals / config / agent / exec ...

**AGENTS.md 警告**：
> "Over time, the codex-core crate has become bloated... **resist adding code to codex-core!** Particularly when introducing a new concept/feature/API, before adding to codex-core, consider whether there is an existing crate other than codex-core that is an appropriate place for your new code to live."

**对 FFAI 的启示**：
- agent loop 集中在一个文件（control.rs）有利可追踪，但需要从 day 1 设防止膨胀的规则
- input → Op → execution 三段式状态机值得借鉴

---

### 2. core-api

| | |
|---|---|
| 路径 | `codex-rs/core-api/` |
| LoC | **78** |
| 入口 | `src/lib.rs` |
| 关键依赖 | core（re-export）· config · app-server-protocol · extension-api · arg0 · analytics |

**职责**：codex-core 的公共门面（facade），条件导出与重新导出。

**核心导出**：`CodexThread` / `ThreadManager` / `NewThread` / `StateDbHandle` / `SkillsManager` / `Config`

**模式**：经典 Rust facade crate——把 `core` 的内部实现挡住，只暴露 stable 公共 API。其他 crate 应该 depend on `core-api`，不直接依赖 `core`。

---

### 3. protocol

| | |
|---|---|
| 路径 | `codex-rs/protocol/` |
| LoC | **17,822** |
| 入口 | `src/lib.rs` |
| 关键依赖 | 无（最小化依赖）|

**职责**：类型定义骨架（ID、错误、权限、MCP、模型、config），无业务逻辑，跨 crate 共享。

**核心导出**：`ThreadId` / `SessionId` / `AgentPath` / `ToolName` / `models`（OpenAI schema）/ `approvals` / `protocol`（枚举）

**设计要点**：
- 是整个 workspace 的"类型零层"——不依赖任何其他 codex-* crate
- 所有跨 crate 共享的 ID、enum、schema 都集中在这里
- 这是 Rust 大型 workspace 的标准做法（避免循环依赖）

---

### 4. app-server v1 vs v2 双协议

| | v1 | v2 |
|---|---|---|
| LoC | **248** | **12,392** |
| 状态 | 反向兼容标记，**冻结** | 当前活跃协议 |
| 路径 | `app-server-protocol/src/protocol/v1.rs` | `app-server-protocol/src/protocol/v2/` |
| 模块化 | 单文件 | 按 thread/turn/item/mcp/permissions/config 分域 |

**v2 设计强约束**（来自 AGENTS.md）：
- RPC 方法名格式 `<resource>/<method>`，resource 必须单数（`thread/read` / `app/list`）
- 字段统一 `camelCase`（`#[serde(rename_all = "camelCase")]`）
- 时间戳 `i64` Unix seconds，命名 `*_at`（`created_at` / `updated_at` / `resets_at`）
- ID 在 API 边界用 `String`，内部转 UUID
- 所有 v2 类型必须 `#[ts(export_to = "v2/")]` 把 TS 生成定向到正确命名空间
- 所有 optional 字段必须 `#[ts(optional = nullable)]`，禁止 `#[serde(skip_serializing_if = "Option::is_none")]`
- 列表方法默认 cursor pagination：`pub cursor: Option<String>` + `pub limit: Option<u32>` + `pub data: Vec<...>` + `pub next_cursor: Option<String>`
- experimental API 用 `#[experimental("method/or/field")]`

**v1 → v2 的 50× 演进**说明 OpenAI 经历过一次完整重设计，且必须保留 v1 兼容老客户端。

---

### 5. app-server 五件套

OpenAI 把 RPC server 拆成 5 个 crate，**Rust workspace 最典型的"领域分层"**：

| Crate | LoC | 职责 |
|---|---|---|
| `app-server` | **38,077** | 核心运行时 server，session 管理，消息处理，多 transport 复用，**含 `in_process` 嵌入模式** |
| `app-server-protocol` | **23,622** | RPC 协议定义（v1+v2 + TS export pipeline）|
| `app-server-transport` | **8,876** | 连接抽象（stdio / WebSocket / UDS / remote-control），消息路由 |
| `app-server-daemon` | **2,229** | lifecycle（start/restart/stop）+ 托管自我升级 + 进程监控 |
| `app-server-client` | **3,291** | TUI/CLI 到 daemon 的异步通道，bounded mpsc + backpressure |
| `app-server-test-client` | **2,238** | 集成测试工具（CLI），自动化 approval/auth 流程 |

**架构含义**：
- `app-server` 既能作为独立 daemon 跑（`bin/`），也能作为 in-process 库被其他 crate 嵌入（`lib::in_process`）—— 测试和 IDE 集成都用 in-process
- `transport` 与 `protocol` 解耦：协议是消息格式，transport 是怎么传，可以各自演进
- `daemon` 单独成 crate 说明 lifecycle 是一等公民

**对 FFAI 的启示**：Web 服务版的 FFAI 不需要 daemon-client 分离（HTTP 服务器本身就是 daemon），但 `protocol`/`transport` 解耦是好范式——FFAI 应该把 schema 定义（protocol）跟 WebSocket/HTTP 处理（transport）也分开。

---

### 6. thread-store / agent-graph-store / agent-identity

CC 的"会话历史 = 单一 JSONL"在 Codex 里被拆成三个独立抽象：

#### 6.1 thread-store (7,343 LoC)

| | |
|---|---|
| 路径 | `codex-rs/thread-store/` |
| 职责 | 存储无关的线程持久化接口（trait），含本地/内存实现 |
| 核心导出 | `ThreadStore` (trait) / `LocalThreadStore` / `InMemoryThreadStore` / `StoredThread` / `LiveThread` |

存 thread = 一次 agent 会话的事件序列。

#### 6.2 agent-graph-store (454 LoC)

| | |
|---|---|
| 路径 | `codex-rs/agent-graph-store/` |
| 职责 | **agent 衍生拓扑（parent-child 边）存储抽象** |
| 核心导出 | `AgentGraphStore` (trait) / `LocalAgentGraphStore` / `ThreadSpawnEdgeStatus` |

**关键差异 vs CC**：CC 的 sub-agent 是同进程 fork，上下文共享但拓扑隐式。Codex 把 parent-child 关系**显式存储**——这是 multi-agent 长期演进的基础设施。

#### 6.3 agent-identity (737 LoC)

| | |
|---|---|
| 路径 | `codex-rs/agent-identity/` |
| 职责 | **JWT / JWKS agent 身份验证** |
| 核心导出 | `AgentIdentityKey` / `decode_jwt` |

**这是 CC/OC 都没有的设计**：每个 agent 有独立 JWT identity，可以做企业级审计、跨服务身份传递、agent 间互相验证。

**对 FFAI 的启示**：multi-tenant + multi-agent 场景必须有 agent identity。FFAI 应该考虑 OAuth2 service account 或 JWT 方案。

---

### 7. message-history / rollout / rollout-trace

Codex 的"会话持久化"分三层，**event sourcing 思路明显**：

#### 7.1 message-history (633 LoC)

| | |
|---|---|
| 路径 | `codex-rs/message-history/` |
| 职责 | **全局 append-only 日志** `~/.codex/history.jsonl`，并发写保护（POSIX `O_APPEND` 原子性） |
| 核心导出 | `MessageHistory` |

最简单的一层：所有 agent 消息按时间序写入单文件，POSIX `O_APPEND` 保证并发原子。

#### 7.2 rollout (8,780 LoC)

| | |
|---|---|
| 路径 | `codex-rs/rollout/` |
| 职责 | **线程持久化格式**（TOML + JSON 混合），快照与恢复 |
| 核心导出 | `Rollout` / `RolloutSnapshot` / `ThreadRollout` |

`rollout` = 把一个 thread 的完整状态序列化到磁盘，支持恢复（resume）。CC 也有类似设计，但 Codex 显式分出独立 crate。

#### 7.3 rollout-trace (12,020 LoC)

| | |
|---|---|
| 路径 | `codex-rs/rollout-trace/` |
| 职责 | **运行时事件追踪**（压缩包 + reducer 模式），inference / MCP call / compaction 事件检测点 |
| 核心导出 | `InferenceTraceContext` / `CompactionTraceContext` / `McpCallTraceContext` / `reduced_state` 缓存 |
| 关键子模块 | `reducer.rs` (状态投影) / `writer.rs` (hot-path 记录) / `payload.rs` (事件编码) |

**这是 Redux/event-sourcing 的 reducer 模式在 agent 上的应用**：
- writer 把每个事件追加到压缩包
- reducer 把事件流投影成"当前状态快照"
- 缓存 reduced_state 加速读取

**对 FFAI 的启示**：v1 不需要 rollout-trace 这层（太重）。但 message-history 的"global append-only JSONL"和 rollout 的"thread snapshot"是必需的。

---

### 8. model-provider 三件套

CC 的"上游就是 Anthropic"在 Codex 里扩展成三层抽象：

#### 8.1 model-provider (1,778 LoC)

| | |
|---|---|
| 路径 | `codex-rs/model-provider/` |
| 职责 | 多 provider 抽象（OpenAI、Bedrock、自定义），auth provider 工厂 |
| 核心导出 | `ModelProvider` (trait) / `SharedModelProvider` / `ProviderCapabilities` / `create_model_provider()` |
| 关键依赖 | protocol · models-manager · model-provider-info · api · client · login · agent-identity · otel · aws-auth · feedback |

#### 8.2 model-provider-info (976 LoC)

| | |
|---|---|
| 路径 | `codex-rs/model-provider-info/` |
| 职责 | **provider 配置注册表**（默认 + 用户定义 `config.toml`），重试策略 |
| 核心导出 | `ModelProviderInfo` / provider ID/auth mode 常量（OpenAI / Bedrock / Azure） |

#### 8.3 models-manager (2,022 LoC)

| | |
|---|---|
| 路径 | `codex-rs/models-manager/` |
| 职责 | **模型目录与协作模式预设管理**，bundled `models.json` 加载 |
| 核心导出 | `bundled_models_response` / `ModelsManagerConfig` / `client_version_to_whole()` |

**三层职责**：trait（model-provider）+ 注册表/重试策略（model-provider-info）+ 模型目录/协作预设（models-manager）。比 OC 的 vendor descriptor + gateway adapter + routeMetadata 三层略浅，但本质同构。

---

### 9. backend HTTP 层

底层 HTTP 调用相关 crate：

| Crate | LoC | 职责 |
|---|---|---|
| `codex-api` | 9,141 | **ChatGPT backend API 桥接**（responses stream、内存压缩、telemetry）。SSE 解析 |
| `codex-client` | 1,996 | HTTP 传输（reqwest 包装），重试、自定义 CA、Cloudflare cookies 处理 |
| `backend-client` | 1,253 | Codex backend RPC 客户端（code tasks / turn siblings） |
| `responses-api-proxy` | 1,007 | **本地 HTTP 代理**：把 OpenAI responses API 暴露给前端，auth 头转换。tiny_http 服务器 |
| `codex-backend-openapi-models` | 706 | **OpenAPI 自动生成的 model 类型**，无手写内容 |

**关键点**：
- `responses-api-proxy` 是个独立 binary，把 `https://api.openai.com/v1/responses` 代理到本地 → 前端只需要连本地端口，不需要管 auth
- `codex-backend-openapi-models` 是 OpenAPI codegen 产物，跟 OpenAI 后端的 OpenAPI spec 同步
- `codex-client` 处理 Cloudflare cookies 说明 OpenAI 自家服务在某些路径上挂了 CF

---

## Part II：工具与执行 / 沙盒层

这是 Codex 相对 CC 工程量最重的一层。直接看 LoC 对比：

| 维度 | Codex | CC |
|---|---|---|
| 工具系统 | `tools` 4.3K LoC + `ToolExecutor<Invocation>` trait | Tool.ts 单文件 |
| Patch 协议 | `apply-patch` 4.7K LoC + 自定义 DSL | Edit tool（字符串替换） |
| Shell 解析 | `shell-command` 5.9K LoC + tree-sitter-bash | 字符串匹配 + 黑名单 |
| 执行策略 | `execpolicy` v2 1.8K + `execpolicy-legacy` v1 1.8K（Starlark） | 三态权限 |
| Sandbox | 三平台独立 crate，Linux 6.6K + Win **15K** + macOS Seatbelt | landlock / sandbox-exec 调用 |
| 网络代理 | `network-proxy` 9.3K LoC + MITM TLS | 无 |

### 10. tools crate + ToolExecutor trait

| | |
|---|---|
| 路径 | `codex-rs/tools/` |
| LoC | **4,346** |
| 入口 | `src/lib.rs` |
| 关键依赖 | app-server-protocol · code-mode · protocol · rmcp（含 schemars + macros 用于 MCP interop） |

**核心抽象**：
- `ToolExecutor<T>` —— **异步 trait，泛型 over invocation 类型**（不是 CC 那种固定 trait）
- `ToolSpec` / `ToolDefinition` —— JSON schema + 描述
- `ToolOutput` / `ToolCall` —— 调用 IO
- `FreeformTool` / `ResponsesApiTool` —— 两种 tool 形态
- `ToolName` —— 强类型工具名
- `ToolsConfig` —— 工具集合配置

**`ToolExposure` 枚举**（三态可见性）：
- `Direct` — 工具直接可调用
- `Deferred` — 延迟暴露（按 context/skill 触发）
- `DirectModelOnly` — 只允许 model 调用，不暴露给用户

**vs CC 的 Tool.ts**：
CC 的 Tool.ts 用 `isReadOnly: boolean` + `isEnabled: () => boolean` 两个布尔来控制行为；Codex 的 `ToolExposure` 三态 + `ToolExecutor<Invocation>` 泛型 trait，表达力更强但工程量也更大。

**对 FFAI 的启示**：
- 三态 ToolExposure 直接借鉴
- `ToolExecutor<Invocation>` 泛型在 TypeScript 里难表达，FFAI 可用 discriminated union + 类型守卫近似

---

### 11. apply-patch 自定义 DSL

| | |
|---|---|
| 路径 | `codex-rs/apply-patch/` |
| LoC | **4,672** |
| 关键依赖 | exec-server（用 `ExecutorFileSystem` trait 解耦文件系统） |

**重大事实**：**Codex 的 patch 协议既不是 unified diff，也不是 Aider 的 SEARCH/REPLACE block，是自定义 DSL**：

```
*** Begin Patch
*** Add File: path/to/new.rs
+pub fn hello() {
+    println!("hi");
+}
*** Update File: path/to/existing.rs
*** Move to: path/to/renamed.rs
@@ fn old_signature() @@
-    old_line
+    new_line
*** Delete File: path/to/gone.rs
*** End Patch
```

**关键特性**：
- 4 种文件操作：`*** Add File` / `*** Update File` / `*** Delete File` / `*** Move to`
- `@@` 是 hunk 上下文锚点（不是行号——Aider 同思路）
- `+/-/ ` 行 marker 跟 unified diff 类似
- **streaming parser**：大 patch 边读边解，适合 LLM 流式输出
- **heredoc-aware**：能识别嵌套 heredoc，避免分隔符冲突

**核心导出**：`parse_patch()` / `StreamingPatchParser` / `ApplyPatchArgs` / `Hunk` (AddFile|DeleteFile|UpdateFile variants) / `ApplyPatchError`

**对 FFAI 的启示**：
- LLM 输出 unified diff 行号容易错；SEARCH/REPLACE 块太冗长；Codex DSL 在两者间找平衡
- streaming 解析对流式 token 很关键
- 但**直接复用 Codex DSL** 是个开放问题——LLM 训练数据里这个 DSL 频率远低于 unified diff

---

### 12. shell-command

| | |
|---|---|
| 路径 | `codex-rs/shell-command/` |
| LoC | **5,992** |
| 入口 | `src/lib.rs` |
| 关键依赖 | protocol · **tree-sitter-bash**（真 Bash parser） |

**职责**：命令解析、安全性校验、shell-dialect 检测（Bash / PowerShell）。

**核心导出**：
- `is_safe_command()` / `is_dangerous_command()` —— 安全性判断
- tree-sitter 驱动的命令 AST 解析
- URL / argument 提取

**关键差异 vs CC**：CC 是字符串/正则匹配检测危险命令（`rm -rf` / 重定向到 `/dev/...` 等），Codex 用 **tree-sitter-bash** 真 parser 解析 AST，能识别：
- 管道串联
- 子 shell 内的危险命令
- 变量展开后的实际命令
- here-doc 内嵌内容

**对 FFAI 的启示**：
- 多租户场景必须用真 parser，字符串匹配太容易绕过
- 但 tree-sitter 是 Rust 生态成熟，Node 也有 binding（`web-tree-sitter`），TS 可用
- shell-dialect 检测对 Windows 兼容很关键，CC/OC 这块都不行

---

### 13. shell-escalation

| | |
|---|---|
| 路径 | `codex-rs/shell-escalation/` |
| LoC | **2,217** |
| 关键依赖 | protocol |

**职责**：**Unix-only 提权 & 执行策略强制（via Unix sockets）**

**核心导出**：
- `ShellCommandExecutor`
- `EscalationPolicy` / `EscalationSession`
- `PreparedExec`
- `ExecParams` / `ExecResult`
- Unix escalation 状态机

**架构含义**：
- "提权"不是 sudo，是从"沙盒内"→"沙盒外"的执行通道协商
- 通过 Unix domain socket 跟沙盒外的特权 helper 通信
- 状态机管理"是否需要用户审批"、"审批后多久过期"等

---

### 14. exec / exec-server 分离

| | exec | exec-server |
|---|---|---|
| 路径 | `codex-rs/exec/` | `codex-rs/exec-server/` |
| LoC | **4,995** | **12,502** |
| 形态 | **CLI binary**（不是库） | RPC server crate |
| 职责 | JSONL 事件处理器，bridging app-server 协议到 human/machine 输出 | **核心执行运行时**：抽象 local/remote 后端，流式 IO，沙盒集成 |
| 核心导出 | `Cli` / `Command` enum / event processing pipeline | `ExecServerClient` (HTTP) / `ExecutorFileSystem` trait / `ExecProcess` / `ExecParams` / `ExecResponse` |

**这是又一次"daemon-client"分离**：
- `exec-server` 是真正干活的（spawn 进程 / 流式收集输出 / 应用沙盒策略）
- `exec` 是 CLI multiplexer，把人类/机器友好的命令翻译成 RPC 调用

**`ExecutorFileSystem` trait** 是 `apply-patch` / `git-utils` 等共享的文件系统抽象，让这些 crate 可以在 local exec 和 remote exec 间无缝切换。

---

### 15. execpolicy v2 / v1 双引擎

跟 app-server v1/v2 一样，Codex 的执行策略引擎也并存两个版本：

#### 15.1 execpolicy (v2, 当前)

| | |
|---|---|
| 路径 | `codex-rs/execpolicy/` |
| LoC | **1,790** |
| 关键依赖 | utils-absolute-path（仅这一个） |

**形态**：**声明式 DSL**，prefix-pattern 规则 + 网络沙盒。

**核心导出**：`Policy` / `PolicyParser` / `Rule` / `Decision` (Allow/Deny/Prompt) / `NetworkRuleProtocol` / `Evaluation`

**规则形态**：
- allow/deny 规则
- 命令 prefix + args 模式匹配
- 网络规则（host / port / protocol）

#### 15.2 execpolicy-legacy (v1, 弃用)

| | |
|---|---|
| 路径 | `codex-rs/execpolicy-legacy/` |
| LoC | **1,807** |
| 关键依赖 | **starlark**（嵌入式 Starlark runtime） |

**形态**：**Starlark 脚本 DSL**——Python 语法子集，Google 用它写 BUILD 文件。

```python
define_program(
    name="git_status",
    args=[
        ARG("git"),
        ARG("status"),
    ],
    network=False,
)
```

**核心导出**：`PolicyParser` / `Policy` / `ExecvChecker` / `ValidExec` / 默认 Starlark 规则嵌入

**对 FFAI 的启示**：
- v1 Starlark 灵活但学习曲线陡（用户要写 Python 子集）
- v2 声明式（TOML/YAML）更易接受
- 选 v2 路线，FFAI 直接做声明式即可

---

### 16. 文件系统四件套

| Crate | LoC | 职责 |
|---|---|---|
| `file-system` | **192** | **抽象 FS trait 层** + 沙盒上下文（PermissionProfile → FS 限制转换） |
| `file-search` | **1,312** | **模糊文件查找**：nucleo matcher（FZF 风格）+ gitignore-aware walker，crossbeam 流式 |
| `file-watcher` | **1,393** | 文件变化通知：`notify` crate + 订阅路由 + 路径合并 |
| `git-utils` | **2,942** | **高层 git 封装**：status / diff / apply / baseline 快照 / 分支操作 |

**关键点**：
- `file-system` 只有 192 LoC——它是个**纯 trait crate**，只定义 `ExecutorFileSystem` async trait，让 local 和 remote 实现都满足同一契约
- `file-search` 用 nucleo（FZF 算法的 Rust 实现）+ ignore crate，**性能远超字符串扫描**
- `git-utils` 不依赖 libgit2，是 git CLI 的封装层
- `file-watcher` 不直接订阅 inotify，包了一层订阅路由（多个 client 订阅同一路径只触发一次 OS watcher）

**核心导出**：
- file-system: `ExecutorFileSystem` (trait) / `FileMetadata` / `FileSystemSandboxContext`
- file-search: `run()` (event generator) / `FileMatch` / `FileSearchOptions` / `FileSearchResults`
- file-watcher: `FileWatcherSubscriber` / `FileWatcherEvent` / `WatchPath`
- git-utils: `apply_git_patch()` / `GitInfo` / `collect_git_info()` / `GitBaselineDiff` / `current_branch_name()`

---

### 17. sandboxing 三平台实现

Codex 的沙盒是整个项目最重的工程，单 Windows 实现就 15K LoC。

#### 17.1 sandboxing crate (多平台选择器)

| | |
|---|---|
| 路径 | `codex-rs/sandboxing/` |
| LoC | **4,926** |
| 关键依赖 | network-proxy · protocol |

**职责**：policy 转换 + 平台特定 sandbox 选择器。

**核心导出**：
- `SandboxManager`
- `SandboxType` enum：`None | MacosSeatbelt | LinuxSeccomp | WindowsRestrictedToken`
- `SandboxCommand`
- `get_platform_sandbox()` —— 自动选择当前平台实现
- 策略兼容性 checker（哪些命令在哪个平台 sandbox 内能跑）

#### 17.2 Linux: bwrap + landlock + seccomp 三件套

| Crate | LoC | 职责 |
|---|---|---|
| `linux-sandbox` | **6,645** | **Linux 沙盒可执行**：组合 in-process seccomp（no_new_privs）+ bubblewrap（filesystem isolation）+ landlock（capability restrictions） |
| `bwrap` | **~50** | **vendored bubblewrap C 库的 FFI wrapper**，单 binary executable |

**三件套分工**：
- **bwrap (bubblewrap)** —— 文件系统隔离（绑挂载、PID/network namespace、tmpfs 替换）
- **landlock** —— Linux 5.13+ 内核能力（细粒度文件路径 ACL，no-net 隔离）
- **seccomp** —— 系统调用过滤（设置 `no_new_privs` 阻止后续提权）

**bwrap crate 的 50 LoC** 只是个 Rust shim，真正实现是 vendored C 库通过 `bwrap_main()` FFI 调用。**编译时 vendored 进来，不依赖系统 bubblewrap**——保证可控。

#### 17.3 Windows: AppContainer + Job Object + Restricted Tokens

| | |
|---|---|
| 路径 | `codex-rs/windows-sandbox-rs/` |
| LoC | **15,023** ⚠ |
| 关键依赖 | utils-pty (ConPTY) + Windows API 大量 unsafe binding |

**核心机制**：
- **AppContainer** —— Windows 8+ 进程隔离原语（类似 macOS App Sandbox）
- **Job Object** —— 资源限制（CPU / 内存 / 进程数 / kill-on-job-close）
- **Restricted Tokens** —— SID 限制 + privilege 剥离
- **ACL deny rules** —— 用 ACE 显式拒绝访问敏感路径
- **ConPTY** —— Windows 10+ 终端模拟器原语，让沙盒内进程也能产生 PTY 输出
- **命名管道 IPC** —— sandbox 内外通信
- **Elevated runner** —— 部分操作（设置 ACL）需要 admin，通过单独的 elevated helper 进程做

**核心导出**：`add_deny_read_ace()` / `add_deny_write_ace()` / `allow_null_device()` / ACL 工具 / elevated runner / ConPTY 集成

**为什么是 15K LoC**：Windows 沙盒原语分散在 5 个不同的 Win32 API surface，每个都有自己的怪癖（句柄 inherit / 安全描述符序列化 / SID 编码）。CC 在 Windows 上几乎没沙盒（仅靠 OS 用户权限）。

#### 17.4 macOS: Seatbelt

通过 `sandboxing` crate 调用 `/usr/bin/sandbox-exec` + 自定义 `.sb` 配置文件。
**无独立 crate**——macOS Seatbelt 是 OS API 直接调用，比 Linux/Windows 简单得多。

**AGENTS.md 警告**：
> "Never add or modify any code related to `CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR` or `CODEX_SANDBOX_ENV_VAR`."
> 沙盒会设置 `CODEX_SANDBOX_NETWORK_DISABLED=1` 和 `CODEX_SANDBOX=seatbelt` 环境变量。测试代码用这些 env vars 做"沙盒内 / 沙盒外"分支。

---

### 18. process-hardening

| | |
|---|---|
| 路径 | `codex-rs/process-hardening/` |
| LoC | **200** |
| 关键依赖 | libc · ctor macro |

**职责**：**pre-main 进程加固**——在 `main()` 之前禁用以下能力：
- ptrace（防调试器附加 dump 内存）
- core dumps（防崩溃时泄露内存）
- 剥离 `LD_PRELOAD` / `DYLD_*` / 类似 env vars（防注入共享库）

**核心导出**：`pre_main_hardening()` / `disable_process_dumping()` (Unix)

**实现技巧**：通过 `#[ctor]` 宏（C++ static initializer 风格）在 main 之前执行加固代码，**LLM 工具的任何攻击者都没机会撤销**。

**为什么需要**：agent 进程会处理用户代码、运行第三方工具，环境变量可能被污染。pre-main 加固确保即使被入侵也最大限度限制损失。

**对 FFAI 的启示**：
- Web 服务版的 FFAI 在 Docker 内运行，OS 级 hardening 价值降低
- 但运行用户代码的 worker（Bash / Edit tool 执行）应该考虑 ctor-style pre-main 加固

---

### 19. network-proxy

| | |
|---|---|
| 路径 | `codex-rs/network-proxy/` |
| LoC | **9,352** |
| 关键依赖 | rustls · hyper · tokio（无 codex-* 内部依赖） |

**职责**：HTTP/SOCKS5 代理 + **MITM TLS 拦截** + 域名/socket allowlist + blocked request observer。

**核心导出**：
- `NetworkProxy` / `NetworkProxyBuilder`
- `NetworkPolicyDecider`
- `NetworkProxyConfig`（域名 / socket 规则）
- `ConfigReloader`（运行时刷新规则）

**关键设计**：
- 工具（Bash / curl / git）的网络访问被**强制走 codex 自己的 proxy**，由它执行 allowlist 检查
- 走 MITM TLS：proxy 用自签 CA 拦截 HTTPS，看到实际 URL / Host / 内容
- 这是单租户 agent 罕见但合理的设计——多租户更需要
- 配置可热加载（运行时改 allowlist 不重启）

**对 FFAI 的启示**：
- 多租户 FFAI 必须有 egress 控制（防数据外泄 / 防工具滥用）
- network-proxy 的 MITM 思路可借鉴，但实现成本高（自签 CA 注入到容器）
- 简单版：仅在 Docker 网络层做 IP/port allowlist，URL 级控制可以延后

---

## Part III：UI / 扩展 / 协作 / 云端

这一层是 Codex 跟 CC 在功能面最容易直观对比的层。

### 20. tui crate

| | |
|---|---|
| 路径 | `codex-rs/tui/` |
| LoC | **~188,000**（**比 codex-core 还大**） |
| 关键依赖 | codex-core · codex-config · codex-app-server-client · **ratatui**（unstable: widget-ref + rendered-line-info）· crossterm · **cpal**（音频）· codex-skills · codex-core-plugins · codex-mcp · codex-realtime-webrtc |
| 子模块数 | 60+ |

**职责**：交互式终端 UI 引擎，agent session 渲染，含音频。

**核心导出**：`run_main()` / `Cli` parser / `App` / `AppExitInfo` / `ExitReason` / `Terminal` (ratatui 包装)

**主要子模块覆盖**：
- chat widget（消息渲染）
- diff rendering（差异可视化）
- markdown rendering
- keymaps
- file search UI
- approval UI（工具审批弹窗）
- realtime audio（cpal 音频流）
- bottom_pane / chat_composer / footer

**反直觉事实**：
- TUI 比 core 还大（188K vs 152K LoC），说明 OpenAI 在终端 UX 上投入巨大
- 用 ratatui，**不是 React/Ink**（CC 用 Ink）—— 纯 Rust TUI 生态
- 单 crate 60+ 模块，AGENTS.md 反复警告别再往 `chatwidget.rs` / `app.rs` / `bottom_pane/` 加方法
- 用 **insta** 做 snapshot 测试，每个 UI 改动必须 `cargo insta accept`

**Ratatui 风格约定**（来自 AGENTS.md）：
- 优先 Stylize trait helpers：`"text".dim()` / `.bold()` / `.cyan()` 而不是手动 `Style`
- `"text".into()` 转 Span，`vec![…].into()` 转 Line
- 不要硬编码白色，让默认前景色生效
- 文本换行用 `textwrap::wrap`，Line 换行用 `tui/src/wrapping.rs` helpers

**对 FFAI 的启示**：
- FFAI 走 Web UI，TUI 不是主战场，188K 工程量不必复制
- 但 ratatui 的设计原则（声明式样式 + 组件 split）跟 React 同构，TUI 经验对 Web 组件库设计有参考

---

### 21. cli crate（命名反直觉）

| | |
|---|---|
| 路径 | `codex-rs/cli/` |
| LoC | **14,604** |
| 关键依赖 | utils-absolute-path · clap · utils-cli |

**反直觉**：名字叫 `cli`，**实际不是命令行入口 parser**（那个在 `arg0` 和 `exec` crate）。`cli` crate 实际职责是：
- **3 个平台 sandbox 命令抽象**：seatbelt（macOS）/ landlock（Linux）/ Windows restricted tokens
- **login 流程编排**：device code / API key / ChatGPT 三种登录方式

**核心导出**：
- `SeatbeltCommand` / `LandlockCommand` / `WindowsCommand`
- `run_login_with_chatgpt()` / `run_login_with_device_code()` / `run_login_with_api_key()`
- `run_logout()` / `run_login_status()`
- sandbox execution helpers

**为什么命名这样**：历史遗留——早期可能是 CLI 入口，后来主入口迁到 `arg0` / `exec`，但旧命名保留了。

**对 FFAI 的启示**：从 day 1 就把 crate/模块命名跟实际职责对齐，避免历史遗留命名让后续读者困惑。

---

### 22. hooks

| | |
|---|---|
| 路径 | `codex-rs/hooks/` |
| LoC | **9,778** |
| 关键依赖 | config · protocol · plugin · regex · serde_json · tokio |

**职责**：hook 生命周期管理 + 调度引擎。

**核心导出**：
- `HOOK_EVENT_NAMES` 常量 —— **8 个 hook 事件名**
- 事件类型：`PreToolUseRequest` / `PermissionRequestOutcome` / `PostCompactRequest` / `SessionStartOutcome` 等
- `Hooks` / `HooksConfig` —— 注册表
- 6 种事件的 matcher
- `hook_key()` —— persistence builder

**8 个 hook 事件**：
- `PreToolUse` —— 工具调用前
- `PostToolUse` —— 工具调用后
- `PermissionRequest` —— 权限请求
- `PostCompact` —— 上下文压缩后（**CC 把 compact 藏在 sub-agent 里，Codex 作为 first-class hook 暴露**）
- `SessionStart` —— 会话启动
- `UserPromptSubmit` —— 用户提交输入
- `Stop` —— 会话停止
- 还有一个事件待补

**对 FFAI 的启示**：
- 8 hook 比 CC 多了 `PostCompact`、`UserPromptSubmit` 等——FFAI 应该至少覆盖这 8 个点
- Hook 用 regex matcher 做选择性触发（vs CC 的 glob）—— regex 表达力强但用户写起来更难

---

### 23. skills + core-skills 双层

Codex 把 skills 系统拆成"内置资产"和"运行时框架"两层：

#### 23.1 skills (169 LoC)

| | |
|---|---|
| 路径 | `codex-rs/skills/` |
| 职责 | **极简 facade**：内置 skill 资产 + 安装到 `$CODEX_HOME/skills/.system` + fingerprint 跳过重复工作 |
| 核心导出 | `install_system_skills()` / `system_cache_root_dir()` |

#### 23.2 core-skills (7,053 LoC)

| | |
|---|---|
| 路径 | `codex-rs/core-skills/` |
| 职责 | **完整框架**：skill 加载、渲染、注入、环境依赖检测 |
| 核心导出 | `SkillsManager` / `SkillMetadata` / `SkillLoadOutcome` / `AvailableSkills` 渲染模板 / `detect_implicit_skill_invocation_for_command()` |

**双层模式的含义**：
- `skills` = **打包的内置资产**（OpenAI 出厂的 system skills）
- `core-skills` = **运行时加载/管理框架**（用户加载第三方 skills 也走这里）

**对 FFAI 的启示**：
- 内置 vs 运行时分离让升级路径清晰（升内置 = 升 skills crate；升框架 = 升 core-skills）
- FFAI 多租户场景，"内置"应该按 org 而不是按 codex 全局——可以参考 skills 的 fingerprint + 安装路径模式做 per-org skill 缓存

---

### 24. plugin + core-plugins 双层 + Plugin Marketplace

Codex 的 plugin 系统是 **CC/OC 都没有的最差异化设计**。

#### 24.1 plugin (386 LoC)

| | |
|---|---|
| 路径 | `codex-rs/plugin/` |
| 职责 | Plugin 身份/元数据 schema |
| 核心导出 | `PluginId` / `LoadedPlugin` / `PluginLoadOutcome` / `PluginCapabilitySummary` / `PluginHookSource` / telemetry helpers |

#### 24.2 core-plugins (20,648 LoC)

| | |
|---|---|
| 路径 | `codex-rs/core-plugins/` |
| 职责 | **完整 marketplace 集成**：install/uninstall + 远程同步 + manifest 解析 + 内置 SaaS 允许列表 |

**核心常量**：
- `"openai-curated"` 命名空间 —— OpenAI 审核过的 plugin
- `"openai-bundled"` 命名空间 —— 出厂自带的 plugin
- 远程 plugin bundle 处理

**内置 SaaS 工具建议允许列表**（硬编码在 source）：
- **GitHub** / **Notion** / **Slack** / **Gmail** / **Google Calendar** / **Figma** / **Linear** / **Canva** / **Microsoft Teams**

**含义**：
- Codex 出厂就支持以上 9 大 SaaS 的 plugin 集成
- 这些 plugin 的发现、安装、auth 都集成到 core-plugins
- 对企业用户：OpenAI 在做"agent + 现成 SaaS 集成"的捆绑，跟 Microsoft Copilot 路线对齐

**对 FFAI 的启示**：
- Plugin Marketplace 是企业版最大卖点之一
- 但实现成本极高（每个 SaaS 的 OAuth + API + plugin 定义都要做）
- v1 先做"plugin 加载机制"，marketplace 留 v2
- 内置 SaaS 列表参考 Codex 的 9 项即可——这就是企业用户最常用的 SaaS

---

### 25. MCP 三件套

Model Context Protocol 在 Codex 里被切成 3 个 crate：

| Crate | LoC | 角色 |
|---|---|---|
| `rmcp-client` | **6,990** | **底层 RMCP 协议实现 + transport** |
| `codex-mcp` | **5,179** | **Codex 内部 MCP 客户端集成** |
| `mcp-server` | **2,491** | **standalone MCP server binary**（`codex-mcp-server`） |

#### 25.1 rmcp-client（底层协议）

**职责**：RMCP（Rust MCP）客户端库，包装 `rmcp` crate。

**核心导出**：
- `RmcpClient`
- `ToolWithConnectorId` / `ListToolsWithConnectorIdResult`
- `StdioServerLauncher` / `InProcessTransportFactory`
- `OAuthProviderError` + OAuth login/discovery 函数

**transport**：stdio launcher / in-process / HTTP 三种

#### 25.2 codex-mcp（Codex 集成）

**职责**：Codex 应用层的 MCP 客户端集成——connection manager、runtime environment、MCP server discovery、tool collection。

**核心导出**：
- `McpConnectionManager`
- `McpRuntimeEnvironment`
- `EffectiveMcpServer`
- `ToolInfo`
- OAuth/auth elicitation API：`CodexAppsAuthElicitation` / `auth_elicitation_completed_result`
- Sandbox state tracking

**AGENTS.md 警告**：
> "When working with MCP tool calls, prefer using `codex-rs/codex-mcp/src/mcp_connection_manager.rs` to handle mutation of tools and tool calls."

#### 25.3 mcp-server（对外暴露）

**职责**：**Codex 自己也作为 MCP server 暴露**，让其他工具（Cursor / 其他 agent）通过 MCP 调用 Codex。

**核心导出**：`CodexToolCallParam` / `ExecApprovalElicitationRequestParams` / `PatchApprovalResponse` / `run_main()`

**架构闭环**：
- rmcp-client（底层 protocol + transport + OAuth）
- → codex-mcp（discovery + tool 调用）
- → mcp-server（向外暴露 Codex 能力）

Codex **既是 MCP client 也是 MCP server**，跟其他 agent 系统形成 mesh。CC 主要是 client，OC 同。Codex 的 server 角色是差异化点。

---

### 26. ext/ 扩展机制（Contributor 模式）

Codex 把扩展点放在 `ext/` 子目录而不是顶层，**信号是"这些是 plugin/extension 模式"，跟 core 隔离**。

#### 26.1 ext/extension-api (607 LoC)

| | |
|---|---|
| 路径 | `codex-rs/ext/extension-api/` |
| 职责 | **Agent 宿主接口**——extension 通过 trait 贡献能力 |
| 核心导出 | `ExtensionRegistry` / `ExtensionRegistryBuilder` / 4 种 Contributor trait + `PromptFragment` / `PromptSlot` |

**4 种 Contributor trait**：
- `ToolContributor` —— 贡献工具
- `TurnItemContributor` —— 贡献每轮的 item（消息、调用、结果）
- `ThreadLifecycleContributor` —— 贡献 lifecycle hook（start/stop/turn_complete）
- `ApprovalReviewContributor` —— 贡献审批审查逻辑

**这是 trait-based DI（依赖注入）模式**，跟 CC 的 hooks（命名事件 + callback）模型完全不同：
- CC：注册 callback 到事件名
- Codex：实现 Contributor trait，由 ExtensionRegistry 编排调用顺序

**优势**：类型安全，编译期检查 contributor 实现完整性。
**劣势**：Rust 之外不易复制（TS/Python 没有 trait）。

#### 26.2 ext/guardian (70 LoC)

| | |
|---|---|
| 路径 | `codex-rs/ext/guardian/` |
| 职责 | **Subagent spawner extension** —— thread fork 跟踪、host-provided agent spawn callback |
| 核心导出 | `GuardianExtension<S>` / `GuardianThreadContext` / `install()` |

**含义**：subagent 的派生不在 core 里硬编码，是 ext/guardian 通过 extension API 注入。这是"反 monolith"的具体体现。

#### 26.3 ext/memories (1,599 LoC)

| | |
|---|---|
| 路径 | `codex-rs/ext/memories/` |
| 职责 | **持久化记忆工具**：list / read / search 三个工具，可配置结果数限制 |
| 核心导出 | `install()` / 工具命名空间 `"memories/"`（含 LIST / READ / SEARCH） |

**对 FFAI 的启示**：
- Contributor 模式 vs hooks 模式——FFAI 选 hooks（TS/Python 友好）
- 但 ext/ 把 lifecycle 扩展和 core 隔离的目录约定可以借鉴
- memories 作为 extension（不是 core）的设计很妙——记忆系统的存储后端可以多实现并存

---

### 27. cloud-tasks 三件套

Codex 内置"云端任务"功能，对接 OpenAI 的 ChatGPT Cloud Tasks 后端：

| Crate | LoC | 职责 |
|---|---|---|
| `cloud-tasks` | **4,742** | **CLI TUI** for long-running cloud tasks（创建 / apply / list / 滚动 diff 视图） |
| `cloud-tasks-client` | **~1,000** | HTTP client for cloud tasks backend API |
| `cloud-tasks-mock-client` | small | dev-only test double |

**Base URL**：`https://chatgpt.com/backend-api`（可通过 `CODEX_CLOUD_TASKS_BASE_URL` 环境变量配置）

**关键导出**（cloud-tasks-client）：
- `HttpClient`
- `CloudBackend` (trait)
- `TaskStatus` / `TaskId` / `TaskSummary` / `DiffSummary` / `CreatedTask`
- 错误类型

**含义**：
- Codex 不只跑本地任务，还能让 LLM 在云端跑长任务（OpenAI 后端帮你执行 patch / 跑测试 / 提 PR）
- 对应 ChatGPT 网页版"Codex"的"in cloud"模式
- CC 没有对应概念

**对 FFAI 的启示**：
- 多租户 FFAI 天生就是"云端 agent"，不需要把 cloud-tasks 作为独立子系统
- 但"任务排队 + 长跑 + 状态轮询 + diff 摘要"这套 UX 模型可借鉴

---

### 28. external-agent-migration / sessions（from Claude Code）

**最 spicy 的 crate 对**：源码里把 Claude Code 称为 `external-agent (predecessor)`，**Codex 内置从 CC 迁移工具**。

#### 28.1 external-agent-migration (2,098 LoC)

| | |
|---|---|
| 路径 | `codex-rs/external-agent-migration/` |
| 职责 | 导入 external-agent 配置 / hooks / MCP servers 到 Codex |
| 核心导出 | `build_mcp_config_from_external()` / `hooks_migration_description()` / command skill prefix generation |
| 关键依赖 | hooks · serde_json · serde_yaml · toml |

**读取来源**：
- `.mcp.json`（CC 的 MCP 配置）
- `hooks/` 子目录（CC 的 hooks 配置）

**输出**：Codex 格式的 TOML MCP config + hooks 注册。

#### 28.2 external-agent-sessions (1,421 LoC)

| | |
|---|---|
| 路径 | `codex-rs/external-agent-sessions/` |
| 职责 | **加载并导入 external-agent 会话历史**到 Codex |
| 核心导出 | `detect_recent_sessions()` / `load_session_for_import()` / `summarize_session()` / `prepare_pending_session_imports()` |

**Ledger 防重复**：`has_current_session_been_imported` / `record_imported_session`

**含义**：
- OpenAI 在源码层面承认 CC 是先驱
- 把"挖墙脚"做成产品功能：用户切换到 Codex 时不用丢掉 CC 历史
- ledger 模式确保不会重复导入同一会话

**对 FFAI 的启示**：
- 兼容竞品的迁移工具是企业 ROI 撬动器
- FFAI 应该考虑 from CC / from Codex / from Cursor 的迁移工具（v2 优先级）
- 迁移设计的核心：detect → summarize（让用户预览）→ prepare（生成迁移计划）→ apply + ledger

---

### 29. collaboration-mode-templates + code-mode

Codex 把"协作模式"和"代码模式"作为 first-class concept。

#### 29.1 collaboration-mode-templates (4 LoC)

| | |
|---|---|
| 路径 | `codex-rs/collaboration-mode-templates/` |
| 职责 | **协作模式的内联 markdown 模板** |
| 核心导出 | 4 个常量字符串 |

**4 种模式**：
- `PLAN` —— 规划模式（先想后做）
- `DEFAULT` —— 默认模式
- `EXECUTE` —— 执行模式（直接动手）
- `PAIR_PROGRAMMING` —— **结对编程模式**（Aider 风格，把人当 pair）

**4 LoC 的极简**：每个模式是个 markdown 字符串常量，由 prompt builder 注入到 system prompt。

#### 29.2 code-mode (4,232 LoC)

| | |
|---|---|
| 路径 | `codex-rs/code-mode/` |
| 职责 | **代码执行运行时**：暴露 `exec` 和 `wait` 工具给 LLM |
| 核心导出 | `CodeModeService` / `ExecuteRequest` / `WaitRequest` / `RuntimeResponse` / `CodeModeNestedToolCall` / schema/description builders / JSON-schema-to-TypeScript renderer |

**工具命名**：
- `"exec"` (PUBLIC_TOOL_NAME)
- `"wait"` (WAIT_TOOL_NAME)

**关键差异**：CC 也有 Bash tool，但 Codex 把"执行 + 等待"作为成对工具暴露——LLM 可以发起后台命令然后用 wait 取结果，类似 ChatGPT 的 code interpreter。

**对 FFAI 的启示**：
- 协作模式 first-class 概念是好设计，FFAI prompt 系统应该支持模式切换
- exec + wait 的成对模式适合长跑命令（编译 / 测试），但增加 LLM 状态管理复杂度

---

### 30. realtime-webrtc

| | |
|---|---|
| 路径 | `codex-rs/realtime-webrtc/` |
| LoC | **317** |
| 平台 | **macOS only**（其他平台返回 UnsupportedPlatform 错误） |
| 关键依赖 | macOS native WebRTC stack via FFI（无 codex-* 依赖） |

**职责**：macOS-only WebRTC 音频桥，给 agent 实时语音交互用。

**核心导出**：
- `RealtimeWebrtcSession::start()` / `StartedRealtimeWebrtcSession`
- `RealtimeWebrtcSessionHandle`：apply answer SDP / close / local audio peak meter
- 事件：`Connected` / `LocalAudioLevel` / `Closed` / `Failed`

**含义**：Codex 支持 voice agent，对接 OpenAI 的 Realtime API。仅 macOS 是因为用了 macOS native binding，Linux/Windows 还没做。

**对 FFAI 的启示**：voice agent 在企业场景（会议助手 / 客服）有价值，但 v1 不需要。

---

### 31. connectors / chatgpt（stub）

| Crate | LoC | 职责 |
|---|---|---|
| `connectors` | **1,394** | **外部 app/connector 目录的缓存层**（ChatGPT app connectors / metadata / logos / branding） |
| `chatgpt` | **6 字节** | **几乎空的 stub** —— 包含 `apply_command` / `get_task` / `workspace_settings` 模块声明 + `connectors` re-export |

**connectors 缓存键**：`ConnectorDirectoryCacheKey` + `cached_directory_connectors()` + `DirectoryApp` schema + 1-hour TTL 缓存。

**chatgpt 6 字节**：极可能是占位 crate，实际逻辑在其他地方。或者是为了将来扩展占位 namespace。

---

## Part IV：Provider / 认证 / SDK / 构建系统

### 32. lmstudio + ollama（OSS 默认）

#### 32.1 lmstudio (443 LoC)

| | |
|---|---|
| 路径 | `codex-rs/lmstudio/` |
| 职责 | 本地 OSS 模型集成 via LM Studio HTTP API |
| 默认模型 | `openai/gpt-oss-20b` |
| 关键导出 | `LMStudioClient` / `ensure_oss_ready()` / `DEFAULT_OSS_MODEL` |
| 关键依赖 | core · model-provider-info · reqwest · **which**（找 LM Studio binary） |

**功能**：
- 检查 LM Studio server 是否运行
- 查询/下载模型
- 后台加载模型
- 通过 model-provider trait 接入

#### 32.2 ollama (772 LoC)

| | |
|---|---|
| 路径 | `codex-rs/ollama/` |
| 职责 | 本地 OSS 模型集成 via Ollama HTTP API |
| 默认模型 | `gpt-oss:20b` |
| 关键导出 | `OllamaClient` / `ensure_oss_ready()` / `DEFAULT_OSS_MODEL` / `PullProgressReporter` (trait) / `TuiProgressReporter` |
| 关键依赖 | core · model-provider-info · reqwest · **semver** · async-stream · wiremock（test） |

**比 lmstudio 多的功能**：
- semver 版本检查
- pull 进度上报（trait 抽象出 CLI / TUI / 自定义 reporter）
- 流式输出

**含义**：
- OpenAI **官方支持自家 gpt-oss 系列**作为本地默认（gpt-oss-20b 是 200 亿参数的 open-weight 模型）
- 用户可以完全本地跑 Codex（虽然能力会下降）
- 对企业内部部署是好信号——可以做"敏感代码本地跑、其他云端跑"的混合策略

**对 FFAI 的启示**：v1 不需要本地 OSS provider，但 trait-based provider abstraction 让后续加 Ollama 几乎免费。

---

### 33. 认证四件套

Codex 把"认证"切成 4 个独立 crate，分工极细：

| Crate | LoC | 职责 |
|---|---|---|
| `login` | **7,310** | **OAuth2 device-code 主入口** + PKCE + token 刷新 + 环境变量 auth |
| `keyring-store` | **226** | **OS 原生 keyring 抽象**（macOS/Linux/Windows/BSD） |
| `aws-auth` | **375** | AWS SigV4 签名 + AWS credential chain |
| `secrets` | **682** | **仓库级 secrets**（age 加密 + redaction） |

#### 33.1 login（7.3K LoC）

**核心**：`AuthManager` 编排 reading `~/.codex/auth.json` + OAuth server + token refresh + revocation。

**核心导出**：
- `run_device_code_login()`
- `AuthManager::load()`
- token env vars：`CODEX_ACCESS_TOKEN` / `OPENAI_API_KEY`
- `ExternalAuthTokens`（refresh context）
- `AuthEnvTelemetry`（追踪 token 来源）

#### 33.2 keyring-store（226 LoC）

**Trait**：`KeyringStore { load / save / delete (service, account) }`

**4 平台实现**（通过 `keyring` crate features）：
- macOS → Keychain
- Linux → libsecret-async
- Windows → CredentialManager
- BSD → SecretService

#### 33.3 aws-auth（375 LoC）

**职责**：AWS SigV4 HTTP request 签名 + credential provider wrapper。

**核心导出**：`AwsAuthConfig` / `AwsRequestToSign` / `AwsSignedRequest` / 签名方法

**特点**：用 `aws_credential_types::SharedCredentialsProvider`，尊重 `AWS_PROFILE` 和 `AWS_REGION`。**不集成 keyring**，纯 AWS SDK credential chain。**专门为 Bedrock 而生**。

#### 33.4 secrets（682 LoC）

**职责**：层级 secret 管理。

**核心组件**：
- `SecretName` 强制 `[A-Z0-9_]+` 命名 + SHA256 hash 验证
- `LocalSecretsBackend` for `.codex/secrets.toml`
- **age 加密** 用于本地持久化
- `redact_secrets()` 工具：从输出里抹掉 secret

**集成**：`git-utils`（仓库根检测）+ `keyring-store`

**Auth 流总结**：
1. `login` 检查 env vars (`CODEX_ACCESS_TOKEN` / `OPENAI_API_KEY`) → fallback OAuth device-code
2. Tokens 经 `AuthManager` 缓存到 `keyring-store`（OS 原生）
3. `aws-auth` 单独走 AWS credential chain 给 Bedrock
4. `secrets` 提供仓库级 secret（age 加密）

**对 FFAI 的启示**：
- FFAI 是 Web 服务，不能用 OS keyring（没有"OS 用户"概念）
- 凭据走 vault/KMS，但仓库级 secrets 的 age 加密 + redaction 思路可借鉴
- redaction 是企业 audit log 的必需功能

---

### 34. otel + analytics + feedback

可观测性三件套，**OpenAI 自家技术栈**：

#### 34.1 otel (3,718 LoC)

| | |
|---|---|
| 路径 | `codex-rs/otel/` |
| 职责 | OpenTelemetry provider（metrics / traces / logs），含 Statsig 和自定义 OTLP exporter |
| 默认 endpoint | **`https://ab.chatgpt.com/otlp/v1/metrics`**（Statsig 后端，prod 启用 / debug 禁用） |

**核心配置**：`OtelSettings { exporter, trace_exporter, tls_config }`

**支持的 exporter**：
- Statsig（默认）
- `OtlpHttp { endpoint, headers, protocol: Json | Protobuf, tls }`

**集成**：`opentelemetry-otlp` (gRPC + HTTP) · `opentelemetry_sdk` (batch trace processor) · `tracing-opentelemetry`

**核心导出**：`SessionTelemetry` / `Timer` / `TelemetryAuthMode` / `current_span_trace_id()` / W3C `traceparent` helpers

**关键事实**：**OpenAI 把 telemetry 接到 Statsig**——Statsig 是 OpenAI 内部的 feature flag + experimentation 平台。

#### 34.2 analytics (9,231 LoC)

| | |
|---|---|
| 路径 | `codex-rs/analytics/` |
| 职责 | Event facts reducer + send 到 app-server 的 `AppServerRpcTransport` |
| 关键依赖 | login · model-provider · plugin · otel |

**核心 fact 类型**：`SkillInvocation` / `CodexCompactionEvent` / `GuardianReviewTrackContext` / `CompactionPhase` / `CompactionStatus` / `HookRunFact`

**特殊工具**：`accepted_line_fingerprints_from_unified_diff()` —— 把 diff 转成行指纹，用于追踪 LLM 建议的接受率。

#### 34.3 feedback (1,049 LoC)

| | |
|---|---|
| 路径 | `codex-rs/feedback/` |
| 职责 | **Crash + diagnostic 上报**（via Sentry SaaS） |
| Sentry DSN | `ae32ed50620d7a7792c1ce5df38b3e3e@o33249.ingest.us.sentry.io`（写死） |
| 附件大小上限 | 4 MiB |
| 上传超时 | 10 秒 |

**核心导出**：`FeedbackDiagnostics` / `FeedbackRequestTags`

**含义**：crash 上报走 Sentry SaaS，跟 OTLP 是两套上行通道。

**对 FFAI 的启示**：
- OTLP 标准照搬，但 endpoint 改自托管 OTel collector（不接 Statsig）
- Sentry SaaS 路线 vs 自托管 GlitchTip，FFAI 应该选自托管
- analytics 的 reducer 模式（事件 → fact）是好设计，FFAI 可借鉴

---

### 35. config + features + install-context

#### 35.1 config (14,616 LoC)

| | |
|---|---|
| 路径 | `codex-rs/config/` |
| 职责 | 层级化配置：`config.toml` + `~/.codex/config/` profiles + env overrides |
| 关键依赖 | features · model-provider-info · protocol · Tonic/Prost proto |

**Schema**：TOML + protobuf fallback + 约束（`ConfigRequirements` / `AppToolRequirementsToml`）

**Loader 类型**：cloud requirements / hook configurations / MCP server registry / marketplace plugins

**核心导出**：`Config` / `ConfigLayerSource` / `ProfileV2Name` / `ConstrainedWithSource`

**示例 binary**：`generate-proto`（导出 proto schema）

**AGENTS.md 警告**：
> "If you change `ConfigToml` or nested config types, run `just write-config-schema` to update `codex-rs/core/config.schema.json`."

#### 35.2 features (2,158 LoC)

| | |
|---|---|
| 路径 | `codex-rs/features/` |
| 职责 | Feature registry + 运行时解析 + lifecycle stages |
| 关键依赖 | otel · protocol · schemars |

**Lifecycle stages**：
- `UnderDevelopment`
- `Experimental { name, description }`
- `Stable`

**核心导出**：`Stage` / `FeatureRegistry` / legacy toggle 映射

**集成**：跟 OTEL `SessionTelemetry` 联动 —— 可观测哪些 feature 被用、哪些 experimental 被启用

#### 35.3 install-context (258 LoC)

| | |
|---|---|
| 路径 | `codex-rs/install-context/` |
| 职责 | 平台感知的安装方式检测 |

**4 种安装形态**：
- Standalone（release dir）
- Npm / Bun shim
- Homebrew
- Other（cargo / bundled）

**单例**：`INSTALL_CONTEXT.get_or_init()`

**资源发现**：自动找 binary 旁的 codex-resources

**对 FFAI 的启示**：
- 三段 feature lifecycle（UnderDevelopment / Experimental / Stable）+ OTEL 集成是工业级 feature flag，FFAI 应该照做
- config 14K LoC 的复杂度是历史累积，FFAI 早期不需要

---

### 36. IPC + 工具杂项

| Crate | LoC | 职责 |
|---|---|---|
| `uds` | **452** | 跨平台 async Unix Domain Socket 包装（macOS/Linux/Windows via `uds_windows`） |
| `stdio-to-uds` | **66** | **桥接：stdin/stdout ↔ UDS**（用于 stdio-based protocol 的 IPC shim） |
| `terminal-detection` | **1,495** | 终端 emulator 识别（iTerm2/WezTerm/Ghostty/VS Code/kitty/Windows Terminal/Konsole/VTE/...） |
| `ansi-escape` | **58** | ANSI color/style → ratatui widget |
| `async-utils` | **86** | Tokio async helper（spawn / 取消模式） |
| `arg0` | **585** | **CLI arg parsing dispatcher** + 集成 sandboxing/escalation/patch |
| `vendor` | small | Vendored 第三方 |
| `v8-poc` | small | V8 engine POC（实验） |
| `test-binary-support` | small | 测试 binary 支持 |

**stdio-to-uds 的用途**：app-server-daemon 接受 stdio-based 协议时，用这个 shim 把 stdio 桥接到 UDS。让 daemon 内部统一只处理 UDS。

**arg0 是真正的 CLI 入口分发**（不是 `cli` crate）—— `arg0` 依赖 apply-patch / exec-server / linux-sandbox / shell-escalation，是个集成层。

---

### 37. SDK 生成路径

Codex 提供 3 套 SDK，但**生成方式不同**：

| SDK | 路径 | 生成方式 |
|---|---|---|
| TypeScript | `/sdk/typescript/` | **自动生成** via `ts-rs` 派生 + schemars JSON Schema |
| Python | `/sdk/python/` | **手写 wrapper**：spawn CLI + 解析事件流 |
| Python runtime | `/sdk/python-runtime/` | Python SDK 的运行时依赖 |

#### 37.1 TypeScript SDK（自动生成）

**生成链**：
1. `app-server-protocol` 的 Rust types 派生 `#[derive(TS)]` (来自 ts-rs crate)
2. 同时派生 `schemars` JSON Schema
3. 用 `#[ts(export_to = "v2/")]` 控制输出 namespace
4. binary `write_schema_fixtures` 触发生成
5. 命令：**`just write-app-server-schema`**（可加 `--experimental` 包含实验 API）

**字段命名映射**：Rust 字段名（snake_case）→ TS（camelCase）via `#[serde(rename_all = "camelCase")]` + 同步 `#[ts(rename = "...")]`

#### 37.2 Python SDK（手写 wrapper）

**形态**：
- 不是 pyo3 binding（不直接调 Rust 函数）
- 而是 spawn `codex` CLI + 解析 JSONL 事件流
- 比 TS SDK 灵活但性能差，没有零开销

**为什么选 wrapper 而不是 pyo3**：
- pyo3 跨平台分发需要 wheel × 平台 × Python 版本矩阵，工程成本高
- wrapper 只需 codex binary 装好就能用
- LLM agent 的吞吐瓶颈在远端 LLM，wrapper 开销可忽略

**对 FFAI 的启示**：
- FFAI 是 Web 服务，HTTP/WebSocket 接口本身就是 SDK，不需要单独 SDK 生成
- 但**类型从 Rust/Go 后端 → TS 前端的自动生成**是好习惯，省去手写类型同步
- ts-rs / openapi-typescript-codegen / Prisma 生成都是这个模式

---

### 38. 五套构建系统并存

Codex 同时维护 **Bazel + Cargo + Just + npm/pnpm + Nix** 五套构建系统：

#### 38.1 Bazel（hermetic multi-language）

- **Module**：`MODULE.bazel` pin LLVM (C++ toolchain) + macOS SDK (nix-imported) + 平台抽象
- **Targets**：`//codex-rs/cli:codex` / `//codex-rs/cli:release_binaries`
- **命令**：`just bazel-codex`（via RBE remote build execution）/ `just bazel-lock-update` / `bazel-clippy` / `bazel-remote-test`
- **配置**：`clippy` / `argument-comment-lint` / `remote` + RBE 平台覆盖

**含义**：Bazel 是 OpenAI 的 CI 主力，做 hermetic build + remote cache + 跨平台 release。

#### 38.2 Cargo（开发主力）

- 标准 `cargo build` / `cargo test` / `cargo clippy`
- 用 `cargo nextest` 跑测试（更快）
- 用 `cargo insta` 管 snapshot

#### 38.3 Just（任务运行器）

**任务列举**（from justfile）：
- `test` — via `cargo nextest`
- `fmt` — Rust + Python SDK via `uv`
- `clippy`
- `install`
- **`write-config-schema`** — 重新生成 config JSON schema
- **`write-app-server-schema`** — 触发 protocol → TS 生成
- **`tui-with-exec-server`** — 起 app-server + codex-tui 联调
- `bazel-codex` / `bazel-lock-update` / `bazel-clippy` / `bazel-remote-test`
- `argument-comment-lint`
- `fix` / `fix -p <project>`

**含义**：Just 是 Bazel 和 Cargo 的统一入口，开发者只记 `just <name>` 不需要管底下是哪个。

#### 38.4 npm / pnpm

- `/package.json` —— monorepo 维护（prettier / hooks schema generation）
- `/codex-cli/package.json` —— **npm 包入口**：`bin: { codex: bin/codex.js }`
- **bin/codex.js shim 模式**：`bin/` 下含平台特定 Rust binaries，JS shim 根据当前平台 spawn 对应 binary
- `/pnpm-workspace.yaml` —— pnpm workspace 定义

**bin/codex.js shim 的关键意义**：**OpenAI 通过 npm 分发 Rust binary**。用户 `npm install -g codex` 装的是个 JS 脚本，第一次运行时根据 `process.platform` + `process.arch` 调用对应 native binary。

#### 38.5 Nix flake

- `/flake.nix` —— 4 平台支持（x86_64-linux / aarch64-linux / x86_64-darwin / aarch64-darwin）
- 从 `/codex-rs/Cargo.toml` 读 workspace version
- 输出 `packages[system].default`（dev environment + release binaries）

**含义**：Nix 是开发环境可复现的兜底，CI 也用它做 hermetic build。

#### 38.6 这五套怎么协同

```
开发者输入：           工具链：             落实到：
                                          
just <task>     ───→  Just (justfile)  ───→  cargo / cargo nextest / cargo insta
                                       └──→  bazel build / bazel test
                                       └──→  uv（Python SDK 格式化）
                                       └──→  自定义 binary（schema 生成）

npm install -g codex ───→ pnpm/npm  ───→  bin/codex.js (JS shim)
                                       └──→ bin/codex-{platform}.{arch} (Rust binary)

nix develop      ───→  Nix flake     ───→  hermetic dev shell
```

**对 FFAI 的启示**：
- 五套构建系统是 OpenAI 这种规模公司才能维护的复杂度
- FFAI 一开始用 npm/pnpm + GitHub Actions 即可，等到需要 hermetic build 再考虑 Bazel
- 但 `just`（任务运行器统一入口）的思路很赞，FFAI 应该有一个 `Makefile` 或 `package.json scripts` 作为统一入口

---

### 39. AGENTS.md 工程规范摘要

`/AGENTS.md` 是 Codex 写给自己 AI 看的工程指令，长度 17K，是 Codex 工程纪律的事实源：

**Rust 风格规则**：
- `format!` 内联变量（`format!("{x}")` 而不是 `format!("{}", x)`）
- 折叠 `if` 语句（clippy collapsible_if）
- 优先 method reference over closure
- 避免 `bool` / `Option<T>` 的位置参数（`foo(false)` / `bar(None)` 难读）→ 用 enum / newtype / 命名方法
- 不能改 API 时用 `/*param_name*/` 注释（`argument_comment_lint` 强制）
- `match` 尽量穷举，避免 wildcard
- 新 trait 加文档注释解释角色
- **不用 `#[async_trait]`**，优先 RPITIT（Return Position Impl Trait In Trait）：
  ```rust
  fn foo(&self, ...) -> impl std::future::Future<Output = T> + Send;
  ```
- 测试用 `pretty_assertions::assert_eq` + 整对象比较（不要逐字段）

**模块大小约束**：
- 目标 Rust 模块 < 500 LoC（不含测试）
- 超过 800 LoC 应拆分新模块
- **特别提到**几个高触摸文件：`tui/src/app.rs` / `tui/src/bottom_pane/chat_composer.rs` / `tui/src/bottom_pane/footer.rs` / `tui/src/chatwidget.rs` / `tui/src/bottom_pane/mod.rs`
- 不要给 `chatwidget.rs` 加方法

**测试规则**：
- UI 改动必须加/更新 `insta` snapshot
- 用 `core_test_support::responses` 写 E2E
- 用 `mount_sse_once` 而不是 `mount_sse_once_match`
- 用 `wait_for_event` 而不是 `wait_for_event_with_timeout`

**API 规则（已在 §4 列出）**：camelCase / `*_at` 命名 / `String` ID / cursor pagination 默认

**Bazel + Cargo 同步**：
- 改 `Cargo.toml` / `Cargo.lock` 必须 `just bazel-lock-update`
- Bazel 不会自动暴露源代码文件给 compile-time read（`include_str!` / `include_bytes!` / `sqlx::migrate!` 要在 `BUILD.bazel` 里手动加 `compile_data`）

**对 FFAI 的启示**：
- AGENTS.md 不是 README，是**给 AI 看的工程纪律**——FFAI 的 CLAUDE.md/AGENTS.md 已经在做这件事，对齐
- "新 trait 必须有文档注释"、"模块 < 500 LoC"等纪律值得复制
- "高触摸文件清单"（明确点名容易膨胀的文件）是个好做法，避免反复返工

---

## Part V：横向对比与 FFAI 决策影响

### 40. 与 CC / OC 关键差异速查表

| 维度 | Claude Code (CC) | OpenClaude (OC) | OpenClaw | **Codex (CDX)** | FFAI 当前/计划 |
|---|---|---|---|---|---|
| **核心定位** | Anthropic 垂直整合 | 多 provider 平台 | OpenClaude fork（多渠道） | **OpenAI 多端 daemon-client** | 多租户 Web 内置 |
| **目标用户** | 单租 / 个人 | 单租 / 自托管 | 单租 / 多渠道用户 | 单租 + 企业 cloud tasks | 多租 / 企业 |
| **运行形态** | 本地 Node 进程 | 本地 Node 进程 | 本地 Node 进程 | **本地 Rust daemon + 多 client** | Web 后端常驻 |
| **接入面** | CLI(Ink TUI) + VSCode + 远程 WS | + gRPC + Web + Python | + 7 渠道（WhatsApp/TG/Slack/...） | **TUI(ratatui) + CLI + IDE + Python SDK + TS SDK 自动生成 + cloud tasks** | Web UI + IDE + (未来) SDK |
| **语言** | TypeScript | TypeScript | TypeScript | **Rust 96.2%** | TypeScript |
| **包模型** | npm 单包 | npm 单包 | npm 单包 | **Cargo workspace ~98 crate + npm shim 分发** | npm 单/多 |
| **架构纪律** | 隐式 | 隐式 | 隐式 | **AGENTS.md 写明"resist adding to core"** | 待定 |
| **provider 模型** | Anthropic 直连 | 11 vendor × 18 gateway × 200+ 模型 | 同 OC | OpenAI Responses API + Bedrock + Ollama + LM Studio + 自定义 | 多 provider |
| **协议层** | Anthropic 一种 | 三协议归一 | 同 OC | **JSON-RPC 2.0 v1+v2（v2 12K LoC）** | 待定 |
| **工具系统** | Tool.ts 8 生命周期方法 | 同 fork | 同 fork | **`ToolExecutor<Invocation>` 异步泛型 trait + ToolExposure 三态** | 待设计 |
| **工具数** | 43+ | 49 | 50+ | code-mode + apply-patch + shell + memories + ext + connectors（动态注册） | 待设计 |
| **patch 协议** | Edit tool 字符串替换 | 同 | 同 | **自定义 DSL**（`*** Begin Patch` envelope）| 待定 |
| **Shell 解析** | 字符串/正则匹配 | 同 | 同 | **tree-sitter-bash 真 parser** | 待定 |
| **执行策略** | 三态（allow/deny/ask）+ 持久化 | 同 + 多租审计 | 同 | **execpolicy v2 声明式 + v1 Starlark 双引擎 + 网络规则** | 待设计 |
| **沙盒** | macOS sandbox-exec / Linux landlock / Docker | 同 + Termux/proot | 同 | **Linux: bwrap+landlock+seccomp 三件套；Win: AppContainer+JobObj+ACL+ConPTY 15K LoC；macOS: Seatbelt** | Docker 容器 |
| **Network 控制** | 无 | 无 | 无 | **MITM TLS proxy + allowlist** (9.3K LoC) | 待定 |
| **进程加固** | 无 | 无 | 无 | **#[ctor] pre-main**: 禁 ptrace / coredump / 剥离 LD_PRELOAD | 无（Docker 内运行） |
| **扩展机制** | skills + plugins + hooks 三层 | 同 | 同 + 渠道适配器 | **同 + ext/Contributor 模式 + Plugin Marketplace（9 大 SaaS 内置）** | 待设计 |
| **Hook 事件数** | ~6 | ~6 | ~7 | **8**（含 PostCompact / UserPromptSubmit） | 待设计 |
| **MCP 角色** | client | client | client | **client + server 双向**（rmcp-client + codex-mcp + mcp-server 三件套） | 待定 |
| **状态持久化** | `~/.claude/` JSONL + memdir | `~/.openclaude/` 同 | 同 | **三层**：message-history(JSONL) + rollout(snapshot) + rollout-trace(event sourcing reducer) | DB（多租必需） |
| **多 agent 持久化** | 隐式（fork） | 同 | 同 | **agent-graph-store 显式 parent-child 边** + agent-identity（JWT/JWKS） | 待设计 |
| **会话格式** | JSONL | + SQLite Phase 2 | 同 | TOML + JSON 混合（rollout） | DB |
| **持久化记忆** | memdir 分类型 + MEMORY.md 索引 | 同 | 同 | ext/memories（list/read/search 工具） + global memdir | DB + vector store |
| **多 agent 协调** | 同进程 fork + resume | 同 | 同 | 同 + agent-graph-store + identity | 待设计（应跨进程） |
| **远程协作** | remote/ WebSocket | 同 + Web | 同 | **cloud-tasks 三件套** 接 chatgpt.com 后端 | 待定 |
| **Telemetry** | Anthropic 后台 | verify:privacy 强制零外发 | 同 | **OTEL → Statsig (ab.chatgpt.com/otlp)** + **Sentry SaaS feedback** | 自托管 OTel |
| **凭据** | OS keyring / env | profile 文件 | 同 | **login + keyring-store(4 平台) + aws-auth + secrets(age 加密)** 四件套 | vault / KMS |
| **OSS 模型默认** | N/A | N/A | N/A | **gpt-oss-20b（LM Studio + Ollama）** | 待定 |
| **TS SDK 生成** | N/A | N/A | N/A | **ts-rs 派生自 Rust types + schemars** | 待定 |
| **构建系统** | npm | npm | npm | **Bazel + Cargo + Just + pnpm + Nix flake** 五套 | npm |
| **协作模式** | N/A | N/A | N/A | **PLAN / DEFAULT / EXECUTE / PAIR_PROGRAMMING** first-class | 待定 |
| **语音 agent** | N/A | N/A | N/A | **realtime-webrtc**（macOS only） | 待定 |
| **竞品迁移** | N/A | N/A | N/A | **external-agent-migration / sessions（from CC）** | 待定 |
| **代码量级** | unknown（闭源 sourcemap 还原 1332 .ts） | ~2451 源文件 | ~2700 源文件（v2026.5.14 重构后） | **codex-rs ~98 crate，主要 crate 加起来 600K+ Rust LoC** | 早期 |
| **开源协议** | 闭源（npm 包可用） | MIT | MIT | **Apache 2.0** | 内部 |

### 41. 5 条对 FFAI 的新决策建议（基于 Codex 独有设计）

> 这 5 条是 Codex 收录后**新增**的建议，不替换 [`agent-implementations-comparison.md`](./agent-implementations-comparison.md) §四已有的 5 条。

**6. 接入面用 Daemon-Client 思路（即使是 Web 服务也适用）。**
Codex 的 app-server v2 给了一个清晰范式：**RPC protocol + transport 解耦**。FFAI 是 Web 服务自然带 daemon 形态，但应该把：
- **协议定义**（事件、命令、payload schema）独立成一层（类似 Codex `app-server-protocol`）
- **WebSocket / HTTP / 未来 SSE** 等 transport 实现独立成一层
不要把"WebSocket handler 直接调业务函数"——拆开后未来加 IDE HTTP poll / SDK gRPC 都不痛。

**7. Tool 接口加 ToolExposure 三态。**
CC 的 `isReadOnly + isEnabled` 两个布尔表达力不够。Codex 的 `Direct / Deferred / DirectModelOnly` 三态对应：
- **Direct** —— 默认显示给用户和 model
- **Deferred** —— 按 context（skill 触发 / 用户开启）才暴露
- **DirectModelOnly** —— 只让 model 调用，不显示在用户工具列表（用于内部工具如 self-reflection / planning）

FFAI 工具系统应该一开始就有这三态，避免后续改 schema。

**8. 持久化分三层（即使简化也要保留概念）。**
Codex 的 message-history (append-only JSONL) + rollout (thread snapshot) + rollout-trace (event sourcing reducer) 三层对应：
- **append-only audit log** —— 多租户合规必需
- **session 快照** —— resume 必需
- **状态投影 reducer** —— 高级：让 UI 从事件流重建状态

FFAI v1 至少做前两层（DB 表 audit_log + sessions）。第三层留 v2，但**事件 schema 设计要 reducer-friendly**（避免后续重写）。

**9. 工具网络访问走 egress proxy。**
Codex 的 network-proxy 9.3K LoC 用 MITM TLS 拦截工具的所有 HTTPS 出站。多租户 FFAI 必须有 egress 控制：
- **v1**：Docker 网络层 IP/port allowlist（简单）
- **v2**：HTTP proxy + URL allowlist（不需要 MITM TLS，URL 级 allowlist 在 client config 里）
- **v3**：MITM TLS（如果合规要求看到内容）

**10. Marketplace 内置 9 大 SaaS（企业版差异化）。**
Codex 出厂即装 GitHub / Notion / Slack / Gmail / Google Calendar / Figma / Linear / Canva / Microsoft Teams 的 plugin。FFAI 企业版的差异化路径：
- **v1**：plugin 加载机制 + 自家 SaaS（飞书 / 钉钉 / 企微，OpenAI 没覆盖国内市场）
- **v2**：marketplace 框架 + 国内 SaaS（金山 / 腾讯文档 / 字节内部工具）+ 选择性国际 SaaS（GitHub / Slack 必备）

国内市场的"出厂即装"清单跟 Codex 的国际 9 项完全不重叠——这是 FFAI 的真实差异化机会。

### 42. 不直接借鉴的部分（带原因）

| 不要照搬的设计 | 原因 |
|---|---|
| **Rust workspace ~98 crate** | FFAI 团队规模 + TypeScript 生态使然，目标 ~10-20 个 monorepo package 即可 |
| **app-server v1+v2 双协议** | FFAI 早期没历史包袱，v1 直接做对的 |
| **execpolicy v1 Starlark DSL** | Starlark 用户学习曲线陡，TS/YAML 声明式即可 |
| **sandbox 三平台 28K LoC** | FFAI 在 Docker 容器内跑，不需要 OS 级 sandbox（Docker 是第一道，OS sandbox 是第二道——多租户场景 Docker 已够） |
| **process-hardening #[ctor]** | Web 服务 + Docker，不需要 pre-main 加固 |
| **MITM TLS proxy** | 实现成本高（自签 CA 注入容器），URL 级 allowlist 已够 |
| **TUI 188K LoC ratatui** | FFAI 走 Web UI，不需要 TUI |
| **realtime-webrtc** | voice agent v1 不做 |
| **OSS 默认模型 + lmstudio + ollama** | FFAI 是 SaaS，本地模型不是主战场 |
| **Bazel + Nix** | npm/pnpm + GitHub Actions 已够，Bazel 等到需要 hermetic build 再说 |
| **OS keyring 四平台** | Web 服务用 vault/KMS，没有 OS user 概念 |
| **ext/Contributor trait 模式** | TypeScript 没有 trait，hooks 模式（CC 范式）更合适 |
| **5 套构建系统** | 工程团队规模不够维护，npm/pnpm 单一即可 |
| **Statsig telemetry** | OpenAI 内部平台，FFAI 自托管 OTel collector |
| **Sentry SaaS 写死 DSN** | 自托管 GlitchTip 或 Sentry on-prem |

---

## 附录 A：完整 crate 清单（按 LoC 降序，TOP 30）

| Rank | Crate | LoC | 主要职责 |
|---:|---|---:|---|
| 1 | `tui` | ~188,000 | 交互式 TUI（ratatui + 60+ 模块 + 音频） |
| 2 | `core` | 152,279 | 主 agent 运行时（含 agent loop） |
| 3 | `app-server` | 38,077 | RPC server 核心运行时 |
| 4 | `app-server-protocol` | 23,622 | RPC 协议定义（v1+v2 + TS export） |
| 5 | `core-plugins` | 20,648 | Plugin marketplace + 内置 SaaS 允许列表 |
| 6 | `protocol` | 17,822 | 共享类型零层 |
| 7 | `windows-sandbox-rs` | 15,023 | Windows AppContainer + JobObj + ACL + ConPTY |
| 8 | `cli` | 14,604 | 3 平台 sandbox 命令 + login 编排 |
| 9 | `config` | 14,616 | 层级化配置 + 约束 + protobuf fallback |
| 10 | `exec-server` | 12,502 | 执行 RPC server（local/remote 后端） |
| 11 | `rollout-trace` | 12,020 | Event sourcing trace + reducer |
| 12 | `network-proxy` | 9,352 | MITM TLS proxy + allowlist |
| 13 | `analytics` | 9,231 | Event facts reducer |
| 14 | `codex-api` | 9,141 | ChatGPT backend API 桥接 |
| 15 | `app-server-transport` | 8,876 | 4 transport 抽象 |
| 16 | `rollout` | 8,780 | Thread snapshot 持久化 |
| 17 | `hooks` | 9,778 | 8 hook 事件 + 调度 |
| 18 | `thread-store` | 7,343 | Thread 持久化 trait |
| 19 | `login` | 7,310 | OAuth2 device-code + token 管理 |
| 20 | `core-skills` | 7,053 | Skill 加载/管理框架 |
| 21 | `rmcp-client` | 6,990 | RMCP 协议 + transport + OAuth |
| 22 | `linux-sandbox` | 6,645 | bwrap + landlock + seccomp 三件套 |
| 23 | `shell-command` | 5,992 | tree-sitter-bash 命令解析 |
| 24 | `codex-mcp` | 5,179 | Codex 内部 MCP 客户端集成 |
| 25 | `exec` | 4,995 | CLI multiplexer（JSONL 事件处理） |
| 26 | `sandboxing` | 4,926 | 多平台 sandbox 选择器 |
| 27 | `cloud-tasks` | 4,742 | Cloud tasks TUI |
| 28 | `apply-patch` | 4,672 | 自定义 patch DSL parser |
| 29 | `tools` | 4,346 | ToolExecutor trait + ToolExposure |
| 30 | `code-mode` | 4,232 | exec + wait 工具 runtime |

**剩余约 70 个 crate 多在 100-3000 LoC 范围**，包括 utils-* 系列、各类 client、test 工具、stub crate 等。完整列表见 `codex-rs/Cargo.toml` 的 `[workspace] members` 段（已在本文档 §0 引用）。

---

## 附录 B：术语表

| 术语 | 含义 |
|---|---|
| **AGENTS.md** | 项目根目录的 agent 工程纪律文件，对应 CC 的 CLAUDE.md |
| **app-server** | Codex 的常驻 daemon，所有客户端通过 RPC 跟它通信 |
| **bubblewrap (bwrap)** | Linux 容器化沙盒库（Flatpak 同款），FS 隔离 |
| **ConPTY** | Windows 10+ 终端模拟器原语 |
| **Contributor** | Codex ext/ 扩展机制的核心 trait（4 种：Tool/TurnItem/ThreadLifecycle/ApprovalReview） |
| **execpolicy** | Codex 的执行策略引擎（v2 声明式 / v1 Starlark） |
| **external-agent** | Codex 源码里对 Claude Code 的称呼（"predecessor"） |
| **landlock** | Linux 5.13+ 内核 capability 限制 |
| **MCP (Model Context Protocol)** | Anthropic 提出的工具/资源 RPC 协议，已成事实标准 |
| **memdir** | CC/OC/Codex 的本地 markdown 记忆目录约定 |
| **PostCompact** | Codex 独有 hook：上下文压缩后触发（CC 把 compact 藏在 sub-agent） |
| **ratatui** | Rust 的 TUI 框架（rust-tui 的继任者） |
| **rmcp** | Rust MCP 实现 |
| **rollout** | Codex 术语：thread 完整状态的磁盘快照 |
| **rollout-trace** | Codex 术语：thread 事件流追踪（reducer 模式） |
| **seccomp (no_new_privs)** | Linux 内核能力：阻止后续提权 |
| **Statsig** | OpenAI 用的 feature flag + experimentation 平台，OTLP 数据接到 ab.chatgpt.com |
| **ts-rs** | Rust crate，把 Rust types 派生为 TypeScript 类型 |
| **ToolExposure** | Codex 工具可见性三态（Direct / Deferred / DirectModelOnly） |

---

## 文档元信息

- **创建**：2026-05-15
- **基于版本**：openai/codex 0.130.0（commit `4f2918d`）
- **作者**：FFAI Agent 内核调研团队
- **下次更新触发**：Codex 0.140+ 大版本 / 出现重大架构变更 / FFAI Agent 决策需要新维度对比
- **配套文档**：[`claude-code-reference.md`](./claude-code-reference.md) · [`openclaude-reference.md`](./openclaude-reference.md) · [`openclaw-reference.md`](./openclaw-reference.md) · [`agent-implementations-comparison.md`](./agent-implementations-comparison.md)
- **方法论**：4 个并行 Explore agent 按 crate 自然边界分扫，输出整合（参考 [`learnings/2026-05-15-clone-upstream-for-oss-research.md`](../../../.learnings/2026-05-15-clone-upstream-for-oss-research.md)）
- **Clone 副本**：`/tmp/codex-fresh/`（临时，不进 git）
