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.
Cloned menu plugin loses its scoped shell API during shell startup - installed apps vanish from menu and search
Reported by TymekTM · filed Sep 22, 2026 · open at source
This defect is tracked under R-180. This report describes the same defect, so it is folded under it in the inbox.
Earliest report of this defect: R-187 (filed Sep 22, 2026).
Decided by agents · verified· Oct 8, 2026
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?
- 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
System details
AMD Ryzen AI 5 340 w/ Radeon 840M (Framework), Omarchy 4.0.4-1, Quickshell 0.3.1-1, Hyprland 0.56.2, kernel 7.2.5-3-omarchy, Wayland.
What's wrong?
After cloning the menu plugin with the documented flow (omarchy plugin clone omarchy.menu), installed applications disappear from the launcher: searching for any installed app (e.g. pinta with com.github.PintaProject.Pinta.desktop present) returns no app rows, and the Apps submenu shows only "Nothing here yet". JSONC menu items and install-catalog rows still show, so the menu looks healthy - there is just never an app. No warning or error is logged.
The first-party omarchy.menu keeps working; only the clone is affected.
Steps to reproduce
omarchy plugin clone omarchy.menu(creates<user>.menu, disablesomarchy.menu)- Restart the shell (
omarchy restart shell) or reboot - Open the menu (Super+Space) and type the name of any installed application
- No app rows appear;
omarchy menu summon appsshows an empty submenu
Root cause (traced in shell.qml, 4.0.4)
- The panel loader injects the shell API only once, in
Loader.onLoaded:item.shell = shell.pluginShellFor(panelEntry.manifest)(shell.qml:1342). - For non-first-party plugins
pluginShellForreturns a scoped API created bycreateScopedPluginShelland cached under the plugin id (shell.qml:739-744). - During startup, the reconcile pass (shell.qml:797-810) calls
revokePluginShellApiwhenactiveis false.activerequirespluginRegistry.isEnabled(pluginId), and for non-first-party pluginsisEnabledresolves through the bar layout inshell.json- which loads asynchronously. So there is a startup window where an enabled clone looks disabled and its API is revoked. revokePluginShellApidestroys the cached QObject (cacheWithoutKey(..., destroyValue=true), shell.qml:533-543, 559-567). A destroyed object assigned to the item'sshellproperty becomesnull.- Because the menu manifest sets
keepLoaded: true, the loader item survives andonLoadednever fires again - the shell API is never re-injected. - In the cloned
Menu.qml,root.shellis nownull, soroot.appLibraryisnullandmergeAppRows()returns early (if (!root.appLibrary) return). Hence: zero app rows, zero log output.
Evidence from temporary instrumentation in the cloned Menu.qml:
Component.onCompleted: shell = null (expected)
Qt.callLater: shell = PluginShellApi_QMLTYPE_57(...) (injection works)
Timer 500ms tick 1: shell = null (already revoked, stays null)
mergeAppRows: appLibrary = null (apps silently skipped)Workaround I applied locally
In the clone, fall back to Quickshell's global DesktopEntries when appLibrary is null: build app rows directly from DesktopEntries.applications.values (same noDisplay filtering), launch via uwsm-app -- gtk-launch <id>.desktop (same command AppLibrary.launch uses), resolve icons through the themed lookup, and re-merge on every menu open. Apps come back in search and the Apps submenu.
Possible fix directions
- Defer startup reconcile revocation until the shell config has actually loaded (the "not enabled" signal is transient while
shell.jsonis still async-loading), or - Re-inject the (re-created) scoped API into registered panel loaders when a revoked API is replaced, or
- Have
pluginShellFor/reconcile hand panel items a stable proxy that survives underlying API swaps.
Happy to prepare a PR for whichever direction you prefer.
Diagnostics
omarchy-debug requires an interactive sudo password in this session, so the full log could not be generated; the partial log from the same machine is at /tmp/omarchy-debug.log (fastfetch summary: Omarchy 4.0.4, Quickshell 0.3.1, Hyprland 0.56.2, kernel 7.2.5-3-omarchy). All file/line references above are from /usr/share/omarchy/shell/shell.qml as shipped in 4.0.4-1.
View raw text
### System details AMD Ryzen AI 5 340 w/ Radeon 840M (Framework), Omarchy 4.0.4-1, Quickshell 0.3.1-1, Hyprland 0.56.2, kernel 7.2.5-3-omarchy, Wayland. ### What's wrong? After cloning the menu plugin with the documented flow (`omarchy plugin clone omarchy.menu`), **installed applications disappear from the launcher**: searching for any installed app (e.g. `pinta` with `com.github.PintaProject.Pinta.desktop` present) returns no app rows, and the `Apps` submenu shows only "Nothing here yet". JSONC menu items and install-catalog rows still show, so the menu looks healthy - there is just never an app. No warning or error is logged. The first-party `omarchy.menu` keeps working; only the clone is affected. ### Steps to reproduce 1. `omarchy plugin clone omarchy.menu` (creates `<user>.menu`, disables `omarchy.menu`) 2. Restart the shell (`omarchy restart shell`) or reboot 3. Open the menu (Super+Space) and type the name of any installed application 4. No app rows appear; `omarchy menu summon apps` shows an empty submenu ### Root cause (traced in shell.qml, 4.0.4) - The panel loader injects the shell API only once, in `Loader.onLoaded`: `item.shell = shell.pluginShellFor(panelEntry.manifest)` (shell.qml:1342). - For non-first-party plugins `pluginShellFor` returns a scoped API created by `createScopedPluginShell` and cached under the plugin id (shell.qml:739-744). - During startup, the reconcile pass (shell.qml:797-810) calls `revokePluginShellApi` when `active` is false. `active` requires `pluginRegistry.isEnabled(pluginId)`, and for non-first-party plugins `isEnabled` resolves through the bar layout in `shell.json` - which loads asynchronously. So there is a startup window where an enabled clone looks disabled and its API is revoked. - `revokePluginShellApi` destroys the cached QObject (`cacheWithoutKey(..., destroyValue=true)`, shell.qml:533-543, 559-567). A destroyed object assigned to the item's `shell` property becomes `null`. - Because the menu manifest sets `keepLoaded: true`, the loader item survives and `onLoaded` never fires again - the shell API is never re-injected. - In the cloned `Menu.qml`, `root.shell` is now `null`, so `root.appLibrary` is `null` and `mergeAppRows()` returns early (`if (!root.appLibrary) return`). Hence: zero app rows, zero log output. Evidence from temporary instrumentation in the cloned `Menu.qml`: ``` Component.onCompleted: shell = null (expected) Qt.callLater: shell = PluginShellApi_QMLTYPE_57(...) (injection works) Timer 500ms tick 1: shell = null (already revoked, stays null) mergeAppRows: appLibrary = null (apps silently skipped) ``` ### Workaround I applied locally In the clone, fall back to Quickshell's global `DesktopEntries` when `appLibrary` is `null`: build app rows directly from `DesktopEntries.applications.values` (same `noDisplay` filtering), launch via `uwsm-app -- gtk-launch <id>.desktop` (same command `AppLibrary.launch` uses), resolve icons through the themed lookup, and re-merge on every menu open. Apps come back in search and the Apps submenu. ### Possible fix directions - Defer startup reconcile revocation until the shell config has actually loaded (the "not enabled" signal is transient while `shell.json` is still async-loading), or - Re-inject the (re-created) scoped API into registered panel loaders when a revoked API is replaced, or - Have `pluginShellFor`/reconcile hand panel items a stable proxy that survives underlying API swaps. Happy to prepare a PR for whichever direction you prefer. ### Diagnostics `omarchy-debug` requires an interactive sudo password in this session, so the full log could not be generated; the partial log from the same machine is at `/tmp/omarchy-debug.log` (fastfetch summary: Omarchy 4.0.4, Quickshell 0.3.1, Hyprland 0.56.2, kernel 7.2.5-3-omarchy). All file/line references above are from `/usr/share/omarchy/shell/shell.qml` as shipped in 4.0.4-1.
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
- Duplicate ofR-180Cloned menu plugin loses its scoped shell API: Apps submenu permanently empty· decided by agents · verified
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.