从 .codex 目录反推 Codex 内核:一个本地 Agent OS 的剖面

从 CODEX_HOME 的目录、SQLite schema 和官方文档出发,把 Codex 拆成控制面、状态面、执行面、扩展面、安全面、后台面和记忆面,理解它为什么更像本地 agent runtime。

这篇不是源码逆向,也不是把本地缓存当成绝对真相。更准确地说,它是一种“运行时考古”:观察 $CODEX_HOME 下由 Codex 内核管理的目录、SQLite schema、缓存和官方文档之间的对应关系,反推出 Codex 的核心抽象和工程哲学。

结论先放前面:.codex 不是普通配置目录。它更像一个本地 agent runtime home,里面同时放着控制面、状态面、执行面、扩展面、安全面、后台任务和长期记忆。Codex 也不只是一个“会调用模型的 CLI”,而是一个围绕线程、工具、权限、扩展和可恢复执行组织起来的轻量 agent OS。

1. 先把 .codex 看成 CODEX_HOME

如果只看目录名,很容易把 .codex 理解成:

config.toml
sessions
cache
plugins
skills
worktrees
logs

但换一个视角,它其实更像一个运行时根目录:

CODEX_HOME
├── control plane
├── state plane
├── execution plane
├── extension plane
├── isolation plane
├── audit plane
└── memory plane

这个视角比“按目录逐个解释”更有用,因为 Codex 的内核不是围绕文件夹命名组织的,而是围绕 agent 工作流组织的:

  1. 用户发起一个线程。
  2. 线程里产生 turn 和 item。
  3. item 可以是消息、工具调用、命令、文件变化、浏览器动作或 agent 输出。
  4. 执行过程受 sandbox、approval、project trust、hooks、rules 控制。
  5. 能力通过 skills、plugins、MCP servers、apps 注入。
  6. 长任务、后台任务和并行任务通过 worktrees、automations、subagents 隔离。
  7. 结果被写入 sessions、SQLite、logs、history、snapshots,方便恢复、索引、审计和继续执行。

所以 .codex 透露出的第一条内核原则是:

Codex 把 agent 工作当成可恢复、可审计、可扩展的本地运行时,而不是一次性 prompt-response。

2. 控制面:config.toml 是本地内核的装配表

config.toml 暴露出 Codex 的控制面。它不是只有模型名,而是把几个关键维度放在同一个配置层里:

model / model_provider / reasoning_effort
sandbox_mode / approval_policy
features
mcp_servers
plugins
projects.*.trust_level
skills.config

这说明 Codex 的默认行为不是写死在某个客户端里,而是由配置层叠加出来的。Config basics 也明确说,Codex 会从 CLI overrides、项目 .codex/config.toml、profile、用户级 config.toml、系统级配置和内置默认值里解析最终配置。

这背后有一个很重要的工程判断:不同工作区的风险边界不同。一个 Git 项目、一个下载目录、一个临时目录、一个企业托管环境,不应该共享同一套权限和工具策略。

所以 projects.*.trust_level 很关键。项目被信任之后,Codex 才会加载项目级 .codex 配置、hooks、rules。否则用户级和系统级配置仍然生效,但项目本地的可执行控制面不会自动进入运行时。

这是一种典型的 agent 安全设计:能力可以分层注入,但项目本地能力必须先过 trust boundary。

3. 状态面:Thread 是 Codex 的第一公民

.codex/sessionsstate_*.sqlite 暴露了 Codex 的状态模型。App Server 文档把核心原语定义成:

Thread:一段用户和 Codex agent 的对话
Turn:一个用户请求和随后的 agent 工作
Item:输入或输出单元,例如消息、命令、工具调用、文件变化

本地状态也正好围绕这个模型展开:

sessions/        原始会话与 rollout
session_index    会话索引
history          历史事件
state.sqlite     thread 元数据、动态工具、远程控制、agent jobs
logs.sqlite      本地运行日志
goals.sqlite     thread goal 与预算状态
memories.sqlite  memory 生成流水线状态

这透露出第二条原则:

Codex 不只保存聊天记录,它保存 agent 工作的结构化索引。

普通聊天产品只需要按时间存 message。Codex 需要更多维度:

这个 thread 在哪个 cwd 里?
使用了哪个模型和 provider?
当时 sandbox / approval 是什么?
关联哪个 git branch / sha?
有没有动态工具?
有没有子 agent 派生关系?
有没有 goal budget?
是否已归档?
能不能从本地、worktree 或远程恢复?

这些字段不是 UI 装饰,而是 agent runtime 的必要状态。因为 Codex 要支持恢复线程、fork 线程、handoff、后台执行、远程控制、自动化和审计,就必须把“对话”升级成“可管理的任务实体”。

4. 执行面:Shell、Browser、Computer Use 是不同等级的现实接口

.codex 里有几类执行相关目录:

