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-394GitHub issuePublicDecided· Duplicate

Third-party menu-kind plugin gets shell.appLibrary === null, leaving Apps submenu empty

Reported by gbflores · filed Sep 17, 2026Closed upstream on 2026-10-12 by the bot omarchybot, as a duplicate (target not recorded).

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

This defect is tracked under R-5209. This report describes the same defect, so it is folded under it in the inbox.

Earliest report of this defect: R-394 (filed Sep 17, 2026).

Decided by agents · verified· Oct 9, 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?
AreaIn the audited areamenu· 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

Third-party menu-kind plugin gets shell.appLibrary === null, leaving Apps submenu emptyrevision 1 · captured 2026-09-28 21:23 UTC via poll

What happened

The Apps submenu of a third-party/cloned "menu" kind plugin (io.github.surfacedp.xmb-menu, a public clone of the built-in omarchy.menu) rendered completely empty — no rows, no icons — no matter how it was opened (bar click, omarchy menu summon apps, after omarchy plugin update, after a full omarchy restart shell).

Switching the same install temporarily back to the built-in omarchy.menu (omarchy plugin disable io.github.surfacedp.xmb-menu && omarchy plugin enable omarchy.menu) showed every installed app correctly, Discord included. So the desktop entries, icons, and DesktopEntries scanning are all fine — the difference is specific to how a non-first-party "menu" kind plugin gets its shell.appLibrary wired up.

Root cause

I added a temporary console.warn inside the plugin's mergeAppRows() (which mirrors /usr/share/omarchy/shell/plugins/menu/Menu.qml's own mergeAppRows() almost verbatim) and got:

XMBDEBUG mergeAppRows called, appLibrary= null shell= PluginShellApi_QMLTYPE_54(0x...)

So root.shell is a valid PluginShellApi instance, but root.shell.appLibrary is null.

Tracing through /usr/share/omarchy/shell/shell.qml:

  • pluginShellFor(manifest) (line 739): if (!manifest || manifest.__isFirstParty) return shell — first-party plugins get the real shell singleton directly, so shell.appLibrary is always the live AppLibrary instance for them. Everything else falls through to createScopedPluginShell(manifest, key, true, shell.pluginHasBarCapabilities(manifest)).
  • createScopedPluginShell(...) (line 569) builds the plugin-scoped API object with (line 603):
  appLibrary: shell.manifestHasKind(manifest, "menu")
    ? shell.pluginAppLibraryFor(cacheKey, key) : null,
  • manifestHasKind(manifest, kind) (line 349) is !!manifest && Array.isArray(manifest.kinds) && manifest.kinds.indexOf(kind) !== -1.
  • pluginAppLibraryFor(cacheKey, pluginId) (line 423) creates/caches a PluginAppLibraryApi (services/PluginAppLibraryApi.qml) that proxies _sortedEntries/_entryName/_iconSource/_launch/_remove back to the real shell.appLibrary.

The plugin's manifest (manifest.json) does declare "kinds": ["menu", "bar-widget"], so manifestHasKind(manifest, "menu") should be true and pluginAppLibraryFor should return a working proxy — but empirically root.shell.appLibrary comes back null on this install. I could not instrument pluginAppLibraryFor/manifestHasKind directly without editing packaged files under /usr/share/omarchy, so I can't pin down which of the two conditions is failing, but the net effect is: any third-party "menu" kind plugin can silently get `appLibrary: null`, and any code that (correctly, defensively) does if (!root.appLibrary) return before populating its Apps list ends up rendering nothing, with no warning anywhere in journalctl or the quickshell log.

Expected behavior

A third-party clone of omarchy.menu that declares "kinds": ["menu", ...] in its manifest should receive a working shell.appLibrary proxy, the same way the built-in menu gets the real one — or, if it can legitimately be null in some state (e.g. before some service is ready), the plugin-facing API should make that a documented, retryable condition (e.g. an appLibrary property that emits a change signal once it becomes available) rather than a silent, permanent null.

Steps to reproduce

  1. omarchy plugin clone omarchy.menu (or install any third-party plugin declaring "kinds": ["menu", ...] in its manifest.json) so it is no longer first-party.
  2. Give it an Apps submenu the same way plugins/menu/Menu.qml does: guard on root.shell.appLibrary, call root.appLibrary.sortedEntries("") when opening the "apps" node.
  3. omarchy restart shell, open the plugin's menu, navigate into Apps.
  4. Apps submenu is empty. Add a console.warn("appLibrary:", root.shell && root.shell.appLibrary) to confirm it logs null.

System info

  • omarchy version: 4.0.4-1
  • quickshell: 0.3.1-1
  • hyprland: 0.56.2-2
  • CPU: AMD Ryzen 9 5900XT
  • GPU: AMD Radeon RX 580 (Polaris 20 XL)
  • Kernel: 7.2.5-3-omarchy

(omarchy debug --no-sudo --print is not a recognized command on 4.0.4 — omarchy commands --all has no debug entry — so I could not attach that log; happy to run whatever the current equivalent is if pointed to it.)

Workaround shipped in the affected plugin

I opened surfacedP/omarchy-xmb-menu#3, which works around this by reading Quickshell.DesktopEntries directly (falling back off root.appLibrary) whenever the host hands back null. That restores the Apps submenu for that specific plugin, but any other third-party menu-kind plugin following the same first-party pattern would hit the same silent empty list.

