codex resume 与 fork:长任务恢复、多方案实验和上下文债务
TL;DR
codex resume 用来继续之前的 Codex 会话,适合长任务中断后恢复上下文;codex fork 用来从已有会话分出新线程,适合在同一理解基础上尝试不同方案。二者管理的是 Codex 线程和 transcript,不管理 Git 文件状态。恢复或分叉前必须检查当前分支、工作区 diff 和关键文件是否仍与旧会话假设一致。需要比较方案时,fork 要配合 Git 分支或 worktree;需要批处理恢复时,可以使用官方文档中的 codex exec resume。把会话上下文当成“记忆”,把 Git 当成“事实”,二者混在一起会制造很隐蔽的错误。
读者定位
这篇适合经常让 Codex 做多小时任务、复杂调试、迁移、重构、审查或多方案设计的开发者和技术负责人。你应该熟悉 Git 分支、worktree、stash、commit、CI 验证和代码审查。本文重点是长会话的工程管理:什么时候恢复,什么时候新开,什么时候分叉,什么时候丢弃旧上下文。
问题:长任务真正难的不是“继续聊”,而是“继续得对”
一次复杂 Codex 任务可能已经读了十几个文件、排除了几个错误方向、跑过一组失败命令、形成了某个设计假设。终端关闭、网络中断、上下文变长、你临时离开,都会让任务中断。如果重新开一个会话,Codex 可能重复之前的探索,浪费时间,还可能忘记已排除路径。
但直接恢复也有风险。旧会话里有很多当时成立的事实:某个文件内容、某个测试错误、某个分支状态、某个依赖版本。多协作仓库里,这些事实可能已经变了。你恢复了会话,Codex 仍然带着旧推理前进,就会出现“上下文自信但事实过期”的问题。
多方案实验也有同样矛盾。Codex 已经理解了项目,你想让它从“最小补丁”转向“抽象公共模块”;如果在同一会话里直接继续,两条思路会互相污染。fork 能复制旧上下文,让新线程走另一条路,但文件层面的隔离仍要靠 Git。很多失败案例来自把 fork 当成 Git branch:会话分叉了,工作区却没分叉,最后两个方案改在同一批文件上。
心智模型:会话历史和文件历史是两条轨道
最有用的模型是:
Codex session 管“为什么这么想”
Git 管“实际改了什么”
resume 回到旧白板继续写。它保留之前的对话、计划、失败尝试和推理路径,适合中断恢复。
fork 复制旧白板,开一块新白板。它继承已有理解,但后续讨论和操作进入新线程,适合多方案实验。
Git 分支、commit、stash、worktree 管的是文件状态。它们决定你能不能比较 diff、回滚、合并、清理和审查。Codex 会话不能替代 Git,因为 Codex 的 transcript 不会自动把工作区恢复到当时状态。
因此,恢复前先问两个问题:
旧会话上下文还有价值吗?
当前工作区是否仍匹配旧会话里的事实?
如果第一个答案是否,直接新开会话;如果第二个答案是否,先让 Codex 重新核对当前状态,或从干净分支重新开始。
官方命令边界
官方 CLI reference 中,codex resume 是稳定命令,用于继续之前的交互式会话,可以按 session ID 或最近会话恢复。codex fork 也是稳定命令,用于把之前的交互式会话分叉成新线程,并保留原 transcript。官方非交互文档还说明,codex exec resume --last "..." 可以在非交互模式中恢复旧上下文并追加新指令;恢复的运行会保留原 transcript、计划历史和审批信息,同时可以通过 --cd 或 --add-dir 调整环境。
这些能力都不表示文件系统会回到旧状态。恢复上下文前,你仍要自己确认 Git 状态。官方也强调本地线程能读写文件和运行命令,受沙箱和审批策略控制;这意味着恢复后 Codex 的后续动作仍会作用在当前真实工作区,而不是 transcript 里的旧工作区。
详细机制:什么时候用 resume
适合 resume 的场景:
- 同一个任务中断,当前分支和文件状态基本没变。
- Codex 已经完成大量有效分析,重新开始成本高。
- 上次会话里有明确下一步,例如“继续补测试并运行 typecheck”。
- 你希望保留失败命令和已排除路径,避免重复探索。
不适合 resume 的场景:
- 需求已经明显变化。
- 同一批文件被其他人或其他 worker 改过。
- 旧会话已经偏离目标或积累大量错误假设。
- 你只想做一个相邻但独立的新任务。
- 上次会话没有留下清晰状态摘要。
恢复前建议运行:
git status --short
git branch --show-current
git diff --stat
然后用一个校准 prompt 开始,而不是立刻让它继续改:
恢复之前,请先检查当前 git status、当前分支和你上次涉及的关键文件。
对比旧会话里的假设,列出哪些信息可能过期。
确认后再继续,不要立即编辑文件。
这个步骤看似多余,但能避免旧上下文直接污染当前事实。
详细机制:什么时候用 fork
适合 fork 的场景:
- 已经完成问题分析,想比较两个实现方案。
- 想保留原会话方向,同时试一个更激进方案。
- 需要让一个线程继续修补,另一个线程做设计评估。
- 想从同一上下文生成候选方案,供人工选择。
fork 不适合无目的探索。每个分叉都应该有明确假设,例如:
方案 A:最小修复,只改调用方。
方案 B:抽取 retry policy,补充测试后替换调用方。
方案 C:不改实现,只修正错误测试假设。
没有假设的分叉会把 review 成本推高。三个线程都给出不同 diff,但没有统一评分标准,人只能凭感觉选。
推荐工作流:长任务中断恢复
假设你让 Codex 排查支付重试测试不稳定,中途断开。
第一步,检查文件事实:
git status --short
git diff --stat
第二步,恢复会话:
codex resume --last
第三步,校准上下文:
先不要改代码。请重新读取当前分支、git status、src/payment/retry.ts 和对应测试。
列出你上次分析里仍然成立的结论,以及可能过期的结论。
然后给出下一步最小动作。
第四步,继续执行:
按刚才确认的最小动作修复。只修改 retry 相关实现和测试。
完成后运行 pnpm test -- payment-retry 和 pnpm typecheck。
恢复会话时,最重要的是让 Codex 重新读取事实,而不是让它直接沿旧思路写。
推荐工作流:多方案实验
先让 Codex 在只读模式做分析:
codex --sandbox read-only \
"Analyze the flaky payment retry tests. Do not edit. Propose two implementation options: minimal fix and retry policy extraction."
然后为方案 A 创建隔离分支或 worktree:
git worktree add .worktrees/retry-minimal -b codex/retry-minimal
cd .worktrees/retry-minimal
codex resume --last
给它明确方向:
采用最小修复方案。不要抽取新模块。只修复触发 flaky 的边界。
运行 pnpm test -- payment-retry 和 pnpm typecheck。
方案 B 使用另一个 worktree:
git worktree add .worktrees/retry-policy -b codex/retry-policy
cd .worktrees/retry-policy
codex fork --last
给它另一条指令:
采用 retry policy 抽取方案。保持公开 API 不变。
补充 focused tests,运行 pnpm test -- payment-retry 和 pnpm typecheck。
最后在主工作区比较:
git -C .worktrees/retry-minimal diff --stat
git -C .worktrees/retry-policy diff --stat
选择方案时,不要把两个 diff 拼起来。选一个,或者基于人工判断重开第三个任务。
会话摘要:给未来的 resume 留路
长任务结束或暂停前,要求 Codex 输出恢复摘要:
请输出本会话恢复摘要:
- 当前目标
- 已修改文件
- 已运行验证命令及结果
- 已排除方案
- 未解决问题
- 下次恢复前需要重新读取的文件
- 推荐下一步
这段摘要不替代 transcript,但能降低恢复成本。下次 resume 后,把摘要贴给 Codex,并要求它先核对当前事实。
团队可以把摘要保存到 PR 描述、issue 评论或本地任务记录里。不要依赖“我记得上次聊到哪了”。长会话上下文一旦跨天,人工记忆和模型上下文都会变脆。
操作清单
resume前检查git status --short、当前分支和git diff --stat。- 恢复后先让 Codex 重新读取关键文件,不要立即编辑。
- 旧需求变化较大时,新开会话,不要恢复。
fork前先定义每个方案的假设和评分标准。- 多方案实验必须使用分支或 worktree 隔离文件状态。
fork管会话,Git 管 diff;不要混用。- 长会话暂停前让 Codex 输出恢复摘要。
- 恢复摘要要包含已排除方案和未解决风险。
- 最终只合并一个方案,避免把多个候选手工拼接成无来源 diff。
- 恢复会话后仍要重新跑验证命令。
权衡与风险
resume 的收益是节省重新分析时间。成本是上下文债务:旧假设、旧文件内容、旧错误输出、旧审批状态都可能过时。长会话越长,越需要重新校准。
fork 的收益是保留共同理解,同时探索不同方案。成本是审查负担增加。每个分叉都会产生新的推理和可能的 diff;如果没有统一验证标准,候选越多越难选。
会话恢复还可能掩盖用户最新指令。当前需求永远优先于旧 transcript。如果你恢复一个旧任务,但现在用户要求缩小范围,Codex 应明确丢弃旧方向,而不是把新要求解释成旧目标的一部分。
非交互恢复也要谨慎。codex exec resume 适合继续一个已有分析并执行明确下一步,但它不适合含糊任务。恢复上下文越长,自动化越需要先输出计划和状态校准,而不是直接改。
常见误区
误区一:以为 resume 会恢复文件。它恢复会话,不恢复工作区。文件状态看 Git。
误区二:在同一工作区里 fork 多个方案。会话分开了,文件没分开,结果是 diff 混在一起。
误区三:长会话无限续。旧上下文会积累噪声。超过一定复杂度后,输出摘要,新开干净任务往往更稳。
误区四:没有恢复摘要。没有摘要的 resume 很容易重新走旧路,或者忘记关键失败。
误区五:候选方案没有同一验证标准。方案 A 跑了定向测试,方案 B 跑了全量测试,结果不可比。
会话生命周期治理
长会话需要生命周期,而不是无限续命。可以把 Codex 会话分成四种状态:
| 状态 | 含义 | 处理方式 |
|---|---|---|
| active | 当前正在推进,工作区匹配上下文 | 可以继续 |
| paused | 暂停但目标未变,已有恢复摘要 | resume 前重新核对事实 |
| branched | 已分叉成多个方案 | 每个方案绑定独立分支或 worktree |
| stale | 需求、分支或关键文件已变化 | 新开会话或只保留摘要 |
不要把所有旧会话都当作可恢复资产。有些会话已经包含太多无关讨论、失败尝试和过时假设,继续使用只会增加噪声。一个实用规则是:如果恢复后第一步需要花大量时间解释“哪些内容不要再按旧的来”,那就新开会话。把旧会话摘要作为参考输入即可。
会话命名也有价值。长任务可以在 issue、PR 或本地记录里写:
Session purpose: payment retry flaky test
Primary branch: codex/retry-minimal
Known good checkpoint: after root-cause analysis, before implementation
Do not reuse after: retry module refactor lands
这样团队成员能判断是否值得恢复。没有命名、没有摘要、没有分支关联的会话,恢复成本往往接近重开。
多人协作中的 resume 风险
多 worker 或多人同时改同一仓库时,resume 的风险会放大。旧会话可能认为某个文件尚未修改,但另一个人已经重写了它;旧会话可能计划改测试,但当前分支已经删除了相关测试;旧会话可能基于旧接口设计,最新 main 已经改变契约。
在多人环境中,恢复前要增加三步:
git fetch origin
git status --short
git log --oneline -5
然后让 Codex 明确回答:
请先判断本会话是否仍适合恢复。
如果当前分支、关键文件或需求与旧会话冲突,请建议新开任务,而不是继续。
这句话能避免 Codex 为了“继续”而强行解释不一致。恢复不是义务。很多时候,最专业的选择是承认旧上下文过时。
fork 候选的评审协议
fork 生成的多个方案需要统一评审协议。可以要求每个候选都输出同一份表:
## Candidate summary
- Strategy:
- Files changed:
- Public API impact:
- Tests added or changed:
- Verification:
- Known tradeoff:
- Why this is preferable:
候选比较时,不要只看代码量。最小 diff 不一定最好,抽象方案也不一定过度。要看它是否解决根因、是否保留现有契约、是否降低未来修改成本、是否让测试覆盖更贴近真实风险。
如果两个候选各有优点,不要直接手工拼接。更好的做法是让 Codex 或人基于评审结论开第三个干净任务:
基于候选 A 的最小改动和候选 B 的测试覆盖,重新实现一个第三方案。
从当前 main 的干净 worktree 开始,不要复用两个候选的工作区。
这样能保持来源清晰,也能重新跑完整验证。
何时归档或删除会话
会话也是信息资产,但不是越多越好。完成的会话如果已经合并、摘要已进入 PR、关键决策已写入文档,可以归档。包含敏感信息、错误方向或过时凭据片段的会话,不应继续被当作模板复用。
官方 CLI reference 中还有 archive、unarchive 和 delete 这类会话管理命令。归档适合把会话从活跃列表中移走但保留 transcript;删除适合你确实要移除保存的会话。团队不需要把所有个人会话统一管理,但在共享机器、CI runner 或演示环境里,应避免长期保留含敏感上下文的 transcript。
会话治理的原则是:有复用价值的上下文写进文档,临时推理留在会话,敏感信息不要进入会话。Codex 记住了什么,不应成为团队唯一知识来源。
恢复前检查清单模板
可以把下面模板贴给 Codex:
在继续旧会话前,请先执行恢复检查:
1. 当前分支是什么?
2. git status 是否干净?
3. 与旧会话相关的关键文件是否变化?
4. 旧会话的下一步是否仍符合当前用户要求?
5. 是否需要新开会话而不是 resume?
请先报告结论,不要编辑文件。
这个模板能把恢复从“直接继续”变成“先审查上下文”。它尤其适合长任务、跨天任务和多人协作仓库。
长会话的风险:记忆不是事实
resume 的便利在于保留上下文,但上下文不是事实。会话里记着的计划、文件状态、测试结果和用户意图,可能已经过期。仓库可能被别人改过,分支可能切换,依赖可能升级,用户也可能改变目标。恢复旧会话前,必须重新读取当前环境。
一个危险模式是跨天继续任务时直接说“继续”。Codex 会沿着旧计划走,但旧计划可能针对已经删除的文件,或忽略新加入的约束。正确做法是先要求它执行恢复审计:当前分支、git status、相关文件摘要、旧计划是否仍适用、是否有新冲突。只有审计通过,才允许写文件。
长会话还容易积累错误假设。早期一次误读,如果没有被纠正,会在后续多轮中反复影响决策。定期把确认过的事实写进任务摘要,把推测和待验证事项分开,可以降低这个风险。不要让 transcript 成为唯一信息源。
fork 的真正用途:探索互斥方向
fork 适合探索互斥方向,而不是制造更多随机尝试。互斥方向指的是架构、边界或取舍不同,例如“保持现有 API 只修内部实现”和“调整 API 并迁移调用方”;“用配置解决”和“用代码路径隔离”;“补测试后修复”和“先重构再修复”。这些方向不能在同一个工作区里混写。
每个 fork 都应该有明确假设。候选 A 假设改动应最小,候选 B 假设要消除重复抽象,候选 C 假设问题来自配置。评审时先看假设是否成立,再看代码质量。没有假设的 fork 只是多生成几份 diff,增加 review 成本。
fork 结果也要能被丢弃。很多候选的价值是证明某条路不该走。比如某方案测试通过但需要改 20 个公共接口,另一个方案改动小但覆盖不到根因。丢弃候选时要保留结论:为什么不用,它暴露了什么约束。这个结论应写进最终任务记录。
会话恢复与 Git 工作流
恢复会话前,Git 状态决定风险。干净工作区最安全;只有自己改动的工作区可继续;混有他人改动、生成文件、冲突标记或大量未跟踪文件时,应先暂停。Codex 不能可靠地区分所有未跟踪文件来源,尤其是在多人共享目录或自动生成目录里。
建议恢复前固定三步:
git branch --show-current
git status --short
git diff --stat
如果旧会话涉及远程任务,还要确认本地是否落后远程。长期任务中,主分支变动会让旧方案失效。不要把 rebase、冲突解决和继续实现混成一轮。先更新基线,再重新确认计划。
会话恢复也要尊重新用户消息。用户最新要求优先级高于旧会话计划。如果旧计划说“实现方案 A”,新消息说“先别改代码,只解释风险”,必须停在解释。长会话里最常见的错误之一,就是 agent 继续执行旧目标。
候选评审后的整合
从多个 fork 选出方向后,不建议直接在获胜候选上继续无边界修改。更稳的流程是把评审结论转成新任务,从干净基线实现最终方案。这样能避免候选探索期间留下的临时文件、调试代码和折中判断混入最终 diff。
如果必须在候选上继续,也要先清理:删除调试输出,确认未跟踪文件,重新运行验证,写清楚哪些改动来自候选探索,哪些是最终收敛。最终 PR 不应让 reviewer 同时审探索过程和最终方案。
整合阶段还要防止“把两个候选优点都拿来”变成范围膨胀。两个候选的优点可能依赖不同假设,硬拼会制造新复杂度。整合前先写一句决策:最终方案选择哪个约束作为主约束,例如最小 API 变化、最高测试覆盖、最低运行风险或最清晰迁移路径。
会话生命周期管理
团队使用 Codex 时间长了,会产生大量会话。活跃会话太多会增加误恢复概率。建议给会话加生命周期:进行中、待审查、已归档、应删除。进行中会话必须有当前目标;待审查会话等待人类决定;已归档会话只作为记录;应删除会话包含敏感或错误上下文。
有复用价值的内容应迁移到文档或 AGENTS.md,而不是让新人翻旧 transcript。旧会话适合保存推理轨迹,不适合作为团队规范。规范要短、明确、可执行。
发布前复核
会话管理文章发布前要确认一个核心信息:恢复旧会话前必须重新读取现实状态。旧 transcript 可以提供线索,但不能替代当前分支、工作区、文件内容和用户最新要求。只要这条边界写清楚,resume 和 fork 就会从便利功能变成可治理的协作机制。
延伸阅读
GitHub 原文:12-codex-resume-fork.md