Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A 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.

Inbox
ReportR-1103GitHub issuePublicDecided· Out of scope

snapper.sh overwrites /etc/conf.d/snapper, silently de-registering user configs (home) so omarchy-snapshot stops covering /home

Reported by CaptainVirgil · filed Sep 1, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

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

snapper.sh overwrites /etc/conf.d/snapper, silently de-registering user configs (home) so omarchy-snapshot stops covering /homerevision 1 · captured 2026-09-28 21:24 UTC via poll

System details

Omarchy 4.0.2-1 (version file reports 4.0.0.alpha), snapper 0.13.1 / libsnapper 8.0.0, btrfs root with separate @home subvolume.

What's wrong?

install/config/snapper.sh writes /etc/conf.d/snapper with a truncating redirect rather than merging:

https://github.com/omacom/omarchy/blob/master/install/config/snapper.sh#L20

printf '%s\n' 'SNAPPER_CONFIGS="root"' >"$SNAPPER_CONF_PATH"

SNAPPER_CONFIGS is what registers configs with snapperd. Overwriting it silently de-registers every other snapper config the user has, most commonly home on the standard @/@home layout.

The consequence is not limited to timeline snapshots. omarchy-snapshot create enumerates configs from that same registry:

mapfile -t CONFIGS < <(sudo snapper --csvout list-configs | awk -F, 'NR>1 {print $1}')
for config in "${CONFIGS[@]}"; do
    sudo snapper -c "$config" create -c number -d "$DESC"

so once home is de-registered, `/home` is silently dropped from pre-update snapshots too. The user keeps getting "Snapshots can be selected during boot" on every omarchy update while /home has no coverage at all.

It fails closed and silently: the config file is untouched and still valid, so nothing looks broken. snapper -c home list just returns Unknown config.

Reproduce

# given a working home config
sudo snapper list-configs                 # root, home
sudo bash install/config/snapper.sh
sudo systemctl restart snapperd
sudo snapper list-configs                 # root only
sudo snapper -c home list                 # Unknown config.
cat /etc/conf.d/snapper                   # SNAPPER_CONFIGS="root"

Confirmed as the mechanism by round-tripping it (note snapperd caches the list at startup, so a restart is required to observe either direction):

printf 'SNAPPER_CONFIGS="root home"\n' | sudo tee /etc/conf.d/snapper
sudo systemctl restart snapperd
sudo snapper list-configs                 # root, home  -> restored
sudo snapper -c home list                 # works, snapshots intact

Observed on this machine

The config was de-registered on 2026-08-19 (mtime of the snapper.sh-installed /etc/snapper/configs/root is 08:19 that day). /home snapshots stop dead at that moment and none have been created since, across four subsequent omarchy update runs which each created a root snapshot:

# snapper --no-dbus -c home list   (still readable directly)
40 │ Wed 19 Aug 2026 07:30 │ timeline │ timeline
41 │ Wed 19 Aug 2026 07:39 │ number   │ 3.8.4
45 │ Wed 19 Aug 2026 08:18 │ number   │ 3.8.5      <- last ever

# snapper -c root list
127 │ Wed 26 Aug 2026 13:12 │ number │ 4.0.0-1
128 │ Wed 26 Aug 2026 14:29 │ number │ 4.0.1-1
129 │ Mon 31 Aug 2026 07:40 │ number │ 4.0.1-1
130 │ Tue 01 Sep 2026 07:41 │ number │ 4.0.2-1

The timing is unlucky: the same Aug 19 run was the quattro upgrade, which orphaned a lot of user config under /home. The pre-update /home snapshot that would have covered it was prevented by the same script, in the same run.

Suggested fix

Merge rather than truncate — preserve configs Omarchy did not create, while still guaranteeing root is present:

existing=""
[[ -f $SNAPPER_CONF_PATH ]] && existing="$(. "$SNAPPER_CONF_PATH" 2>/dev/null; printf '%s' "${SNAPPER_CONFIGS:-}")"
merged="root"
for c in $existing; do [[ $c == root ]] || merged+=" $c"; done
printf 'SNAPPER_CONFIGS="%s"\n' "$merged" >"$SNAPPER_CONF_PATH"

If root-only is a deliberate policy rather than an oversight, then it would help a lot for the script to say so out loud when it drops a config, since today it is completely silent.

Related

  • #5546 — migration 1776927490 deleting user-configured timeline snapshots. Same theme (Omarchy vs a user home config) but a different mechanism: that one deletes snapshots, this one de-registers the config so nothing new is ever created, including the number snapshots omarchy-snapshot would otherwise take.

Note snapper.sh also runs systemctl disable --now snapper-timeline.timer, which independently stops timeline snapshots for all configs. That part looks intentional and is arguably reasonable for a desktop; this report is specifically about the SNAPPER_CONFIGS overwrite, which additionally removes the event-driven pre-update coverage.

