Sessions & Checkpoints

Every conversation you have with Command Code is a session: a durable transcript on disk that you can resume, rename, fork, clone, rewind, share, and export. Close your terminal mid-task, come back tomorrow, and pick up exactly where you left off.

A session is a single append-only JSONL file — one JSON record per line. The first line is a header (session id, creation time, working directory); every line after it is an entry: your messages, the model's replies (with token usage and cost), model and effort changes, compaction summaries, and more.

Entries form a tree, not just a list. Each entry points at its parent, so a session can hold multiple branches of the same conversation — this is what powers /rewind, /tree, and forking. The file itself is never rewritten in place: navigating history just moves a pointer, and new entries are appended.

Where session files live

Sessions are stored per project, keyed by a slug of the working directory:

~/.commandcode/projects/<project-slug>/<session-id>.jsonl

Because the catalog is project-scoped, /resume and --continue only ever see sessions from the directory you launched Command Code in.

Alongside the transcript, a session can have sidecar files:

FileContents
<id>.jsonlThe transcript itself (header + entries)
<id>.meta.jsonTitle, model, lineage, trace ids, compaction stats
<id>.share.jsonShare link state, if the session was shared
<id>.checkpoints.jsonlCheckpoint snapshots for /rewind
<id>.prompts.jsonlPrompt history

Finding the current session file

# In Command Code session /session-file

/session-file prints the current session id and the absolute path of its transcript. In terminals that support hyperlinks the path is clickable. If you haven't sent a message yet you'll see a (not created yet) note — the transcript is created on the first save.

Sessions are designed so you never lose committed work:

  • Per-turn commit: Every completed turn is appended to the transcript as it commits — not on exit. Kill the process mid-run and everything up to the last committed turn is on disk.
  • A turn either commits or is lost: There is no torn state: an interrupted turn simply doesn't make it into the file, and the session resumes cleanly from the previous commit.
  • User messages survive failed turns: If a turn dies on a model/API error, your message that opened it is still written to disk — so a session that errored on its very first turn still shows up in /resume.
  • Empty sessions leave no file: A brand-new session buffers in memory until the first assistant reply, so opening Command Code and quitting without a real exchange doesn't litter your session catalog.
  • Torn files never block startup: If a transcript is damaged, corrupted lines are skipped and the session still loads.

In a session: /clear

# In Command Code session /clear

/clear starts a new session with empty context. The previous session stays on disk, fully resumable with /resume. /new is an alias — same command, same menu row.

At launch

FlagWhat it does
-n, --name <name>Set the new session's display name at startup
--no-sessionDon't persist the session to disk at all (in-memory only)
cmd -n "auth refactor" # named session cmd --no-session # throwaway session, nothing written to disk
Note

--no-session sessions never appear in /resume and leave no transcript. Use them for experiments you explicitly don't want in your history.

The resume picker

# In Command Code session /resume

/resume (alias /sessions) opens the session picker — the same picker you get from cmd -r with no argument. It supports search, renaming (without leaving the picker), deleting sessions, and filtering by the git branch a session was started on. Forked sessions show their provenance (fork of <parent>), and the session you're currently in is highlighted and can't be deleted.

Two kinds of sessions are hidden from the picker:

  • Headless (cmd -p) sessions — they carry no title and stay out of the picker and --continue, but an exact session id still resumes them.
  • In-memory (--no-session) sessions — they were never written to disk.

At launch

FlagWhat it does
-r, --resume [name]Resume a session by id or name; with no argument, open the picker
--sessions [name]Alias of --resume
-c, --continueContinue the most recent session in the current directory
--session <path|id>Resume by transcript path (.jsonl) or a unique session-id prefix
--fork-sessionWith --resume/--continue/--session: fork the resolved session into a new one, leaving the original untouched
cmd -r # open the resume picker cmd -r "auth refactor" # resume by name (or id) — id is tried first, then a case-insensitive title match cmd -c # continue the most recent session here cmd --session 3f9a # unique id prefix cmd --session ~/exported/session.jsonl # a transcript file directly cmd -c --fork-session # branch off the latest session without touching it

A --session path inside the current project resumes like -r; a path outside it keeps appending to that file where it is.

Model restored on resume

The model a session was using is stored in its meta and adopted when you resume. An in-session /resume always adopts the resumed session's model (clearing any --model launch override so the resumed model wins); a cold cmd -r adopts it unless you explicitly passed --model for that launch.

Three commands let one conversation become many. They differ in what comes with you:

