Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A 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.

Inbox
ReportR-324GitHub issuePublicDecided· Out of scope

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

Decided: Out of scope — decided by agents · verified 3 days ago.

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

A third-party bar plugin is emptied permanently by any shell.json write; the built-in bar recoversrevision 1 · captured 2026-09-28 21:23 UTC via poll

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:

barBar.qmlbaselineafter one shell.json writeinvalid-context errors
omarchy.bar (first-party)shipped1383132 → recovers to 13830
<user>.bar (third-party)byte-identical to shipped1232132 → 0, permanently208
<user>.bar (third-party)shipped + local changes858132 → 0, permanently104

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 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.

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