| name | codex-chat-history |
|---|---|
| description | Backup, search, and inspect Codex CLI session rollout JSONL under $CODEX_HOME/sessions (date-partitioned tree). Use for mirroring rollouts to sync storage (e.g. iCloud), listing or bounding sessions by time, profiling large JSONL before reading, or extracting user-authored messages with jq or the bundled helper script. |
Codex stores each session as append-only rollout JSONL files. The on-disk layout is stable and predictable:
$CODEX_SESSIONS_ROOT/YYYY/MM/DD/rollout-YYYY-MM-DDThh-mm-ss-<uuid>.jsonl
Defaults (overridable; see Environment variables):
$CODEX_SESSIONS_ROOT— if unset, use$CODEX_HOME/sessions.$CODEX_HOME— if unset, use~/.codex.
So the usual path is ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl, which matches the structure Codex uses when CODEX_HOME is not set.
Archived sessions (after an archive action in product) may appear under:
$CODEX_HOME/archived_sessions/
with the same rollout-*.jsonl filename pattern.
Each JSON line is a rollout record: a top-level timestamp plus a type / payload pair (for example session_meta, event_msg, response_item, compacted, turn_context). User-typed prompts are generally type == "event_msg" with payload.type == "user_message" and payload.message.
This skill is not about Cursor IDE transcripts (~/.cursor/projects/.../agent-transcripts/...); for those, use cursor-chat-history (script cursor_chat_history.py).
- Backup / mirror rollouts to another directory or cloud-synced folder (gzip mirror preserves
YYYY/MM/DDand stores.jsonl.gz). - Search or recover what was said: extract user lines, then
rg/ filter by topic. - Inspect large files safely: histogram or line-slice before loading whole files into context.
- Bound by time: first/last
timestampper file, or filesystem mtime with--since.
All paths support ~ expansion. Use absolute paths when clarity matters.
| Variable | Purpose | If unset |
|---|---|---|
CODEX_HOME |
Codex data root (config.toml, state DB, sessions/, etc.) |
~/.codex |
CODEX_SESSIONS_ROOT |
Explicit directory containing the YYYY/MM/DD rollout tree |
$CODEX_HOME/sessions |
CODEX_SESSIONS_BACKUP_ROOT |
Default destination root for backup (gzip mirror) |
~/icloud/.codex/sessions |
CODEX_HISTORY_PATH |
Override path to history.jsonl for codex_prompt_history_search.py |
$CODEX_HOME/history.jsonl |
CLI overrides: subcommands accept --src; backup also accepts --dst or --dest for the backup root, which wins over env defaults for that run.
--archived (optional, default off): For backup, list, profile, and bounds, pass --archived to also include $CODEX_HOME/archived_sessions/ after finishing the same logic for --src. Archived rollouts use the same rollout-*.jsonl layout as active sessions. Does not apply to user-messages (single file).
| File | Role |
|---|---|
codex_chat_history.py |
PEP 723 uv run --script helper (requires-python = ">=3.13.0,<3.14", dependencies = []): backup, list, profile, bounds, user-messages; optional --archived on the first four to include $CODEX_HOME/archived_sessions/ after --src. |
codex_prompt_history_search.py |
Search history.jsonl only: **`--mode EXACT |
line_histogram.awk |
Optional: line-size histogram or extract specific line(s) from huge JSONL before parsing. |
chmod +x codex_chat_history.py codex_prompt_history_search.py
./codex_chat_history.py --help
./codex_prompt_history_search.py --helpExample profile with histogram (from repo or gist):
./codex_chat_history.py profile --awk ./line_histogram.awk --since 1dExample backup (default destination = $CODEX_SESSIONS_BACKUP_ROOT or ~/icloud/.codex/sessions):
./codex_chat_history.py backup --dry-run
./codex_chat_history.py backup --dest "$HOME/icloud/.codex/sessions"
./codex_chat_history.py list --archivedResolve the sessions root once:
echo "${CODEX_SESSIONS_ROOT:-${CODEX_HOME:-$HOME/.codex}/sessions}"find "${CODEX_SESSIONS_ROOT:-$HOME/.codex/sessions}" -type f -name 'rollout-*.jsonl' | sort \
| while read -r f; do
echo "=== $f ==="
awk -f line_histogram.awk "$f"
done./codex_chat_history.py boundsWith jq:
jq -r 'select(.type == "event_msg" and .payload.type == "user_message") | .payload.message' \
"$ROLL_FILE"With the script (includes simple path redaction):
./codex_chat_history.py user-messages "$ROLL_FILE"Replace host-specific paths and usernames in anything you copy out (<PATH>, <USER> placeholders).
Rollouts may contain compaction-related content (compacted lines and/or event_msg variants such as context_compacted). Inspect with small slices:
grep -E 'context_compacted|"compacted"' "$ROLL_FILE" | head
jq -r 'select(.type == "compacted") | .payload.message' "$ROLL_FILE"$CODEX_HOME/history.jsonl is a separate, smaller prompt history log (not the full rollout). Rollouts under sessions/ are the complete session transcript for resume/replay tooling.
Each line is JSON: {"session_id":"<uuid>","ts":<unix_seconds>,"text":"<message>"} (ts is Unix seconds; treat calendar YYYY-MM-DD in the first output column as UTC derived from that instant).
chmod +x codex_prompt_history_search.py
./codex_prompt_history_search.py "your phrase"--mode EXACT(default): substring match of the full phrase intext.--mode ANY: phrase split on whitespace; match if any token appears as a substring intext.--mode FUZZY:difflib.SequenceMatcherquick_ratioagainst fulltext(plus substring shortcut); tune with--fuzzy-threshold(default0.65).-j/--json: one JSON object per match (date,ts,session_id,text).--file: override path (default$CODEX_HISTORY_PATHor$CODEX_HOME/history.jsonl).
Default (non-JSON) lines are CSV (four columns: UTC date, ts, session_id, text) suitable for log-style grepping.
Codex does not auto-expire rollout files by age; backups and pruning are operator concerns. See Codex release notes / issue trackers for current behavior of history.jsonl trimming vs rollouts.
- Repository: https://github.com/simbo1905/codex-chat-history
- Public gist (mirrors this folder’s files): https://gist.github.com/simbo1905/34f66e28462c02a2e64ecdf9389fbe51
For smoke tests, optional git tag, and gist sync commands, see the Release checklist in the repo root README.md.
Skill text and tooling © 2026 LiveMore Capital https://www.livemorecapital.com (where not otherwise noted).