---
title: Backup Mirror (encrypted off-machine snapshot)
---

# Backup Mirror (encrypted off-machine snapshot)

## What it is

Encrypted full snapshot of your Omniscio state — the entire database, your config, and every attachment — written to a folder you choose. Point it at a cloud-sync target (Dropbox / OneDrive / iCloud / Google Drive Desktop) and your Omniscio install can be reconstructed on a different machine after a hard-drive failure.

Unlike [Setup Backup to Gmail](setup-backup.md), which mails only your _configuration_ (projects, snippets, settings — no chats), Backup Mirror writes a **full snapshot**: every session, every conversation message, every attachment, every account record, every cron job. The archive is a single `.amcmirror` file: an AES-256-GCM-encrypted archive holding `manifest.json` + `mission-control.db` + `config.json` + `attachments/`. It is written and read as a **memory-bounded stream** — a framed container, compressed as a whole and then sealed inside a chunked AES-256-GCM envelope — so it works for a workspace of **any size**, and a database-heavy workspace makes a much smaller file than the data it holds (earlier versions assembled the whole bundle in one buffer and failed above ~2 GiB with `ERR_FS_FILE_TOO_LARGE`; archives from those versions, and mirrors written before compression was added, still restore — the header tells them apart). Point at the file from another Omniscio install with the same passphrase and you get your entire workspace back — sessions resumable, attachments intact, settings preserved.

The point is **disaster recovery + machine migration**. Setup Backup answers "I want to put my project list and snippets on a fresh laptop." Backup Mirror answers "my SSD died — give me back my whole Omniscio, conversations and all." Both can coexist; they target different failure modes.

## Where to find it

### How to use it

1. Open **Settings → Backup & Restore → Backup Mirror** (search for "mirror" in the settings search bar).
2. **Pick a folder.** Omniscio detects your cloud-sync folders (Dropbox / OneDrive / iCloud Drive / Google Drive) and offers each as a **one-click chip** — click one and Omniscio creates an `Omniscio-mirror` subfolder inside it and fills the path for you. Prefer to choose it yourself? **Browse…** opens the OS folder picker pointed at your most likely cloud folder. A bare local folder works too if you'd rather rsync / robocopy the archives yourself. (Detection is best-effort — if nothing shows up, just Browse.)
3. **Set a passphrase.** Click **Generate strong passphrase** and Omniscio makes a strong, _typeable_ one (real words, so you can re-type it on the new machine) — then copy it with one click — or type your own into **Encryption passphrase**. Either way, save it in your password manager and tick **I've saved this passphrase**: that confirm is required before your first backup, because **without the passphrase the archives are unrecoverable** — there is no recovery code, no key escrow, no per-machine override.
4. Set **Retention** (default 5). Omniscio keeps the newest N `.amcmirror` files in the folder and prunes older ones on every write.
5. Toggle **Enable backup mirror** on. From now on, every time Omniscio writes its routine local backup, it ALSO writes a mirror archive to your chosen folder — and, the **first** time you enable it, **Automatic sync** defaults to _When I open & close AMC_ so it's genuinely set-and-forget (change it any time; a returning user who set it back to Off is never overridden). The Settings panel surfaces `Last mirror: …` and `Last error: …` so you can spot a broken sync.
6. Click **Mirror now** to verify the round-trip end-to-end before trusting the schedule. The first archive lands in your folder within seconds; your cloud-sync client picks it up over the next few minutes.

To restore on a new machine, there are two paths:

- **Restore from the folder listing** — if you've already configured the mirror folder, scroll to **Restore from mirror** in the Settings panel. It lists every `.amcmirror` file in that folder. Pick one, type the passphrase, and choose a mode.
- **Restore from file** (recommended for fresh machines) — the **Restore from file** button is always visible in the Backup Mirror section, even when no mirror folder is configured. It opens an OS file picker filtered for `.amcmirror` files, previews the archive manifest (size, date, source hostname), and lets you choose **Replace** or **Merge** mode. This is the primary path for the "just bought a new computer" migration scenario — copy your `.amcmirror` file onto the new machine by any means (USB, cloud drive, email), then browse to it.

