Lesson 15 of 32
Managing Sessions
Every conversation is saved to disk and tied to a directory. How to resume one, when to fork instead, and why naming sessions turns them into branches.
Everything you have done so far has happened inside one conversation. This lesson is about the conversation itself: what it is, where it lives, and how to have several without confusing yourself.
A session is a saved conversation tied to a project directory. It is written
to disk continuously as you work, not when you exit, so it survives you closing
the terminal, losing the window, or running /clear.
Each one starts empty
The first thing to internalise, because it causes more confusion than anything else here: sessions are independent. A new session begins with a fresh context window and none of the history from previous ones.
So when you run claude in a project you worked in yesterday, it does not
remember yesterday. It has your files, and whatever you have put in a
CLAUDE.md — the file it reads at the start of every conversation, which gets
its own lesson shortly — and nothing else. This is not a limitation to work
around so much as a fact to plan around. Anything that must survive across
sessions belongs in a file, not in a chat.
Getting back into one
Three ways in, depending on how sure you are about which conversation you want.
claude --continue
Resumes the most recent session in the current directory, immediately and with no questions. This is the one you will type most: you were here an hour ago and you want to carry on. If there is no session yet, it says so and exits.
claude --resume
Opens the session picker: a searchable list of sessions for this directory, showing each one's name, when it was last active, its git branch and its size. Use it when the most recent session is not the one you mean.
/resume
The same picker, from inside a running session, so you can switch conversations without leaving Claude Code. You can also pass a name to go straight there.
The picker is worth five minutes of your life. Arrow keys move, Enter resumes,
Space previews the conversation so you can confirm it is the right one before
committing, and typing anything filters the list. Ctrl+R renames the
highlighted session. By default you see sessions from the current worktree;
Ctrl+W widens to every worktree of the repository, Ctrl+A to every project on
the machine, and Ctrl+B narrows to the branch you are on.
Name them, and treat them like branches
An unnamed session is not anonymous — it gets a display name from the directory, and Claude writes it a short generated title based on your first prompt. Both are labels for the picker. Neither is something you can resume by.
A name you set yourself is. Give one at startup with claude -n auth-refactor,
or at any point during a session with /rename auth-refactor. Now
claude --resume auth-refactor takes you straight back to it.
Once naming is cheap, a habit becomes available that changes how the whole thing
feels: one named session per workstream. The migration lives in
db-migration, the bug you are chasing lives in flaky-upload-test, the feature
lives in saved-searches. Each keeps its own accumulated context, and you move
between them the way you move between git branches, rather than dragging three
unrelated tasks through one conversation and wondering why the answers got
worse.
You typed: claude --resume
Output: saved-searches 2 hours ago feat/saved-searches 184 KB flaky-upload-test yesterday main 41 KB Refactor the tag parser 3 days ago main 302 KBWhyThe first two were named. The third is a generated title from its first prompt — readable, but you cannot resume it by typing that. Naming takes three seconds and this is the moment you wish you had.
You typed: Where did we get to on the schema?
Claude replied: We added the saved_searches table and its migration, and the tests pass. Still outstanding: the two routes and the broken-filter behaviour from SPEC.md.
WhyIt knows this because the resumed session restored the whole conversation, including every tool call and result — not a summary of it.
You typed: Before we do the routes, I want to try serving them from the existing search controller instead of a new one. Fork this first.
Claude ran: /branch routes-in-search-controller
Output: Branched to routes-in-search-controller (a1f4…) Original session saved (7c02…)WhyTwo ids: the copy you are now in, and the original, untouched, still in the picker. If the experiment is a mess you abandon this branch and resume the other. Nothing was risked.
Resume or fork
These two look similar and are not.
Resuming reopens a session under the same id and appends your new messages to the existing conversation. One conversation, longer.
Forking copies the history so far into a new session id and leaves the
original exactly as it was. Two conversations, sharing a past. From inside a
session that is /branch, optionally with a name; from the command line it is
--fork-session alongside --continue or --resume.
Fork when you are about to try something you might want to walk away from. The value is not the copy, it is the original — being able to return to the state of mind you had before the experiment, with a context window that never heard about it.
One difference worth knowing: /branch keeps running in the same process, so
permissions you granted for the session still apply in the branch. Forking from
the command line starts a new process, which begins without them, and you
approve things again there.
There is a second command in this area, and the names are close enough to be
worth separating carefully. /branch copies the conversation and moves you into
the copy. /fork copies it and leaves you where you are, sending the copy off
to run as a background session alongside you — it inherits the model, the
permission mode and the grants you have already given, and shows up as its own
row in claude agents. Give it a prompt, as in /fork open a draft pull request for the work so far, and it starts immediately; give it nothing and it waits.
The two conversations are independent from that moment on.
So: /branch when you want to try the other approach yourself, /fork when you
want it tried without your attention. A third, /subtask, hands a side task to
a subagent that reports back into this conversation rather than becoming a
session of its own. These names were rearranged fairly recently, so if /fork
on your machine reports back instead of going away, you are on a version where
it did what /subtask does now.
They belong to a directory
Sessions are stored per project directory, which is why --continue needs you
to be in the right place and why the picker shows what it shows.
Switching git branches inside a session does not confuse it in the way people expect. Claude reads files fresh, so after a checkout it sees the new branch's files, while the conversation carries on as before. It remembers what you were discussing; it just looks at different code. What you cannot do is run two sessions on two branches in the same directory, because there is only one working tree. That is what git worktrees are for, and there is a lesson on them in the final part of the course.
What is actually on disk
Nothing here is magic or remote. Claude Code writes transcripts as JSONL —
plaintext, one JSON object per line, a line per message, tool use or metadata
entry — under ~/.claude/projects/, in a subdirectory named after the working
directory path with the awkward characters replaced by dashes.
Three consequences.
It is inspectable. You can look, count, grep, and back it up. Old conversations are files, not cloud state.
It is readable by anything on your machine. If you pasted a production credential into a prompt, it is now sitting in a plain-text file. Transcripts are cleaned up after thirty days by default, and that period is a setting, but until then they are there. This comes up again in the security lesson.
And it is not an API. The entry format is internal to Claude Code and
changes between releases, so a script that parses these files will break on some
random Tuesday. When you want a conversation out, run /export to copy it or
write it to a file as readable text, optionally passing a filename to skip the
menu.
What resuming does not bring back
Being precise about this saves a puzzling ten minutes. A resumed session restores the conversation, the model it was using, its permission mode, and the agent it was running as, with a couple of deliberate exceptions: plan mode is never restored, and neither is the mode that skips permission checks entirely. Both have to be asked for again on purpose.
Configuration you passed as flags at launch is not remembered either. If the session depended on extra directories, a settings file, an MCP configuration or a plugin directory given on the command line, pass those again when you resume. Anything living in your settings files is re-read at startup and needs no help.
Finally, avoid resuming the same session in two terminals at once without forking. Both write to one transcript and the messages interleave, which is exactly as confusing to read afterwards as it sounds. If you want two, fork.
What to take away
A session is a saved conversation tied to a directory, written to disk as you
go, and every new one starts with an empty context window — so anything that
must persist between them belongs in a file. Get back into one with --continue
for the most recent, --resume for the picker, or /resume from inside another
session, and name them so each workstream has a handle you can return to.
Resuming appends to the same conversation; forking with /branch copies it and
leaves the original safe, which is what makes risky experiments cheap, while
/fork makes the same copy but runs it in the background instead of switching
you into it.
Transcripts are plain JSONL on disk, so treat them as both convenient and
readable by anyone with your laptop.
Next: git — letting Claude stage, commit, branch and open pull requests, and where your responsibility for that work begins.
Check yourself
5 questions · pass 4/5 to unlock Git, Commits and Pull Requests
1.You finish work, close the terminal, and open Claude Code in the same project tomorrow. What does it know?
2.What is the difference between resuming and forking a session?
3.Which command resumes the most recent session in the current directory without asking you anything?
4.Why is naming sessions worth the small effort?
5.Session transcripts are stored as plaintext JSONL on your machine. What follows from that?
5 left to answer