Skip to content
History storage

Where Claude Code stores your conversations

Every session is a file you already own. Knowing its shape is the difference between recovering an afternoon of work and starting the conversation over.

The Claude Code transcript record chain A Claude Code session is one JSONL file. Each line is a record with its own uuid, and each record points back to the previous one through parentUuid. Resume walks that chain from the last record to the first, which is why the links and the tool pairings must stay intact. ~/.claude/projects/<slug>/<session-id>.jsonl uuid: a1… uuid: b2… uuid: c3… uuid: d4… parentUuid: a1… parentUuid: b2… parentUuid: c3… user assistant · tool_use user · tool_result assistant One line per record. Every record points back at its parent, and resume follows those links. tool_use and tool_result are a pair Break the pairing and the session stops resuming, however good the text is.
What is on disk One JSONL file per session, one record per line. Each record carries its own uuid and points back at its parent through parentUuid, and a tool_use block and its tool_result have to survive together for the session to resume. Ids are shortened for the drawing.
At a glance

Claude Code writes one JSONL file per session to ~/.claude/projects/<slug>/<session-id>.jsonl, where the slug comes from the working directory. Each line is a record with a uuid, and each record points back through parentUuid. Codex does not offer an equivalent file you should read: its supported route is the codex app-server protocol.

A Claude Code session is one JSONL file you already own.

There is no database and no cloud record to request. Each session is a plain text file where every line is one JSON record, stored under a directory named for the project the session ran in:

~/.claude/projects/<slug>/<session-id>.jsonl

That layout has three consequences worth knowing before you go looking for anything.

  • The project slug is derived from a path. Sessions are grouped by the working directory they ran in, so the same repository opened from two different paths lands in two different directories.
  • Records are a linked chain, not an array. Each carries a uuid and a parentUuid. The harness walks that chain when it resumes a session, which is why the order of lines in the file is not the thing that matters — the links are.
  • Tool calls come in pairs. An assistant tool_use block has a matching tool_result. Both halves have to survive together.

Because it is a file, it is also yours: greppable, diffable, and backed up by whatever already backs up your home directory. Nothing has to leave the machine for you to read your own history.

Codex history is a protocol, not a file to open.

The obvious next question is where Codex puts the same thing. The honest answer is that you should not be reaching for its files at all. Codex keeps its own rollout records and an internal database, and neither is a supported read surface — the shape can change without notice, and a reader that parses them is guessing.

The supported route is the codex app-server protocol, which exposes discovery, reading, limits, and account usage through documented calls. Crowsnest uses exactly that: thread/list to discover conversations and thread/read for their contents. It never reads Codex's internal database.

Claude Code

A readable, resumable, editable JSONL transcript per session. The deep format, and the only one where a past turn can be rewritten in place.

Codex

Completed items are immutable. Changes happen through the official fork and retry operations rather than by rewriting a rollout behind the protocol's back.

Two details catch people out. First, the protocol's own default lists interactive sessions only, so non-interactive codex exec runs are missing unless a client asks for those source kinds by name — Crowsnest does, with a fallback for older Codex builds that do not know the parameter. Second, the fast listing response omits turns entirely, so message counts have to be filled in afterwards from thread/read rather than by parsing anything private.

If a tool claims to show you Codex history and cannot say which protocol call it came from, ask what it is parsing.

Finding the conversation again is the actual problem.

Knowing the path solves storage, not recall. A month in, you have hundreds of session ids that mean nothing, spread across directories named after paths you have since renamed. Two things fix that, and they are different tools.

  1. Narrow by place.Browse projects as a directory tree built from the paths the sessions actually came from, with counts rolled up at every level. Selecting a folder includes everything beneath it, and chains of single-child folders are compressed into one row so deep paths do not waste three indents on the same number.
  2. Then search by memory.You rarely remember the project. You remember a phrase. Searching titles, prompts, project, and id is enough when you half-remember the task; searching every message across every conversation is what you need when all you have is one line the agent wrote.
  3. Keep both composable.Search inside the selected subtree when you know roughly where you were, and clear the folder to search everything when you do not.
  4. Check the provider mark.With two agents writing history on one machine, a result is only useful if it says which runtime produced it and which model answered.

In Crowsnest, / focuses the title and metadata search, and ⌘K searches every message in every conversation with multi-word results ranked by relevance, each carrying its Claude or Codex mark.

The file is editable. That is not the same as safe to edit.

Once you know a transcript is plain JSONL, rewriting a bad answer by hand looks like a two-minute job. It usually is not, because resume validates more than your text.

  • The chain is checked. A regenerated uuid or a broken parentUuid orphans everything after it.
  • The pairings are checked. A tool_use without its tool_result is an invalid transcript, not a shorter one.
  • Round-tripping is not free. Loading the whole file into a JSON library and writing it back reformats lines you never intended to touch, and thinking blocks carry signatures that do not survive casual re-serialization.
  • There is no undo. The agent's own history has no version control unless you gave it some.

The safe shape of the operation is narrow: read the file as raw bytes, re-serialize only the one line being changed, leave every other byte identical, write atomically, and keep a timestamped backup first. That is what makes the edit resumable rather than merely saved.

Crowsnest reads that history in place, and never uploads it.

Crowsnest is a local workspace over the files and protocols described above. It browses Claude Code and Codex history in one provider-marked gallery, gives you the folder tree and both search modes, and — for Claude transcripts — edits a past turn in place while preserving uuids, tool pairings, and every untouched line byte for byte, so claude --resume picks the rewrite up with its original context.

Edits are backed by timestamped copies in <project>/.crowsnest-backups/ — the last thirty are kept — alongside an .audit.jsonl recording each edit's original and new text. Writes are atomic and path-confined.

The server binds to 127.0.0.1. Transcripts are not uploaded to Crowsnest or any third party; the browsing, searching, and editing described here all happen on your machine. Reading and repairing local history, including full-message search, is part of the Standard workspace rather than an add-on.

Sources and related field notes

Provider reference: Anthropic's Claude Code documentation. Storage layout, record linkage, Codex protocol use, search behavior, and backup paths were checked against the released Crowsnest source on September 3, 2026.

Find the recordSearch Claude Code and Codex conversationsHistory correctnessEdit Claude Code history safely

Published and source-reviewed September 3, 2026. Provider file layouts and protocols can change; treat first-party documentation as authoritative for the version you are running.