CodexHost 如何实现消息级 Fork:Thread 映射存储、Turn Anchor 与 Native Session 完整指南
【免费下载链接】codex-hostRun Pi and Claude Code directly in Codex Desktop. 在 Codex Desktop 中直接运行 Pi 和 Claude Code。项目地址: https://gitcode.com/gh_mirrors/co/codex-host
CodexHost 是一个让你在 Codex Desktop 中直接运行 Pi 和 Claude Code 的宿主层。它最让人惊艳的能力之一是消息级 Fork:点击任意一条历史消息上的 Fork 按钮,就能从那个精确位置派生出一条全新的独立会话,而原始对话保持不动。本文带你拆解背后三个核心机制——Thread 映射存储(Mapping Store)、Turn Anchor 与 Native Session 的工作原理,让你彻底理解 CodexHost 的会话分叉是如何做到"精确、可恢复、不丢消息"的。
什么是消息级 Fork?为什么它不容易做到
在 Codex Desktop 里,"Fork" 意味着从对话的某个历史位置复制出一条新时间线。难点在于:
- 对话的真实历史存放在Pi 或 Claude Code 自己的会话文件里,而不是 Codex 的数据库中;
- 每条 UI 消息必须能稳定地对应到 Harness 内部的历史条目;
- Fork 之后,新对话必须能独立继续,且不能污染源会话,更不能改动你的项目文件。
CodexHost 用三层结构解决了这个问题,下面逐个拆解。
三个核心概念:先建立正确的"词汇表"
Native Session:Harness 原生的会话
每个外部 Harness(如 Pi、Claude Code)维护自己的原生会话状态,称为Native Session。CodexHost 不复制它的内容,只持有指向它的不透明引用(NativeSessionRef)。这是"第二事实源"问题的根源——历史只存在于原生会话里,CodexHost 只记录"在哪、对应谁"。
Turn Anchor:把 UI 消息钉在历史坐标上
这是 CodexHost 的关键发明。领域术语表 中的定义是:
Turn Anchor:CodexHost 保存的
Host Turn ID → Native Checkpoint ID定位元数据,用于 Fork 等精确会话操作。它不包含消息正文,不构成第二份会话事实源。
通俗地说:界面上每一条消息轮次(Turn)都有一个稳定的 Host Turn ID,而 Turn Anchor 记录了"这条消息在 Pi/Claude 原生历史中的精确位置"(Native Checkpoint)。Fork 某条消息时,CodexHost 只需查出它的 Anchor,就能调用原生的精确分叉操作,而不是靠"数第几条消息"这种脆弱的做法。
Host Thread:Codex 侧的"影子会话"
Codex UI 看到的 Thread 是 Host Thread,由 CodexHost 负责把它和某个 Harness 的 Native Session 绑定。Fork 时创建的新 Host Thread 会指向一个全新的派生 Native Session,源 Thread 原封不动。
Mapping Store:Thread 映射存储的"账本"
Thread 与 Native Session 的映射关系由独立的 mapping-store 模块持久化。它的源码在 packages/mapping-store/src/mapping-store.ts,记录结构定义在 packages/mapping-store/src/records.ts。
每个外部 Thread 对应一个严格版本化的 JSON 文件,核心字段包括:
hostThreadId/harnessId:这条 Thread 属于谁、归哪个 Harness;nativeSessionRef:指向原生会话的引用;turnMappings[]:有序的 Turn 映射列表,每项含hostTurnId、nativeTurnRef和可选的nativeCheckpointRef(也就是 Turn Anchor);forkSource:如果是 Fork 出来的,记录"源 Thread + 停在源 Thread 的哪个 Turn";revision:版本号,用于并发写保护。
几个值得新手记住的设计原则:
- 只存坐标,不存内容——记录中严禁出现 Prompt、消息正文、工具输出或凭据;
- 原子写入——每次更新都是"写临时文件 → 备份 → 原子替换",失败时旧记录依然权威;
- 单写者锁——同一时间只有一个进程能写 Store,重启后还能识别 macOS 上被复用的僵尸 PID 并恢复过期锁;
- 启动自愈——损坏的主记录可从备份恢复,无法恢复的被隔离,临时文件被清理。
完整的行为规范见 external-thread-mapping-store spec。
Fork 执行流程:一次点击背后发生了什么
当你点击某条消息的 Fork 时,external-thread-fork.ts 中的路由逻辑按下面步骤工作:
- 所有权判定:
thread/fork请求先按源 Thread 的所有权路由——Codex 原生的 Thread 原样透传;外部 Thread 则由 CodexHost 本地处理,绝不转发给官方 Codex; - 边界解析:支持三种取法——
lastTurnId(含该轮)、beforeTurnId(不含该轮)、都不传(从最新一轮)。边界最终落到"该轮的 Turn Anchor(Checkpoint)"; - 原子打开:通过
adapter.open(fork)让 Harness 从精确 Checkpoint 派生一个独立的新 Native Session(Pi 内部用原生fork/clone操作),并先写入一条"预备"记录; - 重建映射:读取派生会话的 Snapshot,为派生 Thread 重新分配自己的 Host Turn ID 和 Anchor——绝不复制源 Thread 的映射;
- 提交后返回:全部映射持久化成功后才返回 Fork 响应。即使原生 Fork 成功但存储提交失败,CodexHost 会关闭派生运行时、清理预备记录并报错,保证不留下"幽灵映射"。
规范细节见 external-thread-fork-routing spec 与 harness-adapter-history-fork-session spec。
兼容细节:两阶段 Fork 与"回滚修正"
一个有意思的现实问题:受支持的 Codex Desktop 版本在选中非尾部消息时,实际发送的是"无边界 Fork + 一条thread/rollback { numTurns }"的组合拳。CodexHost 专门实现了这条兼容路径:
- 只对"派生 Thread 恰好是源 Thread 前缀"这一精确场景生效;
- 用持久化的有序 Turn 映射解析
numTurns,从源 Checkpoint 重新派生最终 Native Session; - 通过带版本号的原子替换(compare-and-swap)一次性换掉派生记录的
nativeSessionRef、Turn 映射与forkSource边界,同时保留派生 Host Thread ID,UI 上看起来就像"原地缩短"了对话。
这条路径的设计记录见 harden-history-mapping-cas,它保证了并发修改时旧版本写入会被干净地拒绝。
重启后依然精确:持久化带来的恢复能力
因为 Turn Anchor 与映射都落了盘,CodexHost 重启后:
- 任何已持久化的外部 Thread 都能通过
thread/read、thread/resume、thread/fork按需恢复——Host 调用adapter.open(resume)重新打开精确的原生会话; - 如果原生会话文件丢失,会返回明确的
sessionNotFound错误,而不是静默降级到 Codex; - 只分配了预备记录、尚无 Native Session 的 Thread 会在启动时被清理,不会暴露为"半成品"对话。
代码地图:想深入看哪里
| 想了解的内容 | 入口位置 |
|---|---|
| 映射记录 Schema 与字段 | packages/mapping-store/src/records.ts |
| 原子写、锁与启动恢复 | packages/mapping-store/src/mapping-store.ts |
| Fork 请求路由与边界解析 | packages/host-runtime/src/external-thread-fork.ts |
| 两阶段回滚兼容 | packages/host-runtime/src/external-thread-rollback.ts |
| 历史 Fork 能力契约 | openspec/specs/harness-adapter-history-fork-session/spec.md |
| 最初的设计决策记录 | openspec/changes/archive/2026-07-30-implement-external-thread-history-fork-slice/design.md |
| 术语定义(Turn Anchor 等) | docs/project/领域术语表.md |
小结
CodexHost 的消息级 Fork 本质上是一套"坐标系统 + 精确原生操作 + 可靠账本"的组合:Turn Anchor 把 UI 消息钉在原生历史的精确坐标上,Mapping Store 以原子方式持久化这些坐标,open(fork)则让 Harness 在原生层完成真正的分叉。三者叠加,才让"点一下任意历史消息就能开出一条新时间线"这个体验,在重启、并发和失败场景下都依然可信。
【免费下载链接】codex-hostRun Pi and Claude Code directly in Codex Desktop. 在 Codex Desktop 中直接运行 Pi 和 Claude Code。项目地址: https://gitcode.com/gh_mirrors/co/codex-host
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考