Claude Code 与 Codex 交接:哪些状态搬得过去,哪些搬不过去

会话是本地文件,能增量搬;系统提示、权限批准、没落盘的推理搬不过去。搬不动的部分,只能靠交接件重述。

分享
Claude Code 与 Codex 交接:哪些状态搬得过去,哪些搬不过去

一句话结论:会话不是黑盒——Claude Code 的每一次会话就是 ~/.claude/projects/ 下的一个 JSONL 文件,Codex 可以走它自己的 app-server 读,所以"把任务搬到另一侧"是可以做成增量的,不需要你重讲背景。但能搬的只是"消息 + 压缩后的工具痕迹";系统提示、权限批准、MCP 连接状态、以及模型没落盘的那段推理,永远搬不过去。所以正确姿势是两段式:能搬的用游标搬,搬不动的用交接件重述。

披露:本文编译五篇 2026-10 的一手文章与一份备考资料,作者立场各有不同(见文末)。ccx 的实现细节来自其作者自述,我们没有在 macOS 上跑过它;其余方案(half-clone、Stop hook、子 agent 边界)同样未独立复现。


一、先认清:会话是一堆状态,不是一段对话

原文作者的切换理由很朴素:一侧额度用完了(Claude Code 有 5 小时窗口和周上限,Codex 也有),或者换模型查 bug(一个模型在原地打转,另一个一遍过)。

两种情况下,新的一侧都是"冷的":不知道项目是什么、做到哪、哪些方案已经排除、现在坏在哪。把 transcript 粘过去也不行——工具调用加输出动辄几万词,粘过去直接撑爆上下文。

于是问题变成:到底有哪些状态,各自存在哪,能不能搬。

状态四类分桶:逐字搬(消息)、压缩后搬(工具痕迹、todo、图片路径)、按引用搬(git status、完整 transcript)、搬不动(系统提示、权限批准、MCP 连接状态、未落盘推理、被压缩掉的文本)

图:把"会话"拆成四类状态,决定了你能自动化到哪一步。(编者据源文绘制)

状态 存在哪 能不能搬 怎么搬
用户消息、助手回复 Claude:JSONL 一行一个事件 ✅ 逐字
工具调用与结果 同上 ⚠️ 能搬但不能原样 压缩:调了什么、作用于什么、大约返回什么
todo / plan 会话内(Claude todo、Codex plan) ✅ 取最新一份带上
是否停在半步 会话内 ✅ 标注"上一侧是中断的"
粘贴的图片 应用自己的缓存副本 ⚠️ 只搬缓存副本的路径
git status 仓库 ✅ 现取现带(代码本来就在盘上)
系统提示 / 项目指令 各工具自己拼 ❌ 只能是"重述",不是"迁移"
权限批准、MCP 连接状态 运行时 ❌ 到另一侧要重新批准/重新连
未落盘的推理、被压缩掉的原文 上下文里 ❌(半救) 压缩掉的部分用 read_session 分页找回

这张表的用处:看到 ❌ 的那几行,就知道"全自动交接"不可能做满。它们不是工程没做好,是设计上就不该跨进程搬(权限尤其:搬过去等于绕过批准)。

二、Claude 侧:整段历史就是一个 JSONL

这是整套方案的地基,也是很多人不知道的一点:

~/.claude/projects/<escaped-project-path>/<session-id>.jsonl

一个会话一个文件,一行一个事件:用户消息、助手回复、工具调用、工具结果、todo 更新。所以不需要任何 API 就能读完整段会话。

(顺便:另一个源文给了同一件事的路径规则——项目路径里的 / 变成 -,例如 /Users/yk/Desktop/projects/claude-code-tips 对应 ~/.claude/projects/-Users-yk-Desktop-projects-claude-code-tips/。这也解释了"老对话去哪了":一直在你自己的机器上。)

作者说,难的不是读,是决定读多少:

  • 工具结果可能巨大(整份文件读取、完整跑一遍测试);
  • 所以压缩:消息逐字保留,每个工具调用降维成"调了什么 / 作用于什么 / 大约返回什么",再附上当前 todo 和 git status。

这三行 bash 就够你自己翻历史(需要 jq):

