Search your local coding conversation history from the command line.
Claude Code and Codex record conversations as .jsonl transcripts. agsearch
searches both Stores by default, so you do not need to remember which Harness
you used.
$ agsearch "borrow checker"
claude · d712581e · E:\projects\rust\demo · Lifetimes and the borrow checker · 2026-06-02 · main
[14] user: how do I satisfy the borrow checker here without cloning
[16] assistant: …the borrow checker is complaining because the reference outlives…
… +3 more › agsearch show d712581e
$ agsearch show d712581e # reopen the whole conversation
$ agsearch current # inspect the Session that invoked this commandThe transcripts use Harness-specific layouts and JSON formats. agsearch
turns them into six jobs:
- find a conversation with
agsearch <query> - read a conversation with
agsearch show <id> - inspect the Current Session with
agsearch current - preserve a conversation with
agsearch export <id> <file> - analyse what went wrong with
agsearch --failedor--stats - measure token Usage with
agsearch usageoragsearch usage <id>
Status: early.
agsearchis at 0.x. Verbs and flags can still change between minor versions. Open an issue if something breaks for you.
Prebuilt binaries for Linux, macOS, and Windows are attached to each
GitHub Release.
The installers put the agsearch binary onto your PATH:
# Linux / macOS
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/Hazzajenko/agent-conversation-search/releases/latest/download/agsearch-installer.sh | sh# Windows
powershell -ExecutionPolicy Bypass -c "irm https://github.com/Hazzajenko/agent-conversation-search/releases/latest/download/agsearch-installer.ps1 | iex"With a Rust toolchain:
cargo install agsearch # from crates.io
# or, from a clone of this repo
cargo install --path .agsearch reads $CLAUDE_CONFIG_DIR or ~/.claude for Claude Code and
$CODEX_HOME or ~/.codex for Codex. For OpenCode it reads opencode.db in
$XDG_DATA_HOME/opencode or ~/.local/share/opencode, on every platform. Use
--claude-dir <PATH>, --codex-dir <PATH>, or --opencode-dir <PATH> to
override a Store. A missing Store is skipped. Search, show, sessions,
projects, --failed, and --stats cover OpenCode Sessions. An OpenCode
Failure is a tool call with status error. A shell command that exits non-zero
but completes is not a Failure. For an OpenCode Session, -l prints
<path to opencode.db>#<session id>, and show - accepts that form.
Windows and WSL keep separate histories. Run agsearch in the environment that
has the Sessions, or point the Store flags at the other environment.
Every verb is welded together by one identifier: the short session-id. It is a
git-style unique prefix. It is the shortest prefix of the session-id that no
other Session in any Store shares, with at least 8 characters. search and --failed
print it, and show resolves it.
That is the whole loop. Find something, copy its id, open it:
$ agsearch "diesel migration" # find, then note the id in each header
$ agsearch show 4c28878f # read the full transcript
$ agsearch show 4c28878f --around 220 # read just the turns around turn 220You can also pipe by path instead of copying ids:
$ agsearch -l "diesel migration" | agsearch show - # open the first matchagsearch <query> searches the current directory's Project for a
case-insensitive substring, grouped by Session, newest first. It is the default
verb, so the word search is optional (agsearch foo ≡ agsearch search foo).
| Flag | Effect |
|---|---|
-e, --regex |
treat the query as a regular expression |
-s, --case-sensitive |
match case-sensitively |
--thinking |
also search assistant thinking blocks |
--tools |
also search tool calls and tool results |
--all-content |
search everything (--thinking --tools) |
-m, --max-per-session <N> |
cap matches shown per Session (0 = unlimited, default 3) |
-l, --files |
print only matching file paths, for piping |
--file <SELECTOR> |
list file Touches by File Selector. With a Query, search text only inside Sessions touching the file |
--written |
with --file, show only write Touches (Edit, Write, MultiEdit, NotebookEdit, Codex apply_patch, OpenCode edit, write, and patch) |
--harness <claude|codex|opencode> |
search only one Harness |
--include-subagents |
include Codex subagent Sessions and OpenCode child sessions and mark them in output |
--include-current |
include the Current Session Family (excluded by default) |
By default only Prompts, Replies, and Titles are searched. Thinking and tool content are opt-in.
Search covers historical conversations. When a Harness identifies the Current Session, search excludes its Current Session Family. This prevents a search from matching the Prompt that started the search.
Pass --include-current to include the family. Pass --session current to
search the top-level Current Session directly, or --session current-thread
to search the calling thread. At the top level that is the same Session. From a
spawned worker it is the worker's own thread. A Session id selects that
Session even when it belongs to the family.
The exclusion also covers --failed and --stats. When
--include-subagents is active, it hides every worker in the family. Outside a
supported Harness, no Current Session is available and search excludes
nothing.
When identity resolves only partly, search hides every family it can identify. If both Harnesses identify a Session, search excludes both families. If a family ancestor is missing from the Store, search still excludes the calling thread and its workers.
agsearch show <id> renders a Session as a readable transcript. Tool calls
collapse to one-liners, failed tool calls are flagged, and thinking is hidden.
| Flag | Effect |
|---|---|
--thinking |
expand assistant thinking blocks |
--around <turn> |
show only the turns around this turn, such as a search hit |
--context <N> |
turns of context on either side of --around (default 3) |
<id> is a git-style prefix resolved across your whole history. current
renders the top-level Current Session and current-thread renders the calling
thread, which is the same Session at the top level. - reads a file path from stdin.
agsearch current prints the Current Session identified by the Harness that
launched the command: Harness, full Session ID, Project, title, source path,
and whether the caller is a worker. It does not guess from the newest
conversation.
| Flag | Effect |
|---|---|
--id-only |
print only the full top-level Session ID |
--path |
print only the source Session path |
Claude identity comes from $CLAUDE_CODE_SESSION_ID. Codex identity comes from
$CODEX_SESSION_ID for the top-level Session and $CODEX_THREAD_ID for the
calling thread. At the top level those two identify the same Session. A
spawned worker still resolves current to the top-level Session.
If no supported Harness identity is available, the command fails rather than
picking a Session. If the identity is not in the configured Stores, it fails.
If both Harnesses supply a valid identity, it reports the ambiguity until you
pass --harness claude or --harness codex.
$ agsearch current
Harness: claude
Session: 11111111-aaaa-bbbb-cccc-ddddeeee0001
Project: E:\projects\demo
Title: Lifetimes and the borrow checker
Path: C:\Users\you\.claude\projects\E--projects-demo\11111111-aaaa-bbbb-cccc-ddddeeee0001.jsonl
Caller: top-level
$ agsearch current --id-only
11111111-aaaa-bbbb-cccc-ddddeeee0001agsearch export <SESSION> <DEST> writes one point-in-time snapshot of one
Session to one destination. The Session accepts a unique id prefix, current
for the top-level Current Session, or current-thread for the calling thread.
current exports only the top-level Session, never a combined family document.
The destination is required. - writes the Export to standard output.
| Flag | Effect |
|---|---|
--format markdown|raw |
readable document by default, or an exact raw copy |
--force |
overwrite the destination when it already exists |
--thinking |
expand assistant thinking blocks in Markdown Export |
Readable Export (Markdown) is a portable document with provenance followed by
the Transcript. Provenance carries the title, full Session ID, Harness,
Project, source timestamp, export timestamp, and snapshot status, so the file
identifies its origin without agsearch. The Transcript body uses the same
renderer as show: Messages only, tool calls as compact one-liners, failed
tool results flagged, thinking hidden unless --thinking is passed.
Raw Export (--format raw) copies the Harness Session file exactly, with no
added metadata and no interactive confirmation beyond the explicit format
option. It is the way to preserve the source data.
Every Export is a snapshot. It captures the content available when the command runs and finishes without waiting for the Harness. A Markdown snapshot renders every complete Record and ignores an incomplete trailing JSONL record. The document identifies itself as a snapshot so nobody mistakes it for a final transcript. A raw snapshot contains the source bytes captured by the operation.
An existing destination file is rejected unless --force is passed, so an
earlier snapshot is never destroyed silently.
$ agsearch export 4c28878f transcript.md # readable snapshot
$ agsearch export current transcript.md # preserve the Current Session
$ agsearch export current-thread worker.md # preserve only the calling thread
$ agsearch export 4c28878f - | less # pipe through stdout
$ agsearch export 4c28878f raw.jsonl --format raw --forceagsearch sessions lists the Sessions in scope, newest first, one per line.
Use it when you want to reopen a recent conversation but don't remember anything to
search for. Each row is paste-able into show.
$ agsearch sessions
codex · de151981 · E:\projects\rust\demo · Test app runtime and functionality · 2026-06-02
claude · d712581e · E:\projects\rust\demo · Lifetimes and the borrow checker · 2026-06-02 · mainagsearch projects lists every Project across the whole Store, newest
first, with how many Sessions each holds and when it was last touched. The name
is the real path, recovered from the transcripts.
$ agsearch projects
E:\projects\rust\agent-conversation-search · 7 sessions · 2026-06-02
E:\projects\games\creature-game · 43 sessions · 2026-06-01agsearch usage ranks the Sessions in scope by total token Usage, biggest first. It counts tokens
only, not money. Use it to find which
conversations burned the most tokens. agsearch usage <id> shows one row
per model call inside that Session, in turn order for Claude Code or file
order for Codex token_count Records, with a total line.
$ agsearch usage
session project harness title subagents calls input cache-write cache-read output total
aaaaaaaa E:\projects\rust\demo claude Refactor auth middleware 0 2 215 1,200 165,000 10,600 177,015
bbbbbbbb E:\projects\rust\demo claude Debug flaky test 0 1 80 200 12,000 900 13,180
$ agsearch usage aaaaaaaa
turn timestamp model input cache-write cache-read output total subagent preview
2 2026-08-20T04:00:10.000Z claude-opus-4-6 120 800 45,000 2,100 48,020 Draft the middleware refactor plan
4 2026-08-20T04:00:20.000Z claude-opus-4-6 95 400 120,000 8,500 128,995 Apply the edit to auth.rs
total 215 1,200 165,000 10,600 177,015 2 calls| Flag | Effect |
|---|---|
--sort {total,output,input,calls} |
rank by this column, default total. On the breakdown only total is valid. It sorts biggest first, and the default is turn order for Claude Code and file order for Codex |
--limit <N> |
maximum Sessions in the ranking (default 20, ranking only) |
--all, --project <substr>, --harness <claude|codex>, --since <when> |
scope the ranking like sessions (current Project by default) |
--include-subagents |
list subagent threads as their own rows instead of folding them into the parent |
--include-current |
put the Current Session Family back into the ranking (excluded by default) |
Subagent threads fold into their parent row by default. The subagents
column shows how many were folded. The breakdown of a parent includes its
workers' calls marked in the subagent column, so its total matches the
ranking row. Sessions with no Usage are omitted with a skipped N sessions with no usage line. The selector accepts the same forms as show: id
prefix, current, current-thread. A Codex Session whose summed turns
disagree with its final running total keeps the sums and warns on stderr.
Find and aggregate failed tool calls by structure, independent of any
Query. Failure analysis covers historical conversations. It excludes the
Current Session Family unless you pass --include-current.
$ agsearch --failed # list failed tool calls, joined to the command
$ agsearch --failed cargo # filter failures by command / error text
$ agsearch --stats # aggregate into a counts table by tool + error$ agsearch --stats
19 ✗ PowerShell error:
3 ✗ Edit String to replace not found
… +2 more singleton signaturesOne-off signatures fold into the trailing +N more line so the table stays
readable at --all scale. If every row is a one-off, all rows
are shown. Use --failed to see every failure individually.
Add --full to a --failed listing to print each failure's complete error text
instead of the single salient line.
These compose with search, --failed, --stats, and the listing verbs
where noted:
| Flag | Effect | Applies to |
|---|---|---|
| (default) | the current directory's Project | search, sessions, usage |
--all |
every Project in your history | search, sessions, usage |
--project <substr> |
Projects whose name contains the substring | search, sessions, projects, usage |
--session <selector> |
one Session, selected by id-prefix, current, or current-thread. The selected Session remains included when it belongs to the Current Session Family |
search |
--file <SELECTOR> |
list Touches of the selected file. With a Query, restrict Matches to touching Sessions | search |
--written |
with --file, keep only write Touches |
search |
--include-current |
put the Current Session Family back into the results | search, --failed, --stats, usage |
--since <when> |
only Sessions/Projects touched since a duration (3d, 2w, 1h) or ISO date (2026-05-01) |
all |
The default scope merges Sessions from both Harnesses by their encoded working
directory. projects shows one row when both Harnesses used the same directory.
Subagent threads stay excluded unless you pass --include-subagents.
usage instead folds workers into the parent row unless you pass it.
sessions and projects are inventory verbs. They keep listing and counting
the Current Session. usage ranking excludes the Current Session Family like
search and failure analysis.
- Output is colorized on a TTY and plain when piped or under
NO_COLOR. - "No matches" / "No sessions" / "No projects" / "No sessions with usage" exit 0. An empty result is not an error.
- Bad input exits non-zero with a readable message. Bad input is an
unparseable regex, an unparseable
--since, an ambiguous id, a missing Session, unavailable or ambiguous current context, or an existing Export destination without--force.
This repo also ships a Claude Code skill in skills/agsearch, declared in
.claude-plugin/plugin.json. It lets Claude recall past conversations for you,
for example "did we ever discuss X?" or "find the session where we set up Y". The skill is
thin glue over the same binary, so install agsearch on your PATH first.
The plugin also ships /retro-sessions in skills/retro-sessions. It reads
past sessions through agsearch and suggests repo changes that answer a focus
you give it, for example /retro-sessions read my last 10 sessions and find where agents took too long to find information. Only you can start it.
The precise vocabulary this tool is built around lives in CONTEXT.md:
Harness, Project, Session, Record, Message, Query, Match, Failure, Usage, Store.
The reasoning behind the bigger design decisions is in
docs/adr/. They cover locating Projects, the verb/handoff model,
failure grouping, and the listing verbs.
MIT.