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

"Launching <app>…" OSD stays on screen forever when the detached osd close is lost

Reported by juanchandias · filed Sep 16, 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

"Launching <app>…" OSD stays on screen forever when the detached osd close is lostrevision 1 · captured 2026-09-28 21:23 UTC via poll

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 = 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.
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