Every Claude Code session lives forever on your disk under ~/.claude/projects/. That is hundreds of conversations, thousands of tool calls, weeks of working memory — saved as newline-delimited JSON and effectively invisible. Finding the one where you fixed the auth bug last month is technically possible with grep. Practically it is a small archeology project. Here is the workflow that works, what it cannot do, and what a session explorer adds.
Where Claude does store your transcripts
The layout is consistent across recent Claude Code versions. Every session you have ever started lives under:
~/.claude/projects/<encoded-cwd>/<session-id>.jsonl
encoded-cwdis your working directory at session start, with path separators replaced by dashes and prefixed with a dash. A v3 project at/home/you/work/myprojectbecomes-home-you-work-myproject.session-idis a UUID generated when the session starts. Each file is one conversation.
The format is newline-delimited JSON. One record per line. Records have a type field — user, assistant, tool_use, tool_result — and a payload that varies by type.
A quick inventory:
find ~/.claude/projects -name '*.jsonl' | wc -l
# 412
du -sh ~/.claude/projects
# 1.4G
Four hundred sessions, one and a half gigabytes of working history. Most users have something in this range after a few months of use. None of it is searchable through any UI Claude Code ships.
Grep workflows — what works
The default tool for searching the corpus is the one developers reach for first: grep. The pattern that works:
# Find every session that mentioned "JWT" in any context
grep -rl "JWT" ~/.claude/projects --include='*.jsonl'
# Find sessions that ran a specific tool call
grep -rl '"name":"Edit","input":{"file_path":"src/Auth' ~/.claude/projects
# Find sessions from a specific project root
ls ~/.claude/projects/-home-you-work-myproject/
# Count sessions per project
find ~/.claude/projects -mindepth 1 -maxdepth 1 -type d -printf '%f
' |
while read d; do
count=$(ls ~/.claude/projects/"$d" 2>/dev/null | wc -l)
echo "$count $d"
done | sort -rn | head -20
These produce useful results. You can find the auth session from grep-able strings. You can see which projects you used Claude Code on most. You can grep tool call payloads to find sessions that touched a specific file.
What you cannot do with grep alone:
- Search by what the session accomplished. "Find the session where I fixed the rate-limit bug" requires the JSONL to have explicit metadata that says "this session fixed the rate-limit bug." It does not.
- Filter by date easily. The session-id UUID is not time-ordered. The file's mtime is. A grep for "sessions from last week" requires combining
find -newerorfind -mtimewith the grep. - Aggregate by topic. "Show me all sessions that involved Stripe integration" requires either every session to mention Stripe explicitly (most do), or a tagging layer on top of the corpus.
- Resume a found session. Claude Code's
claude resumeoperates on the most recent session, not on an arbitrary session ID. To resume an old session you have to manually invoke it with the right flags, or pipe its transcript into a new session as priming context.
The grep workflow is good for "find the session that contains this exact string." It is not good for "find the session about this topic" or "show me all sessions tagged for follow-up."
The tagging gap
The information that would make session history actually navigable is metadata that Claude Code does not capture: human-assigned tags, project labels, outcome status, follow-up flags.
If you are running Claude Code as a small engineering team's pair programmer, the categories you want are predictable:
- By outcome. Successful refactor, partial refactor, abandoned. Bug fixed, bug worsened, bug investigated but not fixed.
- By area of code. Auth, billing, frontend, infra, tests.
- By follow-up state. Done. Needs review. Needs revert. Blocked on external decision.
- By cost intent. Quick experiment. Production change. Spike. Refactor.
None of these are intrinsic to the session — they have to be assigned by the human afterwards. Claude Code does not surface a tagging UI. The closest thing in the JSONL is the TodoWrite list, which captures what the session intended to do but not whether it succeeded or whether the work needs follow-up.
The grep-workaround is to mention tags in your prompts ("This is the auth refactor session") and then grep for the tag. It works inconsistently because some sessions remember to tag and some do not. The grep produces partial coverage.
What a Session Explorer adds
A productized session-history UI fills the gap by giving you the surfaces grep cannot reach:
- A chronological list of every session, indexed by date, project, and a session title automatically derived from the first user prompt.
- Full-text search across all transcripts, with snippet preview showing where the match landed (which turn, which file, which tool call).
- Filter facets: project, date range, model, outcome (if tagged), cost.
- Per-session detail view: the conversation, the TodoWrite trajectory across turns, the tool calls invoked, the files touched, the dollar cost (or subscription budget burn), and the active account.
- Manual tagging: click-to-tag sessions after the fact with labels you define. Tags persist across sessions and are queryable.
- Resume from any session: open the historical session as a starting point for a new conversation, with the cached state pre-loaded as priming context.
The architectural pattern that makes this work is to treat the JSONL files as a flat-file database and build a small indexer over them. The index lives separately from Claude Code's own state — it is a local SQLite or LMDB store that gets updated when new sessions land. Search hits the index; rendering reads the JSONL on demand for the matching session.
The key property is that the index is derived data. It can be regenerated from the JSONL at any time. Nothing critical is lost if the index file is deleted — it just gets rebuilt on next launch. The Session Explorer that ships with Power Claude is this indexer already built; it is free to download and try, no credit card needed.
When the corpus is large
Above a few thousand sessions, naive grep starts to feel slow and the JSONL files start to take a noticeable fraction of disk. The mitigations:
- Compress old transcripts. JSONL compresses extremely well — typically 90%+ reduction with zstd. Older sessions can be moved to
~/.claude/projects.archive/in compressed form and decompressed on-demand for search. - Project-scope your search by default. Most queries are within a single project. Adding
--include='~/.claude/projects/-home-you-myproject/*'to grep speeds up searches by orders of magnitude. - Build a derived full-text index. Tools like
ripgrep's--no-messagesplus a SQLite FTS5 index update incrementally as new sessions land. The first build is slow; subsequent searches are sub-second. - Prune sessions older than your useful memory horizon. Most developers stop referencing sessions older than six months. Archiving (not deleting — archive to compressed form) keeps the working set small without losing forensic access.
For most developers the corpus stays under a thousand sessions and a couple of gigabytes. Naive grep stays workable. The pruning and indexing matter mostly for heavy users running multiple autonomous loops with long retention horizons.
Frequently asked questions
Can I delete old Claude Code sessions to reclaim disk space?
Yes. The JSONL files are standalone — deleting them does not affect Claude Code's current state, the watchdog (if you run one), or future sessions. The trade-off is the forensic value: a session you delete today is one you cannot grep next month. Most developers archive rather than delete (compress and move to a sibling directory).
Is there a Claude Code CLI command to list past sessions?
Not currently a single-command list of arbitrary sessions. claude resume shows recent ones. The full corpus is reachable only by directly listing ~/.claude/projects/<encoded-cwd>/. Third-party tools build a session-explorer UI on top of this directory layout.
Will my session transcripts ever be uploaded to Anthropic?
No. The JSONL transcripts live entirely on your local machine. Anthropic receives the API requests (which contain the current turn's context) but does not receive the persisted transcript files. Your session history is yours, and it never leaves the machine unless you exfiltrate it deliberately.
How do I share a session transcript with a coworker?
Copy the relevant <session-id>.jsonl file. The format is portable — your coworker can view it with jq, paste it into a new Claude Code session as priming context, or load it into a session-explorer UI. Be aware: transcripts can contain file contents you read during the session, including any sensitive data the agent encountered.
Can I export a session to Markdown?
Not natively. The JSONL can be transformed to Markdown with a one-liner (extract the assistant text records and the user prompts). The result is a readable transcript, although it loses the tool-call detail and the per-turn token usage. Productized session explorers offer this as a built-in export.
Closing
The transcripts contain weeks of useful working history that no UI lets you reach. Grep gets you partway there. The Session Explorer we ship is the productized version — searchable, taggable, filterable, and resumable — for developers who want to actually navigate the history they have been silently accumulating.
If you want to point it at the history you have already accumulated, the 14-day Premium Trial is $0 today and you can cancel anytime before day 15 — it adds the Session Explorer, the watchdog, and usage analytics on top of rotation. Not ready to enter a card? Install Power Claude Free instead: the 7-day free trial gives you full Pro access, no credit card.