SSD Nodes Learn 🎉 VPS from $5.50/mo
Guides Matt ConnorBy Matt Connor

Claude Code resume and session history

Resume a Claude Code session by name or from the picker, and find the plaintext transcripts it leaves behind on the machine where the agent ran.

How do you resume a Claude Code session

To resume a Claude Code session, run claude --continue for the most recent conversation in the current directory, or claude --resume to pick an older one from a list. From inside a session that is already running, the /resume command switches you to a different conversation without quitting. The short forms are -c and -r.

claude --continue
claude --resume
claude --resume auth-refactor

If you already know the session name or its ID, pass it as an argument and Claude Code goes straight there without showing the picker.

Everything below matches the official session documentation as of August 2026. Claude Code releases often, and flag names and keyboard shortcuts do change between versions, so treat claude --help and that page as the authority when something here does not match what your terminal shows.

What a session actually is

A session is one saved conversation tied to a project directory. It holds the whole message history, including the tool calls Claude made and the results those calls returned. Claude Code writes it to disk continuously while you work, not once at the end, so a conversation survives closing the terminal or losing the SSH connection.

Resuming restores more than the text. The conversation history comes back in full, along with the model the session was using and the subagent it was started with if you used --agent. The permission mode comes back too, with exceptions that exist for safety: plan mode and bypass-permissions mode are never restored, so a session that was in one of them resumes in the mode a new session would start in.

Some things do not come back, because they were launch-time flags rather than saved state. Directories added with --add-dir, and options such as --mcp-config, --settings and --plugin-dir, have to be passed again when you resume. Settings files such as settings.json are re-read at launch, so anything that lives in them needs no repeating.

Why session history matters more on a VPS

Here is the fact that surprises people. The transcript is written on the machine where the agent ran. It is not held in your account and not synced to a cloud. It is a file on that box's disk.

So a session you left inside a tmux window on your VPS does not appear in the picker on your laptop, and a session from your laptop does not appear on the VPS. Nothing moves between them. If you work the way most people do when running Claude Code in tmux on a VPS, the server is where your real conversation history accumulates, and the picker you see locally shows a different and much smaller set.

The same split applies across interfaces. The desktop app and the VS Code extension each keep their own session history, and neither of them is the CLI's history. Claude Code on the web keeps its own as well.

Within one machine the search is wider than you might expect. claude --resume <session-id> looks in the current project directory and its git worktrees first, then in every other project on that machine. The phrase to hold on to is "on that machine". A session ID from another host resolves to nothing, and Claude Code tells you so with No conversation found with session ID: <session-id>.

Where does Claude Code store session history

By default, transcripts live under your Claude Code config directory, at a path of the form ~/.claude/projects/<project>/<session-id>.jsonl.

<project> is your working directory path with every non-alphanumeric character replaced by a hyphen, so a session started in /home/deploy/apps/api is stored under a directory named -home-deploy-apps-api. If that converted name would run past 200 characters, Claude Code truncates it and appends a hash of the full path, so the directory name stays inside filesystem limits.

The file is JSONL: one JSON object per line, each line a message, a tool use, or a metadata entry. It is readable text, and reading it is fine.

Writing a parser against it is not fine. The entry format is internal to Claude Code and changes between versions, so a script that reads these files directly can break on any update. Anthropic's own documentation says to use /export or the documented script interfaces instead, which is good advice for exactly that reason.

Two settings move the goalposts. CLAUDE_CONFIG_DIR relocates the whole config directory, which is how you put transcripts on a separate volume or an encrypted one. cleanupPeriodDays in settings.json controls how long they are kept, and it defaults to 30 days with a minimum of 1.

What is actually inside those transcript files

Every tool result is recorded, which means a transcript contains the contents of files Claude read and the output of commands Claude ran. Anthropic's data usage page states it plainly: Claude Code stores session transcripts locally in plaintext under ~/.claude/projects/.

Think about what that means on a server. If Claude read a .env file to work out why a service would not start, that file's contents are now sitting in a JSONL file in your home directory. If a command printed a connection string, that string is in there too. Nothing leaked. The transcript recorded what happened, which is the whole point of it, and that is precisely why it belongs in your threat model.

  • Backups: a plain backup of /home or /root copies your transcripts to wherever backups go. Add an exclusion, or accept that copies of your prompts and your file contents now live in your backup store.
  • Snapshots and images: a VPS snapshot taken for any reason contains the whole directory. So does an image you clone to build a second server from.
  • Other accounts on the box: check the modes yourself with ls -ld ~/.claude ~/.claude/projects rather than assuming they are tight.
  • Deliberate uploads: the /feedback command sends conversation history to Anthropic on purpose, and /bug and /share report through the same path. Those are things you choose to do, so know what you are agreeing to before you confirm.

If you would rather no transcript existed, CLAUDE_CODE_SKIP_PROMPT_HISTORY suppresses transcript writes, and --no-session-persistence suppresses them for a single non-interactive claude -p run. Be clear about the trade before you set either. Transcripts are what resume reads, so no transcript means no resume.

How do you find an old conversation

Open the picker with claude --resume, or with /resume from inside a running session. Each row shows the session name if you set one, or a generated title if you did not, plus the time since the last activity, the git branch, and the file size.

The picker searches. Press /, or just start typing, to filter the list. The shortcuts worth learning are the ones that widen it: Ctrl+A shows sessions from every project on this machine, Ctrl+W shows every worktree of the current repository, and Ctrl+B filters down to the current git branch. Press Space to preview a session's content before you commit to it, and Ctrl+R to rename the highlighted one.

