线程管理
别让对话失控 —— fork、resume、compact 让每个任务各得其所
6 个核心命令 · 会话生命周期 · SDK 集成一个线程走到底?
那些让你后悔"没早点分叉"的瞬间
它把上下文搞乱了
一个线程里既改了认证模块,又重构了数据库层。现在 Codex 满脑子都是数据库的上下文,认证修改的细节已经模糊了。上下文污染。
你不敢试危险方案
你想让 Codex 尝试一个激进的方案,但怕搞砸现有的进度。只能小心翼翼,或者手动备份整个目录。没有安全网。
对话越来越长,越来越笨
线程已经 50+ 轮对话了。每次请求都要重读全部历史,token 消耗爆炸,响应变慢,Codex 开始"忘记"早期的决策。上下文膨胀。
线程是什么?
一次对话 = 一个线程
线程(Thread)是 Codex 中一次独立对话的完整上下文。它包含了所有的消息、工具调用结果、文件变更历史。
物理存储
每个线程对应 ~/.codex/sessions/ 下的一个 JSONL 文件(按 YYYY/MM/DD/ 分目录),记录了完整的消息序列。
逻辑边界
每个线程有独立的上下文窗口。一个线程的对话不会影响另一个线程。fork 创建的新线程从当前状态分叉,之后各自独立演化。
# 会话文件存储结构
~/.codex/sessions/
├── 2026/
│ └── 07/
│ └── 04/
│ ├── session-abc123.jsonl # 每个文件 = 一个线程
│ ├── session-def456.jsonl
│ └── session-ghi789.jsonl
关键术语
Thread · Turn · Rollout
Thread(线程)
一次完整对话。有唯一 thread_id(全局唯一、创建后不可变),包含所有历史消息。每个线程对应一个 JSONL 文件。
Turn(轮次)
一次"用户提问 → Codex 回答"的交互。一个线程包含多个 turn。fork 操作发生在 turn 之间——从某个 turn 的结束点分叉。
Rollout(执行轨迹)
Codex 内部记录的完整执行轨迹,包含工具调用、中间状态。rollout 是 fork/resume 操作的数据基础——app-server 通过 rollout 记录来恢复或复制线程状态。
6 个命令掌控线程
TUI 内斜杠命令一览
| 命令 | 做什么 | 何时用 |
|---|---|---|
/new | 开始新线程 | 切换到完全不同的任务 |
/fork | 从当前轮次分叉 | 想尝试新方案但保留现状 |
/resume | 恢复已保存的线程 | 继续之前中断的工作 |
/compact | 压缩当前对话 | 上下文太长、响应变慢 |
/archive | 归档并退出 | 任务完成,归档保存 |
/delete | 永久删除并退出 | 废弃的实验线程 |
/rename 可重命名当前线程,便于在 /resume 选择器中识别。/clear 清空终端并新建对话(比 /new 更彻底,会重置终端视图)。/archive 和 /delete 执行后会退出 Codex。/delete 不可撤销。命令 vs SDK
两种使用方式
交互式(TUI 斜杠命令)
在 Codex TUI 中输入 /fork、/resume 等。适合人在回路的开发流程。
> /fork
> /resume
> /compact
CLI 子命令(终端)
在终端直接运行,不进入 TUI。适合脚本和自动化。
$ codex fork # 打开会话选择器后 fork
$ codex resume --last # 恢复最近的会话
$ codex archive <id> # 按 ID 归档
$ codex unarchive <id> # 恢复归档
SDK(Python)
通过 codex-sdk-py 的 thread_start() / thread.run() / thread_resume() 管理会话。fork / archive 等操作需通过 CLI 子进程调用。
from codex_sdk import Codex
codex = Codex()
thread = codex.thread_start()
/fork:分叉实验
保留现状,探索可能
/fork 把当前线程完整复制到一个新线程。原线程不受影响,你在新线程里可以大胆尝试。
# 在 TUI 中
> /fork
✅ 已创建分叉 thread-xyz789
原线程 thread-abc123 不受影响
# 或在终端
$ codex fork # 打开会话选择器
何时 fork?
- 方案选型:A 方案 vs B 方案,fork 后分别尝试
- 危险操作前:fork 一个安全副本再动手
- 并行任务:同一上下文分出多条线索
关键特性
- fork 后的新线程有独立的 ID
- 之后两线程各自独立,互不影响
- fork 发生在当前 turn 的结束点
- 原线程的 rollout 记录是 fork 的基础
/resume:恢复线程
从中断处继续
/resume 打开会话选择器,从历史线程中选一个恢复。原历史完整保留。
# 在 TUI 中
> /resume
# 弹出会话选择器:
┌─────────────────────────────────────┐
│ fix-auth-bug 2026-07-04 14:30 │
│ refactor-db 2026-07-04 11:15 │
│ add-tests 2026-07-03 18:45 │
└─────────────────────────────────────┘
# 或在终端直接恢复最近的会话
$ codex resume --last
resume vs fork 的区别
- resume:继续已有线程,原历史不变
- fork:基于当前线程创建新线程
- resume 后继续追加 turn 到同一个线程
SessionStart hook
当通过 resume 恢复线程时,SessionStart hook 会触发,source 值为 "resume"。你可以用它加载上下文笔记。
/compact:压缩对话
释放上下文空间
/compact 将当前对话历史摘要化,用一份精炼总结替代冗长的早期消息,释放 token 预算。
# 对话变长后
> /compact
# Codex 会确认后执行摘要
compact 做了什么
- 摘要替代早期消息(非删除,是压缩)
- 保留关键决策和文件变更信息
- 释放上下文窗口空间
- 触发 PreCompact / PostCompact hooks
何时 compact?
- 对话超过 30+ 轮
- 响应明显变慢
- token 用量告警
- 早期细节已不重要
/copy 或手动记录。/archive & /delete:归档与删除
完成后清理
/archive — 归档
归档当前线程并退出 Codex。归档后的线程变为只读、受保护状态,不会被 /resume 误选。
> /archive
# 归档后退出 Codex
# 恢复归档的会话
$ codex unarchive <id>
/delete — 永久删除
永久删除当前线程并退出 Codex。JSONL 文件被移除,不可恢复。
> /delete
⚠️ 此操作不可撤销!
# 确认后删除并退出
/archive(可恢复),废弃的实验用 /delete(彻底清理)。两者都会退出 CLI。实战:fork 的工作流
同一上下文,探索两种方案
# 1. 当前线程:讨论认证模块重构
> 我想把 JWT 验证从中间件抽到独立服务
# 2. Codex 给出方案 A(拦截器模式)
> 好的,先记下这个方案
# 3. fork 一个分支探索方案 B
> /fork
✅ 已创建分叉 thread-def456
# 4. 在分叉中探索方案 B(代理模式)
> 如果用代理模式呢?
# 5. 对比两个线程的结果
# thread-abc123: 方案 A 的完整讨论
# thread-def456: 方案 B 的完整讨论
# 互不干扰,可随时 /resume 切换
实战:resume 的工作流
中断后无缝恢复
# 昨天的工作中断了
$ codex resume --last
# 或通过 TUI 选择器
> /resume
选择 "fix-auth-bug" 线程
# Codex 加载完整历史
# 你可以接着说:
> 继续昨天的,我们改到 password-validator.ts 的第 42 行
resume 恢复了什么
- 完整的消息历史
- 所有文件变更的上下文
- Codex 对项目的理解
- 之前的决策和理由
最佳实践
- 有意义的线程名:用
/rename起一个描述性名字 - 一个线程一个任务:便于快速定位
- 中断前 compact:如果对话很长
实战:compact 的工作流
长对话瘦身
# 线程已经很长了
> /status
# 查看 token 使用情况
# 执行压缩
> /compact
# Codex 确认后摘要历史
# 压缩后
> /status
# token 使用量下降,响应恢复流畅
/fork 保留完整副本。compact vs new
/compact:保留摘要,延续当前任务/new:清空上下文,切换新任务- 同一任务对话太长 → compact
- 换一个完全不同的任务 → new
用 SDK 管理线程
Python 自动化集成
通过 codex-sdk-py(或 codex-app-server SDK),你可以在 Python 脚本中启动和管理 Codex 线程。
from codex_sdk import Codex
codex = Codex()
# 启动新线程
thread = codex.thread_start()
# 发送 prompt 并获得响应
turn = thread.run("帮我检查 auth.ts 的安全问题")
# 打印结果
print(turn.messages)
# 之后可以用 thread_id 恢复
thread_id = thread.thread_id
# ... 存储 thread_id 供后续使用
恢复已有线程
# 用之前保存的 thread_id 恢复
thread = codex.thread_resume(thread_id)
turn = thread.run("继续修复刚才的问题")
fork / archive(CLI 子进程)
SDK 不直接支持 fork/archive/compact。需要通过 subprocess 调用 CLI:
import subprocess
# fork 最近会话
subprocess.run(["codex", "fork"])
# 归档指定会话
subprocess.run(["codex", "archive", thread_id])
SDK 生命周期示例
完整的线程管理工作流
from codex_sdk import Codex
import subprocess, json
codex = Codex()
# === 1. 启动线程做代码审查 ===
thread = codex.thread_start()
turn = thread.run("审查 src/ 目录的安全性,只读不改")
print(turn.messages)
thread_id = thread.thread_id
# === 2. fork 一个分支尝试修复(通过 CLI) ===
result = subprocess.run(
["codex", "fork"],
capture_output=True, text=True
)
# fork 创建新线程,原审查线程不变
# === 3. 恢复原线程继续讨论 ===
thread = codex.thread_resume(thread_id)
turn = thread.run("详细解释第 3 个安全问题")
# === 4. 任务完成后归档(通过 CLI) ===
subprocess.run(["codex", "archive", thread_id])
thread_start() / thread.run() / thread_resume() 是核心 API。fork / archive / compact / delete 等操作需要通过 CLI 子进程调用——SDK 层暂未封装这些命令。会话文件结构
JSONL 中的线程数据
每个线程以 JSONL 文件存储在 ~/.codex/sessions/YYYY/MM/DD/ 下。每行是一条 JSON 消息。
{"type":"message","role":"user","content":"帮我重构 auth.ts"}
{"type":"message","role":"assistant","content":"好的,我来分析..."}
{"type":"tool_call","name":"read_file","input":{"path":"src/auth.ts"}}
{"type":"tool_result","output":"export function validateToken..."}
{"type":"message","role":"assistant","content":"我发现三个问题..."}
直接读取会话文件
JSONL 是纯文本,可以用任何工具读取:
# 读取会话历史
import json
with open(session_path) as f:
for line in f:
msg = json.loads(line)
print(msg["type"], msg.get("role",""))
会话浏览方式
codex resume:TUI 选择器- 直接读取 JSONL 文件
- 第三方工具解析 JSONL
与 Hooks 集成
在线程事件上触发自动化
SessionStart
当线程启动或通过 /resume 恢复时触发。source 字段区分 "startup"(新启动)和 "resume"(恢复)。
[[hooks.SessionStart]]
matcher = "startup|resume"
PreCompact / PostCompact
当执行 /compact 时触发。PreCompact 在压缩前(可注入提醒),PostCompact 在压缩后(可记录日志)。
/archive 和 /delete 操作不触发 Hook。如果需要在归档时执行操作,用 SDK + CLI subprocess 包装。实战:自动会话归档
用 Python 脚本管理线程
#!/usr/bin/env python3
"""自动归档 7 天前的会话"""
import subprocess, json, os
from pathlib import Path
from datetime import datetime, timedelta
sessions_dir = Path.home() / ".codex" / "sessions"
cutoff = datetime.now() - timedelta(days=7)
# 遍历会话目录
for session_file in sessions_dir.rglob("*.jsonl"):
mtime = datetime.fromtimestamp(session_file.stat().st_mtime)
if mtime < cutoff:
session_id = session_file.stem.replace("session-", "")
print(f"归档: {session_file.name} (最后修改: {mtime})")
# 调用 CLI 归档
subprocess.run(["codex", "archive", session_id])
codex archive 后可用 codex unarchive 恢复,但 /delete 不可撤销。常见错误 1:fork 时机
不是所有时候都该 fork
该 fork 的时候
- Codex 给出了方案,你想试另一种
- 即将执行有风险的操作
- 想并行探索多条路径
不该 fork 的时候
- 任务才刚开始(直接
/new) - 只是想撤回最后一步(用 rollback)
- 对话太长(先
/compact)
常见错误 2:过度 compact
压缩不是免费的
# ❌ 错误:每次对话都 compact
> 问一个问题
> /compact # 没必要!
> 再问一个问题
> /compact # 还是不必要!
# ✅ 正确:只在需要时 compact
> /status # 先看 token 用量
# 如果还有充足空间,不需要 compact
# 接近上限时才执行
过度 compact 的后果
- 关键细节被摘要掉
- Codex"忘记"早期决策的上下文
- 每次 compact 自身也消耗 token
常见错误 3:线程爆炸
创建太多不清理
# 查看 sessions 目录
$ ls ~/.codex/sessions/2026/07/*/
session-aaa111.jsonl # 不知道是啥
session-bbb222.jsonl # 好像是昨天的实验
session-ccc333.jsonl # 已经没用了
session-ddd444.jsonl # 又一个忘了的
...
解决方案
- 及时归档:完成的任务立刻
/archive - 起好名字:用
/rename标记任务名 - 定期清理:废弃实验用
/delete - 脚本归档:用自动化脚本定期归档旧会话
命令速查表
完整参考
| 命令 | TUI 斜杠 | CLI 等价 | SDK |
|---|---|---|---|
| 新建线程 | /new | codex(直接启动) | thread_start() |
| 分叉线程 | /fork | codex fork | —(CLI subprocess) |
| 恢复线程 | /resume | codex resume | thread_resume() |
| 压缩对话 | /compact | — | —(CLI subprocess) |
| 归档线程 | /archive | codex archive <id> | —(CLI subprocess) |
| 删除线程 | /delete | — | — |
| 重命名线程 | /rename | — | — |
| 查看状态 | /status | codex status | — |
thread_start / thread.run / thread_resume。fork / archive / compact / delete 等需通过 subprocess 调用 CLI。线程管理最佳实践
核心原则
1. 一个线程一个任务
不要在一个线程里混合多个无关任务。任务切换时用 /new 或 /resume,保持上下文干净。
2. 关键决策前 fork
如果即将做出可能影响方向的决定,先 /fork 保留安全副本。
3. 对话太长就 compact
监控 /status 的 token 用量,接近上限时执行 /compact。但记住它是有损压缩。
4. 完成后归档
任务完成后及时 /archive,保持会话列表干净。废弃实验用 /delete。
5. 起有意义的名字
用 /rename 给线程起描述性名字(如 fix-auth-bug),方便 /resume 时快速识别。
6. compact 前保存关键信息
如果有特别重要的上下文(具体行号、关键约束),compact 前先用 /copy 或手动记录。
总结
掌控你的对话
今天学到了什么
- 6 个核心命令:
/new·/fork·/resume·/compact·/archive·/delete - 辅助命令:
/rename·/status - 线程以 JSONL 文件存储在
~/.codex/sessions/ - SDK 支持
thread_start/thread.run/thread_resume - fork/archive 等通过 CLI subprocess 实现
- Hooks:SessionStart(resume 时触发)+ PreCompact/PostCompact
核心心智模型
- fork = 复制:保留现状,探索分支
- resume = 恢复:继续中断的工作
- compact = 压缩:有损释放空间
- archive = 归档:可恢复地清理
- delete = 删除:不可撤销地清理