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.
Third-party (cloned) menu plugin: Apps submenu stays empty — shell never grants appLibrary
Reported by Hangoverdk · filed Sep 16, 2026 · open at source
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-494 (filed Sep 16, 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 8C/16T, AMD RX 9070 (Navi 48, amdgpu), Omarchy 4.0.4-1, kernel 7.2.5-3-omarchy, quickshell 0.3.1-1, Hyprland.
Full omarchy-debug --no-sudo --print log: /tmp/omarchy-debug.log
What's wrong?
When you clone the first-party menu plugin (omarchy plugin clone omarchy.menu -> e.g. jan.menu), disable omarchy.menu, and add the clone to the bar, the Apps submenu is empty even though .desktop entries exist.
Steps to reproduce:
1. omarchy plugin clone omarchy.menu (produces a third-party plugin like jan.menu)
2. Add the clone as a bar widget, and put omarchy.menu in disabledPlugins in ~/.config/omarchy/shell.json
3. omarchy restart shell
4. Press SUPER+SPACE -> Omarchy menu -> Apps submenu shows no rows.
Expected: installed applications are listed (I have 95 .desktop files on this system).
First-party omarchy.menu is NOT affected - only clones. Only the Apps submenu breaks; other menu sections (System, Power, etc.) work fine.
Root cause
The Apps rows come from the shell's shared AppLibrary proxy, which is only granted when the shell detects the plugin has the menu kind:
shell/shell.qml:349
function manifestHasKind(manifest, kind) {
return !!manifest && Array.isArray(manifest.kinds)
&& manifest.kinds.indexOf(kind) !== -1
}shell/shell.qml:603(insidecreateScopedPluginShell):
appLibrary: shell.manifestHasKind(manifest, "menu")
? shell.pluginAppLibraryFor(cacheKey, key) : null,For third-party menu plugins, the manifest that reaches createScopedPluginShell (via the panel loader's Instantiator model) carries kinds as an array-like backed by QJsonArray rather than a real JS Array. Array.isArray(manifest.kinds) is therefore false, so manifestHasKind returns false and:
appLibraryis set tonull, andmergeAppRows()in the menu'sMenu.qmlbails out immediately (if (!root.appLibrary) return) -> empty Apps submenu.- The capability profile flips to
"no-menu"(shell/shell.qml:529), which revokes and re-creates the plugin shell API chip on menu capability.
The QML menu code hands the appLibrary down via root.shell.appLibrary, so it silently degrades to an empty list.
Workaround
Patch manifestHasKind to accept array-like kinds (this resolves the issue locally):
function manifestHasKind(manifest, kind) {
if (!manifest) return false
var kinds = manifest.kinds
if (Array.isArray(kinds)) return kinds.indexOf(kind) !== -1
if (!kinds || typeof kinds.length !== "number" || Number(kinds.length) === 0) return false
var count = Number(kinds.length)
for (var i = 0; i < count; i++) if (String(kinds[i]) === kind) return true
return false
}Since I edited the package-owned file, this is overwritten on omarchy update - so a real upstream fix would be great. It would be even better to normalize the manifest shape once at the plugin-registry boundary so kinds is always a real JS Array (e.g. Array.prototype.slice.call) rather than teaching manifestHasKind about array-likes.
View raw text
## System details
AMD Ryzen 8C/16T, AMD RX 9070 (Navi 48, amdgpu), Omarchy 4.0.4-1, kernel 7.2.5-3-omarchy, quickshell 0.3.1-1, Hyprland.
Full `omarchy-debug --no-sudo --print` log: `/tmp/omarchy-debug.log`
## What's wrong?
When you clone the first-party menu plugin (`omarchy plugin clone omarchy.menu` -> e.g. `jan.menu`), disable `omarchy.menu`, and add the clone to the bar, the **Apps submenu is empty** even though `.desktop` entries exist.
Steps to reproduce:
1. `omarchy plugin clone omarchy.menu` (produces a third-party plugin like `jan.menu`)
2. Add the clone as a bar widget, and put `omarchy.menu` in `disabledPlugins` in `~/.config/omarchy/shell.json`
3. `omarchy restart shell`
4. Press SUPER+SPACE -> Omarchy menu -> **Apps** submenu shows no rows.
Expected: installed applications are listed (I have 95 `.desktop` files on this system).
First-party `omarchy.menu` is NOT affected - only clones. Only the Apps submenu breaks; other menu sections (System, Power, etc.) work fine.
### Root cause
The Apps rows come from the shell's shared `AppLibrary` proxy, which is only granted when the shell detects the plugin has the `menu` kind:
- `shell/shell.qml:349`
```qml
function manifestHasKind(manifest, kind) {
return !!manifest && Array.isArray(manifest.kinds)
&& manifest.kinds.indexOf(kind) !== -1
}
```
- `shell/shell.qml:603` (inside `createScopedPluginShell`):
```qml
appLibrary: shell.manifestHasKind(manifest, "menu")
? shell.pluginAppLibraryFor(cacheKey, key) : null,
```
For **third-party menu plugins**, the manifest that reaches `createScopedPluginShell` (via the panel loader's Instantiator model) carries `kinds` as an array-like backed by `QJsonArray` rather than a real JS Array. `Array.isArray(manifest.kinds)` is therefore `false`, so `manifestHasKind` returns `false` and:
1. `appLibrary` is set to `null`, and `mergeAppRows()` in the menu's `Menu.qml` bails out immediately (`if (!root.appLibrary) return`) -> empty Apps submenu.
2. The capability profile flips to `"no-menu"` (`shell/shell.qml:529`), which revokes and re-creates the plugin shell API chip on menu capability.
The QML menu code hands the `appLibrary` down via `root.shell.appLibrary`, so it silently degrades to an empty list.
### Workaround
Patch `manifestHasKind` to accept array-like `kinds` (this resolves the issue locally):
```qml
function manifestHasKind(manifest, kind) {
if (!manifest) return false
var kinds = manifest.kinds
if (Array.isArray(kinds)) return kinds.indexOf(kind) !== -1
if (!kinds || typeof kinds.length !== "number" || Number(kinds.length) === 0) return false
var count = Number(kinds.length)
for (var i = 0; i < count; i++) if (String(kinds[i]) === kind) return true
return false
}
```
Since I edited the package-owned file, this is overwritten on `omarchy update` - so a real upstream fix would be great. It would be even better to normalize the manifest shape once at the plugin-registry boundary so `kinds` is always a real JS Array (e.g. `Array.prototype.slice.call`) rather than teaching `manifestHasKind` about array-likes.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-5209Cloned menu gets null appLibrary — manifestHasKind Array.isArray fails on QVariantList kinds· 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.