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.
"Launching <app>…" OSD stays on screen forever when the detached osd close is lost
Reported by juanchandias · filed Sep 16, 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
What happened
Launched Google Chrome from the Omarchy menu (Apps). The "Launching Google Chrome…" OSD appeared after the usual 2 s delay, Chrome opened normally ~12 s later, but the OSD never went away. It stayed on screen after Chrome was closed, for ~5 minutes, until an unrelated menu launch (Files) ran a new launch-feedback cycle whose osd close finally took it down. omarchy-shell osd close also clears it manually.
Expected
The OSD closes as soon as the launched window appears (or at the 15 s launchTimeout fallback at the latest).
Root cause (from reading shell/services/AppLibrary.qml, identical on master)
AppLibrary lives inside the shell process, but it drives the OSD through an external CLI round-trip:
// launchDelay.onTriggered
Quickshell.execDetached(["omarchy-shell", "osd", "show", JSON.stringify({ icon: "", message: ..., duration: 0 })])
// closeLaunchFeedback()
Quickshell.execDetached(["omarchy-shell", "osd", "close"])
root.launchOsdOpen = falseThree things combine into a stuck OSD:
- The OSD is shown with
duration: 0, so its only exit is that detachedomarchy-shell osd close. omarchy-shellwrapsqs ipcintimeout --kill-after=1s 2s. Each call spawnsbash → timeout → qs(a full Qt6 process). If that exceeds 2 s the call is killed and the close is silently lost — nothing is logged because the detached child's stderr goes nowhere.closeLaunchFeedback()setslaunchOsdOpen = falseand stops `launchTimeout` before knowing the close landed, so there is no retry and the 15 s safety net never fires.
Step 2 is exactly the situation a heavy app launch creates. This machine is a 2012 Mac mini: 3.8 GB RAM, 5400 rpm HDD. Chrome's cold start hit 1.5 GB peak with zram swap in use, evicting page cache; paging qs + Qt back in from a spinning disk trivially exceeds 2 s. I measured omarchy-shell osd state at 2.015 s cold right after the incident vs ~50 ms warm. A show/close ordering race between two independent detached processes has the same effect.
Suggested fix
Drive the OSD in-process, the way omarchy.audio / omarchy.media / omarchy.monitor already do via shell.summon("omarchy.osd", payload) — no subprocess, no timeout, ordering guaranteed. As a belt-and-braces measure, show the launch OSD with a finite duration (e.g. the remaining launchTimeout budget) instead of 0, so a lost close self-heals rather than sticking forever.
System
- Omarchy 4.0.3-1, Hyprland, kernel 7.2.3-arch1-3
- Intel Core i7-3615QM (Ivy Bridge), Intel HD 4000, 3.8 GB RAM, HDD (APPLE HDD HTS541010A9E662), zram swap
- Journal timeline:
gtk-launch google-chrome.desktop10:37:28 → Chrome scope 10:37:40 → Chrome closed 10:39:32 → OSD still visible at 10:42:06 (screenshot attached) → cleared by Files launch at 10:42:36.
View raw text
## What happened
Launched Google Chrome from the Omarchy menu (Apps). The "Launching Google Chrome…" OSD appeared after the usual 2 s delay, Chrome opened normally ~12 s later, but the OSD **never went away**. It stayed on screen after Chrome was closed, for ~5 minutes, until an unrelated menu launch (Files) ran a new launch-feedback cycle whose `osd close` finally took it down. `omarchy-shell osd close` also clears it manually.
## Expected
The OSD closes as soon as the launched window appears (or at the 15 s `launchTimeout` fallback at the latest).
## Root cause (from reading `shell/services/AppLibrary.qml`, identical on master)
`AppLibrary` lives inside the shell process, but it drives the OSD through an **external CLI round-trip**:
```qml
// launchDelay.onTriggered
Quickshell.execDetached(["omarchy-shell", "osd", "show", JSON.stringify({ icon: "", message: ..., duration: 0 })])
// closeLaunchFeedback()
Quickshell.execDetached(["omarchy-shell", "osd", "close"])
root.launchOsdOpen = false
```
Three things combine into a stuck OSD:
1. The OSD is shown with `duration: 0`, so its **only** exit is that detached `omarchy-shell osd close`.
2. `omarchy-shell` wraps `qs ipc` in `timeout --kill-after=1s 2s`. Each call spawns `bash → timeout → qs` (a full Qt6 process). If that exceeds 2 s the call is killed and the close is silently lost — nothing is logged because the detached child's stderr goes nowhere.
3. `closeLaunchFeedback()` sets `launchOsdOpen = false` and **stops `launchTimeout`** *before* knowing the close landed, so there is no retry and the 15 s safety net never fires.
Step 2 is exactly the situation a heavy app launch creates. This machine is a 2012 Mac mini: 3.8 GB RAM, 5400 rpm HDD. Chrome's cold start hit 1.5 GB peak with zram swap in use, evicting page cache; paging `qs` + Qt back in from a spinning disk trivially exceeds 2 s. I measured `omarchy-shell osd state` at **2.015 s** cold right after the incident vs ~50 ms warm. A show/close ordering race between two independent detached processes has the same effect.
## Suggested fix
Drive the OSD in-process, the way `omarchy.audio` / `omarchy.media` / `omarchy.monitor` already do via `shell.summon("omarchy.osd", payload)` — no subprocess, no timeout, ordering guaranteed. As a belt-and-braces measure, show the launch OSD with a finite `duration` (e.g. the remaining `launchTimeout` budget) instead of `0`, so a lost close self-heals rather than sticking forever.
## System
- Omarchy 4.0.3-1, Hyprland, kernel 7.2.3-arch1-3
- Intel Core i7-3615QM (Ivy Bridge), Intel HD 4000, 3.8 GB RAM, HDD (APPLE HDD HTS541010A9E662), zram swap
- Journal timeline: `gtk-launch google-chrome.desktop` 10:37:28 → Chrome scope 10:37:40 → Chrome closed 10:39:32 → OSD still visible at 10:42:06 (screenshot attached) → cleared by Files launch at 10:42:36.
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 14:15 UTC