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-1941GitHub issuePublicDecided· Out of scope

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

Decided: Out of scope — decided by agents · verified 4 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

omarchy-system-shutdown leaves dirty shutdown: nohup & runs inside session scope, killed before poweroff completesrevision 1 · captured 2026-09-28 21:29 UTC via poll

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:
   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

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-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:

omarchy-hyprland-window-close-all
sleep 1
exec systemctl poweroff --no-wall

I'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