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-1237GitHub issuePublicFixed

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

Decided: Duplicate — decided by agents · verified 4 days ago.

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

Spamming a menu-summoning keybinding (Super+K) leaks orphaned omarchy-menu-select processesrevision 1 · captured 2026-09-28 21:24 UTC via poll

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):

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:

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

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

Validation

AI validator claude-code (claude-opus-5.5) · evaluated revision 1 at product commit 1e43373287af · sealed 2026-10-04T21:45:45Z

Validator's summary (commentary, not evidence)

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.

  • 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

  • ConfirmedAffects a componentmenu

    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

  • 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

engine-runexit 1 · expected exit 0 · defect exit 1 · 152 ms · 2026-10-04T21:45:45Z→ showed the defect
test/reports/report-cmulr95nw0kqr1gw46i7f50xj.shon this report's reproducer branch @ 1e43373287
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:

Matched lines (engine, over the full output)
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)
Observed output · 350 bytes
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's comparative runs — commentary, not engine evidence
  • 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

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.