blog

Where Claude Code Stores Your Transcripts (and How to Actually Use Them)

Quick answer

Claude Code writes every session to a JSON Lines file under your home directory:

~/.claude/projects/<project>/<session-id>.jsonl
OSTranscript folder
macOS~/.claude/projects/ (/Users/you/.claude/projects/)
Linux~/.claude/projects/ (/home/you/.claude/projects/)
Windows%USERPROFILE%\.claude\projects\ (C:\Users\you\.claude\projects\)

Each file is one session, and each line is one record: a message you typed, a reply from Claude with its tool calls, a tool result, or session metadata.

Claude Code deletes transcripts older than 30 days by default. If you want your history, raise cleanupPeriodDays before it ages out.

The projects/ directory structure

Claude Code keeps one folder per project. The folder name is the absolute path of the directory you started Claude Code in, with every / and . replaced by -. Session files are named by UUID:

~/.claude/projects/
├── -Users-you-Documents-GitHub-myrepo/
│   ├── 5b16ffd3-c8e8-462b-8223-849a55a92f92.jsonl
│   ├── 5b16ffd3-c8e8-462b-8223-849a55a92f92/
│   │   ├── subagents/        # transcripts of subagents this session ran
│   │   └── tool-results/     # large tool outputs spilled out of the transcript
│   └── 26795d81-809d-4077-b09b-b9afb9ce7f91.jsonl
└── -Users-you-code-my-site-com/
    └── 9dcf238a-3662-4ce5-aaa3-2317a872952a.jsonl

So a session started in /Users/you/Documents/GitHub/myrepo lands in ~/.claude/projects/-Users-you-Documents-GitHub-myrepo/, and one started in /Users/you/code/my-site.com lands in -Users-you-code-my-site-com/. A Claude Code worktree under myrepo/.claude/worktrees/feature gets its own folder ending in -myrepo--claude-worktrees-feature, because the dot in .claude becomes a second dash. (If you run risky work in worktrees, expect one transcript folder per worktree.)

UUIDs don’t sort by time, so sort by modification time instead:

# Your 10 most recent Claude Code sessions across all projects
ls -t ~/.claude/projects/*/*.jsonl | head -10

Anatomy of a session JSONL file

Each line is a JSON object with a type, plus shared fields such as sessionId, uuid, parentUuid, timestamp, cwd, gitBranch, and version. Simplified, a short exchange looks like this:

{"type":"user","message":{"role":"user","content":"Why is my test failing?"}}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"Let me look at the test file."},{"type":"tool_use","id":"toolu_01...","name":"Read","input":{"file_path":"test.spec.ts"}}],"usage":{"input_tokens":12,"output_tokens":48,"cache_read_input_tokens":18000}}}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_01...","content":"...file contents..."}]}}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"The assertion expects 2 but the function returns 3 because..."}]}}

The records you’ll care about:

  • user: either what you typed (content is a string) or a tool result being handed back to the model (content is an array of tool_result blocks). Tool results are not a separate record type.
  • assistant: Claude’s reply. Its content array holds text, thinking, and tool_use blocks (Read, Edit, Bash, Grep, MCP tools, and so on), and message.usage holds the token counts for that API call.
  • system: session events such as hook results and errors.
  • attachment and file-history-snapshot: injected context and the checkpoint bookkeeping used by rewind.

The exact set of record types changes between Claude Code versions, so filter on the ones you need rather than assuming a fixed schema. Because it’s JSONL, grep and jq work on it directly.

Things you can actually do with this data

Find that prompt you half-remember

# Search every session across every project
grep -l "the bug with the auth middleware" ~/.claude/projects/*/*.jsonl

If you only need the prompt itself, not the conversation, search your prompt history instead: ~/.claude/history.jsonl has one line per prompt you’ve typed, with its timestamp and project path.

Extract just your own messages

# Every prompt you typed in one session (skips tool results)
jq -r 'select(.type=="user" and (.message.content|type)=="string") | .message.content' \
  ~/.claude/projects/-Users-you-Documents-GitHub-myrepo/<session-id>.jsonl

See every tool call from a session

# All tool invocations, with the start of their inputs
jq -r 'select(.type=="assistant")
        | .message.content[]?
        | select(.type=="tool_use")
        | "\(.name): \(.input | tostring | .[0:80])"' \
  ~/.claude/projects/<project>/<session-id>.jsonl

Handy for “what files did Claude read?” or “what commands did it run?”

Add up the tokens in a session

