
关闭 Codex,再从历史列表打开一条 thread,前面的对话仍然能回来。最顺手的解释是:聊天记录写进 SQLite,resume 时再读出来。codex 的实现不是这条线。进程活着时,下一次模型请求读取的是 session 里的 ContextManager;进程退出后,可重放正文来自 rollout JSONL;SQLite 保存的是 thread metadata 投影,主要服务 list、read 和筛选。三者描述同一条 thread,却没有哪一个是另外两个的完整副本。
三个 owner,回答三个问题
Live history:下一次 sampling 带什么。 ContextManager 持有按时间排列的 ResponseItem,还持有 history_version、token 信息、reference context 和 world-state baseline。它由当前 Session 的 state owner 管理,服务 sampling、rollback、compaction 和本轮 context diff。这份 history 可以整体替换:replace 覆盖 items、递增 history version,并清掉 world-state baseline。它是一份可重写的工作集,不是 append-only 文件的内存映射。
Rollout JSONL:重启后拿什么 replay。 local ThreadStore 的注释直接把 JSONL 定义成 durable replay format。它保存经过 persistence policy 接受的 RolloutItem,包括 session metadata、turn context、response items、compaction checkpoint 和一部分 lifecycle event。这里的 durable 是相对于进程内 history 而言:writer 的 flush 是队列和文件 writer 的完成边界,不是断电后的 fsync。
SQLite projection:历史列表拿什么显示。 SQLite row 保存 path、cwd、model、reasoning、preview、title 和时间等投影,但它不是可独立重建 prompt 的正文数据库。Compacted 和 WorldState 不会被当作 transcript row 写进去。LocalThreadStore 把 JSONL 定义为 durable replay surface,把 SQLite 定义为 queryable metadata index——append 派生的 metadata 单独应用。

写入顺序与观察路径是两回事
record_conversation_items 的顺序是:先准备 item,记录进 live session state,请求 rollout 持久化,然后才发出 raw response item。SQLite metadata 还要经过 live observation 的独立路径——不能从写序推出「SQLite 一定同步更新」。
两个测试把这个边界钉死了:raw_append_items_does_not_update_sqlite_metadata——raw JSONL append 不会顺带更新 SQLite thread metadata;live_thread_observes_appended_items_into_sqlite_metadata——只有 live observation 接受 append 后,才更新 first message、preview 与 title。
目录同名陷阱
这个仓库里同名很常见:history 可能指模型可见序列、InitialHistory 或 app-server 返回的 turns;state 可能指 session mutex、SQLite runtime 或 client projection。工作方法只有一条:先找类型的 owner 和 durable artifact,再看调用者,不用目录名替代结论。
拆完这章,我的感受是:「持久化」在不同层有完全不同的含义。live history 是可重写的工作集,rollout 是 durable replay(但 flush 不是 fsync),SQLite 只是 metadata 索引。三份真相没有一份是完整的,但每一份都回答了各自的问题:下一次带什么、重启拿什么重放、列表拿什么显示。做 Agent 平台的人,最怕的就是把三份真相当一份用——在 live history 里找「历史记录」,或者拿 SQLite 当正文数据库,都会在恢复和审计时发现对不上。
源码依据:codex-rs/core/src/context_manager/history.rs L36-L57、L200-L204;thread-store/src/local/mod.rs L45-L57;state/src/extract.rs L14-L57;session/rollout_reconstruction.rs,rust-v0.144.6,commit 5d1fbf26c43abc65a203928b2e31561cb039e06d。