Persistence & recovery
How atrium journals state and restores after quits, crashes, and reboots.
atrium's durability guarantee is simple: if you can quit and reopen the app and see your workspace unchanged, a crash or a reboot should produce the same result.
What gets persisted
Every interesting piece of state lands on disk under ~/.atrium/:
- App-level state (
state.json) — which workspaces are open, which workspace is focused, window geometry. - Per-workspace snapshots (
workspaces/{id}/workspace.{timestamp}.json) — workspace metadata, the list of rooms, each room's mosaic tree, every pane's snapshot (type, cwd, scrollback, session IDs, editor buffer state, browser URL and history, per-note viewport state for notepad panes). - Configuration (
config.json) — theme, keybinding overrides, terminal and markdown editor settings, telemetry preferences, LSP overrides, worktree defaults. - Tasks and runs (
tasks.db) — SQLite database with cards, statuses, labels, comments, runs, segments. - Reviews (
review.db) — SQLite database with diff-review comment threads, attribution, and state changes. - Themes (
themes/*-custom.json) — user-created custom themes. - Adapters (
adapters/<name>/) — installed adapter manifests and scripts. - Snapshots (
snapshots/) — a content-addressed git-style repository of point-in-time state captures (see Snapshots & Vault below).
How journaling works
atrium does not wait for you to hit save. The backend writes through three layers:
- Dirty tracking — every state mutation bumps a dirty flag. A heartbeat writer checks the flag and skips writes when nothing changed.
- Atomic writes — snapshots are written to a temp file and renamed. Partial writes are impossible on a crash because the rename is atomic at the filesystem level.
- Timestamped rotation — workspace snapshots are written with timestamps, and multiple recent timestamps are retained. If the latest snapshot is corrupt, atrium can fall back to the previous one.
0600, state files and directories are 0700.
Restoring on launch
On launch:
- Read
state.jsonto find open workspaces and the focused one. - Load each workspace's most recent snapshot from
workspaces/{id}/. - Rebuild the mosaic tree for each room.
- Materialize each pane:
While the app starts, the launching screen shows live restore progress with the workspace currently being rehydrated and a per-step status. If a step hangs for more than a few seconds the screen surfaces a stuck? reload escape hatch — clicking it triggers a fresh launch instead of leaving you staring at a spinner.
The RestoreChooser is the recovery UI shown when atrium detects that the last exit was unclean. It lists rooms and panes with running-process indicators so you can choose which to restore.
Lazy pane mount
Inside a running workspace, atrium lazy-mounts panes at two levels:
- Workspace level — panes in a workspace other than the active one aren't mounted at all until you switch to that workspace. Their snapshots are loaded into atoms, so the layout previews are correct, but their React components don't run.
- Tab level — within the active workspace, only the panes in the focused room (and a small window of recent rooms) are mounted. Panes that scroll off the focused room remain in the workspace atoms; their components remount when the room becomes active again.
Agent session resume
Agent panes go through an extra step:
- atrium looks up the pane's stored session ID.
- The adapter's
launch.resumeFlagis applied — for Claude Code this is--resume <session-id>, for Codex it is--resume <session-id>, for Gemini it is its own convention. - The adapter's session store is checked (for example Claude's
~/.claude/history/); if the session is not found, atrium stops and marks the paneresume failedinstead of silently starting a fresh session.
What does not resume
- Unsaved editor buffers are flushed to disk on close; there is no separate unsaved-buffer journal.
- In-flight HTTP requests and long-running foreground shell commands (not adapter-managed) do not resume — the command finishes or is killed when the process dies. The pane records the last command so the activity sidebar can offer a Replay action.
- Browser pane cookies do not carry over across CEF engine upgrades (for example, moving from WKWebView to Chromium). Sign-ins made before the upgrade must be redone once.
- Reaped adapter sessions — when restoring a workspace whose adapter session ID has been garbage-collected by the adapter (Claude's
~/.claude/history/, Codex's local state), atrium fresh-launches a new session in that pane instead of leaving it stuck trying to resume. Any launcher overrides you'd configured (per-pane YOLO mode, custom flags, env vars) are re-applied to the auto-resumed session so the fresh launch matches the original launch's profile.
Snapshots and Vault
Above the per-write snapshot rotation sits a second-tier history: a content-addressed snapshot repository at ~/.atrium/snapshots/ that captures the full state of every workspace, the tasks database, and configuration as a single commit. The Library surfaces this history as the Vault.
A snapshot is committed when any of the following triggers fires:
- Interval — every 30 minutes when state has changed since the last commit.
- Shutdown — on clean exit, after the final state flush.
- Pre-update — before
tauri-plugin-updaterinstalls a new build. - Pre-restore — automatic safety net before the user restores from any earlier snapshot.
- Manual — when you click Take snapshot now in the Vault.
- Event — when something destructive happens (workspace deleted, settings reset, bulk-delete from the Library).
Interval, Shutdown, event-driven) no-op when the canonical state hash matches the previous snapshot. User-initiated and safety-net triggers always commit. A retention engine prunes old snapshots according to a tiered policy (more recent commits kept densely, older commits sparsely).
Restoring from a snapshot opens a restore dialog that semantically diffs the snapshot against current state — file by file for workspace JSON, row by row for tasks.db — so you can preview exactly what will change before confirming. A pre-restore snapshot is committed first, so the restore is itself reversible. A shutdown gate prevents the app from exiting mid-snapshot.
The on-disk format is intentionally git-shaped: each snapshot is a commit referencing tree objects for each workspace plus a tasks.db exporter (VACUUM INTO). This makes snapshots cheap to take, fast to diff, and trivially deduplicated — re-snapshotting an unchanged workspace is essentially free.
Manually clearing state
- Remove a specific workspace: delete its directory under
~/.atrium/workspaces/{id}/. - Reset all app state but keep configuration:
rm -rf ~/.atrium/workspaces ~/.atrium/state.json. - Full reset:
rm -rf ~/.atrium. This deletes configuration, snapshots, the Vault history, custom themes, installed adapters, and task data.
