This report has been rewritten. The original version claimed the menu never rendered; that was a measurement error on my part, and the correction is in a comment below. The bug below is the real one, reproduced against stock Omarchy with no third-party menu code involved.
What happens
A third-party plugin that declares "kinds": ["menu"] is handed a capability-scoped shell whose appLibrary is null, while the other capabilities on the same object are populated.
shell/plugins/menu/Menu.qml opens mergeAppRows() with:
function mergeAppRows() {
if (!root.appLibrary) return
So a third-party or cloned menu has no applications at all — nothing in the Apps submenu, nothing in app search — and nothing is logged to say why. The stock menu is unaffected, because pluginShellFor() returns the shell itself for a first-party manifest.
This matters more than it might sound, because a menu plugin that clones omarchy.menu replaces it: omarchy.menu goes into disabledPlugins, so there is no second menu still listing the user's apps.
Minimal reproduction
No third-party menu is needed. This probe plugin is enough — drop it in ~/.config/omarchy/plugins/zz.probe.applibrary/:
manifest.json:
{
"schemaVersion": 1,
"id": "zz.probe.applibrary",
"name": "AppLibrary Probe",
"version": "1.0.0",
"kinds": ["menu"],
"keepLoaded": true,
"entryPoints": { "menu": "Menu.qml" }
}
Menu.qml:
import QtQuick
Item {
id: root
property string omarchyPath: ""
property var shell: null
property var manifest: null
property bool opened: false
function open(payloadJson) { root.opened = true }
function close() { root.opened = false }
onShellChanged: {
console.warn("PROBE shell=" + (root.shell ? "yes" : "null")
+ " pluginId=" + (root.shell ? root.shell.pluginId : "-")
+ " appLibrary=" + (root.shell && root.shell.appLibrary ? "PRESENT" : "NULL")
+ " bar=" + (root.shell && root.shell.bar ? "PRESENT" : "NULL")
+ " barConfig=" + (root.shell && root.shell.barConfig ? "PRESENT" : "NULL"))
}
}
Then omarchy plugin enable zz.probe.applibrary and omarchy restart shell. The log shows:
WARN qml: PROBE shell=yes pluginId=zz.probe.applibrary appLibrary=NULL bar=PRESENT barConfig=PRESENT
pluginId, bar, and barConfig all arrive correctly on the same object, so the scoped API is constructed and alive. Only appLibrary is null.
Why this looks unintended
The plumbing to provide it is all present and appears to be meant to fire for exactly this case:
services/PluginAppLibraryApi.qml exists as a detached app-library capability, documented as being "for third-party menus"
pluginAppLibraryFor(cacheKey, pluginId) builds one
createScopedPluginShell() passes it in conditionally:
appLibrary: shell.manifestHasKind(manifest, "menu")
? shell.pluginAppLibraryFor(cacheKey, key) : null,
pluginShellCapabilityProfile() even carries a "menu" / "no-menu" dimension so the cached facade is rebuilt when that changes
I could not work out from reading the source why the result is null for a manifest whose kinds contains menu. computePanelEntries() has already matched the same manifest on the same array to give the plugin its menu entry point, so manifestHasKind(manifest, "menu") should be true by then. No QML error is logged at creation. I'm reporting the reproduction rather than guessing at a patch.
Corroboration
The author of omarchy-menu-calculator-plugin hit this independently and shipped a workaround in 2ffacdd, rebuilding the capability inside the plugin from DesktopEntries plus the shell's own AppSearch.js, hidden-entries.sh, and launcher.hides. Their swap is conditional on the host providing nothing, so a fix here takes the capability back automatically.
Secondary ask
Whatever the cause, mergeAppRows() returning silently is what made this expensive to track down. A menu with no application library is never intentional, so a single warning naming the plugin would turn "my apps disappeared" into something searchable.
System details
|
|
| Omarchy |
4.0.3-1 (stable) |
| Kernel |
7.2.3-arch1-3 |
| CPU |
AMD Ryzen 7 5825U with Radeon Graphics |
| GPU |
AMD/ATI Barcelo (rev c1) |
| Hyprland |
v0.56.2 |
| quickshell |
0.3.1-1 |
This report has been rewritten. The original version claimed the menu never rendered; that was a measurement error on my part, and the correction is in a comment below. The bug below is the real one, reproduced against stock Omarchy with no third-party menu code involved.
What happens
A third-party plugin that declares
"kinds": ["menu"]is handed a capability-scopedshellwhoseappLibraryisnull, while the other capabilities on the same object are populated.shell/plugins/menu/Menu.qmlopensmergeAppRows()with:So a third-party or cloned menu has no applications at all — nothing in the Apps submenu, nothing in app search — and nothing is logged to say why. The stock menu is unaffected, because
pluginShellFor()returns the shell itself for a first-party manifest.This matters more than it might sound, because a menu plugin that clones
omarchy.menureplaces it:omarchy.menugoes intodisabledPlugins, so there is no second menu still listing the user's apps.Minimal reproduction
No third-party menu is needed. This probe plugin is enough — drop it in
~/.config/omarchy/plugins/zz.probe.applibrary/:manifest.json:{ "schemaVersion": 1, "id": "zz.probe.applibrary", "name": "AppLibrary Probe", "version": "1.0.0", "kinds": ["menu"], "keepLoaded": true, "entryPoints": { "menu": "Menu.qml" } }Menu.qml:Then
omarchy plugin enable zz.probe.applibraryandomarchy restart shell. The log shows:pluginId,bar, andbarConfigall arrive correctly on the same object, so the scoped API is constructed and alive. OnlyappLibraryis null.Why this looks unintended
The plumbing to provide it is all present and appears to be meant to fire for exactly this case:
services/PluginAppLibraryApi.qmlexists as a detached app-library capability, documented as being "for third-party menus"pluginAppLibraryFor(cacheKey, pluginId)builds onecreateScopedPluginShell()passes it in conditionally:pluginShellCapabilityProfile()even carries a"menu"/"no-menu"dimension so the cached facade is rebuilt when that changesI could not work out from reading the source why the result is null for a manifest whose
kindscontainsmenu.computePanelEntries()has already matched the same manifest on the same array to give the plugin itsmenuentry point, somanifestHasKind(manifest, "menu")should be true by then. No QML error is logged at creation. I'm reporting the reproduction rather than guessing at a patch.Corroboration
The author of omarchy-menu-calculator-plugin hit this independently and shipped a workaround in
2ffacdd, rebuilding the capability inside the plugin fromDesktopEntriesplus the shell's ownAppSearch.js,hidden-entries.sh, andlauncher.hides. Their swap is conditional on the host providing nothing, so a fix here takes the capability back automatically.Secondary ask
Whatever the cause,
mergeAppRows()returning silently is what made this expensive to track down. A menu with no application library is never intentional, so a single warning naming the plugin would turn "my apps disappeared" into something searchable.System details