See [Restore flow](#restore-flow) below for the difference between Replace and Merge modes.

### Settings keys

| Key                                   | Type    | Default | Purpose                                                                                                                              |
| ------------------------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `backupMirrorEnabled`                 | boolean | `false` | Master toggle. When off, no mirror writes run regardless of other state — automatic sync, the local-backup mirror and the manual buttons all refuse. |
| `backupMirrorPath`                    | string  | `''`    | Absolute path to the folder where mirror archives are written. Empty disables the list endpoint.                                     |
| `backupMirrorPassphrase`              | string  | `''`    | The encryption passphrase. Stored safeStorage-encrypted with the `enc:` prefix; never crosses IPC outward.                           |
| `backupMirrorRetentionCount`          | number  | `5`     | Newest N archives to keep. After every successful write the older ones are pruned.                                                   |
| `lastBackupMirrorAt`                  | string  | `''`    | ISO timestamp of the most recent successful mirror write. Surfaces in the Settings panel.                                            |
| `lastBackupMirrorError`               | string  | `''`    | Error message from the most recent failed mirror write. Cleared on the next success. Surfaces as a red banner in the Settings panel. |
| `backupMirrorAutoSyncMode`            | string  | `'off'` | Automatic sync: `off` (manual only) · `session` (pull on launch + pull-then-push on quit) · `scheduled` (also on a timer). Every mode additionally requires the master toggle + a folder + a passphrase. |
| `backupMirrorAutoSyncIntervalMinutes` | number  | `180`   | Interval for `scheduled` mode (clamped 60–1440). Sub-hourly disallowed — a snapshot is ~1–3 GB before compression.                   |
| `lastBackupMirrorAutoSyncAt`          | string  | `''`    | ISO timestamp of the last successful automatic sync. Surfaces as "Last synced …".                                                    |
| `lastAutoSyncPulledMirrorId`          | string  | `''`    | Internal: newest archive id observed at the last auto-sync (drives the pull short-circuit + "new work available"). Not user-set.     |
| `lastPushedMirrorChangeMarker`        | string  | `''`    | Internal: DB change fingerprint captured at the last auto-push (drives the push short-circuit). Not user-set.                        |

## How it behaves

### Sync now (one-button, two-device workflow)

Backup Mirror's snapshots also power a lighter everyday flow: keeping **two devices you own** roughly in step without the full setup-and-restore dance. The **Sync now** button (the primary action at the top of the Backup Mirror actions) does both directions of a sync in one click:

1. **Pull** — it scans your mirror folder for the newest archive written by your _other_ device (identified by the source `hostname` in each archive's manifest) and **merges** its work into this device: the sessions and messages you don't already have, **plus the projects those sessions belong to** (and any other active projects that device has). The merge is additive — it only ADDS what's missing here, never overwrites a project or session you already have, and needs no restart. Your own archives in the folder are skipped.
2. **Push** — it then writes a fresh snapshot of _this_ device, so the other device can pull your latest work next time.

Pull runs **before** push on purpose: the push's retention prune sweeps the folder newest-first, so pulling first guarantees the other device's archive is merged before any prune could remove it.

**Requirements** (the button stays disabled until they're met): both devices point their mirror folder at the **same** synced folder, use the **same** passphrase, and run the **same** Omniscio version. When something's off, Sync now says so plainly instead of silently doing nothing — _"make sure both devices point at the same synced folder"_, _"the mirror passphrase must match on both devices"_, or _"your other device is on a different Omniscio version"_. A wrong-passphrase or still-uploading archive is skipped, not treated as a hard failure.

**Sync now vs Mirror now** — **Mirror now** only _sends_ this device's snapshot (push). **Sync now** sends _and_ merges the other device's latest (pull + push). For a single-device disaster-recovery setup, Mirror now (or the automatic write) is all you need; for working across two devices, Sync now is the one button to click when you sit down.

**It is not live sync.** It's one click per switch, not continuous, and it relies on your cloud-sync client to move the files between devices. With three or more devices, one click pulls the newest other-device archive; because every push carries this device's full history, everyone's work still propagates across the fleet over repeated syncs.

Behind the scenes: `backup-mirror:sync-now` runs `syncPullFromFolder()` (pull) then `writeBackupMirror()` (push). Each half reports independently, so a failed push never hides a successful pull, and the stored passphrase is read in the main process — it never crosses to the UI.

### What gets backed up

**Everything that matters for reconstructing your Omniscio install:**

- **The entire SQLite database** — built via `VACUUM INTO` (clean snapshot, no WAL/SHM sidecars). Includes `sessions`, `conversation_messages`, `projects`, `automations`, `recipe_schedules`, `cron_jobs`, every other table. A WAL checkpoint runs first so the snapshot includes all writes through the moment of the mirror.
- **`config.json` — your settings and non-secret preferences (provider/integration secrets are intentionally NOT portable across machines).** Projects, snippets, and app settings restore as-is. **Secrets do not travel:** the mirror writer runs `redactConfigBytesForMirror`, which strips every `enc:`-wrapped settings secret from the embedded config (provider API keys like `geminiApiKey` / `openaiApiKey` / `openrouterApiKey`, integration tokens like `notionApiKey` / `jiraApiToken`, the backup passphrases, the Firebase service-account key — ~50 in all), and the credentials it does keep (top-level OAuth tokens, `accounts[].apiKey`, Google-auth tokens) are machine-bound `safeStorage`/DPAPI `enc:` blobs that **decrypt to empty on a different machine anyway**. So after a restore on a NEW machine you **re-enter your provider keys and re-sign-in once** — exactly like the sibling [Setup Backup to Gmail](setup-backup.md) flow ("After a restore you re-sign in to Claude / Gmail / etc. once"). This is deliberate: a portable, decrypt-anywhere copy of every credential is precisely what the machine-binding exists to prevent. (The file is still `safeStorage`-encrypted at rest, and the mirror's outer AES-256-GCM is the exfil defense if it leaks.)
- **The full attachments tree** — every paperclipped image, every dragged PDF, every Office doc you've extracted. The walk pulls from `<userData>/attachments/` recursively.
- **A manifest** — `manifestVersion`, `id`, `appVersion`, `schemaVersion`, ISO `timestamp`, source `hostname`, byte counts for each section. Used by the restore preview to show you what you're about to apply before any destructive write.

- **Claude Code files from `~/.claude/`** — the global `CLAUDE.md` (cross-project rules), per-project `CLAUDE.md` files (`~/.claude/projects/*/CLAUDE.md`, project-specific instructions not stored in the repo), and per-project auto-memory trees (`~/.claude/projects/*/memory/`). These live outside Omniscio's data directory but are critical for Claude Code session context. Optional — the archive succeeds even if none exist.

- **User-authored skills from `~/.claude/skills/`** — every file under each of your skill folders (the `SKILL.md` plus any bundled scripts or assets), captured into a `skills/` section. This is a **separate** section from the Claude Code files above (which cover only `CLAUDE.md` + memory): before this, skills rode **only** in the lighter [Setup Backup to Gmail](setup-backup.md) bundle, so a restore from the mirror alone silently dropped every skill. No size cap — skills stream like any other file (the 5 MB / 15 MB caps only exist on the emailed Setup Backup). Optional (omitted when you have no `~/.claude/skills/`); on restore, **Replace** overwrites and **Merge** keeps a skill you've edited on this machine. Rides the portable `.amcbackup` export too.

- **Global Claude config from `~/.claude/`** — your `settings.json` (permissions, hooks, model/statusline preferences), `keybindings.json` (custom shortcuts), and the `scripts/` folder (your deployed automation scripts), captured into a `global-claude-config/` section. This is a **narrow allowlist** — the backup reads only those three things and **never** touches `~/.claude/secrets/`, `.credentials.json`, `settings.local.json`, or the `amc-repo.path` pointer (all machine-bound). Optional (omitted when you have none); on restore, **Replace** overwrites and **Merge** keeps a `settings.json` you've edited on this machine. **Heads-up:** `settings.json` holds executable hooks and both it and `scripts/` can contain machine-specific paths, so give them a quick review after a cross-machine restore. Rides the portable `.amcbackup` export too.

- **File-based recipes from `~/.claude/recipes/`** — your `*.recipe.json` recipe definitions, captured into a `recipes/` section. These are the on-disk recipe files; the recipe **database** rows (schedules, metadata) already travel inside the main database — this adds the file definitions themselves, which previously rode **only** in the [Setup Backup to Gmail](setup-backup.md) bundle. Only top-level `*.recipe.json` files are captured. Optional (omitted when you have none); on restore, **Replace** overwrites and **Merge** keeps a recipe you've edited on this machine. Rides the portable `.amcbackup` export too.

- **The KMS/Nothari knowledge vault** — your user-authored notes (`.md` files) plus the `assets/` image store, walked from the user-chosen `nothariVaultRootPath` folder (which may be **external** to Omniscio's data directory). The database only stores _references_ to these files, so without the files a restore would leave every note reference dangling — this is irreplaceable content no backup captured before. Machine-local index/VCS cruft is excluded (`.kms` index DB, `.git`, `.trash` soft-delete sentinel, `node_modules`); `assets/` is kept. Optional — included only when a vault root is configured and readable at write time; on restore the notes land in **this** machine's configured vault folder (so point KMS at your vault before restoring on a new machine).

- **Per-project notes** — the free-text notes you write per project, stored as `<userData>/project-notes/<projectId>.md`. A pure file store with no database row, so before this no backup captured them — machine death silently lost them, with no dangling reference to even flag the loss. Small and irreplaceable, folded in exactly like the vault. Optional (included only when you have any); on restore, **Replace** overwrites and **Merge** keeps a note you've edited on this machine. Rides the portable `.amcbackup` export too.

- **Arij issue attachments** — files you attach to an Arij issue (images, PDFs, docs), stored on disk under `<userData>/arij-attachments/<issueId>/` (the database only holds the path). Irreplaceable user uploads that no backup captured before — a replace restore used to leave every `arij_attachments` row pointing at a missing file. Folded in like session attachments: optional (included only when you have any); on restore, **Replace** overwrites and **Merge** keeps a file already on this machine. Rides the portable `.amcbackup` export too.

- **Captured screenshots** — the snips you take, stored on disk under `<screen-recordings-root>/screenshots/` (the database only holds the file path). Small and irreplaceable, so they ride **every** mirror. On restore they land under this machine's screenshots store.

- **Screen recordings (opt-in)** — the recordings you capture, stored elsewhere under `<screen-recordings-root>/`. Irreplaceable too, but a single recording can be 1–3 GB and the bundle is assembled in memory, so they are **off by default** and only included when you turn on **"Include screen recordings"** in the Backup Mirror settings (which makes each mirror bigger and slower). Secrets remain deliberately out of scope.

- **User-imported books (Books plugin)** — the EPUB/PDF books you import into the Books shelf, stored on disk under `<userData>/plugins/books/data/books/<bookId>/` (the shelf's database rows hold only a reference to the file). Without the files a restore would leave every shelf entry pointing at a missing book. Small and re-importable from your originals, so they ride **every** mirror by default; on restore, **Replace** overwrites and **Merge** keeps a book already on this machine.

- **The google-workspace MCP audit store** — if you use the Google Workspace MCP, its `workspace.db` (a log of every Google-Doc mutation plus batch-job history, at `<userData>/google-workspace-mcp/workspace.db`) is a non-rebuildable trail the main database holds no copy of. It's snapshotted with a WAL-safe online backup. **Only the database is carried — never the sibling `credentials/` refresh token** (that re-derives when you re-authenticate with Google). Included only when the store exists.

**Not included** — the ephemera that's regenerated on restore (plus screen recordings unless you opted in above):

- WAL / SHM sidecars (`mission-control.db-wal`, `mission-control.db-shm`). The VACUUM'd snapshot is self-contained.
- Live process state. Running Claude CLI sessions don't survive — they're system-level processes pinned to the source machine. The restore sets `cli_session_id = NULL` and `force_transcript_on_next_spawn = 1` on every restored session so the next spawn uses the transcript-injection resume path (see [Resume after restore](#resume-after-restore)).
- The cloud test fleet cache (`~/.amc/cloud-fleet.json`). This is auto-discoverable from GCP via `npm run cloud:sync-fleet` and would go stale on a different machine anyway.
- Anything under `<userData>/logs/` or other diagnostic-only state.

### When it writes

There is **no separate scheduler**. The mirror write piggy-backs on the existing local backup service (`src/main/services/backup/backup-service.ts`). Sequence per local-backup tick:

1. Local backup writes `<userData>/backups/backup-<ts>.db` (the on-disk safety net).
2. If the mirror is **fully configured** — enabled **and** a folder **and** a passphrase, checked via `isBackupMirrorFullyConfigured` — **and the database has actually changed** since the last mirror write (a cheap change fingerprint, the same short-circuit the scheduled push uses; a round that carried no new data costs no write at all, and a successful piggy-back write stamps the fingerprint so the next scheduled push skips too) — Omniscio immediately calls `writeBackupMirror()` (the gated piggy-back lives in `src/main/services/backup/backup-mirror-piggyback.ts`, extracted from the backup create path). On success, `lastBackupMirrorAt` advances and `lastBackupMirrorError` is cleared. On a genuine failure it retries a few times, then logs, sets `lastBackupMirrorError`, and raises the "sync is failing" card. The local backup still succeeded — it is the primary guarantee; the mirror is the off-machine layer on top. **An enabled-but-unfinished mirror (no folder and/or passphrase) is NOT written and NOT treated as a failure** — it's an incomplete setup, so the piggy-back simply skips and a gentle "Finish setting up Backup Mirror" reminder is shown instead (see below).
3. **Manual trigger**: clicking **Mirror now** — or the push half of **Sync now** (see [Sync now](#sync-now-one-button-two-device-workflow)) — calls the same `writeBackupMirror()` path, bypassing any "too soon" gate the local backup might apply.

This means the mirror cadence inherits whatever cadence the local backup uses, so flipping the toggle is the only setting you need to think about — you don't have a separate "how often to mirror" knob to keep in sync.

**Disk-citizenship pacing.** The snapshot runs OFF the main thread (a short-lived DB host, so a slow copy never freezes the app), and before the push Omniscio waits (bounded) while the **database drive or the mirror-target drive** is disk-saturated — so a backup never kicks off into an already-busy disk and slows whatever you're loading. It only waits for a calm moment; it never skips or indefinitely delays a backup. The write itself then runs **paced**: while the machine or either drive is busy, the multi-GB copy yields in short bounded pauses instead of saturating the disk the live database shares — the same back-pressure the local backup's own copy already applies to itself, so it is slow on a busy machine but never absent. The **automatic** mirror that follows a local backup is more patient still: if the machine or either drive is busy when it is due, it does not start at all — it checks again every 10 minutes, up to 6 times (about an hour), and then writes regardless, the same patience the local backup ring already has. **Mirror now** and **Sync now** are unaffected. Fail-open (a machine without the per-volume disk sensor — e.g. macOS/Linux — behaves exactly as before). Reversible: the in-write pacing rides the backup load gate, so it is switched off with `AMC_DISABLE_BACKUP_LOAD_GATE=1` (or `AMC_DISABLE_ARCHIVE_BACKUP_LOAD_GATE=1`) — the same switch the local backup copy's own pacing obeys — while `AMC_DISABLE_MIRROR_DISK_PACING=1` turns off only the pre-write saturation wait. See the `mirror-disk-pacing` invariant in `backup-mirror-contract.md`. (The complementary "ship only what changed" work — so a small change no longer re-writes the whole archive (~12 GB before compression) — is a proposed follow-up: [chunked-incremental proposal](../architecture/2026-08-06-backup-mirror-chunked-incremental-proposal.md).)

### Restore flow

The Settings panel's **Restore from mirror** section lists every `.amcmirror` file currently in the configured folder, sorted newest-first, showing `<id>` + size + modified time. Pick one (or browse to a file outside the configured folder), type the passphrase, choose a mode, and confirm.

**Replace mode** — recommended for "my hard drive died" / "I bought a new machine":

1. **Pre-restore safety snapshot.** Before staging anything, Omniscio copies your current `mission-control.db` and `config.json` to `<basename>.pre-restore-<ISO-timestamp>`. The paths land in the `RestoreResult.preRestoreBackups` array so the panel can show you where to find them if you need to revert. There is no automatic prune of these — you delete them when you've confirmed the restore worked.
2. **Stage the new files** alongside the live ones — `mission-control.db.pending-restore`, `config.json.pending-restore`, `attachments-pending-restore/`. The live DB is untouched; an open Omniscio keeps working against it until restart.
3. **Patch the staged DB** — every non-deleted row in `sessions` gets `cli_session_id = NULL` and `force_transcript_on_next_spawn = 1`. (See [Resume after restore](#resume-after-restore) for why.)
4. **Write a flag file** — `<userData>/restore-pending.json` containing the mode, manifest id, archive path, staged-at timestamp, and the pre-restore snapshot paths.
5. **Tell you to restart**. `RestoreResult.requiresRestart = true`.
6. On next startup, the swap happens in two phases to respect startup ordering:
   - **Config swap first** (`consumePendingConfigRestore()` in `index.ts`): BEFORE `initConfigStore()` loads settings, the staged `config.json.pending-restore` is renamed to `config.json`. This ensures the config store loads the _restored_ settings, not the pre-restore ones. Without this ordering, the old settings load into memory and overwrite the restored file on the next save.
   - **DB + attachments swap second** (`consumePendingRestore()` inside `initDatabase()`): the staged DB is renamed over the live DB (after deleting stale WAL/SHM sidecars), the staged attachments tree is merged into the live one, and the flag file is cleared.

   Crash-safe: if the user kills Omniscio during step 6, the staged files remain and the swap retries on the next launch.

**Merge mode** — recommended for "I want to pull session history from another machine into this one without losing my work-in-progress here":

1. **No pre-restore snapshot, no flag file, no restart needed.** Merge is non-destructive by design.
2. **Schema-version gate.** Merge mode INSERTs from the archive's DB into the live DB using `SELECT *`, which depends on identical column order. If `manifest.schemaVersion` doesn't exactly match the local schema version, the restore refuses — different schemas may have reordered columns or different defaults, and a silent corruption is the failure mode you want to avoid. Use replace mode for cross-version restores.
3. **ATTACH the archive DB** as `archive`, read-only.
4. **Bring over the parent projects, then the new rows.** A session's `project_id` is a NOT NULL foreign key into `projects`, so before inserting sessions the merge brings over the source device's **active projects** that aren't here yet — the parents of the merged sessions, plus any chat-less projects — additively, never overwriting an existing project. Foreign-key checks are deferred to commit so parents and children can be copied in one pass; a project that shares a folder path with one you already have is **not** duplicated (its sessions are re-filed onto your existing project), and a project whose sidebar divider isn't here lands ungrouped. Then it inserts the new `sessions` and `conversation_messages` — only rows whose `id` isn't already local, messages scoped to sessions that now exist locally. Existing local rows are never touched; a session whose project genuinely can't be resolved is skipped rather than aborting the whole merge (this is the fix for the old "Sync now merged nothing when the other device added a project" bug).
5. **Patch the newly-inserted sessions** — `cli_session_id = NULL` and `force_transcript_on_next_spawn = 1` (only on the merged rows; your existing sessions are left alone).
6. **Copy attachments for newly-merged sessions only**, walking the archive's attachments tree and writing under the live tree.
7. **Detach + cleanup**. The temp ATTACH-source DB file is `unlink`'d regardless of success/failure.

The restore result reports `restoredSessionCount` (replace: count of patched rows in the staged DB; merge: count of inserted rows), `mergedMessageCount` (merge only), and `restoredProjectCount` (merge only: parent + active projects brought over). The panel renders a green success card with these counts and, for replace mode, a "Restart now" button.

### Resume after restore

Every session in your Omniscio has a `cli_session_id` — the UUID the Claude CLI gave it on first spawn. Resuming a multi-turn conversation means passing `--resume <cli_session_id>` to the CLI, which loads the session state from the CLI's own per-user store at `~/.claude/`. After a restore on a different machine, that CLI store is **empty** — the session IDs in the restored DB don't exist on the new machine, and `--resume <missing-id>` errors out.

Solution: every restored session is patched to set `cli_session_id = NULL` and `force_transcript_on_next_spawn = 1`. On next spawn:

- The spawn gate sees `cli_session_id IS NULL` and routes through the **transcript-injection** path instead of `--resume`.
- Omniscio reconstructs the conversation from `conversation_messages` and stitches it into the new CLI session as the initial context.
- Once the CLI assigns a new `cli_session_id`, that's persisted and subsequent turns use `--resume` again.

The user-visible effect: you lose the CLI's own session-internal state (which doesn't matter for chat continuity), but the conversation reads identically — every message you sent and every message the agent emitted is back in the new session from turn one. Migration v180 added the `force_transcript_on_next_spawn` column specifically to make this transition explicit and persistent (an in-memory flag would have lost the gate on the very first restart).

### Limits and non-goals

- **Storage is your problem.** Omniscio does not check the folder for free space, does not warn before filling a drive, and does not upload anywhere itself. Point at a cloud-sync target and let the sync client handle off-machine replication.
- **No versioned snapshot system.** Retention is a fixed N-newest sweep. If you want a 1-year history, set `backupMirrorRetentionCount` to `365` (or whatever your storage budget allows). There's no "snapshot daily but keep weekly for a year" tiered policy.
- **No partial restore.** Replace is whole-DB-or-nothing. Merge is whole-archive-or-nothing within the schema-match gate. There is no "restore only sessions from project X" surface.
- **Single passphrase.** No per-machine passphrases, no key escrow, no recovery code. Lose the passphrase and the archives become unreadable. This is intentional — every workaround for a lost passphrase weakens the threat model. **Need an off-machine backup you can still open after losing the passphrase?** The newer [Portable Backup](portable-backup.md) DOES escrow a **recovery code** — every export mints one that unlocks the `.amcbackup` on any machine even without the passphrase — so reach for it when cross-machine key portability matters. The mirror (and [Setup Backup to Gmail](setup-backup.md)) keep the no-escrow model as the deliberate trade for the mirror's whole-workspace snapshot.
- **Two archive generations, two version numbers.** The manifest's `manifestVersion` is 2 for the streamed archive Omniscio writes today and 1 for the older whole-buffer archive, which still restores; any other value throws with a clear message at the manifest-read step. The encrypted stream carries its own version: 2 (compressed before it is encrypted) is written now, and 1 (the same stream without compression, which is every streamed mirror written before compression) still restores. A stream version this build does not know is refused by name, and an Omniscio from before compression was added cannot open a mirror written now — update the new machine first.

## Related

- [Setup Backup to Gmail](setup-backup.md) — the lighter, configuration-only sibling. Different threat model (email transport, not local sync), different inclusion list (no conversations). Both can run in parallel.
- [tray-and-window.md](tray-and-window.md) — graceful shutdown sequencing; relevant because the pending-restore swap runs on the **next** startup, so quitting the app cleanly is what gets you to that swap.
- [Backup Mirror (part 2)](backup-mirror-part-2.md) — the rest of this page: first-time activation, the automatic-sync modes, the encryption envelope the archives use, the archive's internal storage layout and retention, the defences the restore path applies, and the IPC channels the settings panel drives.
