Codex CLI 的会话历史:在哪里、怎么读、怎么搜
每个会话都在磁盘上;Codex 只是把它们列出来,并不搜索
Codex 记下你跑的每一个会话。它缺的是:没法问你哪一次会话里有过那个修复,也没法在 resume 选择器之外看它们。文件本身足够简单,jq 和 sqlite3 就能读出大半;可跑上一周,有一个细节会让最顺手的 grep 失灵。
Codex 把它放在哪里
一切都在 ${CODEX_HOME:-~/.codex} 之下:
sessions/YYYY/MM/DD/rollout-<time>-<id>.jsonl:一个会话一个文件,整段对话随运行不断追加。第一行是session_meta,里面是会话 id 和工作目录。- 七天之后,Codex 会在后台把 rollout 压缩成
rollout-….jsonl.zst。两种形式 Codex 都读。而凡是在找*.jsonl的东西,从此再也看不到一周之前的会话。 archived_sessions/:你归档过的会话,格式相同。history.jsonl:只有你敲过的提示词,一行一条,带着会话 id。没有回复,也没有命令。state_5.sqlite:resume 选择器读取的会话列表,含标题、工作目录、git 分支、token 数和归档标记。名字里的数字会跟着 Codex 的版本走。
Codex 自带的东西
codex resume # 选择器,列出在这个目录里开过的会话 codex resume --all # 所有目录 codex resume --last # 直接进入最近的一个 codex resume --include-non-interactive # 连 codex exec 跑的也算 codex fork # 复制一个旧会话继续 codex archive <id> # 藏起来;codex unarchive 可以恢复 codex delete <id> # 永久删除
选择器显示标题和第一条消息,不往对话里面看,也只认 Codex。某个会话在它里面不见了,或者 resume 报出 no rollout found,见Codex resume。
不用任何工具去读
最近几次会话,以及它们是在哪里跑的:
for f in $(ls -t ~/.codex/sessions/*/*/*/rollout-*.jsonl | head -10); do jq -r 'select(.type=="session_meta") | .payload | "\(.timestamp[:16]) \(.cwd) \(.id)"' "$f" done
同一份列表,改成只读地读选择器的数据库:
sqlite3 -readonly ~/.codex/state_5.sqlite " SELECT datetime(updated_at, 'unixepoch', 'localtime'), substr(title, 1, 50), cwd FROM threads WHERE archived = 0 ORDER BY updated_at DESC LIMIT 20;"
一次会话里你敲过什么,从提示词日志里读。它只记交互式会话,交给 codex exec 的提示词不在里面:
jq -r 'select(.session_id=="<id>") | .text' ~/.codex/history.jsonl
哪些会话提到过某个词,压缩过的那批也算:
grep -l "pgbouncer" ~/.codex/sessions/*/*/*/rollout-*.jsonl zstdgrep -l "pgbouncer" ~/.codex/sessions/*/*/*/rollout-*.jsonl.zst
这对一个你记得分毫不差的词管用。放到几个月的历史上就慢,没有排序,还会漏掉那次你换了种说法说起它的会话。
搜索它
deja-vu 会给这些文件建索引——压缩过的、归档过的都算在内——和这台机器上其他每个智能体的历史放在一起。它对它们只读不写。
deja index deja --harness codex "pgbouncer prepared statement" # 带排序,并附会话 id deja last 20 --harness codex # 最近的会话,不限目录 deja show <id> # 那段对话 deja resume <id> # 能在 Codex 里重新打开它的命令 deja resume <id> --app # 或者在 ChatGPT 应用里打开 deja view # 全部内容合成一个本地 HTML 页面
不带参数的 deja 打开的是同一个搜索,只是变成一屏边打字边更新的界面:a 把范围收窄到 Codex,↵ 在命中的地方读那次会话,r 在 Codex 里重新打开它。
去掉 --harness codex,同一个搜索就覆盖 Claude Code、Cursor、opencode 以及其余的——答案往往就落在它们那边。凭据在建索引时就被脱敏。deja 索引过的会话,在 codex delete 或一次清理之后仍然搜得到;只有 deja forget 会有意把它丢掉。
想让 Codex 在会话开始时自己去查,而不是由你手动搜索,见给 Codex CLI 加记忆。
在多台机器上
Codex 把历史留在本机,codex resume 也只列出这块磁盘上有的东西。deja 可以把自己的索引通过 SSH 在机器之间搬运,中间不需要任何服务:
deja sync ssh devbox # 把本机的会话推到那边 deja sync ssh devbox --both # 也把它的会话拉过来
送过去的东西,在那边用 deja 就能搜。它不会把会话加进那台机器的 resume 选择器。跨机器同步有更多细节。