codex-recall
Local search and recall for Codex session JSONL archives.
codex-recall builds a disposable SQLite FTS5 index over transcript archives so you can search, inspect, and reuse prior session context without treating raw JSONL logs as a database.
Raw JSONL files remain the source of truth.
Install
Or install directly from GitHub:
Build from source:
Quick Start
Index your local Codex archives, then query them:
If your transcripts live outside ~/.codex, point the tool at them explicitly:
CODEX_HOME=/path/to/codex-home
Example Output
Search returns grouped receipts with exact source lines:
$ codex-recall search "signing secret" --db /tmp/codex-recall-demo/index.sqlite
1. demo-session:84a7836c808a80c6 demo-session /Users/me/projects/acme-api
- assistant_message /tmp/codex-recall-demo/sessions/2026/04/13/demo.jsonl:3
The production signing secret was stale after the provider rotation.
Recent is useful when you know the repo or time window but not the query:
$ codex-recall recent --repo acme-api --since 30d --db /tmp/codex-recall-demo/index.sqlite
1. demo-session:84a7836c808a80c6 demo-session acme-api
when: 2026-04-13T01:00:00Z
cwd: /Users/me/projects/acme-api
source: /tmp/codex-recall-demo/sessions/2026/04/13/demo.jsonl
show: codex-recall show 'demo-session:84a7836c808a80c6' --limit 120
Doctor gives a fast health check for the index:
Support Scope
- Works anywhere you have Codex-style session JSONL archives on disk.
- Defaults to
~/.codex/sessionsand~/.codex/archived_sessions. - Honors
CODEX_HOMEwhen Codex data lives somewhere else. - Stores index and pin data under XDG-style data/state paths when available, otherwise falls back to
~/.local/shareand~/.local/state. watch --install-launch-agentis macOS-only because it writes and manages a LaunchAgent plist.
Privacy and Safety
- Transcript files stay local.
codex-recallreads JSONL archives from disk and builds a local SQLite index. - The SQLite index is disposable. You can delete it and rebuild from the raw transcript files.
- Pins are stored locally as JSON outside the SQLite index so they survive rebuilds.
- Secret redaction is best-effort. It catches common token patterns before indexing, but it is not a hard security boundary.
- If your transcripts contain data that should never be indexed, keep those files out of the configured source roots.
Default Paths
Source roots:
$CODEX_HOME/sessions$CODEX_HOME/archived_sessions- or, when
CODEX_HOMEis unset:~/.codex/sessions~/.codex/archived_sessions
Index and state files:
$CODEX_RECALL_DBoverrides the SQLite path$CODEX_RECALL_STATEoverrides the watch state path$CODEX_RECALL_PINSoverrides the pins path- otherwise:
$XDG_DATA_HOME/codex-recall/index.sqlite$XDG_DATA_HOME/codex-recall/pins.json$XDG_STATE_HOME/codex-recall/watch.json
- with fallback to:
~/.local/share/codex-recall/index.sqlite~/.local/share/codex-recall/pins.json~/.local/state/codex-recall/watch.json
Commands
Useful flags:
Behavior
- Streams JSONL files and indexes high-signal user, assistant, and command events.
- Redacts common secret shapes before writing searchable text to SQLite.
- Skips Codex instruction preambles such as
AGENTS.mdand environment context blocks. - Deduplicates exact duplicate transcript events.
- Keeps exact source provenance as
path:line. - Stores a stable
session_keyderived fromsession_id + source_file_path. - Deduplicates active/archive copies by
session_idinsearch,recent, andbundleby default, preferring activesessionsfiles overarchived_sessionsfiles. Use--include-duplicatesto inspect every indexed source copy. - Uses SQLite FTS5 with safe query normalization, so punctuation-heavy queries like
source-mapwork. - Falls back to matching any query term when no single event contains every term.
- Supports search filters by repo slug, cwd substring, session start date, event kind, and explicit excluded sessions. Repo matching uses both the session cwd and command cwd values seen inside the session.
- Accepts absolute
--sincedates plus relative values like7d,30d,today, andyesterday. - Accepts
--fromas an explicit lower bound and--untilas an exclusive upper bound. Use--from 2026-04-13 --until 2026-04-14for the local calendar day of April 13. - Accepts
--day YYYY-MM-DDas shorthand for--from YYYY-MM-DD --until <next-day>. - Rejects
--sinceand--fromtogether because both are lower bounds. - Rejects
--daywhen combined with--since,--from, or--until. - Accepts repeatable
--kind user,--kind assistant, and--kind commandfilters. - Accepts
--exclude-currentwhenCODEX_SESSION_IDorCODEX_THREAD_IDis set. - Interprets
todayandyesterdayusing the local day boundary, then compares against UTC transcript timestamps. - Boosts results from the current git repo by default. Use
--repoto filter to a repo, or--all-reposto disable the current-repo boost. - Tracks file size and mtime so repeat indexing skips unchanged sessions.
- Reports indexing progress to stderr with discovered file totals, bytes processed, elapsed time, ETA, current file, and skipped-file reason counts.
- Watches session roots with a polling freshness loop, waits for files to be quiet before indexing, and records watcher state in the configured state path.
- Reports a blunt freshness verdict:
fresh,stale,pending-live-writes, orwatcher-not-running. - Reports freshness status with pending file counts, stable/waiting file counts, last indexed time, last watcher error, and LaunchAgent installed/running state.
- Can write a macOS LaunchAgent plist for the watcher with
watch --install-launch-agent. - Can bootstrap and verify that LaunchAgent immediately with
watch --install-launch-agent --start-launch-agent. - Groups text search output by session, with the best receipts under each session.
- Lists recent sessions without a query when you know the timeframe or repo but not the exact words to search.
- Prints machine-readable
recent --json,show --json, andday --jsonoutput for automation. - Prints a day inventory with
day YYYY-MM-DD --json, including session records plus repo and cwd counts. - Formats search results into an agent-ready context bundle with top sessions, receipts, and follow-up
showcommands. - Stores durable labeled pins outside the disposable SQLite index.
- Ranks sessions by current-repo match, hit count, event kind, FTS rank, and recency.
- Reports source-file counts and duplicate source-file counts in
stats. - Keeps
--jsonoutput compact by returningtext_previewinstead of full transcript blobs. - Separates progress and diagnostics onto stderr so
--jsonoutput stays pipe-safe. - Opens read-only commands without running schema migrations, so
search,recent,bundle,show,doctor, andstatsdo not create missing databases or take writer locks. - Uses SQLite WAL mode, a 30-second busy timeout, and normal synchronous writes for better behavior when the watcher and read commands overlap.
Maintenance
Use doctor when the index feels stale or suspicious:
doctor is read-only when the database is missing. It reports the missing index instead of creating an empty one.
Use rebuild when the disposable SQLite index should be recreated from the raw JSONL source files:
Use watch when the index should stay fresh while Codex writes new transcripts:
On macOS, watch --install-launch-agent writes a plist to ~/Library/LaunchAgents/dev.codex-recall.watch.plist by default and prints the launchctl bootstrap command to start it.
Use bundle when an agent needs compact prior-session context:
Use recent when you do not know the right query yet:
Use pin after finding a high-value session that should be easy to return to:
Agent Workflow
When an agent needs prior-session context:
- Run
codex-recall status --json. - If
freshnessisfreshorpending-live-writes, continue.pending-live-writesmeans very recent files are still settling, so use existing results unless the current turn depends on the last few seconds. - If
freshnessisstale, runcodex-recall watch --once --quiet-for 0orcodex-recall index, then checkstatus --jsonagain. - If
freshnessiswatcher-not-running, start the background watcher withcodex-recall watch --install-launch-agent --start-launch-agent, then runcodex-recall watch --once --quiet-for 0for an immediate catch-up. - Use
codex-recall recent --repo <repo> --since 7d --limit 10when you do not know the right search terms yet. - For calendar-day review, prefer
codex-recall day YYYY-MM-DD --jsonor--day YYYY-MM-DDonrecent,search, andbundle. - Use
codex-recall bundle "<query>" --repo <repo> --day YYYY-MM-DD --limit 5for compact context. - Use
codex-recall search "<query>" --json --day YYYY-MM-DD --exclude-currentwhen programmatic filtering is needed during an automation. - Use
--kind user,--kind assistant, or--kind commandto narrow noisy searches. - Add
--exclude-session <session-id-or-session-key>when the current automation or session id is known and--exclude-currentis unavailable. - Keep the default deduped view unless the question is specifically about active/archive divergence. Use
--include-duplicatesonly for that inspection. - Use
codex-recall show <session_key> --jsononly for sessions that look relevant frombundle,search,day, orrecent. - Use
codex-recall pin <session_key> --label "<why this matters>"for canonical decisions or sessions that are likely to be reused. - Use
codex-recall pins --jsonwhen scripts or agents need stable pin data. - Use
codex-recall unpin <session_key>when a memory anchor is stale or mistaken. - Treat transcript evidence as historical. Verify against the current repo before acting.
Verification Notes
In development, a full rebuild across a four-digit session-file archive completed in tens of minutes, and repeat indexing runs were much faster because unchanged files were skipped.
Release Process
- CI runs
cargo fmt --check,cargo clippy --all-targets -- -D warnings, andcargo teston every push tomainand on pull requests. - Release notes live in CHANGELOG.md.
Project Status
This is maintained as a personal tool that happens to be public. Bug reports are useful. I am not actively reviewing outside pull requests.