# 哪些会话提过某个词
grep -l -i "reddit" ~/.claude/projects/-Users-you-project/*.jsonl

# 今天的会话里搜关键词
find ~/.claude/projects/-Users-you-project/*.jsonl -mtime 0 -exec grep -l -i "keyword" {} \;

# 只抽用户消息
cat ~/.claude/projects/.../<session>.jsonl | jq -r 'select(.type=="user") | .message.content'

三、Codex 侧:走它自己的 app-server,别解析内部文件

Codex 也在本地存会话记录,但原文作者刻意不去解析:

只使用 Codex 自带的 app-server:建 thread、往里发消息、读回来。这样 Codex 某次更新换了文件格式也不会把我的东西搞坏,而且写入走的是官方路径。

具体用到的三个能力:thread/list、thread/read、session import。

这个选择值得单独记一笔:"读别人的私有存储"是最容易在某次升级后静默坏掉的东西。一边是你的解析器,一边是别人的内部格式——没有契约。能用官方接口就别省这一步。

额度检查同理:Codex 有 account/rateLimits/read,直接读。

四、增量同步:配对 + 游标 + 只投递一次

作者的第一版是一次性导出:Claude 写一份 HANDOFF.md,Codex 读。这版能用,但有个明显缺陷——切回来的时候,Claude 不知道 Codex 改了什么,于是你又得导一次。手动,就回到原点了。

现在这版是双向的:

双向游标同步:Claude 会话(JSONL)与 Codex thread(app-server)配对,pairs.json 存两条游标;发送时 UserPromptSubmit hook 把对方的新进展前置到这条消息,然后移动游标

图:配对 + 双向游标 + 一次性投递。(编者据源文绘制)

四个环节:

  1. 配对:Claude 会话 A 与 Codex 线程 T 在 ~/.ccx/pairs.json 里构成一对,每侧记一个游标——"对方已经收到哪了"。
  2. 只发增量:切换时只发游标之后、压缩过的进展。
  3. 投递:你在 A 里发消息时,UserPromptSubmit hook 把 T 的新进展前置到这条消息里,然后移动游标。同一份内容不会送两次,hook 也绝不阻塞你的输入。
  4. 兜底:如果某段内容被压缩掉了,模型可以用 read_session 工具分页翻回来。

原文的形容很准:"这些内容作为上下文到达模型,而不是变成新的聊天气泡。" 每次更新通常几千 token;没有新内容时再点一次,什么也不会发生。

结果就是:两侧在同一个任务上工作,而不是两个互不相关的对话。

五、什么时候该切:盯额度,但别绕过额度

大多数切换是因为额度。所以 ccx 在任一侧 5 小时窗口超过 90%、以及用完时,菜单栏各提醒一次,并给你"用对方继续"的入口。

这里有个不对称,很能说明"哪些状态搬不过去":

  • Codex:额度从 app-server 的 account/rateLimits/read 读,内置。
  • Claude:本地没有任何达标前的信号。所以它只能去读你已经在装的那些工具的文档化输出(CodexBar、Claude Code Usage Monitor、ccusage、abtop、claude-hud、ccstatusline 等),装了哪个用哪个,不需要额外配置。

作者也明确了两条边界:不绕过任何额度(各用各的套餐),不上传任何东西(同步全在本地,只有安装和检查更新时才连 GitHub)。

六、同一个问题,四条路:清、压、写、切

第二篇源文把"上下文快满了怎么办"整理成四级阶梯,从"交出控制权"到"自己动手",这个排序比工具本身更有用。

手段 留下什么 什么时候用 代价
/clear + 新会话 什么都不留 换到不相关的任务 上下文全丢
/compact 模型自己写的摘要 急需腾空间、细节不太重要 摘要不知道什么对你重要
HANDOFF.md 你审过的交接文件 长任务、有死胡同值得记 要人多看一眼
/branch、--fork-session 分叉点之前完整对话 想在某个点试另一条路 会话数变多
half-clone / quarter-clone 后半段(或后四分之一)逐字 长对话、最近状态最重要 丢掉开头

三条值得抄的实践:

1)把自动压缩关掉。 理由不是"压缩不好",而是自动摘要不知道什么对你重要——它可能留下一个已经定论的争论,却丢掉你只提过一次的小约束。关了不等于不压缩,而是你挑时机(通常在某个里程碑之后)并挑留下什么。

2)交接文件比摘要强,因为你能读它。 原文给了一个具体例子:让 Claude 把剩下的计划写进 HANDOFF.md,说明"试过什么、什么成了、什么没成",让"一个有干净上下文的 agent 只读这一个文件就能接着干"——产出是 129 行,开头是目标("把 Claude Code 的系统提示压掉约 45%(现在 11%,还差约 34%)"),后面是进展和已经写好的脚本。

然后关键的一步是:别文件一落地就开新会话。先扫一眼,缺什么就问(比如"你有没有写清楚要迭代测试,而不是想一次做完?")——这个问题常常能省掉下一个会话的整个下午。确认之后再开新会话,只贴路径:

> experiments/system-prompt-extraction/HANDOFF.md

之后每次都让 agent 更新同一个文件,留给下一个接手的人。(源文附了一个 /handoff skill 把这套流程自动化。)

3)half-clone 不做摘要。 它把超长对话复制成"只保留后半段"的副本,你和 Claude 的消息逐字保留,只是丢掉较早的部分;副本第一条消息带 [HALF-CLONE Jan 7 14:30] 标记,让你知道自己在哪个版本里。嫌多还有 --quarter。和压缩的区别很清楚:压缩会重新解释,half-clone 只做截断。

再往前一步是自动化:一个 Stop hook(check-context.sh)在每次回复后检查上下文占用,超过 85% 就不让 Claude 停,让它去跑 /half-clone 生成一个只带后半段的新会话,让新 agent 在那里继续。前提条件写死:必须关掉 Auto-compact,否则 Claude Code 可能在 hook 生效前先自己压了。

原作者的一句话总结很到位:如果只养成一个习惯,就养成交接文件。 它迫使你和 agent 把"现在到底到哪了"讲清楚——而这正好是干净上下文最需要的东西。

七、更窄的边界:子 agent 只拿到 prompt

如果你把"交接"缩小到同一个 agent 内部派活,能过的状态更少。一份备考资料把边界列得很干脆:

方向 能过去的东西
父 → 子 只有 Agent 工具(原 Task 工具)的 prompt 字符串
不继承 父对话历史、工具结果、系统提示;skills 里没列出的技能内容也不会自动带过去
子 → 父 只有最终消息;中间的工具调用留在子 agent 内部
例外 fork(/subtask 或 subagent_type: "fork")会复制整段对话
配置 AgentDefinition 必填 description + prompt;同名时程序化定义覆盖文件定义

所以"发现、约束、质量标准"必须写进那句 prompt——你不能指望它从父上下文里"感受到"。作者给的实践是:上下文用结构化记录传(内容与元数据分开),并要求结构化最终报告。否则协调者拿不回来源。

还有一个容易误读的字段:allowed_tools 是"免批准",不是"权限边界"——它让 Agent 不问你直接跑,不代表它跑不了别的。

八、团队级:共享会话与"可执行的流程"

第三篇介绍的 Agent Relay 把这件事推到团队层(Apache-2.0,v14.0.0,2026-10-13 发布,约 900 star),四件套:

  • Messaging:agent 之间用频道、线程、DM、文件、搜索、实时事件通信,可以跨机器共享工作区(像给 agent 用的 Slack 原语)。
  • Integrations 当虚拟文件系统:GitHub、Linear、Notion、Slack 以 ls/cat/grep/写文件的方式暴露,用来替代"每个工具接一个 MCP server"。
  • Shared Sessions:捕获会话,供队友和他们的 agent 搜索"之前做过什么、为什么这么定";通过 plugin 或 agent-relay mcp --sessions-only 访问(文档提到要云登录)。
  • Flows:用 TypeScript 定义多步流程,带确定性检查、必需步骤和人工闸——把"你希望 agent 遵守的规则"变成"不遵守就过不去的流程"。

写这篇的介绍者明确说自己没有跑过它,并给了一个谨慎的试法:先拿一个废弃仓库,让 Claude Code 干一件小事,再让 Codex 读它的会话接着做;交接能成,再接真仓库。这条建议本身就值钱——它是"先验证通道,再接生产"。

九、三段式:搬状态、搬契约、留在原地

把上面拼起来,判据只有三句话:

层 适用于 手段 判据
搬状态 消息、压缩后的工具痕迹、todo、git status 游标增量同步(JSONL / app-server) 切换后对方不需要你再讲背景
搬契约 revision、命令、预期输出、验收人、未完成项、Do Not Change HANDOFF.md(可读、可提交、可审) 换到任何工具都能开工,包括你下周新装的那个
不搬 权限、系统提示、连接状态、未落盘推理"是否该这么干"的判断 留在原 agent 做完,或人来做 搬过去等于绕过批准 / 等于猜

第三层最容易被忽略。"能不能全自动"的真正答案在第三行:凡是需要重新获得授权的东西(权限、部署、外发消息),都不该被"搬"过去——那正是第 68 篇讲的 staged tools 想在同一个进程里解决的问题。

第四篇源文(团队工作流那篇)把"搬契约"这一层写成了文件名清单,可以直接抄:PROJECT.md(目标与约束)、ARCHITECTURE.md、docs/PLAN.md、docs/TASKS.md、docs/DECISIONS.md、docs/WORKLOG.md、docs/HANDOFF.md;CLAUDE.md 与 AGENTS.md 只当薄适配层,指向上面的规范文件,避免两边规则漂移。

它的交接模板里有三个字段值得直接偷:

  • Revision:branch / base commit / 待评审的 head commit / 未提交改动(有就列出);
  • Verification:命令 × 通过/失败/未跑 × 在哪个提交上跑的;
  • Do Not Change:受保护行为与范围排除项。

最后一条还附了一句提醒:Do Not Change 只是记录约束,不提供强制。 同一篇文章里还有两句同类的:分支不是访问控制边界,worktree 只是组织改动、不是沙箱。这三句放在一起,基本把"用文件解决权限问题"的幻想堵住了。

十、坑(都是踩过的)

  • 平台:ccx 只有 macOS 13+,要 Claude 和/或 Codex 桌面应用;Windows / Linux / 独立 CLI 都还不行。想在 Linux 上用,就得自己照它的思路写。
  • JSONL 会越来越大:一个会话一个文件,工具结果全在里面。要定期清理或按项目归档,别指望它永远轻。
  • 压缩会丢细节:被压掉的内容只能靠 read_session 分页找;如果那一段已经从磁盘上删了(比如你自己清了历史),就真没了。
  • hook 的纪律:不能阻塞输入、不能往 stdout 打印(打印会进上下文)、必须幂等(同一份只投一次)。这几条和第 68 篇里 Claude 生命周期 hook 的规则是同一套。
  • 图片只是路径:搬过去的是一个缓存副本的路径,换机器就断。
  • 自动压缩会让 Stop hook 失效:想让 85% → /half-clone 生效,必须先关 Auto-compact。
  • 别拿旧对话当交接:源文把它列进"常见错误"第一条区——旧会话既没有 revision,也没有验证记录。
  • 子 agent 的 allowed_tools 不是防火墙,prompt 也不是访问控制;审批状态不能搬(搬了就是绕过批准)。

十一、三步落地(每步有判据)

第 1 步(半天):先只做"能搬的那半"。 写个 50 行脚本:读某个会话的 JSONL → 压缩工具结果 → 生成一段"现状摘要"附到新会话开头。判据:新会话接到任务后,第一轮不再问你"项目是干什么的 / 之前试过什么"。

第 2 步(一天):加游标,做成双向。 配对表(一个会话 ↔ 一个对方线程)+ 两个游标 + 一次性投递。判据:来回切三次,没有一次重复投递、没有一次漏掉对方的改动。

第 3 步(一天):把"搬不动"的部分固化成 HANDOFF.md。 字段:revision(含待评审 head)、验证(命令 × 结果 × 提交)、Do Not Change、未完成项、验收人。放在源文件旁边写进仓库;新会话只贴路径。判据:换任意一个工具接手都能开工——包括你下周新装的那个。

团队级共享会话(第 8 节那套)放到这三步之后:先在一个废弃仓库验证"两个 agent 互读会话",再考虑接真仓库。

编者补充:和第 68 篇的关系

  • 第 68 篇讲交接件写什么(revision / 命令 / 预期输出 / 验收人)与台账怎么推导状态;这篇讲这些状态里哪些根本搬不过去,所以你才需要那个交接件(见 多 Agent 交接:把"写条"换成四字段契约与台账)。
  • 两篇叠起来的结论:同步解决"重复叙述",契约解决"无法开工",闸门解决"越权"——三者不能互相替代。
  • 与站内 多 Agent 同机:Git 作者与凭据归属 的关系:那篇讲"谁签的字",这篇讲"谁记得住"。

边界

  • 本文为编译整理,未在 macOS 上运行 ccx,也未实测 half-clone / Stop hook / Agent Relay;所有机制细节来自源文自述。
  • 立场披露:ccx 与 Agent Relay 都是各自作者的项目(前者个人开源,后者是 Agent Workforce 的产品,介绍者声明"未运行过");HANDOFF.md/half-clone 一套来自一份 50 条 tips 的二手整理(原始观点见 YK Sugi 的 claude-code-tips 仓库);子 agent 边界那张表来自一份备考资料(非 Anthropic 官方文档,作者声明与 Anthropic 无关);团队工作流那篇是工具站内容。
  • Agent 工具名、--fork-session、/autocompact、hook 事件名等随版本变化,以你本地 claude --version 的文档为准。
  • 文中"通常几千 token"这类量级是作者在其设置下的观察,不是基准测试。

相关阅读:AI 编程 / Vibe Coding 完全指南 | Agent / MCP / 自动化完全指南 | 多 Agent 交接:四字段契约与台账 | 多 Agent 写代码:协议才是系统 | 子代理交接的三种做法:compaction vs subagent vs fold | 多机并行 coding agent 实战栈

Sources

本文由 hubwiz 编译整理,转载请注明出处。

这是「AI 编程 / Vibe Coding」专题的一部分。完整地图见:AI 编程 / Vibe Coding 完全指南