I opened Claude Code on a side project after a day away, and it greeted me with a careful reconstruction of what we had been doing, pieced together from the notes file and the working tree. It was right, but it was a guess. The whole conversation that produced that work was sitting on disk, one command away. Here is how sessions actually persist, what a resumed one gives you back, and what it never will.
This reflects Claude Code 2.1.x and its documentation as of September 2026. The session picker, the flags and the retention defaults change between releases; check the sessions guide for the current behaviour.
The picture to hold in your head
A Claude Code session is a file on disk, a new session never reads old files, and --resume is how you point a new process at an old file. Everything else follows from those three facts: why a fresh session starts from zero, why the picker only shows some conversations, why sessions vanish after a month, and why a notes file in the repository is still worth keeping even though the transcripts exist.
What happened
The project is a small static site. The previous session had done a batch of search-engine work: sitemap dates from git history, rewritten meta descriptions, longer copy on a thin page, one alt text per photo. None of it was committed. The next morning I started claude in the same directory and asked where we were.
The answer was impressive and slightly unsettling. It listed the uncommitted files, ran the project's check script, summarised the changes from the diff, quoted the next steps from the notes file, and asked whether I had been mid-edit in the one file still open in the editor. Everything was correct. Nothing in it came from the earlier conversation, because the new session had never seen it.
When I asked whether it kept a list of past sessions, it did what I should have done first: listed the transcripts in the project's session folder, four of them, and pointed at the one from the day before.
claude --resume 9c2f0a41-… # yesterday's session, full context, not a summary of it
Then a second question that turns out to have a more interesting answer than I expected: how many sessions does it keep? The last four?
What a session actually is
Every interactive session is written continuously to a transcript file. The format is JSON Lines (JSONL, one JavaScript Object Notation object per line), one entry per message, tool call or piece of metadata. The file lives under your home directory, in a folder named after the project's path with every non-alphanumeric character replaced by a dash:
~/.claude/projects/-Users-pere-Projects-side-project/
├── 9c2f0a41-6d3e-4b8a-9f1c-2e7d5a6b8c01.jsonl
├── 51b7e2d0-8a4c-4f13-b6e9-0c3d7f2a9e44.jsonl
├── d08a3c65-2f1b-4e7d-a5c4-7b9e1f0d2a83.jsonl
└── 2e6f9b17-c4d8-4a02-9e3b-5f1a8c7d0b26.jsonl
That layout explains the first thing people trip over. Sessions are stored per working directory, so the picker in one project never shows the conversations from another. Start claude in a subfolder and you get a different, emptier list. The entry format is internal and changes between versions, so don't build scripts on the raw files; the supported routes for that are /export and claude -p --resume, covered below.
The ways back in
There are five entry points, and they differ in how much you need to remember.
| Command | What it does | You need to know |
|---|---|---|
claude --continue (-c) | Reopens the most recent conversation in this directory | Nothing |
claude --resume (-r) | Opens the interactive picker for this directory | Nothing |
claude --resume <name> | Reopens a named session directly | The name |
claude --resume <session-id> | Reopens one session by id, from any directory | The id |
claude --from-pr <number> | Picker filtered to sessions linked to a pull request (PR) | The PR number |
Inside a running session, /resume opens the same picker and switches conversations without leaving the process. In the picker, Space previews a session, typing filters the list, Ctrl+A widens it to every project on the machine, and Ctrl+B narrows it to the current git branch.
The id-based form is the one nobody remembers, and the fix is to stop needing it. Name your sessions. Start one with claude -n search-pass, or rename the one you are in with /rename search-pass; the name shows in the prompt bar and the picker, and claude --resume search-pass brings it back. Unnamed sessions get an automatically generated title from the first prompt, and that title also works as a resume handle, but "we've published the sitemaps in search google but no results" is not something you will type on purpose.
What comes back, and what doesn't
A resumed session is not a snapshot of the old process. It is a new process reading an old transcript, and the difference shows in what is restored. Launch-time flags are the main casualty: anything you passed on the command line, such as a Model Context Protocol (MCP) server configuration or an extra directory, has to be passed again.
| State | On resume | Notes |
|---|---|---|
| Conversation history, tool calls and results | A tool that was mid-run when the old process died does not finish or re-run | |
| Model | Unless a --model flag or environment variable picks one, or the model was retired | |
Agent (--agent) and its tool restrictions | Looked up in the session's original directory, then the current one | |
| Permission mode | Restored by --continue and --resume <id>; not by the picker or /resume, which use the current default. Bypass mode is never restored | |
settings.json, CLAUDE.md, rules, skills | Read fresh at launch, so edits made since apply | |
--mcp-config, --settings, --plugin-dir, --add-dir | Pass them again on the command line | |
Directories added mid-session with /add-dir | The picker still uses them to find the session | |
| Background Bash commands and monitors | Scheduled tasks that have not expired are | |
| "Allow for this session" permission grants | You approve again |
The permission-mode row is the one that bites. Resume through the picker and a session that ended in plan mode starts in whatever mode a new session would; resume the same session with claude --continue and plan mode comes back. Pass --permission-mode explicitly if it matters.
Resuming a long session costs something
Resuming does not make the old conversation free. The prompt cache that kept a long session cheap expires after about an hour of inactivity, so the first request after a resume reprocesses the whole history. On a Pro or Max plan, when the session was idle for more than an hour and is over 100,000 tokens, Claude Code opens a dialog before your first message:
| Option | What it does | Trade-off |
|---|---|---|
| Resume from summary | Runs /compact first: one summarisation request, then the history is replaced by the summary, your latest exchanges and up to five recently read files | Cheapest per request afterwards; whatever the summary dropped is gone |
| Resume full session as-is | Loads everything; the first message re-caches the full history | Every detail available; per-request cost scales with the conversation |
| Don't ask me again | Resumes as-is and stops showing the dialog | Same as above, permanently |
How many sessions are kept
The answer to "the last four?" is that there is no count. Retention is by age: transcripts older than cleanupPeriodDays are deleted, and the default is 30 days. Four was simply how many sessions that directory had seen in the last month; across all projects on the same machine there were 93.
To keep them longer, set the period in your user settings:
{
"cleanupPeriodDays": 365
}
Anything already swept is gone; the setting only stops future pruning. To delete a project's transcripts sooner, claude project purge. Transcripts are plain text on disk, so if a conversation contained something you would not want lying around in your home directory, that is the command to know.
Branch instead of overwrite
Resuming writes new messages into the same transcript. That is what you want when you are continuing, and exactly wrong when you want to try a different approach and keep the original intact. Two things help:
/branch <name>inside a session copies the conversation so far into a new session and switches you to it. The original stays in the picker unchanged.--fork-sessiondoes the same from the command line:claude --continue --fork-sessionopens the latest conversation under a new id.
One warning the documentation makes and experience confirms: resume the same session in two terminals without forking and both sets of messages interleave into one transcript. If you want two parallel lines of work from the same starting point, fork.
Resume from a script
Sessions are also reachable non-interactively, which is the supported way to get data out of one. Pass the id to print mode and ask a question; the answer comes back as JSON:
claude -p --resume 9c2f0a41-6d3e-4b8a-9f1c-2e7d5a6b8c01 \
--output-format json "summarise what we changed and what is still uncommitted" \
| jq -r '.result'
Sessions created with -p are kept out of the picker and out of --continue, but --resume <id> still finds them. /export is the human-readable counterpart: it writes the current conversation as plain text.
Resume restores conversations; notes restore projects
Now the uncomfortable part of the opening story. The fresh session was right about everything, and it was right because the project keeps a notes file: a CLAUDE.md with a short session log, the decisions made, and the next steps. Claude Code reads that file at the start of every session, resumed or not. The transcript, by contrast, is one directory's private history, expires in a month by default, and is only useful if you remember it exists.
So the two mechanisms are not competing, and the mistake is to lean on either alone.
The habit that makes both work is the last node. Write the session log before you close the terminal, because the transcript remembers what was said and the notes remember what was decided. On the project in the story, the fresh session could reconstruct the pending commit because the previous session had written "nothing is committed yet" into the notes. It could not tell me why one meta-description length had been chosen over another, because that lived in the conversation, and the conversation was a --resume away.
The short version
claude --continuewhen you are picking up yesterday's work in the same directory.claude -n <name>at the start of anything that will take more than one sitting, thenclaude --resume <name>.--fork-sessionor/branchbefore experimenting; never two terminals on one unforked session.- Re-pass
--mcp-config,--add-dirand friends; everything insettings.jsonandCLAUDE.mdcomes back on its own. - Raise
cleanupPeriodDaysif 30 days is shorter than your projects. - Keep the notes file current, because it is the only memory that survives the sweep.
