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

Menu: an uninstall confirmation left open stays over the next prompt, and Enter meant for the prompt uninstalls the app

Reported by buger · filed Oct 2, 2026 · open at source · 3 revisions

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

At a glance

1 · What is claimed?
  • ConfirmedViolates SYS-REQ-260922-X6Z5: a select or input prompt summoned while an uninstall confirmation is open never gets the user's Enter: the stale confirmation takes it, the app is uninstalled and the caller receives a cancel
  • ConfirmedReproducible: Apps menu, Delete on an app row, a prompt is summoned, Enter: the launcher file is removed and the prompt's caller exits 1
  • ConfirmedAffects the menu component
  • LinkedMatches known issue KI-MENU-OPEN-LEAVES-CONFIRM
3 · Is it reproducible?
An engine-executed run exited 1 and showed the defect signal. See reproducer
4 · What remains unclear?
Nothing recorded as open.
5 · What happens next?
Decided by agents and verified by a second, independent agent — see the decision.

Original report

Menu: an uninstall confirmation left open stays over the next prompt, and Enter meant for the prompt uninstalls the apprevision 3 · captured 2026-10-03 18:15 UTC via poll

<!-- Bug template field "System details": -->

System details

Omarchy quattro at 821ae58 (current tip). Reproduced with the shell from that tree under Quickshell, using the scripted steps below and keys sent with wtype. Super+K (omarchy-menu-keybindings) goes through the same omarchy-menu-select summon; I didn't drive that keybinding through Hyprland myself.

<!-- Bug template field "What's wrong?": -->

What's wrong?

TL;DR: if you press Delete on an app in the Apps menu and something summons the menu before you answer (any omarchy-menu-select / omarchy-menu-input caller, such as the Super+K keybindings list, or omarchy menu summon), the "Do you want to uninstall …?" box stays on top of the new prompt. Uninstall is preselected, so the Enter you meant for the prompt uninstalls the app and the prompt's caller gets a cancel (exit 1).

Steps (they use a throwaway launcher, so nothing real gets removed):

  1. Create a throwaway app:
   printf '[Desktop Entry]\nType=Application\nName=Throwaway\nExec=true\n' > ~/.local/share/applications/throwaway.desktop
  1. In a terminal, queue a prompt for 10 seconds from now:
   (sleep 10; omarchy-menu-select "Pick a fruit" apple banana cherry; echo "exit=$?")
  1. Within those 10 seconds, open the Apps menu (Super+Alt+Space), type throwaway, and press Delete. "Do you want to uninstall Throwaway?" comes up.
  2. Don't answer it. When "Pick a fruit" opens, the question is still drawn on top of it, with Uninstall highlighted.
  3. Press Enter to pick apple.

Expected: the prompt prints apple and exit=0, and Throwaway stays installed.
Actual: the prompt prints only exit=1, and ~/.local/share/applications/throwaway.desktop is gone.

The same happens with omarchy menu summon <route> instead of a prompt: the question stays over the new menu, and Enter uninstalls the app. Answering the question (Escape or Cancel) or closing the menu (Super+Space or another menu keybinding, which toggle) clears it, so those paths are fine.

Why it happens

shell/plugins/menu/Menu.qml at 821ae58:

  • requestDeleteSelected() (:792) sets deleteConfirmOpen and deleteTarget. The dialog defaults to the Uninstall button (ConfirmDialog.qml:11, selectedIndex: 1; Enter confirms, :32-34).
  • The question is dropped on its own only when the menu closes: onOpenedChanged: if (!opened) { deleteConfirmOpen = false; deleteTarget = null } (:83).
  • A summon goes through open(payloadJson) (:21) to openDmenu() (:864) or openRoute() → openExistingMenu() (:840). These replace the mode, rows and request files while opened stays true, so the confirmation survives.
  • Every key still goes to the dialog first (keyCatcher, z: root.deleteConfirmOpen ? 20 : 0; if (root.deleteConfirmOpen) { deleteConfirm.handleKey(event) … return }, :1118-1124).
  • Enter → confirmDelete() (:809) → root.cancel(), which finishes the new request with no selection (the caller exits 1), then appLibrary.remove(...). That runs omarchy-remove-launcher-entry.

Introduced when the launcher moved into the menu (7a9947a).