Naming sessions makes all of this much easier. Start one with claude -n auth-refactor, or run /rename auth-refactor partway through, at the point where you realise the conversation has turned into a real piece of work. A named session is then resumable by name straight from the shell.

An unnamed session still gets a generated title, written by a background request to a small fast model that summarises your first prompt. That title helps you recognise the row in the picker, but it is not a resume handle. claude --resume <name> matches only names you set yourself.

Grepping transcripts to find the right session

Sometimes you remember a phrase and nothing else. The transcripts are text, so search them.

grep -rl "nftables" ~/.claude/projects/

That prints the paths of the matching transcripts. The filename without the .jsonl extension is the session ID, and claude --resume <session-id> accepts it. Use grep to work out which session you want, then resume it or export it to actually read it.

Two honest caveats. The content is JSON-escaped, so a phrase containing quote characters, or one that was split across a line break, may not match as a literal string. And a match inside a tool result means Claude saw that text, not that anybody typed it.

Reading and exporting a conversation

/export renders the current conversation as plain text, with messages and tool output written out readably instead of as JSON. With no argument it opens a menu offering the clipboard or a file. With a filename, /export handover.txt writes straight to that path. This is the right way to move a conversation from a server to your laptop, or to attach one to a ticket.

For anything automated, use the interfaces that are meant to be stable. Hooks and status line commands receive a transcript_path field as input, so a SessionEnd hook can archive a transcript when a session ends. You can also ask a stored session a question without opening it:

claude -p --resume <session-id> --output-format json "summarize what we changed" | jq -r '.result'

That sends a follow-up prompt into the old conversation and returns structured JSON. It is a far better foundation than parsing a JSONL format that is free to change in the next release.

When starting fresh beats resuming

Resuming brings the whole history back, and the whole history is what every later request carries. A conversation that ran for four hours yesterday is expensive to continue today, and how token usage adds up across a long session explains where that cost actually comes from.

Claude Code sometimes offers a middle road. On a Pro or Max plan, resuming a session that has been idle for about an hour and holds more than 100,000 tokens opens a dialog before your first message. The prompt cache has expired by then, so the next request reprocesses the full history once no matter which option you pick.

  • Resume from summary runs a compaction immediately, so later requests carry a summary instead of the full history. Cheaper per request, and whatever the summary dropped is no longer available.
  • Resume full session as-is loads the conversation unchanged, keeping every detail at a per-request cost that scales with the conversation's size.

A third option resumes in full and stops the dialog from appearing on later resumes.

The judgement call is simpler than it looks. Resume when the next thing you are about to type depends on what was already said. Start fresh when it does not. Drift is easy to spot once you watch for it: Claude referring to a file you deleted an hour ago, or re-arguing a decision you settled at the top of the session. That is stale context, and carrying it forward costs you tokens and accuracy at the same time.

If the useful part of an old conversation is a decision or a fact you will need again, do not rely on resuming to carry it. Write it down where every session can see it, which is what Claude Code's memory files are for.

/branch is worth knowing here too. It copies the conversation up to the current point and switches you into the copy, leaving the original intact and still in the picker. Use it to try a second approach without losing the first.

How resume differs from compaction and from memory

These get confused constantly, and they solve different problems.

Resume is about getting a conversation back at all, after you exited, rebooted, or moved on to another task. Compaction is about the context window inside a live conversation: /compact replaces what Claude is carrying with a summary, so later requests send fewer tokens. If your problem is that the context window is full, compaction is the tool, and managing the Claude Code context window covers it properly.

Memory is different again. CLAUDE.md files and auto memory hold instructions and facts that load at the start of every session, so they are not a conversation you return to. They are what you write down so that you never need to return to one.

If what you want is two conversations running at the same time and coordinating, that is a separate mechanism. Claude Code sessions can message each other while both are live, which is a different problem from pulling yesterday's session back off disk.

FAQ

Where does Claude Code store my session history?

By default under your config directory, at ~/.claude/projects/<project>/<session-id>.jsonl, where <project> is the working directory path with non-alphanumeric characters replaced by hyphens. Each file is JSONL: one JSON object per line for a message, a tool use, or a metadata entry. CLAUDE_CONFIG_DIR moves the config directory somewhere else, and cleanupPeriodDays in settings.json sets how long transcripts are kept, defaulting to 30 days with a minimum of 1.

Why can I not see my VPS session in the picker on my laptop?

Because transcripts are written to the disk of the machine where the agent ran, and nothing syncs them between machines. A conversation you had inside tmux on your VPS exists only on the VPS. Resume it there over SSH, or run /export inside it and copy the text file across if you want a local record.

Can I resume a session I started in a different directory?

Yes, if you have its session ID. claude --resume <session-id> looks in the current project directory and its git worktrees first, then in every other project on the same machine. Inside the picker, Ctrl+A widens the list to every project on the machine and Ctrl+W widens it to every worktree of the current repository. If nothing matches, Claude Code reports No conversation found with session ID: <session-id>.

Should I resume an old session or start a new one?

Resume when your next message depends on what was already said in that conversation. Start fresh when it does not, because resuming reloads the entire history and every later request then carries it. Watch for drift: a session that keeps referring to files you already deleted is carrying stale context, and that context costs you tokens and accuracy on every turn.

Can I stop Claude Code from writing transcripts to disk?

Yes. CLAUDE_CODE_SKIP_PROMPT_HISTORY suppresses transcript writes, and --no-session-persistence suppresses them for a single non-interactive claude -p run. Understand the trade first, because transcripts are what resume reads, so turning them off means --continue and --resume have nothing to load. If your concern is where the files sit rather than that they exist at all, point CLAUDE_CONFIG_DIR at an encrypted volume and lower cleanupPeriodDays instead.