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.
appLibrary not granted to third-party plugins with kind "menu" (4.0.3)
Reported by julihermes · filed Sep 9, 2026Closed upstream on 2026-09-20 by bjarneo via an automated message, as a duplicate of #10661 (R-860). GitHub close reason: completed.
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?
- Not yet mapped to any requirement or component.
- 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?
- Our staff decide whether the report is valid. Where this project allows it, agents decide whether it duplicates another report or a known issue. No decision has been recorded yet.
Original report
On 4.0.3 a third-party plugin declaring kinds: ["menu", "bar-widget"] receives a scoped shell API whose appLibrary is null, so its Apps submenu is permanently empty.
Per shell.qml:603, a menu-kind plugin is supposed to receive it:
appLibrary: shell.manifestHasKind(manifest, "menu")
? shell.pluginAppLibraryFor(cacheKey, key) : null,
bar: shell.pluginBarStateFor(cacheKey, key),Evidence
Probing the injected shell object from inside the plugin, every 1.5 s for its whole lifetime:
shell=true pluginId=krall.switchboard appLib=null
bar=PluginBarStateApi_QMLTYPE_27(0x7f94...) idleCfg=yes barCfg=yesappLibraryis null from creation onward and never populated — not a startup race.bar— created bypluginBarStateFor(cacheKey, key)in the samecreateObjectproperties block — succeeds. So object creation itself is fine, and the API did come fromcreateScopedPluginShellrather than the bar-entry path.- The manifest carries
kinds: ["menu", "bar-widget"]. It is precisely that"menu"kind that puts the plugin intocomputePanelEntries(which independently checksArray.isArray(m.kinds)andindexOf("menu")), so the plugin does reach the panel loader. - Nothing after
createObjectreassignsappLibrary;syncPluginApisonly refreshesbarConfigandidleConfig. - No QML warning is logged.
So the grant condition evaluates false for a plugin that appears to satisfy it. I could not isolate which branch fails without patching shell.qml, which is package-owned — hence an issue rather than a PR.
Reproduction
Any third-party plugin with kind "menu" — e.g. krall12/omarchy-switchboard. Its Apps list comes up empty on 4.0.3.
It worked on 4.0.2, where the panel loader injected the full shell (shell.qml:630):
if ("shell" in item) item.shell = shell
if ("manifest" in item) item.manifest = panelEntry.manifest4.0.3 routes both through the new sandbox layer (pluginShellFor / publicPluginManifest), which is where the regression lives.
Possibly related
The same sandbox change also strips __sourceDir from third-party manifests (publicPluginManifest, shell.qml:316). That is plausibly deliberate, but it silently breaks any plugin that resolves its own bundled scripts through the manifest — worth a note in the plugin API docs if so, since the failure mode is invisible (no warning, IPC still answers ok).
Environment
- omarchy 4.0.3-1 (regressed from 4.0.2-1)
- quickshell 0.3.1-1
- Hyprland, single monitor
View raw text
On 4.0.3 a third-party plugin declaring `kinds: ["menu", "bar-widget"]` receives a scoped shell API whose `appLibrary` is `null`, so its Apps submenu is permanently empty.
Per `shell.qml:603`, a menu-kind plugin is supposed to receive it:
```qml
appLibrary: shell.manifestHasKind(manifest, "menu")
? shell.pluginAppLibraryFor(cacheKey, key) : null,
bar: shell.pluginBarStateFor(cacheKey, key),
```
## Evidence
Probing the injected `shell` object from inside the plugin, every 1.5 s for its whole lifetime:
```
shell=true pluginId=krall.switchboard appLib=null
bar=PluginBarStateApi_QMLTYPE_27(0x7f94...) idleCfg=yes barCfg=yes
```
- `appLibrary` is null from creation onward and never populated — not a startup race.
- `bar` — created by `pluginBarStateFor(cacheKey, key)` in the **same** `createObject` properties block — succeeds. So object creation itself is fine, and the API did come from `createScopedPluginShell` rather than the bar-entry path.
- The manifest carries `kinds: ["menu", "bar-widget"]`. It is precisely that `"menu"` kind that puts the plugin into `computePanelEntries` (which independently checks `Array.isArray(m.kinds)` and `indexOf("menu")`), so the plugin does reach the panel loader.
- Nothing after `createObject` reassigns `appLibrary`; `syncPluginApis` only refreshes `barConfig` and `idleConfig`.
- No QML warning is logged.
So the grant condition evaluates false for a plugin that appears to satisfy it. I could not isolate which branch fails without patching `shell.qml`, which is package-owned — hence an issue rather than a PR.
## Reproduction
Any third-party plugin with kind `"menu"` — e.g. [krall12/omarchy-switchboard](https://github.com/krall12/omarchy-switchboard). Its Apps list comes up empty on 4.0.3.
It worked on 4.0.2, where the panel loader injected the full shell (`shell.qml:630`):
```qml
if ("shell" in item) item.shell = shell
if ("manifest" in item) item.manifest = panelEntry.manifest
```
4.0.3 routes both through the new sandbox layer (`pluginShellFor` / `publicPluginManifest`), which is where the regression lives.
## Possibly related
The same sandbox change also strips `__sourceDir` from third-party manifests (`publicPluginManifest`, `shell.qml:316`). That is plausibly deliberate, but it silently breaks any plugin that resolves its own bundled scripts through the manifest — worth a note in the plugin API docs if so, since the failure mode is invisible (no warning, IPC still answers `ok`).
## Environment
- omarchy 4.0.3-1 (regressed from 4.0.2-1)
- quickshell 0.3.1-1
- Hyprland, single monitor
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
Not linked to any known issue, other report or change yet.
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.
No decision has been recorded yet.