original session A ── B ── C ── D ← you are here └─ B' ── C' ← an older branch /fork whole tree + checkpoints ┌─────────────────────┐ ABCD │ └ B' ─ C'/rewind works └─────────────────────┘ /clone active branch only ┌─────────────────────┐ ABCD/rewind empty └─────────────────────┘ /tree no copy — jump anywhere in the tree you already have

/fork [name] — copy everything

# In Command Code session /fork /fork payments-experiment

/fork copies the entire session — the full tree with every branch, plus checkpoints and file backup history, so /rewind keeps working in the fork — into a new session and switches to it. The original is left untouched and resumable.

Lineage is recorded on the fork's meta: parentSessionId (the source session) and branchPoint (the stable message id of the last source message at the fork point), so the picker can render fork of <parent> provenance. Names are optional (up to 200 characters) and must be unique.

/clone — copy the current branch only

# In Command Code session /clone

/clone duplicates just the active branch of the conversation (from the current point back to the root) into a brand-new session file and switches into it. Unlike /fork, checkpoints and file history are deliberately not copied — a clone is "duplicate the conversation", and /rewind in the clone legitimately starts empty. The new file's header records the source transcript as its parentSession.

/tree — browse the whole tree

# In Command Code session /tree

/tree opens the session-tree navigator: every branch of the session, not just the active one. From there you can jump to any point in the tree, fold segments, search, attach labels to entries, and cycle display filters (default, no-tools, user-only, labeled-only). When you navigate away from a branch, Command Code can generate a branch summary so the work you're leaving behind stays findable — you can confirm, customize, or skip the summary (and set a default in /config).

CommandWhat it does
/rename <name>Rename the current session; bare /rename auto-generates a title with the model
/nameAlias of /rename; bare /name shows the current name
/session-fileShow the current session id and transcript path
/statusShow comprehensive environment status
/traceCopy the current OpenTelemetry trace id (for support); works mid-turn, and persisted trace ids survive resume

Names must be unique within a project — renaming to a taken name is rejected. The name also becomes your terminal tab title, and it's what -r <name> resolves.

Every prompt you send opens a checkpoint: a snapshot of the conversation plus a backup of every file Command Code goes on to edit. If something goes off track, rewind to any earlier checkpoint and continue from there.

Opening the rewind UI

Press Esc twice within 500ms, or run:

/rewind

Each row in the selector shows when the checkpoint was taken, a preview of the message that opened it, and how many files that checkpoint changed (or No code changes).

Restore modes

ModeWhat it restores
BothRestores conversation and code together (recommended).
Conversation onlyRemoves messages after the checkpoint. Files are untouched.
Code onlyRestores files to their state at the checkpoint. Conversation is untouched.

Checkpoints with no file changes only offer Conversation only.

Note

Rewinding removes the messages after the checkpoint and the checkpoint itself — you land before the message that opened it. The context token count updates to reflect the shorter conversation.

Note

Rewinds persist. If you rewind and then quit, the rewound state is what you'll see when you resume the session later — it isn't a preview.

What a file rewind does to your working tree

A Code only or Both rewind doesn't just undo edits — it puts the tree back the way it was:

If a file was…After the rewind
Modified after the checkpointRestored to its contents at the checkpoint
Created after the checkpointDeleted — it didn't exist at the checkpoint
Deleted after the checkpointRestored

Backups are taken before each write_file or edit_file call and replayed newest-first, so a run of edits to the same file lands back on its oldest state. Backups are byte-faithful, so binary files (images, compiled artifacts) survive a backup–restore round-trip unchanged — no special handling needed.

Restores are verified before they run

Command Code checks every backup in the set can actually be restored before writing anything, so a rewind either applies in full or not at all — it won't leave you half-restored. If a file can't be restored, you're told which one and why.

Limits and pausing

Checkpoints are kept for 30 days, capped at 200 backups per session. Backups live in ~/.commandcode/file-history/<session-id>/, and identical content is stored once no matter how many checkpoints reference it.

Note

File backups are capped at 10MB per file. An oversized file is never read or backed up — and because it was never captured, a rewind leaves it exactly as it is rather than deleting it. Once a session hits the 200-backup cap, or 30 days pass, older checkpoints age out.

Warning

If the disk runs low, checkpointing pauses for the whole session rather than silently degrading file by file, and you'll see a notice. Checkpoints already taken stay usable, and checkpointing resumes on its own — with a second notice — once enough space is free.

Each session gets a scratchpad: a per-session temporary workspace for intermediate files — analysis notes, throwaway scripts, generated data — that don't belong in your project.