View raw text
## What happened

The Apps submenu of a third-party/cloned "menu" kind plugin (`io.github.surfacedp.xmb-menu`, a public clone of the built-in `omarchy.menu`) rendered completely empty — no rows, no icons — no matter how it was opened (bar click, `omarchy menu summon apps`, after `omarchy plugin update`, after a full `omarchy restart shell`).

Switching the same install temporarily back to the built-in `omarchy.menu` (`omarchy plugin disable io.github.surfacedp.xmb-menu && omarchy plugin enable omarchy.menu`) showed every installed app correctly, Discord included. So the desktop entries, icons, and DesktopEntries scanning are all fine — the difference is specific to how a **non-first-party** "menu" kind plugin gets its `shell.appLibrary` wired up.

## Root cause

I added a temporary `console.warn` inside the plugin's `mergeAppRows()` (which mirrors `/usr/share/omarchy/shell/plugins/menu/Menu.qml`'s own `mergeAppRows()` almost verbatim) and got:

```
XMBDEBUG mergeAppRows called, appLibrary= null shell= PluginShellApi_QMLTYPE_54(0x...)
```

So `root.shell` is a valid `PluginShellApi` instance, but `root.shell.appLibrary` is `null`.

Tracing through `/usr/share/omarchy/shell/shell.qml`:

- `pluginShellFor(manifest)` (line 739): `if (!manifest || manifest.__isFirstParty) return shell` — first-party plugins get the real `shell` singleton directly, so `shell.appLibrary` is always the live `AppLibrary` instance for them. Everything else falls through to `createScopedPluginShell(manifest, key, true, shell.pluginHasBarCapabilities(manifest))`.
- `createScopedPluginShell(...)` (line 569) builds the plugin-scoped API object with (line 603):
  ```qml
  appLibrary: shell.manifestHasKind(manifest, "menu")
    ? shell.pluginAppLibraryFor(cacheKey, key) : null,
  ```
- `manifestHasKind(manifest, kind)` (line 349) is `!!manifest && Array.isArray(manifest.kinds) && manifest.kinds.indexOf(kind) !== -1`.
- `pluginAppLibraryFor(cacheKey, pluginId)` (line 423) creates/caches a `PluginAppLibraryApi` (`services/PluginAppLibraryApi.qml`) that proxies `_sortedEntries`/`_entryName`/`_iconSource`/`_launch`/`_remove` back to the real `shell.appLibrary`.

The plugin's manifest (`manifest.json`) does declare `"kinds": ["menu", "bar-widget"]`, so `manifestHasKind(manifest, "menu")` should be `true` and `pluginAppLibraryFor` should return a working proxy — but empirically `root.shell.appLibrary` comes back `null` on this install. I could not instrument `pluginAppLibraryFor`/`manifestHasKind` directly without editing packaged files under `/usr/share/omarchy`, so I can't pin down which of the two conditions is failing, but the net effect is: **any third-party "menu" kind plugin can silently get `appLibrary: null`**, and any code that (correctly, defensively) does `if (!root.appLibrary) return` before populating its Apps list ends up rendering nothing, with no warning anywhere in `journalctl` or the quickshell log.

## Expected behavior

A third-party clone of `omarchy.menu` that declares `"kinds": ["menu", ...]` in its manifest should receive a working `shell.appLibrary` proxy, the same way the built-in menu gets the real one — or, if it can legitimately be null in some state (e.g. before some service is ready), the plugin-facing API should make that a documented, retryable condition (e.g. an `appLibrary` property that emits a change signal once it becomes available) rather than a silent, permanent `null`.

## Steps to reproduce

1. `omarchy plugin clone omarchy.menu` (or install any third-party plugin declaring `"kinds": ["menu", ...]` in its `manifest.json`) so it is no longer first-party.
2. Give it an Apps submenu the same way `plugins/menu/Menu.qml` does: guard on `root.shell.appLibrary`, call `root.appLibrary.sortedEntries("")` when opening the "apps" node.
3. `omarchy restart shell`, open the plugin's menu, navigate into Apps.
4. Apps submenu is empty. Add a `console.warn("appLibrary:", root.shell && root.shell.appLibrary)` to confirm it logs `null`.

## System info

- `omarchy version`: 4.0.4-1
- `quickshell`: 0.3.1-1
- `hyprland`: 0.56.2-2
- CPU: AMD Ryzen 9 5900XT
- GPU: AMD Radeon RX 580 (Polaris 20 XL)
- Kernel: 7.2.5-3-omarchy

(`omarchy debug --no-sudo --print` is not a recognized command on 4.0.4 — `omarchy commands --all` has no `debug` entry — so I could not attach that log; happy to run whatever the current equivalent is if pointed to it.)

## Workaround shipped in the affected plugin

I opened surfacedP/omarchy-xmb-menu#3, which works around this by reading `Quickshell.DesktopEntries` directly (falling back off `root.appLibrary`) whenever the host hands back `null`. That restores the Apps submenu for that specific plugin, but any other third-party menu-kind plugin following the same first-party pattern would hit the same silent empty list.

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

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.

  • DuplicateR-5209Decided by agents · verified · 2026-10-09 03:04 UTC