Skip to main content

Persistence and Restore

What Daintree persists across a restart and how it comes back: panel layout, terminal scrollback serialization and its limits, the restore banner, typed drafts, where it is all stored, and how to turn it off.

Reviewed

What survives a restart

Daintree saves workspace state to disk and restores it the next time you open the project. This happens on its own; there is nothing to turn on.

Per terminal

  • Scroll buffer: serialized to disk and replayed on reopen.
  • Panel arrangement: which panels are open, where they sit in the grid, and their sizes.
  • Custom panel names: a name you set by double-clicking a tab title or through Rename in the context menu comes back, and keeps precedence over whatever title the terminal or agent would otherwise set.
  • Typed but unsent drafts: see below.
  • Launch environment: the environment the panel was launched with, so a restored agent comes back on the same provider.

Per project and per app

  • Active worktree, and which terminal had focus in each worktree
  • Sidebar width, window position, size, and maximized or fullscreen state
  • Portal tabs, links, default target, and width
  • Per-panel resize ratios
  • Focus mode state (see Terminals & Panels)
Note
Restored sessions keep their provider. The environment resolved at launch (from a preset, a recipe, or the caller) is captured in the panel snapshot and replayed on respawn in preference to re-resolving the preset. That matters when a preset points an agent at an alternative endpoint: without the captured environment, a preset that has since changed or been deleted would silently bring the agent back on the default provider instead of the one it was running on.

Scroll buffer serialization

Each terminal's scroll buffer is serialized with xterm's serializer and written to a .restore file. The file carries a version header and the <cols>x<rows> grid it was captured at, so the replay is parsed at the geometry it was written for rather than reflowed against whatever the panel happens to be now.

When a snapshot is taken depends on what's running in the terminal:

  • Plain terminals debounce: Daintree waits five seconds after output settles, then writes.
  • Agent panes skip the debounce entirely and write on agent-state settles instead (waiting, completed, exited), throttled to at most one write every two seconds, with a final flush when the terminal is killed. An agent's meaningful moments are its state transitions, not a gap in output.

Terminals under 1,000 lines serialize synchronously. Larger buffers use an async path that yields to the event loop, so serializing a full agent buffer doesn't stall the PTY host during an active run.

The restore banner

When a terminal is reopened, its .restore file is replayed and a dim separator marks the top of the restored content. The timestamp is the snapshot's own, formatted YYYY-MM-DD HH:MM:

  • ─── Session restored · <timestamp> ───, a normal restore.
  • ─── Restored · <timestamp> · previous session was in a full-screen app ───: the terminal was in a full-screen program such as vim or htop when the snapshot was taken.
  • ─── Session hibernated · <timestamp> · auto-suspended to save resources ───: the project's memory was reclaimed while it was in the background, by Free memory or by idle auto-close. The scrollback is still replayed; the banner tells you why the process behind it is gone.

Serialization limits

Daintree keeps up to 5 MB of serialized scroll buffer per terminal. At roughly 250 bytes per line including ANSI color codes, that is around 20,000 lines, comfortably above an agent terminal's 10,000-line ceiling in ordinary output, but not by the margin the number suggests. Densely colored output (a full-color diff, verbose logging with escape sequences) pushes well past 250 bytes a line and can bring a long agent buffer within reach of the cap.

For the scrollback line limits themselves, and where to change them, see Terminals & Panels.

Note
If a terminal's serialized scroll buffer exceeds 5 MB, Daintree skips saving it. No error is shown. If a terminal isn't restoring its previous output, dense ANSI output from the prior session is the most likely cause, and lowering the scrollback setting reduces the amount serialized.

Drafts

Text you've typed into a terminal's input but not sent survives a window close. Drafts are flushed when the view tears down and persisted with the project's state, using the same merge-safe delta contract as the layout: each window sends what it changed against its own last-acknowledged baseline, so two windows open on the same project merge rather than overwrite each other.

Scratch workspaces

A scratch workspace persists and restores its panel grid the same way a project does. Scratches get a state directory in the same namespace as projects (a scratch id can never collide with a project id), so they inherit the whole atomic-write, quarantine and recovery machinery rather than a parallel, less-tested version of it. Terminals in a scratch are journaled under the scratch id, so their sessions are resumable too.

Storage and eviction

Daintree manages the terminal-sessions/ directory inside its app data directory on its own:

  • 30-day TTL: session files older than 30 days are deleted on startup.
  • 100 MB total cap: if the directory exceeds 100 MB, the oldest files are evicted first.
  • Orphan cleanup: files for terminals that no longer exist are removed on startup, along with any leftover temporary files from an interrupted write.
  • Panel removal: deleting a terminal panel removes its .restore file. For agent panels that happens after the 20-second trash window closes, not the moment you close the panel.

Disabling persistence

To turn terminal session persistence off entirely, set DAINTREE_TERMINAL_SESSION_PERSISTENCE=0 before launching Daintree. Only the literal value 0 disables it: any other value leaves persistence on. This is a developer escape hatch, not a regular setting.