Analyzed: March 31, 2026 leak snapshot
This page covers persistence mechanics. It is separate from the live in-memory app state described in the session-state page.

Three persistence classes

The source separates persisted state into three broad classes:
  • durable config and project metadata
  • session transcripts and resume data
  • session-only process flags that never hit disk
Understanding that split is critical. Many runtime behaviors feel “persistent” in the UI but are intentionally session-only in code.

Session transcript persistence

src/utils/sessionStorage.ts is the core session-persistence layer. It handles:
  • storing transcript and log entries
  • loading sessions for resume and continue flows
  • restoring side-state from log snapshots
  • extracting todo state from the transcript when needed
The source comments make the design intent explicit: resume should rebuild session reality from the authoritative log rather than from a bag of unrelated caches.

What gets reconstructed on resume

restoreSessionStateFromLog() restores more than message history. Visible restore paths include:
  • file history snapshots
  • attribution state
  • context-collapse persistence
  • todo state for non-v2 todo flows
There is also logic to restore agent selection and to re-derive agent definitions after mode switches. So a resumed session is not simply “load old messages and continue.” It is a partial reconstruction of operational state.

Session IDs and project scoping

Bootstrap state in src/bootstrap/state.ts carries:
  • sessionId
  • optional parentSessionId
  • stable project root
  • optional session project directory override
That points to an important persistence property: session identity and project identity are related, but they are not the same thing.

Session-only state

Several pieces of state are intentionally non-persistent in the source. Examples include:
  • session-only trust acceptance
  • session-only bypass-permissions mode
  • session-only scheduled tasks
  • session-created teams
  • prompt-cache latches
  • in-memory error logs
  • some bridge and remote-control runtime flags
This matters because it defines what a resume can and cannot faithfully recreate. If a feature is implemented as a session-only flag in bootstrap state, it will disappear when the process ends.

Configuration persistence versus session persistence

src/utils/config.ts and src/utils/settings/settings.ts handle durable config, not transcript persistence. Those layers store:
  • global config
  • per-project config
  • settings from multiple sources
  • project-level stats and metadata
  • MCP server config
That data survives independently of any one conversation session.

Project config examples visible in source

ProjectConfig in src/utils/config.ts includes fields such as:
  • allowed tools
  • MCP context URIs
  • MCP server config
  • last-run metrics and usage summaries
  • trust-dialog acceptance
  • worktree-session state
  • disabled and enabled MCP server lists
This is operational metadata attached to the project, not to a single transcript.

Global config examples visible in source

GlobalConfig carries user-level settings and metadata such as:
  • onboarding state
  • theme
  • preferred notification channel
  • oauth account info
  • editor mode
  • diff tool choice
  • auto-update metadata
  • connected Claude.ai MCP connectors
This is closer to user profile and installation state than conversation state.

Resume is intentionally selective

A useful takeaway from the source is that Claude Code does not try to serialize every live field in AppState. Instead it persists:
  • the transcript and structured log stream
  • enough snapshots to reconstruct key operational subsystems
  • durable config in separate config files
That keeps persistence more maintainable, but it also means some UI and runtime state is necessarily best-effort after resume.

Practical interpretation

When debugging “why didn’t this persist,” the right first question is: “Was this implemented as config, transcript-derived state, or a session-only runtime flag?” The source is consistent enough that this usually answers the problem quickly.