Impact
  • Data loss for user, web-app and TUI launchers: omarchy-remove-launcher-entry deletes them with no further prompt. For a package it opens the sudo pacman -Rns terminal (for a flatpak, flatpak uninstall).
  • The prompt's caller gets a cancel for an answer the user never gave, so the action behind Super+K or a script's question is silently dropped.
  • It takes an unanswered question plus a summon, such as a script prompt that pops up while you are in the Apps menu.

Fix with tests: #14054

Reproduction on quattro 393a43d, with the fix PR checked against it: https://portal.reqproof.com/projects/omarchy/inbox/2177


Found while auditing the menu with [ReqProof](https://portal.reqproof.com/projects/omarchy).

View raw text
<!-- Bug template field "System details": -->
### System details

Omarchy `quattro` at `821ae58` (current tip). Reproduced with the shell from that tree under Quickshell, using the scripted steps below and keys sent with `wtype`. Super+K (`omarchy-menu-keybindings`) goes through the same `omarchy-menu-select` summon; I didn't drive that keybinding through Hyprland myself.

<!-- Bug template field "What's wrong?": -->
### What's wrong?

**TL;DR:** if you press Delete on an app in the Apps menu and something summons the menu before you answer (any `omarchy-menu-select` / `omarchy-menu-input` caller, such as the Super+K keybindings list, or `omarchy menu summon`), the "Do you want to uninstall …?" box stays on top of the new prompt. Uninstall is preselected, so the Enter you meant for the prompt **uninstalls the app** and the prompt's caller gets a cancel (exit 1).

**Steps** (they use a throwaway launcher, so nothing real gets removed):

1. Create a throwaway app:
   ```sh
   printf '[Desktop Entry]\nType=Application\nName=Throwaway\nExec=true\n' > ~/.local/share/applications/throwaway.desktop
   ```
2. In a terminal, queue a prompt for 10 seconds from now:
   ```sh
   (sleep 10; omarchy-menu-select "Pick a fruit" apple banana cherry; echo "exit=$?")
   ```
3. Within those 10 seconds, open the Apps menu (Super+Alt+Space), type `throwaway`, and press **Delete**. "Do you want to uninstall Throwaway?" comes up.
4. Don't answer it. When "Pick a fruit" opens, the question is still drawn on top of it, with **Uninstall** highlighted.
5. Press **Enter** to pick `apple`.

**Expected:** the prompt prints `apple` and `exit=0`, and Throwaway stays installed.
**Actual:** the prompt prints only `exit=1`, and `~/.local/share/applications/throwaway.desktop` is gone.

The same happens with `omarchy menu summon <route>` instead of a prompt: the question stays over the new menu, and Enter uninstalls the app. Answering the question (Escape or Cancel) or closing the menu (Super+Space or another menu keybinding, which toggle) clears it, so those paths are fine.

<details><summary>Why it happens</summary>

`shell/plugins/menu/Menu.qml` at `821ae58`:

- `requestDeleteSelected()` (`:792`) sets `deleteConfirmOpen` and `deleteTarget`. The dialog defaults to the Uninstall button (`ConfirmDialog.qml:11`, `selectedIndex: 1`; Enter confirms, `:32-34`).
- The question is dropped on its own only when the menu closes: `onOpenedChanged: if (!opened) { deleteConfirmOpen = false; deleteTarget = null }` (`:83`).
- A summon goes through `open(payloadJson)` (`:21`) to `openDmenu()` (`:864`) or `openRoute()` → `openExistingMenu()` (`:840`). These replace the mode, rows and request files while `opened` stays `true`, so the confirmation survives.
- Every key still goes to the dialog first (`keyCatcher`, `z: root.deleteConfirmOpen ? 20 : 0`; `if (root.deleteConfirmOpen) { deleteConfirm.handleKey(event) … return }`, `:1118-1124`).
- Enter → `confirmDelete()` (`:809`) → `root.cancel()`, which finishes the new request with no selection (the caller exits 1), then `appLibrary.remove(...)`. That runs `omarchy-remove-launcher-entry`.

Introduced when the launcher moved into the menu (`7a9947a`).

</details>

<details><summary>Impact</summary>

- **Data loss** for user, web-app and TUI launchers: `omarchy-remove-launcher-entry` deletes them with no further prompt. For a package it opens the `sudo pacman -Rns` terminal (for a flatpak, `flatpak uninstall`).
- **The prompt's caller gets a cancel** for an answer the user never gave, so the action behind Super+K or a script's question is silently dropped.
- It takes an unanswered question plus a summon, such as a script prompt that pops up while you are in the Apps menu.

</details>

Fix with tests: #14054

Reproduction on `quattro` `393a43d`, with the fix PR checked against it: https://portal.reqproof.com/projects/omarchy/inbox/2177

---

*Found while auditing the menu with [ReqProof](https://portal.reqproof.com/projects/omarchy).*

Validation

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

Validator's summary (commentary, not evidence)

Validation of omacom/omarchy#14052 on quattro-proof 1e433732 (upstream quattro 035ce29f product code plus the proof layer). The report is the auditor's own; it is checked against the same bar as third-party reports. Menu.qml keeps an unanswered uninstall confirmation open across a summon: open() replaces the mode, rows and request files while opened stays true, so deleteConfirmOpen survives, and every key still goes to the dialog first, where Uninstall is preselected. Parser level (no compositor): the reproducer runs the real Menu.qml open/delete/key code and ConfirmDialog.qml handleKey in node with a real omarchy-menu-select caller. Apps menu, Delete on the app row, the caller's prompt arrives, Enter: the throwaway launcher is removed and the caller exits 1 with no value. Live shell, checked separately in the real shell (the tree's own, under Quickshell on a headless sway session): the same steps remove demo-notes.desktop and the prompt's caller prints only exit=1, for a select prompt, an input prompt and a route summon (system). Escape on the confirmation, and a prompt with no confirmation open, behave correctly. With upstream PR #14054 (head 09bfcda4) merged, the summon dismisses the confirmation: the caller gets 'apple' (or 'kiwi') with exit 0 and the launcher stays, in the reproducer and in the live shell. #14055 (an unrelated menu fix) is the control and still shows the defect. The baseline tracks this as KI-MENU-OPEN-LEAVES-CONFIRM (open, rated medium). Since 311d29c7 the baseline merged 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. 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 or input prompt summoned while an uninstall confirmation is open never gets the user's Enter: the stale confirmation takes it, the app is uninstalled and the caller receives a cancel

    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-cmur1322h0040rfw45yjijlzu.sh

    Validator's rationale (commentary): SYS-REQ-260922-X6Z5: 'a script-driven select/input prompt delivers the picked value to the caller'. The reproducer's caller asked for a fruit, the user pressed Enter on 'apple', and the caller exited 1 with no value. SW-REQ-260922-8CQ4 removes an app only on the user's confirmation; here the Enter was meant for the prompt.

  • ConfirmedReproducible

    Reproducible: Apps menu, Delete on an app row, a prompt is summoned, Enter: the launcher file is removed and the prompt's caller exits 1

    Engine: engine-executed run exited 1 and showed the defect signal

    Evidence: file test/reports/report-cmur1322h0040rfw45yjijlzu.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-cmur1322h0040rfw45yjijlzu.sh

  • Matches known issue KI-MENU-OPEN-LEAVES-CONFIRM

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

    Evidence: known_issue KI-MENU-OPEN-LEAVES-CONFIRM · requirement SW-REQ-260922-8CQ4

    Validator's rationale (commentary): Same mechanism: openExistingMenu/openDmenu reset the mode and rows but never clear deleteConfirmOpen/deleteTarget. The KI records the stale dialog and the consequence this report shows (Enter answers the dialog, uninstalls the app and cancels the prompt), and rates it medium.

Engine reference checks at 84af5bea68ed (11/11 ok)
  • okcommit84af5bea68ed98eff3aa4ab4f70c847f330f149d
  • okbase commit1e43373287afbd6dca4674ad463d5b5db7812358
  • okbase ancestry1e43373287afbd6dca4674ad463d5b5db7812358
  • okproduct code untouchedthis report's reproducer branch
  • okbranchthis report's reproducer branch
  • okfiletest/reports/report-cmur1322h0040rfw45yjijlzu.sh
  • okrequirementSW-REQ-260922-50RE
  • okrequirementSW-REQ-260922-8CQ4
  • okrequirementSYS-REQ-260922-X6Z5
  • okcomponentmenu
  • okknown issueKI-MENU-OPEN-LEAVES-CONFIRM

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.

9 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 3 on Oct 4, 2026; earlier check, superseded
  • Reproduced— checked report revision 2 on Oct 3, 2026; earlier check, superseded
  • Reproduced— checked report revision 2 on Oct 3, 2026; earlier check, superseded
  • Reproduced— checked report revision 2 on Oct 3, 2026; earlier check, superseded
  • Reproduced— checked report revision 2 on Oct 2, 2026; earlier check, superseded
  • Reproduced— checked report revision 2 on Oct 2, 2026; earlier check, superseded
  • Reproduced— checked report revision 2 on Oct 2, 2026; earlier check, superseded
  • Reproduced— checked report revision 2 on Oct 2, 2026; earlier check, superseded
  • Reproduced— checked report revision 1 on Oct 2, 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 · 147 ms · 2026-10-04T21:45:46Z→ showed the defect
test/reports/report-cmur1322h0040rfw45yjijlzu.shon this report's reproducer branch @ 84af5bea68
sh test/reports/report-cmur1322h0040rfw45yjijlzu.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: the Enter meant for the prompt confirmed the stale uninstall confirmation: the app's launcher file was removed
DEFECT: the prompt's caller did not get the picked value ('apple'): exit 1, printed: 
Observed output · 496 bytes
uninstall confirmation up for Throwaway (Uninstall preselected: true)
prompt summoned: mode=select options=["apple","banana","cherry"] confirmation still open=true
after Enter: menu opened=false; app library removals: ["throwaway.desktop"]; result writes: 1
prompt caller: exit 1, printed: 
DEFECT: the Enter meant for the prompt confirmed the stale uninstall confirmation: the app's launcher file was removed
DEFECT: the prompt's caller did not get the picked value ('apple'): exit 1, printed: 

Needs: linux · bash >= 4, perl with JSON::PP, node >= 18 (exits 2 with SETUP: otherwise) · no compositor or Quickshell: omarchy-shell is stubbed and the Menu.qml/ConfirmDialog.qml functions run in node; the app library's remove deletes a throwaway launcher in a temporary directory · ran on linux/amd64

Author's comparative runs — commentary, not engine evidence
  • author-recordedon this baseline with upstream PR omacom/omarchy#14054 head 09bfcda4 merged · exit 0
    sh test/reports/report-cmur1322h0040rfw45yjijlzu.sh
    confirmation still open=false; app library removals: []; prompt caller: exit 0, printed: apple; ok: the app is still installed
  • author-recordedon this baseline with upstream PR omacom/omarchy#14055 head 48405669 merged (control: an unrelated menu PR) · exit 1
    sh test/reports/report-cmur1322h0040rfw45yjijlzu.sh
    confirmation still open=true; app library removals: ["throwaway.desktop"]; DEFECT: ... the app's launcher file was removed
  • author-recordedon live shell (Quickshell 0.3.1 on headless sway, the tree's own shell, keys sent with wtype), this baseline [run on 20d4e6ae, same menu code] · exit 1
    Apps menu, type demo, Delete, omarchy-menu-select 'Pick a fruit' apple banana cherry, Enter
    prompt up: mode=select confirm=True target=Demo Notes; prompt caller: exit=1; demo-notes.desktop: No such file or directory
  • author-recordedon live shell (Quickshell 0.3.1 on headless sway, the tree's own shell, keys sent with wtype), this baseline with #14054 head 09bfcda4 merged [run on 20d4e6ae, same menu code] · exit 0
    same
    prompt up: mode=select confirm=False; prompt caller: apple exit=0; demo-notes.desktop kept
  • author-recordedon live shell (Quickshell 0.3.1 on headless sway, the tree's own shell, keys sent with wtype), this baseline [run on 20d4e6ae, same menu code] · exit 1
    same with omarchy-menu-input (type kiwi) and with a route summon (system) instead of the select prompt
    input: caller exit=1, launcher removed; route: system menu shown under the confirmation, Enter removes the launcher
  • author-recordedon live shell (Quickshell 0.3.1 on headless sway, the tree's own shell, keys sent with wtype), this baseline with #14054 merged [run on 20d4e6ae, same menu code] · exit 0
    same (input, route)
    input: kiwi exit=0, launcher kept; route: confirm=False, launcher kept
  • author-recordedon live shell (Quickshell 0.3.1 on headless sway, the tree's own shell, keys sent with wtype), this baseline and with #14054 [run on 20d4e6ae, same menu code] · exit 0
    controls: Escape on the confirmation; a select prompt with no confirmation open
    Escape closes the confirmation and keeps the launcher; the prompt alone returns apple exit=0 (both trees)
  • author-recordedon live shell (Quickshell 0.3.1 on headless sway, the tree's own shell, keys sent with wtype), this baseline with #14055 merged (control) [run on 20d4e6ae, same menu code] · exit 1
    same as the first live run (select, input, route)
    launcher removed and the caller exits 1, as on the baseline

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.