shell_snapshots
node_repl
process_manager
browser/sessions
computer-use
generated_images
attachments

它们代表 Codex 接触现实世界的不同层级。

第一层是 shell。Codex 可以执行命令、读写文件、跑测试、启动服务。shell_snapshots 说明它会缓存 shell 环境,用来加速或复现重复命令。

第二层是浏览器。内置浏览器适合本地开发服务器、file-backed preview、公开页面检查。官方文档强调它和用户常用浏览器不同:不共享登录态、扩展、已有 cookies。这个边界很重要,因为浏览器页面是高风险 prompt-injection 来源。

第三层是 Computer Use。它不是代码工具,而是 GUI 操作层:看屏幕、点窗口、输入、跨 app 操作。官方文档也把它定位为命令行和结构化集成不够时的补充,并且强调需要 macOS Screen Recording / Accessibility 这样的系统权限。

这三层共同说明:

Codex 的执行面不是单一工具,而是从文件系统、进程、网页到桌面 GUI 的分层现实接口。

这也解释了为什么 Codex 需要强权限模型。只要 agent 能从“改 repo 文件”扩展到“点浏览器里的按钮”和“操作桌面 app”,它就不再只是代码助手,而是在用户机器上运行的自治工作流系统。

5. 扩展面:Skill、Plugin、MCP 是三种不同抽象

.codex/skills.codex/plugins/cache.codex/vendor_importscache/remote_plugin_catalogcache/codex_apps_tools 暴露出 Codex 的扩展面。

这几个概念容易混在一起,但职责其实不同:

Skill   复用工作流,主要是说明、参考资料、脚本
Plugin  可安装分发单元,可以打包 skills、apps、MCP servers、assets
MCP     工具和上下文协议,让模型接入外部系统或本地工具
App     更高层的连接器或产品集成

Skills 文档里有一句很关键:skills 使用 progressive disclosure。也就是说,Codex 一开始只看 skill 的名称、描述和路径;只有决定使用某个 skill 时,才读取完整 SKILL.md

这是一种面向大上下文系统的工程优化:能力很多,但不能把所有说明都塞进 prompt。先用短描述做路由,再按需加载完整说明。

Plugins 则是分发层。一个 plugin 可以带 skills、app integrations、MCP servers。用户可以安装、启用、禁用插件;插件也可以提供自己的 MCP server 和 lifecycle hooks。

MCP 是工具协议层。Codex 可以通过 stdio 或 HTTP MCP server 获取工具、资源和 server instructions。配置里还支持 tool allowlist、denylist、approval mode、startup timeout、tool timeout。

所以 Codex 的扩展哲学不是“给模型更多 prompt”,而是:

把能力包装成可发现、可路由、可启用、可禁用、可授权、可审计的 runtime component。

这和传统 IDE 插件有相似之处,但更强调模型如何选择工具、如何遵循 workflow、如何受权限约束。

6. 安全面:Sandbox 和 Approval 分工明确

Codex 的安全模型可以用一句话概括:

sandbox 决定技术上能做什么;
approval 决定越界时要不要问人。

Agent approvals & security 把两者分得很清楚。sandbox 是 OS 层或运行时层边界,比如能否写文件、能否访问网络、能否写工作区之外。approval policy 是决策层边界,比如什么时候暂停并请求用户许可。

常见组合大致是:

read-only + on-request
workspace-write + on-request
danger-full-access + never

这背后的哲学不是“默认不信任 agent”,也不是“默认完全信任 agent”。更准确地说:

Codex 试图把低风险重复动作放进边界内自动完成,把高风险动作推到边界上显式审查。

这也解释了 hooks、rules、project trust 的位置。

hooks 是生命周期控制:在 tool use 前后、permission request、compact、session start、stop 等事件上挂检查或自动化。rules 更像命令级策略:允许、提示或禁止某些命令前缀。project trust 则决定项目本地配置和 hooks 是否能被加载。

安全不是一个单点开关,而是多层组合:

project trust
config precedence
sandbox
approval policy
auto-review
rules
hooks
MCP tool approval modes
plugin enablement
computer-use app approvals

这是一套适合 agent 的安全模型,因为 agent 的风险不是单一来源。风险可能来自命令、文件、网络、浏览器页面、MCP tool、插件、项目本地 hooks,甚至来自桌面 GUI 操作。

7. 并行面:Worktree、Automation、Subagent 解决不同并行问题

.codex/worktrees.codex/automations 暴露出 Codex 对后台工作的设计。

Worktrees 解决的是代码隔离。官方文档说 Codex-managed worktree 默认放在 $CODEX_HOME/worktrees,通常处于 detached HEAD,用来让后台线程或 automation 不污染用户当前 checkout。

Automations 解决的是时间维度。它可以定时启动独立任务,也可以作为 thread automation 在同一个线程里周期性唤醒。官方文档还特别提醒,automation 会使用默认 sandbox settings;如果在 full access 下运行无人值守任务,风险更高。

