把 Codex CLI 的会话记录(~/.codex/sessions/**/*.jsonl)解析并渲染成 Markdown 交接文档,
让另一个 Agent(如 Claude Code)可以接续完成被中断的任务。
Codex 里任务做到一半被迫停下是常态:
- 触发用量限制:ChatGPT 账户的 Codex 有使用限额(如 5 小时窗口),任务进行到一半被限流, 不想干等额度恢复——把现场交给 Claude Code 立刻继续;
- 上下文已被压缩:长会话中 Codex 自动 compact,模型自己忘掉了中间过程——
但 JSONL 里全都在。交接文档包含压缩点摘要 + 完整对话流水,比
codex resume恢复的信息更完整; - 会话意外中断:进程崩溃、误退出,或最后一条消息发出后没有得到任何回复;
- 换 Agent 接手:任务在 Codex 里进行到一半,想换一个模型/Agent 继续或接对比。
codex resume 只能回到 Codex 自己;codex-transfer 把会话现场完整搬给任何接手者,
并附「文件修改汇总」(哪些文件已被改过,读取现状即可,禁止重做)和
「当前状态与继续指示」(中断点在哪、下一步从哪接)。
- 零依赖:仅使用 Python 标准库(argparse / json / sqlite3 / pathlib …),无需
pip install任何东西; - 兼容两代会话格式:老格式(≤0.14x,消息在
event_msg)与新格式(≥0.15x,消息在response_item/message), 解析层按会话自动适配,已在 0.14x / 0.15x 真实会话双回归验证; - 三级详略:
summary(用户+最终回答+压缩摘要)/normal(+工具调用证据链,默认)/full(不截断); - 接手即用:文末自动生成「当前状态与继续指示」,含中断点判定(有/无最终回答)与操作指引。
git clone https://github.com/Rostopher/codex-transfer.git
cd codex-transfer要求 Python 3.10+,无任何第三方依赖。
# 1. 先看看最近有哪些会话
python3 codex_transfer.py --list 10
# 2. 迁移指定会话(支持四种输入形态)
python3 codex_transfer.py "codex resume 019fcc57-5522-7781-a797-6ef8c4b3dde5" # resume 命令整串
python3 codex_transfer.py 019fcc57-5522-7781-a797-6ef8c4b3dde5 # 纯 UUID
python3 codex_transfer.py 019fcc57 # UUID 前缀
python3 codex_transfer.py latest # 最近活跃会话(默认)
# 3. 输出在 output/handoff-<id8>-<时间戳>.md,把它交给接手 Agent 即可在 Claude Code 中接续任务:
读一下 <本仓库路径>/output/handoff-019fcc57-xxx.md,
这是 Codex 会话的迁移交接文档,请从「当前状态与继续指示」处继续完成任务。
把如下结构的目录放到 ~/.claude/skills/codex-transfer/,即可用自然语言("迁移 codex 会话")触发:
~/.claude/skills/codex-transfer/SKILL.md # 描述触发词与调用方式,指向本仓库的 codex_transfer.py
| 参数 | 说明 |
|---|---|
target |
会话标识:resume 命令整串 / UUID / UUID 前缀 / JSONL 路径 / latest(默认 latest) |
-o, --output |
输出文件路径(默认 output/handoff-<id8>-<时间戳>.<ext>) |
--level |
summary(用户+最终回答,最小体积)/ normal(+过程与工具摘要,默认)/ full(不截断) |
--format |
md(交接文档,默认)/ json(结构化数据,供程序二次处理) |
--max-output-chars |
单个工具输出截断长度(默认 800;full 级别忽略) |
--list [N] |
列出最近 N 个会话(默认 15)后退出 |
--stdout |
不写文件,直接打印到标准输出(可管道) |
输入(resume 命令串 / id / latest)
│
▼
┌─ 定位层 ─────────────────────────────────────────┐
│ 1. state_5.sqlite threads 表(codex resume 权威索引)│
│ 2. glob ~/.codex/sessions/**/rollout-*<id>*.jsonl │
│ 3. archived_sessions/(归档会话) │
└────────────────────────────────────────────────┘
│
▼
┌─ 解析层 ─────────────────────────────────────────┐
│ 按 turn_id 聚合 6 类记录: │
│ · event_msg:用户/Agent 消息、task 起止、patch 结果 │
│ · response_item:工具调用对(call_id 配对)、命令提取 │
│ · compacted:压缩摘要(前期工作的浓缩,交接高亮) │
│ · session_meta / turn_context:元信息 │
│ 版本适配:≥0.15x 会话无 event_msg 消息时, │
│ 从 response_item/message 提取(过滤系统注入) │
└────────────────────────────────────────────────┘
│
▼
┌─ 渲染层 ─────────────────────────────────────────┐
│ Markdown 交接文档:元信息 → 压缩摘要 → 对话记录 │
│ → 文件修改汇总 → 当前状态与给接手 Agent 的继续指示 │
└────────────────────────────────────────────────┘
结构依据(对真实会话文件的逐行调研报告,见 docs/):
docs/01-meta-and-envelope.md— 顶层结构、session_meta/turn_context/world_state/compacted、 session id ↔ 文件路径映射规则(sqlite 权威索引 + UUID v7 可推导)docs/02-event-msg.md— event_msg 的 8 种 subtype 字段与示例docs/03-response-item.md— response_item 的 6 种 payload 结构、工具调用形态
reasoning(思维链)在 Codex 中加密存储(Fernet),无法还原明文,交接文档不含推理过程;input_image(用户粘贴的图片,base64)不迁移,只在原文位置保留文本;- 工具输出默认截断(
--max-output-chars),完整输出请用--level full; - 新格式(≥0.15x)会话的「文件修改汇总」可能为空:新版不再写
patch_apply_end事件, 写文件多走 shell 命令(Set-Content等),当前未从命令文本反解目标文件; - 同机多账户/多 provider 的会话混存于同一
state_5.sqlite,--list不区分来源; - Codex 未来若升级 sqlite 索引(如
state_6)或更改 rollout 文件名规则,定位层需要跟进调整。
MIT