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 work unchanged, a crash or a reboot should produce the same result.
Two things carry that guarantee. This page covers the journal — what lands on disk and how it comes back. The daemon covers the other half: agents that never stopped running in the first place.
What gets persisted
Every interesting piece of state lands on disk under ~/.atrium/:
- App-level state (
state.json) — which projects are open, which project is focused, window geometry. - Per-project snapshots (
workspaces/{id}/workspace.{timestamp}.json) — project 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 — project 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 projects and the focused one. - Load each project'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 project 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. A setting (and a toggle on the chooser itself) lets you skip the chooser and auto-relaunch your last session on every launch, if you'd rather always pick up exactly where you left off.
Lazy pane mount
Inside a running project, atrium lazy-mounts panes at two levels:
- Project level — panes in a project other than the active one aren't mounted at all until you switch to that project. Their snapshots are loaded into atoms, so the layout previews are correct, but their React components don't run.
- Room level — within the active project, 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 project 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.
- Terminal panes apply the adapter's
launch.resumeFlag— for Claude Code and Codex this is--resume <session-id>; other adapters use their own convention. Chat panes resume over their transport instead, and never shell out to a--resumeflag. - 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.
This gives agents the same survivability as plain terminals: your conversation history is preserved, not just the terminal scrollback.
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 project 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 project, 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 (project 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 project 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 project plus a tasks.db exporter (VACUUM INTO). This makes snapshots cheap to take, fast to diff, and trivially deduplicated — re-snapshotting an unchanged project is essentially free.
Manually clearing state
- Remove a specific project: 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.