Subagent 解决的是任务分解和上下文污染问题。官方文档说 Codex 只有在用户显式要求时才会 spawn subagents。它们适合并行探索、测试、日志分析、总结,把噪声留在子线程里,主线程只接收蒸馏后的结果。

这三个机制看起来都叫“并行”,但其实解决的是三类不同问题:

worktree   文件系统隔离
automation 时间调度和无人值守
subagent   认知分工和上下文隔离

这透露出一个很成熟的工程判断:agent 的并行不只是多开几个模型。并行必须同时考虑代码冲突、权限继承、上下文污染、后台任务生命周期和结果汇总。

8. Memory:有用的本地回忆,但不是规则源

memoriesmemories_*.sqlite 代表 Codex 的长期记忆面。

Memories 文档对 memory 的定位很克制:它可以记住稳定偏好、常见工作流、技术栈、项目约定、已知坑;但团队必须遵守的规则仍应放在 AGENTS.md 或项目文档里。

这一区分很重要:

AGENTS.md  是显式规则和团队约定
config     是运行时控制面
memory     是本地经验回忆层
sessions   是历史事实

如果把 memory 当规则源,就会让系统变得不可预测。因为 memory 是生成态、延迟更新、可能被跳过、也可能被 redaction 或 rate limit 影响。它适合“帮我少重复背景”,不适合“必须永远执行某条安全规则”。

这也反映 Codex 的另一条工程哲学:

生成出来的经验可以辅助,但确定性控制必须留在显式配置、文档和策略里。

9. 这些目录合起来像什么

把所有面合在一起,.codex 可以这样理解:

config.toml
  控制面:模型、权限、功能开关、MCP、插件、项目信任

sessions / state.sqlite / history / logs
  状态面:线程、turn、item、索引、日志、目标、审计

packages / app-server-daemon / app-server-control
  本地 runtime:standalone binary、daemon、rich client control

skills / plugins / vendor_imports / cache
  扩展面:能力包、插件市场、工具目录、按需加载

shell_snapshots / process_manager / node_repl
  命令执行面:进程、shell 环境、交互式执行

browser / computer-use / attachments / generated_images
  多模态执行面:网页、GUI、附件、图片

worktrees / automations
  后台和隔离面:定时任务、独立 checkout、任务恢复

memories
  长期经验面:偏好、稳定上下文、历史总结

这就是我说它像本地 agent OS 的原因。它不是完整操作系统,但它具备 OS-like 的几个特征:

有进程和任务生命周期
有权限边界
有扩展和驱动
有本地状态数据库
有日志和审计
有后台任务
有隔离工作区
有跨客户端控制协议
有长期记忆

如果用一句话概括 Codex 内核的工程哲学,我会写成:

让模型在清晰边界内自治,把能力做成可组合组件,把每次工作保存成可恢复的结构化状态。

10. 对我们使用 Codex 的启发

这个视角对日常使用很有帮助。

第一,不要把 AGENTS.md、skills、memory、config 混用。

一次性约束      放 prompt
团队规则        放 AGENTS.md
运行时默认      放 config.toml
可复用工作流    做 skill
可安装能力包    做 plugin
外部系统工具    接 MCP / app
定时或巡检      用 automation
本地经验        交给 memory
强制安全控制    用 sandbox / approval / rules / hooks

第二,给 Codex 更多权限之前,先想清楚边界。

很多时候不需要 danger-full-access。如果只是需要多写几个目录,可以扩展 writable roots;如果只是某个命令需要例外,可以用 rules;如果只是项目长期约定,可以写进 AGENTS.md;如果只是一次任务,可以留在当前 prompt。

第三,把复杂工作拆成不同隔离层。

代码修改适合 worktree;定时检查适合 automation;读很多材料适合 subagents;固定流程适合 skill;外部系统访问适合 MCP;视觉验证适合 in-app browser;桌面软件才需要 Computer Use。

第四,定期清理 runtime home。

sessionslogsworktreesplugins/cachepackages/releasesgenerated_images 都可能增长很快。清理时不要粗暴删除正在关联的 worktree 或会话,最好通过 Codex app 的归档、清理和设置入口处理。这个目录承载的不只是缓存,还有恢复和审计状态。

结语

.codex 这个目录看 Codex,最有意思的地方不是“它藏了哪些文件”,而是它把 agent 产品的工程边界显露出来了。

一个真正可用的 coding agent,不能只靠一个强模型。它需要本地控制面、结构化状态、工具协议、权限系统、扩展市场、可恢复会话、后台工作区、日志审计和长期记忆。

模型是推理核心,但 .codex 才让这种推理落到一台真实机器、一组真实项目和一套真实工作流里。

这就是 Codex 目录透露出的内核原理:agent 的能力不是一次回答,而是一套可以被配置、执行、约束、扩展、恢复和审计的运行系统。