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

Idle screensaver/lock never fire when shell.json idle timeout differs from defaults (Quickshell IdleMonitor timeout bug)

Reported by stephan-dupreez · filed Oct 7, 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

Idle screensaver/lock never fire when shell.json idle timeout differs from defaults (Quickshell IdleMonitor timeout bug)revision 1 · captured 2026-10-07 12:42 UTC via poll

System details

Intel i7-12800H, Intel Iris Xe + NVIDIA RTX A1000 Laptop GPU, Omarchy 4.0.4-1, Quickshell 0.3.1-1, Hyprland 0.56.2

What's wrong?

If idle.screensaver or idle.lock in ~/.config/omarchy/shell.json differs from the built-in defaults so that the first idle timeout changes, the screensaver and lock never trigger again for the lifetime of the shell. The machine silently stays unlocked.

Cause: Quickshell 0.3.1 IdleMonitor goes permanently silent when timeout is written after creation (upstream: quickshell-mirror/quickshell#938, fix pending in quickshell-mirror/quickshell#1097).

plugins/services/idle/Service.qml creates the IdleMonitor with timeout: root.firstIdleTimeoutSeconds. At startup that evaluates against the built-in defaults (defaultScreensaverSeconds: 150, defaultLockSeconds: 300, so 150s). Then shell.json loads and the binding changes it (e.g. screensaver 600 / lock 1800, so 600s). That runtime write kills the monitor. The same thing happens whenever shell.json idle values are edited while the shell is running.

Steps to reproduce

  1. Set "idle": { "screensaver": 600, "lock": 1800 } in ~/.config/omarchy/shell.json.
  2. omarchy restart shell.
  3. Leave the machine idle for more than 10 minutes. No screensaver, no lock.
  4. quickshell -p /usr/share/omarchy/shell ipc call idle status: lastEvent stays idle-monitor: active with a lastEventAt from shell startup. No window has inhibitingIdle, and no media is playing.

In my case the shell ran from Oct 1 to Oct 7 without a single idle event.

Isolated repro (no Omarchy involved):

import QtQuick
import Quickshell
import Quickshell.Wayland
ShellRoot {
  property int to: 5
  Timer { interval: 1000; running: true; onTriggered: to = 10 }
  IdleMonitor { timeout: to; onIsIdleChanged: console.log("CHANGED idle=" + isIdle) }
  IdleMonitor { timeout: 10; onIsIdleChanged: console.log("CONTROL idle=" + isIdle) }
}

Only CONTROL fires. Toggling enabled false/true after the timeout change revives the monitor.

Workaround: quickshell -p /usr/share/omarchy/shell ipc call idle disable && quickshell -p /usr/share/omarchy/shell ipc call idle enable after the shell has loaded its config (and after each shell.json idle change). I run that from a small user service. After that the screensaver and lock fire normally.

Possible fixes on the Omarchy side until Quickshell ships #1097:
- Keep the IdleMonitor enabled: false until shell.json has loaded, or create it in a Loader that is re-created when the timeout changes.
- Or toggle idleMonitor.enabled off/on in an onFirstIdleTimeoutSecondsChanged handler.

Since this silently disables the screen lock, it's a security issue for anyone who changed the idle timeout.

View raw text
### System details

Intel i7-12800H, Intel Iris Xe + NVIDIA RTX A1000 Laptop GPU, Omarchy 4.0.4-1, Quickshell 0.3.1-1, Hyprland 0.56.2

### What's wrong?

If `idle.screensaver` or `idle.lock` in `~/.config/omarchy/shell.json` differs from the built-in defaults so that the *first* idle timeout changes, the screensaver and lock never trigger again for the lifetime of the shell. The machine silently stays unlocked.

**Cause:** Quickshell 0.3.1 `IdleMonitor` goes permanently silent when `timeout` is written after creation (upstream: quickshell-mirror/quickshell#938, fix pending in quickshell-mirror/quickshell#1097).

`plugins/services/idle/Service.qml` creates the `IdleMonitor` with `timeout: root.firstIdleTimeoutSeconds`. At startup that evaluates against the built-in defaults (`defaultScreensaverSeconds: 150`, `defaultLockSeconds: 300`, so 150s). Then `shell.json` loads and the binding changes it (e.g. screensaver 600 / lock 1800, so 600s). That runtime write kills the monitor. The same thing happens whenever `shell.json` idle values are edited while the shell is running.

**Steps to reproduce**

1. Set `"idle": { "screensaver": 600, "lock": 1800 }` in `~/.config/omarchy/shell.json`.
2. `omarchy restart shell`.
3. Leave the machine idle for more than 10 minutes. No screensaver, no lock.
4. `quickshell -p /usr/share/omarchy/shell ipc call idle status`: `lastEvent` stays `idle-monitor: active` with a `lastEventAt` from shell startup. No window has `inhibitingIdle`, and no media is playing.

In my case the shell ran from Oct 1 to Oct 7 without a single idle event.

**Isolated repro (no Omarchy involved):**

```qml
import QtQuick
import Quickshell
import Quickshell.Wayland
ShellRoot {
  property int to: 5
  Timer { interval: 1000; running: true; onTriggered: to = 10 }
  IdleMonitor { timeout: to; onIsIdleChanged: console.log("CHANGED idle=" + isIdle) }
  IdleMonitor { timeout: 10; onIsIdleChanged: console.log("CONTROL idle=" + isIdle) }
}
```

Only `CONTROL` fires. Toggling `enabled` false/true after the timeout change revives the monitor.

**Workaround:** `quickshell -p /usr/share/omarchy/shell ipc call idle disable && quickshell -p /usr/share/omarchy/shell ipc call idle enable` after the shell has loaded its config (and after each `shell.json` idle change). I run that from a small user service. After that the screensaver and lock fire normally.

**Possible fixes on the Omarchy side** until Quickshell ships #1097:
- Keep the `IdleMonitor` `enabled: false` until `shell.json` has loaded, or create it in a `Loader` that is re-created when the timeout changes.
- Or toggle `idleMonitor.enabled` off/on in an `onFirstIdleTimeoutSecondsChanged` handler.

Since this silently disables the screen lock, it's a security issue for anyone who changed the idle timeout.

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