What Claude Code leaves on disk, and what you can build from it
Every session you run is written to disk as it happens, in a format you can read. Almost nobody looks. Here is what is in those files, the two things that will trip you up, and what becomes possible once you can read them.
Claude Code writes every session to disk while you work, and then gives you no way to look back through them. The files are plain text and sitting in your home directory right now. Once you know what is in them, a surprising amount becomes possible without any API, any account, or any instrumentation of your own.
Where the sessions live
Under ~/.claude/projects there is one folder per working directory, with the path flattened into the folder name, and inside it one JSON Lines file per session named by its session id. A JSONL file is just one JSON object per line, so you can read it with anything that reads lines.
What a line actually is
Each line is one event in the session. Not every line is interesting, but the ones that are carry a small set of fields worth knowing: cwd for the working directory, gitBranch for the branch you were on, timestamp, type to say whether it was you or the assistant, isMeta to mark internal bookkeeping, and message.content for the text itself.
From those fields alone you can recover the useful shape of a session without understanding anything about the conversation:
- The first thing you typed, which is the best label a session will ever have.
- The project and branch it happened in, so you can group by where the work was.
- How many messages it ran to, which is a decent proxy for how involved it got.
- When it was last touched, which is what you actually sort by.
Two things that will trip you up
The records are not uniform. A transcript can open with a marker line that carries no cwd at all, so if you read the first line and trust it you will get null working directories for a slice of your sessions. Scan every line and take the first value that exists.
The other trap is that the first user message is often not a prompt. Tool results and tag-wrapped internal content arrive as user messages too, so the naive first-user-message becomes something like a wrapped tag rather than the thing you typed. Skipping content that starts with an angle bracket gets you the real prompt most of the time.
Cost is not in there
The transcripts carry no pricing, so if you want spend per session you need a second source. ccusage reads the same files and totals cost and tokens per session, which you can merge in by session id. Worth knowing that it is a separate local tool reading the same data, not a service you are calling.
Read them as a stream
This is the one performance decision that matters. A year of daily sessions runs comfortably past a gigabyte, and the interesting fields are all near the start of each line, so reading whole files into memory is wasteful in a way you will feel. Stream line by line and a few hundred sessions scan in seconds.
The first prompt you typed is the best name a session will ever have. Everything else about it you can recompute from the file.
What this unlocks
Once sessions are readable you can search across every project for the one where you solved a thing, sort by what a session cost, see which project is quietly eating your budget, and jump back into any of it by session id. None of that needs permission from anyone, because the data is already yours and already local.
I built a small dashboard on exactly this, claude-console, which lists sessions by their opening prompt and reopens them in a terminal. But the tool is beside the point. The lesson generalises: local tools leave artifacts, and reading the artifacts they already write is usually far easier than instrumenting them to tell you something new.