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.
omarchy-upgrade-to-quattro silently overwrites /etc/snapper/configs/root, discarding user retention settings & sometimes deleting its own snapshot
Reported by abagonhishead · filed Sep 19, 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
Framework 16 (AMD Ryzen 9 7940HS, Radeon 780M iGPU), Omarchy 4.0.4 upgraded from 3.8.4 via omarchy-upgrade-to-quattro (stable channel), snapper 0.13.1-3, btrfs root with separate @home, Limine + limine-snapper-sync.
What's wrong?
Disclosure
I prepared this bug report with the help of AI (Claude.)
I was unsure whether to raise this as I don't want to waste your time with yet another AI-generated bug, but I checked everything very thoroughly, and it was through sheer luck that I had a timeline snapshot fire just before the upgrade which gave me a rollback path.
Silently killing one of the user's main rollback mechanisms felt like an oversight to me, so hopefully this will help prevent it happening to someone else.
Issue
omarchy-upgrade-to-quattro silently replaces the user's Snapper config with a template, discarding their retention settings. Here the next cleanup then deleted 53 snapshots -- all history back to 1 August, manual snapshots included, and the pre-upgrade snapshot the upgrade had just taken for rollback. btrfs snapshot deletion is irreversible.
configure_snapper_policy() runs install/config/snapper.sh, which overwrites rather than adjusts:
install -m 0644 "$template" "$SNAPPER_CONFIG_PATH" # /etc/snapper/configs/rootNo merge, no backup, and nothing printed beyond "Configuring Omarchy Snapper snapshot retention". Every key the user had is discarded (13 → 7 here). The same upgrade run produced four .pacnew files for other config, so the convention exists -- it just isn't applied to this file.
| before | after (default/snapper/root) | |
|---|---|---|
NUMBER_LIMIT | 25 | 5 |
NUMBER_LIMIT_IMPORTANT | 10 | 5 |
NUMBER_MIN_AGE | 7200 | 0 |
TIMELINE_CREATE | yes | no |
NUMBER_MIN_AGE=0 does the damage: with no grace period a snapshot can be deleted seconds after creation. Under the previous settings nothing would have been lost -- 7200 would have exempted every snapshot the upgrade created (5–8 minutes old when cleanup ran), and older history would have been trimmed to 25 rather than 5.
It also isn't visible at upgrade time. snapper-cleanup.timer is OnBootSec=10m / OnUnitActiveSec=1h, so the deletion came in a single run at 19:14:53, five minutes after the upgrade finished. Checking immediately afterwards shows everything present.
Scope
snap-pac is installed here and is not an Omarchy default; its pre/post pairs across the upgrade's 14 transactions are what pushed the pre-upgrade snapshot past the new limit of 5. That churn was harmless under the original NUMBER_MIN_AGE=7200. The loss of pre-existing history doesn't depend on snap-pac -- anyone with more than 5 snapshots or a tuned policy loses it.
Evidence
The config was replaced, not adjusted -- it is byte-identical to the shipped template:
151d960499442fbbc751abe12cec5fb07521cc39bbc616d1ed1eda75f8edad88 /etc/snapper/configs/root
151d960499442fbbc751abe12cec5fb07521cc39bbc616d1ed1eda75f8edad88 /usr/share/omarchy/default/snapper/rootReproduce (no root, no effect on real config)
printf 'NUMBER_LIMIT="25"\nNUMBER_MIN_AGE="7200"\nMY_SETTING="keepme"\n' > /tmp/root
OMARCHY_SNAPPER_CONFIG_PATH=/tmp/root OMARCHY_SNAPPER_CONF_PATH=/tmp/conf \
bash install/config/snapper.sh
cat /tmp/root # replaced by the template; every prior key goneSuggested fix
- Set only the keys Omarchy needs via
snapper set-config KEY=VALUE, keeping the template for the create-from-scratch path. - If the file is replaced, back it up and say so on stdout.
- Don't lower an existing
NUMBER_LIMIT, and use a non-zeroNUMBER_MIN_AGEso a pre-update snapshot can't be deleted minutes after it is taken.
Related
#9619 / PR #9633 cover the other write in the same script -- printf 'SNAPPER_CONFIGS="root"' > truncating /etc/conf.d/snapper. This report is the separate /etc/snapper/configs/root overwrite.
For what it's worth, this upgrade hit both: home was de-registered as #9619 describes, so /home silently stopped being covered (the 15 existing /home/.snapshots subvolumes survived, but nothing manages or creates them). #9619 is therefore still present in 4.0.4.
View raw text
### System details Framework 16 (AMD Ryzen 9 7940HS, Radeon 780M iGPU), Omarchy 4.0.4 upgraded from 3.8.4 via `omarchy-upgrade-to-quattro` (stable channel), snapper 0.13.1-3, btrfs root with separate `@home`, Limine + limine-snapper-sync. ### What's wrong? ## Disclosure I prepared this bug report with the help of AI (Claude.) I was unsure whether to raise this as I don't want to waste your time with yet another AI-generated bug, but I checked everything very thoroughly, and it was through sheer luck that I had a timeline snapshot fire just before the upgrade which gave me a rollback path. Silently killing one of the user's main rollback mechanisms felt like an oversight to me, so hopefully this will help prevent it happening to someone else. ## Issue `omarchy-upgrade-to-quattro` silently replaces the user's Snapper config with a template, discarding their retention settings. Here the next cleanup then deleted **53 snapshots** -- all history back to 1 August, manual snapshots included, and the pre-upgrade snapshot the upgrade had just taken for rollback. btrfs snapshot deletion is irreversible. `configure_snapper_policy()` runs `install/config/snapper.sh`, which overwrites rather than adjusts: ```bash install -m 0644 "$template" "$SNAPPER_CONFIG_PATH" # /etc/snapper/configs/root ``` No merge, no backup, and nothing printed beyond "Configuring Omarchy Snapper snapshot retention". Every key the user had is discarded (13 → 7 here). The same upgrade run produced four `.pacnew` files for other config, so the convention exists -- it just isn't applied to this file. | | before | after (`default/snapper/root`) | |---|---|---| | `NUMBER_LIMIT` | 25 | 5 | | `NUMBER_LIMIT_IMPORTANT` | 10 | 5 | | `NUMBER_MIN_AGE` | 7200 | **0** | | `TIMELINE_CREATE` | yes | no | `NUMBER_MIN_AGE=0` does the damage: with no grace period a snapshot can be deleted seconds after creation. **Under the previous settings nothing would have been lost** -- `7200` would have exempted every snapshot the upgrade created (5–8 minutes old when cleanup ran), and older history would have been trimmed to 25 rather than 5. It also isn't visible at upgrade time. `snapper-cleanup.timer` is `OnBootSec=10m` / `OnUnitActiveSec=1h`, so the deletion came in a single run at 19:14:53, five minutes after the upgrade finished. Checking immediately afterwards shows everything present. ### Scope `snap-pac` is installed here and is not an Omarchy default; its pre/post pairs across the upgrade's 14 transactions are what pushed the pre-upgrade snapshot past the new limit of 5. That churn was harmless under the original `NUMBER_MIN_AGE=7200`. The loss of pre-existing history doesn't depend on `snap-pac` -- anyone with more than 5 snapshots or a tuned policy loses it. ### Evidence The config was replaced, not adjusted -- it is byte-identical to the shipped template: ``` 151d960499442fbbc751abe12cec5fb07521cc39bbc616d1ed1eda75f8edad88 /etc/snapper/configs/root 151d960499442fbbc751abe12cec5fb07521cc39bbc616d1ed1eda75f8edad88 /usr/share/omarchy/default/snapper/root ``` ### Reproduce (no root, no effect on real config) ```bash printf 'NUMBER_LIMIT="25"\nNUMBER_MIN_AGE="7200"\nMY_SETTING="keepme"\n' > /tmp/root OMARCHY_SNAPPER_CONFIG_PATH=/tmp/root OMARCHY_SNAPPER_CONF_PATH=/tmp/conf \ bash install/config/snapper.sh cat /tmp/root # replaced by the template; every prior key gone ``` ### Suggested fix - Set only the keys Omarchy needs via `snapper set-config KEY=VALUE`, keeping the template for the create-from-scratch path. - If the file is replaced, back it up and say so on stdout. - Don't lower an existing `NUMBER_LIMIT`, and use a non-zero `NUMBER_MIN_AGE` so a pre-update snapshot can't be deleted minutes after it is taken. ### Related #9619 / PR #9633 cover the other write in the same script -- `printf 'SNAPPER_CONFIGS="root"' >` truncating `/etc/conf.d/snapper`. This report is the separate `/etc/snapper/configs/root` overwrite. For what it's worth, this upgrade hit both: `home` was de-registered as #9619 describes, so `/home` silently stopped being covered (the 15 existing `/home/.snapshots` subvolumes survived, but nothing manages or creates them). #9619 is therefore still present in 4.0.4.
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 16:01 UTC