Skip to content

Backup and Restore

P3DROVFX edited this page Oct 12, 2026 · 1 revision

Backup and Restore

Two folders hold every choice you have made in the shell, and neither comes back from a reinstall:

Folder Holds
~/.config/illogical-impulse config.json (all settings), presets, profile pictures, widget extensions, workspace profiles, preset-store links
~/.local/state/quickshell states.json, your to-do list, notes, clipboard pins, keybind pages and commands, app-usage history, Email preferences and drafts, Bedtime records…

Losing them is losing the desktop, not the shell. The Settings Backup packs both into one zip, restores it, and can hand the zip to your Google Drive backup. It is in Settings → Accounts & Backup → Settings Backup, and it is offered on the very first page of the Welcome app, so a fresh install can pull your whole setup back before anything else.

This is separate from the Preset Store — presets are strictly visual and share a look, never your personal data — and from Customization → Presets, which snapshot appearance only. A backup is everything.

Back up

  1. Where backups are kept — choose a folder (a zenity or kdialog chooser; the page tells you which to install if neither exists).
  2. Back up now, or enable Back up automatically every (days) (7 by default) and Keep the newest backups (5 by default; older ones are deleted).
  3. Optionally Keep a copy in Google Drive: the backup folder is added to the folders the existing Google Drive backup already syncs, so the zip uploads with that schedule. There is no second uploader; if the Drive backup is off, the page says nothing is being uploaded yet.

The page shows the last backup (time, size, file count). Files are named ii-backup-<date>-<time>.zip and carry an ii-backup.json manifest (format, date, host, counts) at the root.

The automatic backup is not a clock. The shell is not always on, and a backup scheduled for 3 AM is a backup that never happens. Instead, 45 seconds after the shell starts it asks once whether the last backup is older than your interval — which is also true after a week with the computer off.

What is left out

Everything that is either a build artifact or re-fetched on demand: .venv (the ~370 MB Python environment, recreated by setup), the git clones under preset-store/ (~50 MB, re-downloadable; the links.json beside them is kept), __pycache__, .git, .cache, node_modules, *.pyc, *.tmp, *.swp, *.lock, sockets, and the config.json.malformed-* copies the shell makes when it repairs a bad file. On a real system that took 145 MB + 383 MB down to about 100 MB and 260 files. Already-compressed files (images, video, fonts) are stored rather than deflated.

What is not in the backup

  • Secrets. API keys, Gmail / Tasks / Calendar tokens and the OAuth client live in the system keyring, not in these folders; they must be connected again after restoring on a new machine (Google Cloud Setup).
  • ii/.env, vdirsyncer's token and rclone's config (they live elsewhere).
  • Your files: wallpapers outside the folders above, documents, the Drive backup itself.
  • The shell's code — that comes from the repository.

Restore

Restore from a zip file… (or pick one from the list of backups in the folder). The shell first inspects the archive: a zip without the manifest is refused as Not a settings backup, or damaged, so a random zip can never spray files into ~/.config. Then:

  1. The row arms — the button turns into Overwrite my settings — because this is the one action on these pages you cannot undo by hand.
  2. Before extracting, the script writes your current settings next to the archive as a backup of their own (…-before-restore.zip), so a restore can itself be undone. These count as backups in the list and in pruning.
  3. Extraction merges into the two folders; it never wipes them first (clearing the state folder would delete the .venv and break the shell).
  4. While it runs, writes to config.json and to the persistent state are held. Config.qml writes its file on its own debounce; without the hold, a setting changed seconds earlier would be written back over the restored one. This is the same guard the Preset Store uses, extended to states.json; pending changes are flushed first.

On the Welcome app's first page, Restore sits in the bottom-left corner — the slot that is free because there is nowhere to go back to on page one. A fresh machine has no backup folder yet and nothing worth saving, so that path skips the safety copy.

Notes: a zip made on another computer brings that computer's backup-folder path with it (states.json); that is harmless. After a restore the shell's file watchers pick the new files up within a moment (the write hold is released 1.2 s after the restore finishes), so no restart is needed.

From the command line

scripts/backup/shell_backup.py is the whole engine. Every subcommand prints exactly one JSON line and never raises — failure is {"ok": false, "error": "…"}:

python3 scripts/backup/shell_backup.py create  --dest ~/Backups --keep 5 [--label before-upgrade]
python3 scripts/backup/shell_backup.py list    --dest ~/Backups
python3 scripts/backup/shell_backup.py inspect --archive ~/Backups/ii-backup-20261012-093000.zip
python3 scripts/backup/shell_backup.py restore --archive … [--safety-dest ~/Backups]

Under the hood

Piece Role
scripts/backup/shell_backup.py Create, list, inspect, restore; skip rules; pruning
services/ShellBackup.qml One job at a time, the config hold during restore, the 45-second due check, the Drive hand-off
modules/settings/configs/widgets/ShellBackupConfig.qml The settings page
modules/welcome/WelcomeRestoreDialog.qml The first-page restore
Persistent.states.shellBackup enabled, folder, autoDrive, keepCount, intervalDays, lastBackup* — in persistent state because a backup folder is a fact about this machine, and a preset carrying someone else's path would be absurd

Related pages

← Back to Home

Clone this wiki locally