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.
Spamming a menu-summoning keybinding (Super+K) leaks orphaned omarchy-menu-select processes
Reported by FernandoJVideira · filed Aug 30, 2026Closed upstream on 2026-10-09 by the bot omarchybot, as a duplicate (target not recorded).
At a glance
- 1 · What is claimed?
- ConfirmedViolates SYS-REQ-260922-X6Z5: a select prompt superseded by a second summon is never answered: its caller receives neither a value nor the no-selection cancel and polls forever
- ConfirmedReproducible: after summon A, summon B, Escape: Menu.qml writes B's done file only; omarchy-menu-select A keeps polling
- ConfirmedAffects the menu component
- LinkedMatches known issue KI-MENU-REQUEST-LIFECYCLE
- 2 · What does it affect?
- 3 · Is it reproducible?
- An engine-executed run exited 1 and showed the defect signal. See reproducer
- 4 · What remains unclear?
- Open question for maintainers: Semantics: answer a superseded prompt as cancel (#9056) or refuse a second summon?
- Open question for maintainers: A bounded poll (KI-MENU-SELECT-POLL-DEADLOCK, KI-MENU-SELECT-SUMMON-UNBOUNDED) is separate hardening that #9056 does not cover: killing the shell while a caller waits leaves that caller polling on both trees.
- 5 · What happens next?
- Decided by agents and verified by a second, independent agent — see the decision.
Original report
What happened
Pressing Super+K (opens the Keybindings cheat sheet, bin/omarchy-menu-keybindings → omarchy-menu-select) repeatedly, before dismissing/answering the previous popup each time, leaves a permanently stuck omarchy-menu-select bash process behind for every extra press. On my system these had accumulated into 161 orphaned processes (all state S, ~4.2M each), going back roughly half an hour of intermittent key-spamming, none of which ever exited on their own.
fvideira 371018 0.0 0.0 8472 4.0M ? S< ... /bin/bash /usr/share/omarchy/bin/omarchy-menu-select Keybindings -- --width 800 --height 500
fvideira 409939 0.0 0.0 8472 4.2M ? S< ... /bin/bash /usr/share/omarchy/bin/omarchy-menu-select Keybindings -- --width 800 --height 500
... (161 total)What was expected
Pressing the keybinding again (or dismissing/selecting from the popup) should not leave any earlier invocation permanently blocked — each omarchy-menu-select process should eventually exit, even if a later summon superseded it before it was answered.
Steps to reproduce
- Bind (or use the default)
Super+K→ Keybindings menu. - Press
Super+Kseveral times in a row, faster than you dismiss/answer each popup (or just don't dismiss it and press again). - Watch
ps aux | grep omarchy-menu-select(orbtop) — one extra process per press, all in stateS, none ever exit.
Minimal non-interactive repro (bypasses the compositor, drives the same code path):
for i in $(seq 1 20); do
/usr/share/omarchy/bin/omarchy-menu-keybindings >/dev/null 2>&1 &
done
sleep 2
ps aux | grep -c '[o]marchy-menu-select' # grows by ~1 per invocation, never dropsRoot cause (found while investigating)
bin/omarchy-menu-select writes a doneFile path into the summon payload and polls for it:
while [[ ! -e $done_file ]]; do
sleep 0.05
doneIn shell/plugins/menu/Menu.qml, open(payloadJson) dispatches to openDmenu() or openExistingMenu() (via openRoute()). Both unconditionally overwrite selectionFile/doneFile/requestActive with the new request's values, without finishing whatever request was already in flight. If a caller is still waiting on a doneFile that hasn't been written yet, that file is now orphaned — nothing will ever create it, so the earlier omarchy-menu-select process spins in its sleep 0.05 loop forever. cancel() already avoids this for the normal close path by calling finishRequest(null) first; open() just never does the same before replacing an in-flight request.
I've opened a fix for this: fixes basecamp/omarchy#TBD — PR: https://github.com/omacom/omarchy/pull/9056
System details
- Omarchy version: 4.0.1-1 (stable channel)
- Kernel:
Linux 7.2.0-1-cachyos #1 SMP PREEMPT_DYNAMIC Thu, 20 Aug 2026 - GPU: NVIDIA GeForce RTX 2070 (TU106)
- Hyprland: 0.56.2 (v0.56.2, commit efb50993780079460b0cbed1363e2166a2de1d9f)
(omarchy debug isn't available as a command on this version to attach a full diagnostic log.)
View raw text
## What happened Pressing `Super+K` (opens the Keybindings cheat sheet, `bin/omarchy-menu-keybindings` → `omarchy-menu-select`) repeatedly, before dismissing/answering the previous popup each time, leaves a permanently stuck `omarchy-menu-select` bash process behind for every extra press. On my system these had accumulated into 161 orphaned processes (all state `S`, ~4.2M each), going back roughly half an hour of intermittent key-spamming, none of which ever exited on their own. ``` fvideira 371018 0.0 0.0 8472 4.0M ? S< ... /bin/bash /usr/share/omarchy/bin/omarchy-menu-select Keybindings -- --width 800 --height 500 fvideira 409939 0.0 0.0 8472 4.2M ? S< ... /bin/bash /usr/share/omarchy/bin/omarchy-menu-select Keybindings -- --width 800 --height 500 ... (161 total) ``` ## What was expected Pressing the keybinding again (or dismissing/selecting from the popup) should not leave any earlier invocation permanently blocked — each `omarchy-menu-select` process should eventually exit, even if a later summon superseded it before it was answered. ## Steps to reproduce 1. Bind (or use the default) `Super+K` → Keybindings menu. 2. Press `Super+K` several times in a row, faster than you dismiss/answer each popup (or just don't dismiss it and press again). 3. Watch `ps aux | grep omarchy-menu-select` (or `btop`) — one extra process per press, all in state `S`, none ever exit. Minimal non-interactive repro (bypasses the compositor, drives the same code path): ```bash for i in $(seq 1 20); do /usr/share/omarchy/bin/omarchy-menu-keybindings >/dev/null 2>&1 & done sleep 2 ps aux | grep -c '[o]marchy-menu-select' # grows by ~1 per invocation, never drops ``` ## Root cause (found while investigating) `bin/omarchy-menu-select` writes a `doneFile` path into the summon payload and polls for it: ```bash while [[ ! -e $done_file ]]; do sleep 0.05 done ``` In `shell/plugins/menu/Menu.qml`, `open(payloadJson)` dispatches to `openDmenu()` or `openExistingMenu()` (via `openRoute()`). Both unconditionally overwrite `selectionFile`/`doneFile`/`requestActive` with the new request's values, without finishing whatever request was already in flight. If a caller is still waiting on a `doneFile` that hasn't been written yet, that file is now orphaned — nothing will ever create it, so the earlier `omarchy-menu-select` process spins in its `sleep 0.05` loop forever. `cancel()` already avoids this for the normal close path by calling `finishRequest(null)` first; `open()` just never does the same before replacing an in-flight request. I've opened a fix for this: fixes basecamp/omarchy#TBD — PR: https://github.com/omacom/omarchy/pull/9056 ## System details - Omarchy version: 4.0.1-1 (stable channel) - Kernel: `Linux 7.2.0-1-cachyos #1 SMP PREEMPT_DYNAMIC Thu, 20 Aug 2026` - GPU: NVIDIA GeForce RTX 2070 (TU106) - Hyprland: 0.56.2 (v0.56.2, commit efb50993780079460b0cbed1363e2166a2de1d9f) (`omarchy debug` isn't available as a command on this version to attach a full diagnostic log.)
Same defect, also reported as
1 other report describesdmenu request lifecycle drops waiters on re-summon, on a busy resultProc, and for doneFile-only requests KI-MENU-REQUEST-LIFECYCLE
Earliest report: R-1570 (filed Aug 22, 2026).
- Aug 22, 2026Superseding a pending omarchy-menu-select leaks a permanent 20 fork/sec busy-wait loop R-1570
Open upstream.
Validation
AI validator claude-code (claude-opus-5.5) · evaluated revision 1 at product commit 1e43373287af · sealed 2026-10-04T21:45:45Z
Re-validation of omacom/omarchy#9057 on quattro-proof 1e433732 (upstream quattro 035ce29f product code plus the proof layer). Menu.qml and bin/omarchy-menu-select are unchanged since the previous validation (311d29c7..1e433732 merges upstream 035ce29f, whose only menu changes are two data rows in the stock omarchy-menu.jsonc (Install/Remove > Service > Microsoft), the image-picker helper bin/omarchy-menu-images and one display property on the bar's menu button; Menu.qml, MenuModel.js, ConfirmDialog.qml and omarchy-menu-select are byte-identical, and the rest is lock-screen and other non-menu upstream changes plus proof-layer records) and the result holds. A second select summon before the first is answered leaves the first omarchy-menu-select polling its done file forever. The reproducer drives two real callers through the real Menu.qml open/openDmenu/cancel bodies under node: after summon A, summon B, Escape, Menu.qml issues one done-file write (B's), so caller A never exits. SYS-REQ-260922-X6Z5: 'cancellation reaches the caller as no-selection'. Real entry path, checked separately in the running shell (Quickshell on headless sway, real wtype Escape): caller B exits rc 1 and caller A is still running 6 s after the menu closed. With upstream PR #9056 (head b7bd59c4) merged both callers exit rc 1, in the reproducer and in the live shell. Separate leg, not part of this report's claim: if the shell itself dies while a caller waits, the caller keeps polling with or without #9056 (the poll loop is unbounded; KI-MENU-SELECT-POLL-DEADLOCK). The baseline tracks this report as KI-MENU-REQUEST-LIFECYCLE (open, now rated medium). The reproducer was re-run on 1e433732 with identical output; the live-shell runs are reused from 20d4e6ae (author-recorded): Menu.qml, MenuModel.js and omarchy-menu-select are unchanged since then apart from comment-only trace lines, and the two stock-menu rows added since (Install/Remove > Service > Microsoft) are outside what these runs exercise.
- ConfirmedViolates a requirementA script-driven select/input prompt delivers the picked… SYS-REQ-260922-X6Z5
Violates SYS-REQ-260922-X6Z5: a select prompt superseded by a second summon is never answered: its caller receives neither a value nor the no-selection cancel and polls forever
Engine: engine-executed run exited 1 and showed the defect signal
What “confirmed” means here: the requirement exists and the engine reproduced the defect. That the reproducer exercises THIS requirement is the validator's argument (see rationale).
Evidence: requirement SYS-REQ-260922-X6Z5 · file test/reports/report-cmulr95nw0kqr1gw46i7f50xj.sh
Validator's rationale (commentary): SYS-REQ-260922-X6Z5: 'cancellation reaches the caller as no-selection.' Per SW-REQ-260922-C8HX a cancel is delivered by creating only the done file. The reproducer asserts that every caller is answered once the menu has closed; caller A's done file is never written.
- ConfirmedReproducible
Reproducible: after summon A, summon B, Escape: Menu.qml writes B's done file only; omarchy-menu-select A keeps polling
Engine: engine-executed run exited 1 and showed the defect signal
Evidence: file test/reports/report-cmulr95nw0kqr1gw46i7f50xj.sh
Affects the menu component
Engine: confirmed violation of SYS-REQ-260922-X6Z5 owned by menu
Evidence: requirement SYS-REQ-260922-X6Z5 · file test/reports/report-cmulr95nw0kqr1gw46i7f50xj.sh
- LinkedDuplicate ofdmenu request lifecycle drops waiters on re-summon, on a busy resultProc, and for doneFile-only requests KI-MENU-REQUEST-LIFECYCLE
Matches known issue KI-MENU-REQUEST-LIFECYCLE
Engine: the known issue exists; whether the report duplicates it is settled by a human disposition; it affects the mapped requirement(s) SW-REQ-260922-C8HX, SYS-REQ-260922-X6Z5
Evidence: known_issue KI-MENU-REQUEST-LIFECYCLE · requirement SW-REQ-260922-C8HX · requirement SYS-REQ-260922-X6Z5
Validator's rationale (commentary): Exact match on the baseline: KI-MENU-REQUEST-LIFECYCLE's first clause is this defect (re-summon drops the first waiter). The 29 Sep record pointed at KI-MENU-SELECT-POLL-DEADLOCK (same poll, different trigger: peer death), which is only a partial overlap.
Engine reference checks at 1e43373287af (11/11 ok)
- okcommit1e43373287afbd6dca4674ad463d5b5db7812358
- okbase commit1e43373287afbd6dca4674ad463d5b5db7812358
- okbase ancestry1e43373287afbd6dca4674ad463d5b5db7812358
- okproduct code untouchedthis report's reproducer branch
- okbranchthis report's reproducer branch
- okfiletest/reports/report-cmulr95nw0kqr1gw46i7f50xj.sh
- okrequirementSW-REQ-260922-50RE
- okrequirementSW-REQ-260922-C8HX
- okrequirementSYS-REQ-260922-X6Z5
- okcomponentmenu
- okknown issueKI-MENU-REQUEST-LIFECYCLE
The engine's own check, at validation time, that the commits, the reproducer branch (touching only reproducer files), the reproducer files and every mapped requirement / component / known issue really exist.
10 earlier checks — superseded by the newest one above
Each new check of the report replaces the previous one; only the newest result above counts. Earlier results are kept for the record.
- Reproduced— checked report revision 1 on Oct 4, 2026; earlier check, superseded
- Reproduced— checked report revision 1 on Oct 3, 2026; earlier check, superseded
- Reproduced— checked report revision 1 on Oct 3, 2026; earlier check, superseded
- Reproduced— checked report revision 1 on Oct 2, 2026; earlier check, superseded
- Reproduced— checked report revision 1 on Oct 2, 2026; earlier check, superseded
- Reproduced— checked report revision 1 on Oct 2, 2026; earlier check, superseded
- Reproduced— checked report revision 1 on Oct 2, 2026; earlier check, superseded
- Reproduced— checked report revision 1 on Oct 1, 2026; earlier check, superseded
- Reproduced— checked report revision 1 on Oct 1, 2026; earlier check, superseded
- Reproduced— checked report revision 1 on Sep 29, 2026; earlier check, superseded
Validator-authored hypothesis. Each claim's verification is engine-computed: confirmed only from an engine-executed reproducer run recorded in this record, refuted when recorded evidence contradicts it. Prose is commentary. The disposition of the report is a human decision.
Reproducer
sh test/reports/report-cmulr95nw0kqr1gw46i7f50xj.sh
Setup failure: exit 2 means the reproducer could not set up (e.g. the product did not build) — such a run decides nothing.
Defect signal: output contains DEFECT:
DEFECT: caller A (superseded summon) never got an answer: the menu closed without ever creating its done file, so this omarchy-menu-select polls it forever (still running: yes)
menu closed: opened=false requestActive=false; done-file writes issued by Menu.qml: 1 DEFECT: caller A (superseded summon) never got an answer: the menu closed without ever creating its done file, so this omarchy-menu-select polls it forever (still running: yes) ok: caller B was answered and exited (omarchy-menu-select rc 1: cancel = no selection)
Needs: linux · bash >= 4, perl with JSON::PP, node >= 18 (exits 2 with SETUP: otherwise) · no compositor or Quickshell: omarchy-shell is stubbed and Menu.qml's request functions run in node · ran on linux/amd64
- author-recordedon this baseline with upstream PR omacom/omarchy#9056 head b7bd59c4 merged · exit 0
sh test/reports/report-cmulr95nw0kqr1gw46i7f50xj.sh
done-file writes issued by Menu.qml: 2; ok: caller A was answered and exited (rc 1); ok: caller B was answered and exited (rc 1)
- author-recordedon this baseline with upstream PR omacom/omarchy#13968 head b2dae8db merged (control: a parser-only PR) · exit 1
sh test/reports/report-cmulr95nw0kqr1gw46i7f50xj.sh
done-file writes issued by Menu.qml: 1; DEFECT: caller A (superseded summon) never got an answer
- author-recordedon live shell (Quickshell 0.3.1, headless sway), this baseline [run on 20d4e6ae, same menu code] · exit 1
select A, select B, Escape (wtype)
caller B exited rc=1; caller A STILL RUNNING 6s after the menu closed
- author-recordedon live shell, this baseline with upstream PR omacom/omarchy#9056 head b7bd59c4 merged [run on 20d4e6ae, same menu code] · exit 0
same
caller A exited rc=1; caller B exited rc=1
- author-recordedon live shell, this baseline and with #9056 [run on 20d4e6ae, same menu code] · exit 1
select C, then kill -9 the shell
caller C still running 8s after the shell died, on both trees
Linked
- Known issuedmenu request lifecycle drops waiters on re-summon, on a busy resultProc, and for doneFile-only requests KI-MENU-REQUEST-LIFECYCLE· decided by agents · verified
- Fixed bypr/9031· confirmed
- Fixed bypr/9056· confirmed
- Fixed bypr/7826· confirmed
- Related PRpr/9093· confirmed
- Fixed bypr/10402· confirmed
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.
- Duplicatedmenu request lifecycle drops waiters on re-summon, on a busy resultProc, and for doneFile-only requests KI-MENU-REQUEST-LIFECYCLEDecided by agents · verified · 2026-10-08 21:40 UTC