System
- Omarchy 4.0.6-1 (Arch Linux, Hyprland)
- Shell: Quickshell, launched as
quickshell -n -p /usr/share/omarchy/shell - No hardware-specific factors; reproduced entirely with stock Omarchy plugins
Summary
omarchy plugin clone <built-in-bar-widget> reports success and omarchy plugin enable <clone> reports success, the clone is listed as enabled, and the clone's id appears in bar.layout, but the cloned widget is never instantiated. The built-in widget keeps rendering instead. The clone is therefore an inert entry that cannot be edited into effect.
Two independent defects combine, plus a third that silently degrades bar centering:
- User plugin QML lives outside the Quickshell config folder and the scanner refuses to use it as a component source.
- Host property injection throws for non-first-party widgets, so even when the component loads, the slot never becomes live.
omarchy plugin enablerewritesbar.layout.*but notbar.centerAnchor, so anchoring silently degrades.
Steps to reproduce
omarchy plugin clone omarchy.clock # -> "Cloned omarchy.clock to ~/.config/omarchy/plugins/<user>.clock and switched to <user>.clock"
omarchy plugin enable <user>.clock # -> "Enabled <user>.clock"Then add a definitive marker to the clone so instantiation is unambiguous:
# ~/.config/omarchy/plugins/<user>.clock/BarWidget.qml
# insert into the widget root:
Component.onCompleted: { console.log("CLOCKDIAG file=clone instantiated") }Restart the shell or let the live reload fire, then inspect the journal:
journalctl -b -u omarchy-shell --no-pager | grep -E "CLOCKDIAG|outside of the config folder|Cannot assign"Expected
The clone is instantiated and the marker is logged; the bar renders the clone's BarWidget.qml instead of the built-in one. Per shell/README.md, cloning is documented to switch the widget from the built-in to the personal copy ("Cloning switches from the built-in to the new personal plugin").
Actual
- The marker never appears in the journal — the clone's
BarWidget.qmlis never instantiated. - The built-in
/usr/share/omarchy/shell/plugins/panels/clock/BarWidget.qmlis instantiated and keeps rendering. omarchy plugin listshows the cloneenabled=trueand the built-inenabled=false, i.e. state claims the clone is in use.
Journal evidence
WARN quickshell.qmlscanner: Module path "/home/<user>/.config/omarchy/plugins/<user>.clock" is outside of the config folder.
WARN scene: @plugins/bar/Bar.qml[2019:-1]: Error: Cannot assign [undefined] to QObject* (exception occurred during delayed function evaluation)
WARN scene: QML IpcHandler at file:///home/<user>/.config/omarchy/plugins/<user>.clock/BarWidget.qml[129:3]:
Handler was registered but will not be used because another handler is registered for target omarchy.clockThe Cannot assign [undefined] to QObject* warning appears repeatedly (once per bar slot injection attempt) and is the visible symptom of defect 2.
Root cause
Defect 1 — component source is outside the Quickshell config folder
syncPluginWidgets() registers the widget component under the manifest id:
shell.qml:1393—var registryKey = String(manifest.id)shell.qml:1514—shell.barWidgetRegistry.register(registryKey, comp, meta)
but the widget's QML file lives at ~/.config/omarchy/plugins/<clone>/BarWidget.qml, while Quickshell runs with -p /usr/share/omarchy/shell. The scanner logs the path as outside the config folder, so the component cannot be used as a live source. First-party widgets under /usr/share/omarchy/shell/plugins/** are inside it and load cleanly.
Defect 2 — host property injection throws for non-first-party widgets
Bar.qml:2016-2023:
function injectProps() {
var target = activeItem
if (!target) return
if ("bar" in target) target.bar = firstParty
? root : root.pluginBarApiFor(pluginApiId, moduleName, registered)
if ("moduleName" in target) target.moduleName = moduleName
if ("settings" in target) target.settings = moduleSettings
}For a cloned widget firstParty is false (Bar.qml:1796, from metadata.firstParty: !!manifest.__isFirstParty at shell.qml:1415), so the pluginBarApiFor(...) branch runs. The journal records the assignment producing undefined at Bar.qml[2019], so target.bar is never set, and the widget cannot become a functional module.
Note the registry lookup itself is not the problem — it lines up correctly:
Bar.qml:1801-1806looks upvar registryName = root.canonicalWidgetId(moduleName)inbarWidgetRegistry.widgetsBar.qml:1792—moduleNameis the layout entry id (the clone's own id, viaBarModel.entryId)Util.qml:70-72—canonicalWidgetIdis identity (return String(id || ""))
So BarWidgetRegistry genuinely holds the clone key and the slot genuinely looks up the clone key. The clone id is not rewritten to its clonedFrom source on the bar-slot path: resolveEnabledId (PluginRegistry.qml:171-182), restoreCloneSource (:441-472), and activeCloneFor (:426-439) are invoked only from setEnabled and the IPC summon/hide/toggle/service paths — never from Bar.qml.
This means the clone is not instantiable for any built-in bar widget, not just the clock.
Defect 3 — bar.centerAnchor is left pointing at the built-in id
bar.centerAnchor is consumed at Bar.qml:600 (centerAnchor = Util.canonicalWidgetId(config.centerAnchor || "")), and:
Bar.qml:1532-1536—findCenterAnchorEntry()→entryIndex(layoutEntries("center"), root.centerAnchor)Bar.qml:1552—readonly property bool hasAnchor: root.entryIndex(entries, root.centerAnchor) !== -1Bar.qml:1572-1599— the anchored layout is shown only whenhasAnchor; otherwise the fallbackModuleListrenders all center entries
When a widget that is the literal centerAnchor is cloned, setEnabled's clone path rewrites only the bar.layout.* entry id (PluginRegistry.qml:533 — replacement.id = key) and bar.id (:513-515). Nothing writes bar.centerAnchor:
$ grep -rn "centerAnchor" /usr/share/omarchy
plugins/bar/Bar.qml:49 centerAnchor: "omarchy.clock", # fallbackBarConfig default
plugins/bar/Bar.qml:600 centerAnchor = Util.canonicalWidgetId(config.centerAnchor || "")
plugins/bar/README.md:29 "centerAnchor": "omarchy.clock",
shell/README.md:245 "centerAnchor": "omarchy.clock",Because the layout now contains the clone id but centerAnchor still names the built-in id, entryIndex returns -1, hasAnchor becomes false, and the intended anchor-and-flank centering silently degrades to plain group centering — with no user-visible warning that the anchor is dangling.
Impact
omarchy plugin cloneis not usable for any built-in bar widget in this version: the clone is created, enabled, listed as replacing the built-in, and still renders nothing. Any user customization workflow based on cloning bar widgets (documented inshell/README.md) is silently dead.- The failure is silent: clone and enable both exit 0, notifications confirm the switch,
omarchy plugin listreports the desired state, and only persistent journal warnings hint at the problem. - Cloning the clock specifically also leaves
bar.centerAnchordangling, degrading center-section layout.
Suggested direction
- Load user plugin components in a way Quickshell accepts (or import them into the config folder's module path), so a third-party widget's QML is a usable component source.
- Make
pluginBarApiFor(...)return a usable facade for third-party bar widgets, or makeinjectPropstolerate a missing facade instead of assigningundefinedtobar. - In the clone/enable path, rewrite
bar.centerAnchorfrom the source id to the clone id (or, better, resolve the anchor through the same clone-aware routing that IPC already uses viaresolveEnabledId), and warn when the configured anchor does not exist in the layout.
Activity
0No activity yet.