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 …" OSD can linger or stick after app launch; no way to dismiss it
Reported by straficchio · filed Sep 25, 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
Launching Obsidian from the launcher showed the shell's launch-feedback OSD
("Launching Obsidian…"). The OSD remained stuck on screen with no way to
dismiss it from the desktop. It eventually cleared on its own; by the time it
was inspected (~1 minute later) omarchy-shell osd state reported closed
and no omarchy-osd layer surface was mapped in Hyprland, consistent with the
15 s failsafe timer having closed it long after the OSD stopped being useful.
The OSD card is shown with duration: 0 (persistent, no hide timer), so once
it is on screen it only ever goes away through a detachedomarchy-shell osd close IPC call. There is no keybinding or other
user-facing way to dismiss it.
Expected behavior
The OSD dismisses as soon as the launched app's window appears, never lingers
for the full failsafe window while the app is already running, and can never
persist indefinitely. A user-facing dismiss would also be welcome.
Steps to reproduce
- Launch a slow-starting app (Obsidian / Electron here) from the launcher.
- The "Launching …" OSD appears ~2 s later if no window has mapped yet.
- The OSD stays on screen; depending on timing it lingers until the 15 s
failsafe or, per the analysis below, can persist forever.
Analysis (shell/services/AppLibrary.qml, shell/plugins/osd/Osd.qml)
beginLaunchFeedback()startslaunchDelay(2 s) andlaunchTimeout
(15 s, failsafe).
- launchDelay.onTriggered shows the OSD with
Quickshell.execDetached(["omarchy-shell", "osd", "show", … duration: 0])
and sets launchOsdOpen = true. In Osd.qml, duration: 0 stops the hide
timer, so the OSD is persistent from then on.
- When a new/active toplevel appears, maybeFinishLaunchFeedback() calls
closeLaunchFeedback(), which stops both timers and fires
Quickshell.execDetached(["omarchy-shell", "osd", "close"]).
Failure modes that leave the OSD stuck:
- IPC ordering race.
showandcloseare separate detached processes
with no ordering guarantee. If the close IPC is processed before the
show IPC (plausible under the CPU spike of a heavy app starting), the OSD
opens with duration: 0 after the close was consumed. Both timers are
already stopped and launchOsdOpen is false, so nothing will ever close it
again — stuck permanently.
2. Lost close IPC. omarchy-shell gives up after a 2 s IPC timeout
(OMARCHY_SHELL_IPC_TIMEOUT). If the detached close call times out under
load, the end state is the same: timers stopped, launchOsdOpen = false,
OSD open with duration: 0 — stuck permanently.
3. Missed window event. If the toplevel/active-toplevel change that should
trigger maybeFinishLaunchFeedback() does not fire (or fires while the
conditions still read "no new window"), the OSD simply sits there for the
whole failsafe window with no progress indication and no dismiss
affordance — which is what this occurrence looks like.
Possible fix directions: cap the launch OSD duration instead of using 0;
verify/retry the close via omarchy-shell osd state incloseLaunchFeedback; make a pending close always win over an in-flightshow (e.g. serial/token in the payload); and/or bind a dismiss key.
Workaround
omarchy-shell osd close from a terminal (or omarchy restart shell).
System details
- Omarchy 4.0.4-1
- Kernel 7.2.5-3-omarchy, x86_64
- Hyprland 0.56.2
- GPU: Intel Haswell-ULT integrated graphics (i915)
- Full
omarchy-debuglog available on request (509 lines)
Note: no screenshot of the stuck state — the OSD had already cleared by the
time it was investigated.
View raw text
## What happened
Launching Obsidian from the launcher showed the shell's launch-feedback OSD
("Launching Obsidian…"). The OSD remained stuck on screen with no way to
dismiss it from the desktop. It eventually cleared on its own; by the time it
was inspected (~1 minute later) `omarchy-shell osd state` reported `closed`
and no `omarchy-osd` layer surface was mapped in Hyprland, consistent with the
15 s failsafe timer having closed it long after the OSD stopped being useful.
The OSD card is shown with `duration: 0` (persistent, no hide timer), so once
it is on screen it only ever goes away through a detached
`omarchy-shell osd close` IPC call. There is no keybinding or other
user-facing way to dismiss it.
## Expected behavior
The OSD dismisses as soon as the launched app's window appears, never lingers
for the full failsafe window while the app is already running, and can never
persist indefinitely. A user-facing dismiss would also be welcome.
## Steps to reproduce
1. Launch a slow-starting app (Obsidian / Electron here) from the launcher.
2. The "Launching …" OSD appears ~2 s later if no window has mapped yet.
3. The OSD stays on screen; depending on timing it lingers until the 15 s
failsafe or, per the analysis below, can persist forever.
## Analysis (`shell/services/AppLibrary.qml`, `shell/plugins/osd/Osd.qml`)
- `beginLaunchFeedback()` starts `launchDelay` (2 s) and `launchTimeout`
(15 s, failsafe).
- `launchDelay.onTriggered` shows the OSD with
`Quickshell.execDetached(["omarchy-shell", "osd", "show", … duration: 0])`
and sets `launchOsdOpen = true`. In `Osd.qml`, `duration: 0` stops the hide
timer, so the OSD is persistent from then on.
- When a new/active toplevel appears, `maybeFinishLaunchFeedback()` calls
`closeLaunchFeedback()`, which **stops both timers** and fires
`Quickshell.execDetached(["omarchy-shell", "osd", "close"])`.
Failure modes that leave the OSD stuck:
1. **IPC ordering race.** `show` and `close` are separate detached processes
with no ordering guarantee. If the `close` IPC is processed before the
`show` IPC (plausible under the CPU spike of a heavy app starting), the OSD
opens with `duration: 0` *after* the close was consumed. Both timers are
already stopped and `launchOsdOpen` is false, so nothing will ever close it
again — stuck permanently.
2. **Lost close IPC.** `omarchy-shell` gives up after a 2 s IPC timeout
(`OMARCHY_SHELL_IPC_TIMEOUT`). If the detached `close` call times out under
load, the end state is the same: timers stopped, `launchOsdOpen = false`,
OSD open with `duration: 0` — stuck permanently.
3. **Missed window event.** If the toplevel/active-toplevel change that should
trigger `maybeFinishLaunchFeedback()` does not fire (or fires while the
conditions still read "no new window"), the OSD simply sits there for the
whole failsafe window with no progress indication and no dismiss
affordance — which is what this occurrence looks like.
Possible fix directions: cap the launch OSD duration instead of using 0;
verify/retry the close via `omarchy-shell osd state` in
`closeLaunchFeedback`; make a pending `close` always win over an in-flight
`show` (e.g. serial/token in the payload); and/or bind a dismiss key.
## Workaround
`omarchy-shell osd close` from a terminal (or `omarchy restart shell`).
## System details
- Omarchy 4.0.4-1
- Kernel 7.2.5-3-omarchy, x86_64
- Hyprland 0.56.2
- GPU: Intel Haswell-ULT integrated graphics (i915)
- Full `omarchy-debug` log available on request (509 lines)
Note: no screenshot of the stuck state — the OSD had already cleared by the
time it was investigated.
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 19:49 UTC