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.
A third-party bar plugin is emptied permanently by any shell.json write; the built-in bar recovers
Reported by tanayseven · filed Sep 19, 2026 · open at source
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?
- AreaOutside the audited area· 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
What happens
With a third-party bar plugin active (kinds: ["bar"]), any write to~/.config/omarchy/shell.json tears the bar down and it does not come back. The
section empties within a few seconds and stays empty until omarchy restart shell.
The shell log fills with 100–200 of:
QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid contextThe identical write against the built-in omarchy.bar dips for a moment while the
bar rebuilds and then recovers completely, with no errors at all.
Expected
A third-party bar should survive a shell.json write the same way the built-in bar
does — rebuild, then come back.
This is not the plugin's code
I controlled for that by running the **same Bar.qml, byte-identical to the shipped
one**, and changing only whether it loads as omarchy.bar or as a cloned<user>.bar. Measurement is lit (non-background) pixels across the bar's right
section, so "0" means nothing is drawn there at all:
| bar | Bar.qml | baseline | after one shell.json write | invalid-context errors |
|---|---|---|---|---|
omarchy.bar (first-party) | shipped | 1383 | 132 → recovers to 1383 | 0 |
<user>.bar (third-party) | byte-identical to shipped | 1232 | 132 → 0, permanently | 208 |
<user>.bar (third-party) | shipped + local changes | 858 | 132 → 0, permanently | 104 |
Same code, same layout, same machine. Only the plugin identity differs.
Reproduction
omarchy plugin clone omarchy.bar # creates <user>.bar and switches the bar to itThen write any inline widget setting to ~/.config/omarchy/shell.json. I used jq
to add a "hidden": [] key to one widget's entry; `omarchy bar set <id> <key>
<value>` writes the same file and should do as well.
Within a few seconds the bar empties, and stays empty. omarchy restart shell
brings it back until the next write.
Where I suspect it is (hypothesis, not verified)
The one structural difference I can find between the two paths is in shell.qml:
barConfigFor(manifest)returnsshell.barConfigitself to a first-party bar,
but publicBarConfig() to a third-party one — a fresh
JSON.parse(JSON.stringify(...)) snapshot rebuilt on every config change.
- pluginBarWidgetRegistryFor() and pluginShellFor() likewise hand a third-party
bar detached facades rather than the host objects.
A snapshot that is a brand-new object on every change would invalidate bindings that
a live object would leave intact, and the invalid context errors are consistent
with delegates being evaluated after their component was torn down. I have not
confirmed that this is the cause — it is only the difference I could see.
Impact
It makes third-party bars unusable in practice rather than merely awkward, because
the triggering writes are routine: dragging a widget to reorder it, the transparency
toggle, the battery-percentage toggle, pinning a tray item, and any omarchy bar ...
command. Each one silently empties the bar until the shell is restarted.
System
omarchy 4.0.4-1
quickshell 0.3.1-1
qt6-base 6.11.2-3
qt6-declarative 6.11.2-1
hyprland 0.56.2-2(omarchy debug is listed in omarchy --help on 4.0.4-1 but exits with
"Unknown Omarchy command", so the above is by hand.)
Not a duplicate of the existing third-party-bar reports
- #7253 and #8202 — a cloned bar never loads at all on 4.0.0-1
(Required property barConfig was not initialized). That is no longer the
failure here: on 4.0.4-1 the clone loads and works. It just cannot survive
a shell.json write. Those two look fixed; this is the next wall behind them.
- #10992 — third-party bar-widgets and panels breaking on 4.0.3, with the
built-in bar, and reporting the same
attempted to evaluate a function in an invalid context. Different surface,
plausibly the same underlying lifetime problem in the third-party plugin
runtime, so the two may share a fix.
- #12158 — PluginRegistry watching pluginsDir recursively, so plugin
state writes tear the bar down. Different trigger: writes inside the plugin
directory causing repeated reloads, versus one shell.json write causing a
single permanent collapse confined to third-party bars.
- #11063 — third-party bar-widgets never receive barWidgetRegistry, so a
widget cannot host other widgets. Worth mentioning because it is why anyone
ends up on this path: hosting other widgets is only possible from a full bar
plugin, and a full bar plugin is what this issue makes unusable. Between the
two, that capability is currently unreachable by any route.
- #11932, #10979, #11713 — the same first-party/third-party
asymmetry on other surfaces (drag-reorder, popups, service-backed widgets).
Drafted by Claude Opus 5 via Claude Code.
View raw text
## What happens With a third-party bar plugin active (`kinds: ["bar"]`), **any** write to `~/.config/omarchy/shell.json` tears the bar down and it does not come back. The section empties within a few seconds and stays empty until `omarchy restart shell`. The shell log fills with 100–200 of: ``` QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context ``` The identical write against the built-in `omarchy.bar` dips for a moment while the bar rebuilds and then recovers completely, with no errors at all. ## Expected A third-party bar should survive a `shell.json` write the same way the built-in bar does — rebuild, then come back. ## This is not the plugin's code I controlled for that by running the **same `Bar.qml`, byte-identical to the shipped one**, and changing only whether it loads as `omarchy.bar` or as a cloned `<user>.bar`. Measurement is lit (non-background) pixels across the bar's right section, so "0" means nothing is drawn there at all: | bar | Bar.qml | baseline | after one shell.json write | invalid-context errors | |---|---|---|---|---| | `omarchy.bar` (first-party) | shipped | 1383 | 132 → **recovers to 1383** | **0** | | `<user>.bar` (third-party) | **byte-identical to shipped** | 1232 | 132 → **0, permanently** | **208** | | `<user>.bar` (third-party) | shipped + local changes | 858 | 132 → **0, permanently** | 104 | Same code, same layout, same machine. Only the plugin identity differs. ## Reproduction ```bash omarchy plugin clone omarchy.bar # creates <user>.bar and switches the bar to it ``` Then write any inline widget setting to `~/.config/omarchy/shell.json`. I used `jq` to add a `"hidden": []` key to one widget's entry; `omarchy bar set <id> <key> <value>` writes the same file and should do as well. Within a few seconds the bar empties, and stays empty. `omarchy restart shell` brings it back until the next write. ## Where I suspect it is (hypothesis, not verified) The one structural difference I can find between the two paths is in `shell.qml`: - `barConfigFor(manifest)` returns `shell.barConfig` itself to a first-party bar, but `publicBarConfig()` to a third-party one — a fresh `JSON.parse(JSON.stringify(...))` snapshot rebuilt on every config change. - `pluginBarWidgetRegistryFor()` and `pluginShellFor()` likewise hand a third-party bar detached facades rather than the host objects. A snapshot that is a brand-new object on every change would invalidate bindings that a live object would leave intact, and the `invalid context` errors are consistent with delegates being evaluated after their component was torn down. I have not confirmed that this is the cause — it is only the difference I could see. ## Impact It makes third-party bars unusable in practice rather than merely awkward, because the triggering writes are routine: dragging a widget to reorder it, the transparency toggle, the battery-percentage toggle, pinning a tray item, and any `omarchy bar ...` command. Each one silently empties the bar until the shell is restarted. ## System ``` omarchy 4.0.4-1 quickshell 0.3.1-1 qt6-base 6.11.2-3 qt6-declarative 6.11.2-1 hyprland 0.56.2-2 ``` (`omarchy debug` is listed in `omarchy --help` on 4.0.4-1 but exits with "Unknown Omarchy command", so the above is by hand.) ## Not a duplicate of the existing third-party-bar reports - **#7253** and **#8202** — a cloned bar never loads at all on 4.0.0-1 (`Required property barConfig was not initialized`). That is no longer the failure here: on **4.0.4-1 the clone loads and works**. It just cannot survive a `shell.json` write. Those two look fixed; this is the next wall behind them. - **#10992** — third-party bar-*widgets* and panels breaking on 4.0.3, with the built-in bar, and reporting the same `attempted to evaluate a function in an invalid context`. Different surface, plausibly the same underlying lifetime problem in the third-party plugin runtime, so the two may share a fix. - **#12158** — `PluginRegistry` watching `pluginsDir` recursively, so plugin *state* writes tear the bar down. Different trigger: writes inside the plugin directory causing repeated reloads, versus one `shell.json` write causing a single permanent collapse confined to third-party bars. - **#11063** — third-party bar-widgets never receive `barWidgetRegistry`, so a widget cannot host other widgets. Worth mentioning because it is *why* anyone ends up on this path: hosting other widgets is only possible from a full bar plugin, and a full bar plugin is what this issue makes unusable. Between the two, that capability is currently unreachable by any route. - **#11932**, **#10979**, **#11713** — the same first-party/third-party asymmetry on other surfaces (drag-reorder, popups, service-backed widgets). --- Drafted by Claude Opus 5 via Claude Code.
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.
- Out of scopeDecided by agents · verified · 2026-10-09 15:54 UTC