jq -s '[.[] | select(.type=="assistant") | .message.usage // empty]
       | {input: (map(.input_tokens) | add),
          output: (map(.output_tokens) | add),
          cache_read: (map(.cache_read_input_tokens // 0) | add)}' \
  ~/.claude/projects/<project>/<session-id>.jsonl

Streaming can write more than one line per API call, so treat this as a rough count. For exact per-request cost, see tracking Claude Code token usage and cost.

Keep transcripts longer than 30 days

Claude Code’s cleanup deletes transcripts (and their subagents/ and tool-results/ folders) once they’re older than cleanupPeriodDays, which defaults to 30. To keep a year of history, add this to ~/.claude/settings.json:

{
  "cleanupPeriodDays": 365
}

The minimum is 1; 0 is rejected. Raising it only protects sessions that haven’t been deleted yet.

Back up your transcript history

# Snapshot ~/.claude/projects into a private git repo
cd ~/.claude/projects
git init && git add -A && git commit -m "snapshot $(date +%F)"
git remote add origin git@github.com:you/claude-archive.git
git push -u origin main

Run the commit on a schedule and the archive keeps everything, even after Claude Code’s cleanup removes the originals. Transcripts are often more useful than most documents on your machine, and they usually sit on one laptop with no backup.

Move .claude to another drive

Set CLAUDE_CONFIG_DIR to the new location, and Claude Code stores its settings, session history, and plugins there instead of ~/.claude. Copy the existing folder over first if you want to keep your history.

Resume or replay a session

claude --resume opens a picker of the current project’s sessions, read from these same files, and claude --continue reopens the most recent one. There’s no built-in replay command; to replay a session you read the JSONL and render the messages yourself.

Privacy: what’s in there

Transcripts are plaintext. Anything that passed through the conversation or a tool is written to disk, including:

  • API keys you pasted in by mistake
  • Server addresses and database connection strings from deployment discussions
  • Customer data you showed Claude while debugging
  • File contents Claude read and command output it saw

If you back this directory up, encrypt it. If you commit it to a repo, make sure the repo really is private. Before sharing a session file with a teammate, run grep -iE 'password|api[_-]key|secret' over it.

Claude Code keeps these files on your machine; they leave it only if you send them somewhere.

Beyond grep: turning transcripts into reusable skills

The most valuable thing in ~/.claude/projects/ isn’t any single prompt. It’s the patterns that repeat across sessions: the same kind of code review you’ve done 14 times, or the same “branch, failing test, implement, lint” routine.

Those patterns are in the JSONL files; they just need to be found and turned into something reusable. That’s what PromptConduit does. The CLI reads your transcripts, finds sequences of prompts and tool calls you’ve repeated, and writes them to ~/.claude/skills/ as Claude Code skills you can invoke with /<skill-name>.

Skill generation runs locally, with no account and no data leaving your machine:

curl -fsSL https://promptconduit.dev/install | bash
promptconduit skills generate --local

Add --dry-run to preview what would be written. Full docs are at /docs/local-skills. Since transcripts age out after 30 days by default, generate skills (or raise cleanupPeriodDays) before the sessions you care about are gone.


Further reading

Frequently asked questions

Where does Claude Code store transcripts on macOS and Linux?

In ~/.claude/projects/<project>/<session-id>.jsonl. The project folder is the absolute path of the directory you started Claude Code in, with every / and . replaced by -. The session ID is a UUID.

Where does Claude Code store transcripts on Windows?

In %USERPROFILE%\.claude\projects\<project>\<session-id>.jsonl. Claude Code documents ~/.claude as meaning %USERPROFILE%\.claude on Windows; the layout inside is the same as on macOS and Linux.

Does Claude Code delete old transcripts?

Yes. Transcripts older than cleanupPeriodDays are deleted automatically, and the default is 30 days. Set a larger value, such as 365, in ~/.claude/settings.json to keep more history, and back the folder up if you want it permanently.

What is ~/.claude/history.jsonl?

It is your prompt history, not a transcript: one line per prompt you typed, with a timestamp and the project path. Claude Code uses it for up-arrow recall and Ctrl+R search. Full conversations live under ~/.claude/projects/.

Can I move the .claude folder to a different drive?

Yes. Set the CLAUDE_CONFIG_DIR environment variable and Claude Code stores its settings, session history, and plugins there instead of ~/.claude.

Where are subagent transcripts stored?

Next to the parent session, in ~/.claude/projects/<project>/<session-id>/subagents/. Large tool outputs spill into a sibling tool-results/ folder. Both are removed when the parent transcript ages out.

How do I delete Claude Code transcripts for one project?

Run claude purge for that project. It deletes the project's transcripts and auto memory, its per-session file-history and debug entries, and its lines in history.jsonl. Deleting the folder under ~/.claude/projects/ by hand removes only the transcripts.