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-system-shutdown leaves dirty shutdown: nohup & runs inside session scope, killed before poweroff completes
Reported by alanahuel · filed May 15, 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
Summary
omarchy-system-shutdown schedules systemctl poweroff via nohup bash -c "sleep 2 && systemctl poweroff --no-wall" >/dev/null 2>&1 &. Although nohup and & detach from the controlling terminal, the process stays inside the user's `session-N.scope`. When systemd begins the shutdown sequence it stops that scope first, killing the very systemctl poweroff it depends on. Result: every shutdown is "dirty".
Steps to reproduce
- Open the Omarchy menu → Power → Shutdown
- After reboot inspect the previous boot:
journalctl -b -1 --no-pager | grep -E "Stopping timed out|Killing process .* systemctl|Failed unmounting"Expected
Clean shutdown, all mounts unmounted, no session-N.scope: Failed with result 'timeout'.
Actual (consistent across 5+ boots on my system)
systemd[1]: session-2.scope: Stopping timed out. Killing.
systemd[1]: session-2.scope: Killing process <PID> (systemctl) with signal SIGKILL.
systemd[1]: session-2.scope: Failed with result 'timeout'.
systemd[1]: Failed unmounting /var/cache.
umount[<PID>]: umount: /var/cache: target is busy.The Failed unmounting /var/cache follow-on happens because background services (plocate-updatedb, fwupd, pacman temp dirs) are still holding /var/cache when the kill cascade reaches the unmount step — omarchy-hyprland-window-close-all does not give them time to settle, and the SIGKILL of the orchestrating systemctl truncates the orderly shutdown sequence.
Environment
- Omarchy 3.8.0
- Arch / CachyOS base, systemd 257.x, btrfs root with
@cachesubvol mounted at/var/cache - Hyprland 0.55.0 under uwsm
Root cause
nohup bash -c "sleep 2 && systemctl poweroff --no-wall" >/dev/null 2>&1 &nohup only blocks SIGHUP. The detached background process inherits the systemd unit (session-N.scope). When systemd-logind tells systemd to stop the session, that scope is terminated with the standard stop sequence — SIGTERM, wait TimeoutStopSec, then SIGKILL. The pending sleep 2 && systemctl poweroff is killed before it can complete its job, leaving the actual shutdown to fall back to systemd's own mechanism (which is what currently powers the machine off, but only after the noisy timeout).
This is masked but not fixed by lowering DefaultTimeoutStopSec (#3443 / #1886 / #5133): the cleanup is still violent, just faster.
Proposed fix
Run poweroff in a transient systemd unit so it is owned by PID 1, not by the session scope:
systemd-run --no-block --collect --unit omarchy-poweroff /usr/bin/systemctl poweroff --no-wallOr simpler — drop the sleep/detach trick entirely: omarchy-hyprland-window-close-all already runs synchronously and systemctl poweroff returns immediately after handing off to PID 1:
omarchy-hyprland-window-close-all
sleep 1
exec systemctl poweroff --no-wallI'm happy to send a PR with whichever pattern you prefer.
View raw text
## Summary `omarchy-system-shutdown` schedules `systemctl poweroff` via `nohup bash -c "sleep 2 && systemctl poweroff --no-wall" >/dev/null 2>&1 &`. Although `nohup` and `&` detach from the controlling terminal, the process **stays inside the user's `session-N.scope`**. When systemd begins the shutdown sequence it stops that scope first, killing the very `systemctl poweroff` it depends on. Result: every shutdown is "dirty". ## Steps to reproduce 1. Open the Omarchy menu → Power → Shutdown 2. After reboot inspect the previous boot: ```bash journalctl -b -1 --no-pager | grep -E "Stopping timed out|Killing process .* systemctl|Failed unmounting" ``` ## Expected Clean shutdown, all mounts unmounted, no `session-N.scope: Failed with result 'timeout'`. ## Actual (consistent across 5+ boots on my system) ``` systemd[1]: session-2.scope: Stopping timed out. Killing. systemd[1]: session-2.scope: Killing process <PID> (systemctl) with signal SIGKILL. systemd[1]: session-2.scope: Failed with result 'timeout'. systemd[1]: Failed unmounting /var/cache. umount[<PID>]: umount: /var/cache: target is busy. ``` The `Failed unmounting /var/cache` follow-on happens because background services (plocate-updatedb, fwupd, pacman temp dirs) are still holding `/var/cache` when the kill cascade reaches the unmount step — `omarchy-hyprland-window-close-all` does not give them time to settle, and the SIGKILL of the orchestrating systemctl truncates the orderly shutdown sequence. ## Environment - Omarchy 3.8.0 - Arch / CachyOS base, systemd 257.x, btrfs root with `@cache` subvol mounted at `/var/cache` - Hyprland 0.55.0 under uwsm ## Root cause ```bash nohup bash -c "sleep 2 && systemctl poweroff --no-wall" >/dev/null 2>&1 & ``` `nohup` only blocks SIGHUP. The detached background process inherits the systemd unit (`session-N.scope`). When `systemd-logind` tells systemd to stop the session, that scope is terminated with the standard stop sequence — `SIGTERM`, wait `TimeoutStopSec`, then `SIGKILL`. The pending `sleep 2 && systemctl poweroff` is killed before it can complete its job, leaving the actual shutdown to fall back to systemd's own mechanism (which is what currently powers the machine off, but only after the noisy timeout). This is masked but not fixed by lowering `DefaultTimeoutStopSec` (#3443 / #1886 / #5133): the cleanup is still violent, just faster. ## Proposed fix Run `poweroff` in a transient systemd unit so it is owned by PID 1, not by the session scope: ```bash systemd-run --no-block --collect --unit omarchy-poweroff /usr/bin/systemctl poweroff --no-wall ``` Or simpler — drop the `sleep`/detach trick entirely: `omarchy-hyprland-window-close-all` already runs synchronously and `systemctl poweroff` returns immediately after handing off to PID 1: ```bash omarchy-hyprland-window-close-all sleep 1 exec systemctl poweroff --no-wall ``` I'm happy to send a PR with whichever pattern you prefer.
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 02:25 UTC