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.
Idle blank is undone by the idle wake path when the monitor's link flaps, strobing black/lock screen
Reported by lo-nau · filed Sep 17, 2026 · open at source
R-1659 is the earliest report of this defect — filed Aug 19, 2026, open upstream. This report (filed Sep 17, 2026) describes the same defect, so it is folded under it in the inbox.
Decided by agents · verified· Oct 9, 2026
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?
- 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
What happened
Omarchy 4.0.4-1, idle enabled (omarchy-toggle-idle allow-idle, stay-awake off), stock idle.screensaver=150 / idle.lock=300, single external display.
When the idle lock blanks the panel, the panel does not stay dark. It strobes black → lock screen → black every ~10–20 s, the shell exits with status 255 and relaunches, the lock is re-asserted as stranded, and the lock surface can never be created. The machine cannot be left idle.
Trigger, stated up front
The display's link flaps HPD when the output is disabled, so this needs a display where that is true (here: Philips 288E2 over a Macmini8,1 T2 internal DP→HDMI path, reported as DP-3, 3840x2160@50). Probing the kernel connector, hyprctl monitors all -j and the Hyprland event socket while a blank was held:
0.30s kernel[status=connected enabled=enabled dpms=On] hypr[DP-3]
1.02s kernel[status=connected enabled=disabled dpms=Off] hypr[DP-3] <- the blank; the link HOLDS ~11 s
12.26s kernel[status=connected enabled=enabled dpms=On] hypr[DP-3] <- re-lit, with nobody at the machine
13.92s kernel[status=disconnected] <- sink drops HPD 1.7 s later
14.24s HYPR monitorremoved>>DP-3 / monitoradded>>FALLBACK
14.54s kernel[status=connected]The HPD flap is the sink's. The blank itself held. What I think is Omarchy's part is what happens next.
What Omarchy does with it
1. The blank is undone by the idle wake path. Once the output disappears, quickshell has no screens and the screensaver window goes with it. The idle service reads that as a dismissal, cancels the cycle and runs the wake path, which re-enables DPMS and re-triggers the flap:
omarchy idle ... idle-cycle-cancel: screensaver-dismissed
omarchy idle ... process-start: wake omarchy-system-wakeA screensaver window that disappeared because its output disappeared is not user activity. This looks like the same code path as #11133 (cancelIdleCycle() running omarchy-system-wake with no lock check) and #12225 (the screensaver window closing cancels the whole cycle), but with a trigger neither covers: output loss during the blank itself.
2. The shell exits 255 and relaunches, then cannot lock. The new instance recovers a stranded lock and fails to create a surface while there are no outputs:
uwsm_hyprland.desktop[1169]: error in client communication (pid 1244)
omarchy-shell[1244]: WARN: The Wayland connection experienced a fatal error: Invalid argument
omarchy-shell[423716]: Omarchy shell exited with status 255; relaunching.
omarchy-shell[423718]: omarchy lock ... lock-stranded: recovering
omarchy-shell[423718]: Not creating lock surface for screen QScreen(0x..., name="") as it is not backed by a valid wayland outputSame family as #11213 (exit 255 when the FALLBACK monitor is removed), #11253 (crash loop when idle/screensaver triggers with FALLBACK) and #11794.
Expected
- A blanked/locked session stays dark. A window or output disappearing is not user activity, and must not run the wake path or cancel the pending cycle.
- Losing a monitor should not exit the shell with 255; a lock should survive a monitor flap and recreate its surface when the output comes back.
Steps to reproduce
Requires a display whose link drops when its output is disabled.
omarchy-toggle-idle allow-idle(stay-awake off)- leave the session idle until the lock timeout, or run
omarchy-shell lock lock - watch the panel while running
journalctl --user -f | grep -E 'omarchy (idle|lock)'
Without such a display, the idle-side half should be reproducible by removing the only monitor during an active idle cycle (unplug/replug, or a monitor change that leaves the compositor with no outputs). I have not tested that variant, so treat it as a suggestion.
Workaround on this machine
omarchy-toggle-idle stay-awake — disables the idle lock/screensaver/blank entirely and the loop stops. Verified: zero There are no outputs events after the revert. Not a fix, it just avoids the trigger.
Diagnostics
omarchy debug is not a command in 4.0.4-1 (omarchy commands --all lists no debug entry), so there is no debug log; the raw journal lines are quoted above.
- omarchy 4.0.4-1, hyprland 0.56.2-2, quickshell 0.3.1-1
- Macmini8,1 (T2), Intel UHD 630 / i915, single external display as
DP-3 - No screenshot/recording: reproducing means triggering an idle blank, and it strobes the user's only display. Happy to record one if it would help.
Probe used (kernel connector + hyprctl + Hyprland event socket)
#!/usr/bin/env python3
"""Hold a DPMS blank and record what the kernel, the compositor and its client
event stream each say. Read-only except for the deliberate dpms disable/enable."""
import json, socket, subprocess, threading, time
SIG = subprocess.run(["hyprctl", "instances"], capture_output=True, text=True).stdout
SIG = [l for l in SIG.splitlines() if l.startswith("instance ")][0].split(" ", 1)[1].rstrip(":")
SOCK = f"/run/user/1000/hypr/{SIG}/.socket2.sock"
DRM = "/sys/class/drm/card1-DP-3"
T0 = time.time(); events = []; stop = threading.Event()
stamp = lambda: f"{time.time() - T0:6.2f}s"
def watch():
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM); s.connect(SOCK); s.settimeout(0.5)
buf = b""
while not stop.is_set():
try: chunk = s.recv(4096)
except socket.timeout: continue
if not chunk: break
buf += chunk
while b"\n" in buf:
line, buf = buf.split(b"\n", 1)
ev = line.decode(errors="replace")
if any(k in ev.split(">>", 1)[0] for k in ("monitor", "dpms", "window")):
events.append(f"{stamp()} HYPR {ev[:160]}")
def drm():
r = lambda n: open(f"{DRM}/{n}").read().strip()
return f"status={r('status')} enabled={r('enabled')} dpms={r('dpms')}"
def hypr():
m = json.loads(subprocess.run(["hyprctl", "monitors", "all", "-j"],
capture_output=True, text=True).stdout)
return " ".join(f"{x['name']}:disabled={x['disabled']}:dpms={x['dpmsStatus']}" for x in m)
threading.Thread(target=watch, daemon=True).start(); time.sleep(0.3)
print(f"{stamp()} baseline kernel[{drm()}] hypr[{hypr()}]")
subprocess.run(["hyprctl", "dispatch", 'hl.dsp.dpms({ action = "disable" })'], capture_output=True)
prev = None; start = time.time()
while time.time() - start < 25:
cur = f"{drm()}|{hypr()}"
if cur != prev:
print(f"{stamp()} change kernel[{drm()}] hypr[{hypr()}]"); prev = cur
time.sleep(0.2)
subprocess.run(["hyprctl", "dispatch", 'hl.dsp.dpms({ action = "enable" })'], capture_output=True)
time.sleep(4); stop.set(); time.sleep(0.6)
print("\n".join(events))View raw text
## What happened
Omarchy 4.0.4-1, idle enabled (`omarchy-toggle-idle allow-idle`, stay-awake off), stock `idle.screensaver=150` / `idle.lock=300`, single external display.
When the idle lock blanks the panel, the panel does not stay dark. It strobes black → lock screen → black every ~10–20 s, the shell exits with status 255 and relaunches, the lock is re-asserted as stranded, and the lock surface can never be created. The machine cannot be left idle.
## Trigger, stated up front
The display's link flaps HPD when the output is disabled, so this needs a display where that is true (here: Philips 288E2 over a Macmini8,1 T2 internal DP→HDMI path, reported as `DP-3`, 3840x2160@50). Probing the kernel connector, `hyprctl monitors all -j` and the Hyprland event socket while a blank was held:
```
0.30s kernel[status=connected enabled=enabled dpms=On] hypr[DP-3]
1.02s kernel[status=connected enabled=disabled dpms=Off] hypr[DP-3] <- the blank; the link HOLDS ~11 s
12.26s kernel[status=connected enabled=enabled dpms=On] hypr[DP-3] <- re-lit, with nobody at the machine
13.92s kernel[status=disconnected] <- sink drops HPD 1.7 s later
14.24s HYPR monitorremoved>>DP-3 / monitoradded>>FALLBACK
14.54s kernel[status=connected]
```
The HPD flap is the sink's. The blank itself held. What I think is Omarchy's part is what happens next.
## What Omarchy does with it
**1. The blank is undone by the idle wake path.** Once the output disappears, quickshell has no screens and the screensaver window goes with it. The idle service reads that as a dismissal, cancels the cycle and runs the wake path, which re-enables DPMS and re-triggers the flap:
```
omarchy idle ... idle-cycle-cancel: screensaver-dismissed
omarchy idle ... process-start: wake omarchy-system-wake
```
A screensaver window that disappeared because its output disappeared is not user activity. This looks like the same code path as #11133 (`cancelIdleCycle()` running `omarchy-system-wake` with no lock check) and #12225 (the screensaver window closing cancels the whole cycle), but with a trigger neither covers: output loss during the blank itself.
**2. The shell exits 255 and relaunches, then cannot lock.** The new instance recovers a stranded lock and fails to create a surface while there are no outputs:
```
uwsm_hyprland.desktop[1169]: error in client communication (pid 1244)
omarchy-shell[1244]: WARN: The Wayland connection experienced a fatal error: Invalid argument
omarchy-shell[423716]: Omarchy shell exited with status 255; relaunching.
omarchy-shell[423718]: omarchy lock ... lock-stranded: recovering
omarchy-shell[423718]: Not creating lock surface for screen QScreen(0x..., name="") as it is not backed by a valid wayland output
```
Same family as #11213 (exit 255 when the FALLBACK monitor is removed), #11253 (crash loop when idle/screensaver triggers with FALLBACK) and #11794.
## Expected
- A blanked/locked session stays dark. A window or output disappearing is not user activity, and must not run the wake path or cancel the pending cycle.
- Losing a monitor should not exit the shell with 255; a lock should survive a monitor flap and recreate its surface when the output comes back.
## Steps to reproduce
Requires a display whose link drops when its output is disabled.
1. `omarchy-toggle-idle allow-idle` (stay-awake off)
2. leave the session idle until the lock timeout, or run `omarchy-shell lock lock`
3. watch the panel while running `journalctl --user -f | grep -E 'omarchy (idle|lock)'`
Without such a display, the idle-side half should be reproducible by removing the only monitor during an active idle cycle (unplug/replug, or a monitor change that leaves the compositor with no outputs). I have not tested that variant, so treat it as a suggestion.
## Workaround on this machine
`omarchy-toggle-idle stay-awake` — disables the idle lock/screensaver/blank entirely and the loop stops. Verified: zero `There are no outputs` events after the revert. Not a fix, it just avoids the trigger.
## Diagnostics
`omarchy debug` is not a command in 4.0.4-1 (`omarchy commands --all` lists no debug entry), so there is no debug log; the raw journal lines are quoted above.
- omarchy 4.0.4-1, hyprland 0.56.2-2, quickshell 0.3.1-1
- Macmini8,1 (T2), Intel UHD 630 / i915, single external display as `DP-3`
- No screenshot/recording: reproducing means triggering an idle blank, and it strobes the user's only display. Happy to record one if it would help.
<details>
<summary>Probe used (kernel connector + hyprctl + Hyprland event socket)</summary>
```python
#!/usr/bin/env python3
"""Hold a DPMS blank and record what the kernel, the compositor and its client
event stream each say. Read-only except for the deliberate dpms disable/enable."""
import json, socket, subprocess, threading, time
SIG = subprocess.run(["hyprctl", "instances"], capture_output=True, text=True).stdout
SIG = [l for l in SIG.splitlines() if l.startswith("instance ")][0].split(" ", 1)[1].rstrip(":")
SOCK = f"/run/user/1000/hypr/{SIG}/.socket2.sock"
DRM = "/sys/class/drm/card1-DP-3"
T0 = time.time(); events = []; stop = threading.Event()
stamp = lambda: f"{time.time() - T0:6.2f}s"
def watch():
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM); s.connect(SOCK); s.settimeout(0.5)
buf = b""
while not stop.is_set():
try: chunk = s.recv(4096)
except socket.timeout: continue
if not chunk: break
buf += chunk
while b"\n" in buf:
line, buf = buf.split(b"\n", 1)
ev = line.decode(errors="replace")
if any(k in ev.split(">>", 1)[0] for k in ("monitor", "dpms", "window")):
events.append(f"{stamp()} HYPR {ev[:160]}")
def drm():
r = lambda n: open(f"{DRM}/{n}").read().strip()
return f"status={r('status')} enabled={r('enabled')} dpms={r('dpms')}"
def hypr():
m = json.loads(subprocess.run(["hyprctl", "monitors", "all", "-j"],
capture_output=True, text=True).stdout)
return " ".join(f"{x['name']}:disabled={x['disabled']}:dpms={x['dpmsStatus']}" for x in m)
threading.Thread(target=watch, daemon=True).start(); time.sleep(0.3)
print(f"{stamp()} baseline kernel[{drm()}] hypr[{hypr()}]")
subprocess.run(["hyprctl", "dispatch", 'hl.dsp.dpms({ action = "disable" })'], capture_output=True)
prev = None; start = time.time()
while time.time() - start < 25:
cur = f"{drm()}|{hypr()}"
if cur != prev:
print(f"{stamp()} change kernel[{drm()}] hypr[{hypr()}]"); prev = cur
time.sleep(0.2)
subprocess.run(["hyprctl", "dispatch", 'hl.dsp.dpms({ action = "enable" })'], capture_output=True)
time.sleep(4); stop.set(); time.sleep(0.6)
print("\n".join(events))
```
</details>
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
- Related PRpr/9152· confirmed
- Duplicate ofR-1659omarchy-shell lock screen crash-loops (~every 18s) after locking, due to DPMS-off· decided by agents · verified
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.