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

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

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

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

Cloned menu plugin loses its scoped shell API during shell startup - installed apps vanish from menu and searchrevision 1 · captured 2026-09-28 21:23 UTC via poll

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.

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

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-180Decided by agents · verified · 2026-10-08 22:15 UTC