Proof Portal
Omarchy
ProbeLabs65 findings · 95 requirementsA proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.
Isolate /var/lib/docker (and other high-churn data dirs) from root Btrfs snapshots
Reported by chapaghetti · filed Aug 29, 2026 · open at source
At a glance
- 1 · What is claimed?
- Only the report text below — no validator has restated it as checkable claims yet.
- 2 · What does it affect?
- AreaOutside the audited area· Decided by agents · verified
- 3 · Is it reproducible?
- No validation has been run yet.
- 4 · What remains unclear?
- Not validated yet: no claims, no reproducer.
- 5 · What happens next?
- Decided by agents and verified by a second, independent agent — see the decision.
Original report
System details
Intel i7-5820K / Geforce RTX 3080 / 32GB RAM
What's wrong?
Problem
Omarchy's default disk layout (via archinstall's "default partitioning layout") creates four Btrfs subvolumes:
@ -> /
@home -> /home
@log -> /var/log
@pkg -> /var/cache/pacman/pkgEverything else under /var — most importantly /var/lib — remains inside the @ root subvolume. Since install/config/docker.sh installs and enables Docker on every Omarchy system, /var/lib/docker (image layers, container filesystems, volumes) ends up living inside the same subvolume that Snapper snapshots and that limine-snapper-sync lets users roll back from the bootloader.
This creates two concrete problems:
- Rollback silently destroys/reverts container state. Snapper's rollback (and the boot-menu rollback wired up in
install/login/limine-snapper.sh) swaps the entire@subvolume back to a prior snapshot. A user rolling back after a badpacman -Syudoesn't just get their system files reverted — Docker volumes, container layers, and any data-bearing containers (databases, local dev services, etc.) silently revert or disappear too. This is surprising: the average person invoking a snapshot rollback is trying to fix a broken package update, not opt into reverting unrelated application data.
- Snapshot bloat from CoW churn. Container image layers and volumes are exactly the kind of write-heavy, frequently-changing data that generates large amounts of copy-on-write divergence between snapshots. With Snapper's timeline snapshots enabled by default, this data gets pinned across multiple retained snapshots, causing
@to grow in ways that aren't visible fromdfand that can contribute to Btrfs's well-known bad behavior when a filesystem approaches full (ENOSPC / metadata exhaustion issues).
Btrfs snapshots don't recurse into nested subvolumes — the standard fix used by other Btrfs-based distros (openSUSE, CachyOS, and the Arch wiki's own Snapper guidance) is to carve out subvolumes for exactly these kinds of directories (/var/log, /var/cache/pacman/pkg, /var/lib/docker, /var/lib/libvirt, /var/lib/postgres, etc.) so a root snapshot/rollback doesn't touch them.
Omarchy already isolates two of these (@log, @pkg). This PR proposes isolating /var/lib/docker too, since Docker is installed by Omarchy itself.
Proposed change
1. Create /var/lib/docker as its own Btrfs subvolume during install
The best point to do this is in install/config/docker.sh, after the package is installed but before the daemon is ever started — at that point /var/lib/docker doesn't exist yet or is empty, so we can create it as a subvolume in place without a move-and-swap dance.
# install/config/docker.sh
install_docker() {
omarchy-pkg-add docker docker-compose
# Give /var/lib/docker its own subvolume so it's excluded from
# root (@) snapshots and unaffected by snapper rollbacks.
# Must run before the docker service ever starts.
if command -v btrfs >/dev/null && findmnt -no FSTYPE / | grep -q btrfs; then
sudo mkdir -p /var/lib
if [[ ! -d /var/lib/docker ]]; then
sudo btrfs subvolume create /var/lib/docker
fi
fi
# ... existing polkit/sudo group configuration, no docker group by default ...
}No fstab entry is needed — a subvolume created at a path under an already-mounted Btrfs filesystem is automatically part of that mount; it just won't be included in snapshots of its parent.
2. Document the pattern for manual installs
For people following the manual archinstall-based installation (manual/*.md), add a note alongside the existing partitioning instructions recommending an additional subvolume for anyone who expects to run Docker, databases, or VMs day one:
@var_lib -> /var/lib (optional, recommended for Docker/Postgres/libvirt users)This can't be retrofitted automatically for manual installs the way it can in the scripted ISO path, so it's a documentation-only change there.
3. Migration helper for existing installations
For people who already have Omarchy installed with Docker data inside @, retrofitting a subvolume in place requires the standard move-and-swap:
#!/bin/bash
# bin/omarchy-migrate-docker-subvolume
set -euo pipefail
sudo systemctl stop docker.socket docker.service
sudo mv /var/lib/docker /var/lib/docker.old
sudo btrfs subvolume create /var/lib/docker
sudo rsync -aHAX --info=progress2 /var/lib/docker.old/ /var/lib/docker/
sudo rm -rf /var/lib/docker.old
sudo systemctl start docker.service
echo "Done. /var/lib/docker is now its own subvolume and will be excluded from root snapshots."This should be exposed as an omarchy-migrate-docker-subvolume command (or folded into the existing migrations system under migrations/) so existing users can opt in without a reinstall.
Testing
- Fresh ISO install: confirm
btrfs subvolume list /showsvar/lib/dockerafter install, andsudo btrfs subvolume show /var/lib/dockerreports it as a subvolume, not a plain directory. - Snapshot test:
sudo snapper create -d "pre-test", pull a Docker image, run a container that writes to a named volume, thensudo snapper rollbackto the pre-test snapshot and reboot. Confirm/var/lib/dockercontents are unaffected while the rest of@reverts correctly. - Migration script test: run against a system with existing Docker data (images, running containers) and confirm containers still start and volumes retain data afterward.
- Confirm
btrfs subvolume delete/snapper deleteon old snapshots still works cleanly with the new subvolume in place (no "target is busy" issues from nested subvolumes).
Open questions / follow-ups
- Should the same treatment apply to
/var/lib/libvirtand/var/lib/postgresif/when Omarchy ships first-party setup for those? Could generalize into a smallomarchy-btrfs-isolate <path>helper that bothdocker.shand future service installers call. - Should this be opt-out rather than opt-in, given it changes rollback semantics for anyone with existing containers at the time they upgrade to the version of Omarchy that ships this?
- Worth a one-line callout in the Snapper rollback docs (
manual/*.md) clarifying exactly what does and doesn't get reverted, regardless of whether this PR lands, since the underlying "snapshots don't recurse into nested subvolumes" behavior is easy to misunderstand either way.
View raw text
### System details
Intel i7-5820K / Geforce RTX 3080 / 32GB RAM
### What's wrong?
## Problem
Omarchy's default disk layout (via archinstall's "default partitioning layout") creates four Btrfs subvolumes:
```
@ -> /
@home -> /home
@log -> /var/log
@pkg -> /var/cache/pacman/pkg
```
Everything else under `/var` — most importantly `/var/lib` — remains inside the `@` root subvolume. Since `install/config/docker.sh` installs and enables Docker on every Omarchy system, `/var/lib/docker` (image layers, container filesystems, volumes) ends up living inside the same subvolume that Snapper snapshots and that `limine-snapper-sync` lets users roll back from the bootloader.
This creates two concrete problems:
1. **Rollback silently destroys/reverts container state.** Snapper's rollback (and the boot-menu rollback wired up in `install/login/limine-snapper.sh`) swaps the entire `@` subvolume back to a prior snapshot. A user rolling back after a bad `pacman -Syu` doesn't just get their system files reverted — Docker volumes, container layers, and any data-bearing containers (databases, local dev services, etc.) silently revert or disappear too. This is surprising: the average person invoking a snapshot rollback is trying to fix a broken package update, not opt into reverting unrelated application data.
2. **Snapshot bloat from CoW churn.** Container image layers and volumes are exactly the kind of write-heavy, frequently-changing data that generates large amounts of copy-on-write divergence between snapshots. With Snapper's timeline snapshots enabled by default, this data gets pinned across multiple retained snapshots, causing `@` to grow in ways that aren't visible from `df` and that can contribute to Btrfs's well-known bad behavior when a filesystem approaches full (ENOSPC / metadata exhaustion issues).
Btrfs snapshots don't recurse into nested subvolumes — the standard fix used by other Btrfs-based distros (openSUSE, CachyOS, and the Arch wiki's own Snapper guidance) is to carve out subvolumes for exactly these kinds of directories (`/var/log`, `/var/cache/pacman/pkg`, `/var/lib/docker`, `/var/lib/libvirt`, `/var/lib/postgres`, etc.) so a root snapshot/rollback doesn't touch them.
Omarchy already isolates two of these (`@log`, `@pkg`). This PR proposes isolating `/var/lib/docker` too, since Docker is installed by Omarchy itself.
## Proposed change
### 1. Create `/var/lib/docker` as its own Btrfs subvolume during install
The best point to do this is in `install/config/docker.sh`, **after the package is installed but before the daemon is ever started** — at that point `/var/lib/docker` doesn't exist yet or is empty, so we can create it as a subvolume in place without a move-and-swap dance.
```bash
# install/config/docker.sh
install_docker() {
omarchy-pkg-add docker docker-compose
# Give /var/lib/docker its own subvolume so it's excluded from
# root (@) snapshots and unaffected by snapper rollbacks.
# Must run before the docker service ever starts.
if command -v btrfs >/dev/null && findmnt -no FSTYPE / | grep -q btrfs; then
sudo mkdir -p /var/lib
if [[ ! -d /var/lib/docker ]]; then
sudo btrfs subvolume create /var/lib/docker
fi
fi
# ... existing polkit/sudo group configuration, no docker group by default ...
}
```
No fstab entry is needed — a subvolume created at a path under an already-mounted Btrfs filesystem is automatically part of that mount; it just won't be included in snapshots of its parent.
### 2. Document the pattern for manual installs
For people following the manual `archinstall`-based installation (`manual/*.md`), add a note alongside the existing partitioning instructions recommending an additional subvolume for anyone who expects to run Docker, databases, or VMs day one:
```
@var_lib -> /var/lib (optional, recommended for Docker/Postgres/libvirt users)
```
This can't be retrofitted automatically for manual installs the way it can in the scripted ISO path, so it's a documentation-only change there.
### 3. Migration helper for existing installations
For people who already have Omarchy installed with Docker data inside `@`, retrofitting a subvolume in place requires the standard move-and-swap:
```bash
#!/bin/bash
# bin/omarchy-migrate-docker-subvolume
set -euo pipefail
sudo systemctl stop docker.socket docker.service
sudo mv /var/lib/docker /var/lib/docker.old
sudo btrfs subvolume create /var/lib/docker
sudo rsync -aHAX --info=progress2 /var/lib/docker.old/ /var/lib/docker/
sudo rm -rf /var/lib/docker.old
sudo systemctl start docker.service
echo "Done. /var/lib/docker is now its own subvolume and will be excluded from root snapshots."
```
This should be exposed as an `omarchy-migrate-docker-subvolume` command (or folded into the existing migrations system under `migrations/`) so existing users can opt in without a reinstall.
## Testing
- Fresh ISO install: confirm `btrfs subvolume list /` shows `var/lib/docker` after install, and `sudo btrfs subvolume show /var/lib/docker` reports it as a subvolume, not a plain directory.
- Snapshot test: `sudo snapper create -d "pre-test"`, pull a Docker image, run a container that writes to a named volume, then `sudo snapper rollback` to the pre-test snapshot and reboot. Confirm `/var/lib/docker` contents are unaffected while the rest of `@` reverts correctly.
- Migration script test: run against a system with existing Docker data (images, running containers) and confirm containers still start and volumes retain data afterward.
- Confirm `btrfs subvolume delete` / `snapper delete` on old snapshots still works cleanly with the new subvolume in place (no "target is busy" issues from nested subvolumes).
## Open questions / follow-ups
- Should the same treatment apply to `/var/lib/libvirt` and `/var/lib/postgres` if/when Omarchy ships first-party setup for those? Could generalize into a small `omarchy-btrfs-isolate <path>` helper that both `docker.sh` and future service installers call.
- Should this be opt-out rather than opt-in, given it changes rollback semantics for anyone with existing containers at the time they upgrade to the version of Omarchy that ships this?
- Worth a one-line callout in the Snapper rollback docs (`manual/*.md`) clarifying exactly what does and doesn't get reverted, regardless of whether this PR lands, since the underlying "snapshots don't recurse into nested subvolumes" behavior is easy to misunderstand either way.Validation
Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.
Linked
Not linked to any known issue, other report or change yet.
Decision
Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.
- Out of scopeDecided by agents · verified · 2026-10-09 09:56 UTC