View raw text
### System details

Omarchy 4.0.2-1 (version file reports `4.0.0.alpha`), snapper 0.13.1 / libsnapper 8.0.0, btrfs root with separate `@home` subvolume.

### What's wrong?

`install/config/snapper.sh` writes `/etc/conf.d/snapper` with a truncating redirect rather than merging:

https://github.com/omacom/omarchy/blob/master/install/config/snapper.sh#L20

```bash
printf '%s\n' 'SNAPPER_CONFIGS="root"' >"$SNAPPER_CONF_PATH"
```

`SNAPPER_CONFIGS` is what registers configs with `snapperd`. Overwriting it silently **de-registers every other snapper config the user has**, most commonly `home` on the standard `@`/`@home` layout.

The consequence is not limited to timeline snapshots. `omarchy-snapshot create` enumerates configs from that same registry:

```bash
mapfile -t CONFIGS < <(sudo snapper --csvout list-configs | awk -F, 'NR>1 {print $1}')
for config in "${CONFIGS[@]}"; do
    sudo snapper -c "$config" create -c number -d "$DESC"
```

so once `home` is de-registered, **`/home` is silently dropped from pre-update snapshots too**. The user keeps getting "Snapshots can be selected during boot" on every `omarchy update` while `/home` has no coverage at all.

It fails closed and silently: the config file is untouched and still valid, so nothing looks broken. `snapper -c home list` just returns `Unknown config.`

### Reproduce

```bash
# given a working home config
sudo snapper list-configs                 # root, home
sudo bash install/config/snapper.sh
sudo systemctl restart snapperd
sudo snapper list-configs                 # root only
sudo snapper -c home list                 # Unknown config.
cat /etc/conf.d/snapper                   # SNAPPER_CONFIGS="root"
```

Confirmed as the mechanism by round-tripping it (note `snapperd` caches the list at startup, so a restart is required to observe either direction):

```bash
printf 'SNAPPER_CONFIGS="root home"\n' | sudo tee /etc/conf.d/snapper
sudo systemctl restart snapperd
sudo snapper list-configs                 # root, home  -> restored
sudo snapper -c home list                 # works, snapshots intact
```

### Observed on this machine

The config was de-registered on 2026-08-19 (mtime of the `snapper.sh`-installed `/etc/snapper/configs/root` is 08:19 that day). `/home` snapshots stop dead at that moment and none have been created since, across four subsequent `omarchy update` runs which each created a `root` snapshot:

```
# snapper --no-dbus -c home list   (still readable directly)
40 │ Wed 19 Aug 2026 07:30 │ timeline │ timeline
41 │ Wed 19 Aug 2026 07:39 │ number   │ 3.8.4
45 │ Wed 19 Aug 2026 08:18 │ number   │ 3.8.5      <- last ever

# snapper -c root list
127 │ Wed 26 Aug 2026 13:12 │ number │ 4.0.0-1
128 │ Wed 26 Aug 2026 14:29 │ number │ 4.0.1-1
129 │ Mon 31 Aug 2026 07:40 │ number │ 4.0.1-1
130 │ Tue 01 Sep 2026 07:41 │ number │ 4.0.2-1
```

The timing is unlucky: the same Aug 19 run was the quattro upgrade, which orphaned a lot of user config under `/home`. The pre-update `/home` snapshot that would have covered it was prevented by the same script, in the same run.

### Suggested fix

Merge rather than truncate — preserve configs Omarchy did not create, while still guaranteeing `root` is present:

```bash
existing=""
[[ -f $SNAPPER_CONF_PATH ]] && existing="$(. "$SNAPPER_CONF_PATH" 2>/dev/null; printf '%s' "${SNAPPER_CONFIGS:-}")"
merged="root"
for c in $existing; do [[ $c == root ]] || merged+=" $c"; done
printf 'SNAPPER_CONFIGS="%s"\n' "$merged" >"$SNAPPER_CONF_PATH"
```

If root-only is a deliberate policy rather than an oversight, then it would help a lot for the script to say so out loud when it drops a config, since today it is completely silent.

### Related

- #5546 — migration `1776927490` deleting user-configured timeline snapshots. Same theme (Omarchy vs a user `home` config) but a different mechanism: that one deletes snapshots, this one de-registers the config so nothing new is ever created, including the `number` snapshots `omarchy-snapshot` would otherwise take.

Note `snapper.sh` also runs `systemctl disable --now snapper-timeline.timer`, which independently stops timeline snapshots for all configs. That part looks intentional and is arguably reasonable for a desktop; this report is specifically about the `SNAPPER_CONFIGS` overwrite, which additionally removes the event-driven pre-update coverage.

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 10:27 UTC