/tmp/commandcode-<uid>/<sanitized-cwd>/<session-id>/scratchpad
  • Silent access: Reads and writes inside the scratchpad need no permission prompts (explicit deny/ask rules still take precedence). The path is advertised in the system prompt and exported to shell commands as $COMMANDCODE_SCRATCHPAD.
  • Shared with sub-agents: Every sub-agent in the session sees the same directory, so agents can hand intermediate results to each other by file name.
  • Survives compaction: After history compaction, a bounded metadata-only manifest of the scratchpad is re-injected, so the model remembers which working files still exist on disk without re-reading them.
  • Follows launch-time forks: Forking at launch with --fork-session copies the source session's scratchpad into the fork, so the branched conversation keeps its working files.
  • Cleaned up with retention: Scratchpads older than 30 days are swept, and deleting a session deletes its scratchpad. It's temp space — keep durable deliverables in the project itself.

The whole tree can be relocated with the COMMANDCODE_SCRATCHPAD_BASE environment variable. Provisioning is fail-open: if the scratchpad can't be created safely, the feature silently disables and the session runs normally without it.

Disable it entirely in settings.json:

{ "disableScratchpad": true }

# In Command Code session /share

/share uploads the conversation, copies a share URL to your clipboard, and — this is the key part — keeps the shared page live: every turn committed after sharing is streamed to the link automatically. Resuming a previously shared session re-arms the live updates. Run /share again to re-copy the existing link.

# In Command Code session /unshare

/unshare deletes the share and stops the live updates.

/share gist — GitHub gist

# In Command Code session /share gist # secret gist, default format (html unless configured) /share gist md # markdown /share gist jsonl # raw transcript

/share gist [html|jsonl|md] renders the session and posts it as a secret GitHub gist via the gh CLI, then copies the gist URL. The default format comes from /config's "Default share gist format" setting.

/export — write a file

# In Command Code session /export # default format to a generated filename /export md # pick a format: html | jsonl | md /export ~/notes/session.html # or a path; the extension picks the format

With no path, the file is written as command-code-session-<first 8 chars of id>.<format> using /config's "Default export format" (html when unset). jsonl exports the raw transcript.

/copy — clipboard

# In Command Code session /copy

/copy copies the last assistant reply to the clipboard. Best-effort: in headless/SSH terminals without clipboard access, the feed line tells you it couldn't.

When the conversation approaches the context limit, Command Code compacts history (automatically, or on /compact). Two guarantees matter for sessions:

  • The on-disk log is never rewritten: Compaction appends a compaction entry (the summary plus a pointer to the first entry kept verbatim) to the transcript tree. Your full history stays in the file — context building just reads through the compaction entry, and /tree can still reach everything.
  • Savings persist across resumes: Cumulative compaction stats (event count, total tokens saved, last event) are written to the session's meta on every compaction, so the "total this session" figure /compact reports survives --resume.
Complete guideContext & Compaction

What compaction does to the transcript, the tiers and their thresholds, /compact and /compact-mode, and how to keep context lean.

  • One picker, not two. /resume and /sessions open the same unified picker rather than separate interactive/print views, so there's one mental model for "where are my sessions."
  • Rewind is destructive on purpose, but reversible. Restoring is instant and irreversible in the moment, but because it's just moving between checkpoints, you can rewind forward again if you change your mind.
  • Print sessions are real sessions. They're saved and resumable, just hidden from the picker by default — automation output doesn't have to mean throwaway state.

Checkpoints not appearing

  1. Ensure you've sent at least one message in the session
  2. Check if checkpointing is paused (you'll have seen a disk-space notice)
  3. Verify the session has file modifications — a checkpoint with no file changes only offers a conversation restore

Restore failed

  1. Check the error message for which file failed
  2. Ensure backup files haven't been manually deleted from ~/.commandcode/file-history/
  3. Verify you have write permissions to the target files

Double-Esc not working

  1. Press Esc twice within 500ms
  2. Ensure focus is on the Command Code input
  3. Use /rewind instead

  • Name sessions you'll come back to: /rename auth-refactor (or launch with -n) makes cmd -r auth-refactor a one-liner later — and a bare /rename will generate a decent title for you.
  • Fork before risky experiments: cmd -c --fork-session or /fork gives you a full copy — checkpoints included — while the original stays pristine.
  • Use /clone to tidy up: After heavy rewinding, /clone extracts just the branch you kept into a clean new session.
  • Label important points in /tree: Labels survive forks and make long trees navigable.
  • Let the scratchpad absorb clutter: Ask for throwaway scripts and intermediate outputs in the scratchpad — no permission prompts, no files polluting your repo, and it's cleaned up automatically.
  • /share before pairing: The link updates live as the session continues, so a teammate can follow along in real time.
  • Grab /trace when something breaks: The trace id is what support needs, it's copyable mid-turn, and past ids survive a resume.