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-1851GitHub issuePublicDecided· Out of scope

Shell: third-party bar plugins never load — required properties are set after construction

Reported by andrepadez · filed Aug 15, 2026 · open at source

Decided: Out of scope — decided by agents · verified 4 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

Shell: third-party bar plugins never load — required properties are set after constructionrevision 1 · captured 2026-09-28 21:29 UTC via poll

Summary

Any third-party plugin with "kinds": ["bar"] fails to load, leaving the desktop with no bar at all. This makes omarchy plugin clone omarchy.bar unusable: cloning the bar and switching to it silently removes the bar from every monitor.

The cloned file does not need to be modified — an unmodified, byte-identical copy of shell/plugins/bar/Bar.qml reproduces it.

Steps to reproduce

omarchy plugin clone omarchy.bar        # clones to <user>.bar, sets bar.id in shell.json
omarchy plugin enable <user>.bar        # see bug 2 below: clone does not do this itself
omarchy restart shell

Bar disappears from all monitors. Confirm no bar layer surfaces remain:

hyprctl layers | grep omarchy-bar       # no output

Expected

The cloned bar renders identically to the built-in bar, since the QML is unchanged.

Actual

No bar on any monitor. journalctl --user:

WARN scene: file:///home/<user>/.config/omarchy/plugins/<user>.bar/Bar.qml[15:3]: Required property omarchyPath was not initialized
WARN scene: file:///home/<user>/.config/omarchy/plugins/<user>.bar/Bar.qml[17:3]: Required property barWidgetRegistry was not initialized
WARN scene: file:///home/<user>/.config/omarchy/plugins/<user>.bar/Bar.qml[22:3]: Required property barConfig was not initialized
WARN scene: @shell.qml[256:-1]: ReferenceError: errorString is not defined

Root cause

Bar.qml declares three required property values (omarchyPath, barWidgetRegistry, barConfig). QML requires these to be supplied at construction time.

The built-in bar satisfies that, because defaultBarComponent supplies them as initial bindings inside the Component (shell/shell.qml:226):

Component {
  id: defaultBarComponent

  Bar {
    omarchyPath: shell.omarchyPath
    barWidgetRegistry: shell.barWidgetRegistry
    barConfig: shell.barConfig
    ...
  }
}

Third-party bars go through pluginBarLoader instead (shell/shell.qml:246), which sets source to a URL and only supplies the properties afterwards, in onLoaded → configureBar() (shell/shell.qml:214):

Loader {
  id: pluginBarLoader
  source: shell.activeBarId !== shell.defaultBarId ? shell.activeBarSourceUrl : ""
  onLoaded: shell.configureBar(item, shell.activeBarManifest)
  ...
}

function configureBar(target, manifest) {
  if ("omarchyPath" in target) target.omarchyPath = shell.omarchyPath
  if ("barWidgetRegistry" in target) target.barWidgetRegistry = shell.barWidgetRegistry
  if ("barConfig" in target) target.barConfig = shell.barConfig
  ...
}

By the time onLoaded fires, construction has already failed. Assignment after the fact cannot satisfy a required property.

Suggested fix

Use Loader.setSource(url, initialProperties), which supplies properties during construction:

pluginBarLoader.setSource(shell.activeBarSourceUrl, {
  omarchyPath: shell.omarchyPath,
  barWidgetRegistry: shell.barWidgetRegistry,
  barConfig: shell.barConfig,
  shell: shell,
  manifest: shell.activeBarManifest
})

configureBar() can stay for the non-required properties.

Bug 2 — the failure is silent

shell/shell.qml:256 throws while trying to report the load error:

var detail = errorString && errorString() ? errorString() : ""

errorString is not defined in that scope, so the Loader.Error handler raises ReferenceError before it can log which bar failed or set failedBarId. The intended fallback to the default bar therefore never happens either — the user gets no bar and no diagnostic. Loader in this context has no errorString(); the message needs to come from elsewhere (e.g. sourceComponent.errorString()), and the whole block wants a guard.

Fixing this alone would turn the bug above into a graceful fallback plus a clear log line.

Bug 3 — omarchy plugin clone leaves the clone disabled

omarchy plugin clone omarchy.bar writes "id": "<user>.bar" into bar in ~/.config/omarchy/shell.json and reports Now using <user>.bar as the bar, but the plugin is left disabled:

$ omarchy plugin list | grep '\.bar'
omarchy.bar      enabled   first-party  bar  Bar
<user>.bar       disabled  third-party  bar  My Bar

So even with bugs 1 and 2 fixed, the freshly cloned bar would not load until the user separately runs omarchy plugin enable <user>.bar. clone should enable what it switches to, or not switch until enabled.

System details

Omarchy4.0.0.alpha (4.0.0.r1744.gf002044-1)
Kernel7.1.8-arch1-3
Hyprland0.56.2
Quickshell0.3.0.r20.g28771c7-1
CPUAMD Ryzen 9 7940HS w/ Radeon 780M
GPUAMD Phoenix1 (rev c1)
Monitors3 (2x 3840x2160 @1.5, 1x 2560x1440 @1.6)

Reproduced on a multi-monitor setup, but nothing in the failure path looks monitor-dependent.

Context

I was cloning the bar to give each monitor its own bar font size — Style is a singleton, so font.base-size is global, and a bar that reads well on a 1600x900 logical screen is small on a 2560x1440 one. Per-screen scaling in a cloned bar is a reasonable way to do that, and the plugin system looks designed to allow it; it's just that no clone of a bar-kind plugin can load today.


Possibly related: #6913 (cloning a plugin from Setup → Plugins fails with unknown clone option: <id>). That one is a CLI invocation bug; this is a runtime load failure after a successful clone.

View raw text
## Summary

Any third-party plugin with `"kinds": ["bar"]` fails to load, leaving the desktop with no bar at all. This makes `omarchy plugin clone omarchy.bar` unusable: cloning the bar and switching to it silently removes the bar from every monitor.

The cloned file does not need to be modified — an unmodified, byte-identical copy of `shell/plugins/bar/Bar.qml` reproduces it.

## Steps to reproduce

```sh
omarchy plugin clone omarchy.bar        # clones to <user>.bar, sets bar.id in shell.json
omarchy plugin enable <user>.bar        # see bug 2 below: clone does not do this itself
omarchy restart shell
```

Bar disappears from all monitors. Confirm no bar layer surfaces remain:

```sh
hyprctl layers | grep omarchy-bar       # no output
```

## Expected

The cloned bar renders identically to the built-in bar, since the QML is unchanged.

## Actual

No bar on any monitor. `journalctl --user`:

```
WARN scene: file:///home/<user>/.config/omarchy/plugins/<user>.bar/Bar.qml[15:3]: Required property omarchyPath was not initialized
WARN scene: file:///home/<user>/.config/omarchy/plugins/<user>.bar/Bar.qml[17:3]: Required property barWidgetRegistry was not initialized
WARN scene: file:///home/<user>/.config/omarchy/plugins/<user>.bar/Bar.qml[22:3]: Required property barConfig was not initialized
WARN scene: @shell.qml[256:-1]: ReferenceError: errorString is not defined
```

## Root cause

`Bar.qml` declares three `required property` values (`omarchyPath`, `barWidgetRegistry`, `barConfig`). QML requires these to be supplied **at construction time**.

The built-in bar satisfies that, because `defaultBarComponent` supplies them as initial bindings inside the `Component` (`shell/shell.qml:226`):

```qml
Component {
  id: defaultBarComponent

  Bar {
    omarchyPath: shell.omarchyPath
    barWidgetRegistry: shell.barWidgetRegistry
    barConfig: shell.barConfig
    ...
  }
}
```

Third-party bars go through `pluginBarLoader` instead (`shell/shell.qml:246`), which sets `source` to a URL and only supplies the properties afterwards, in `onLoaded` → `configureBar()` (`shell/shell.qml:214`):

```qml
Loader {
  id: pluginBarLoader
  source: shell.activeBarId !== shell.defaultBarId ? shell.activeBarSourceUrl : ""
  onLoaded: shell.configureBar(item, shell.activeBarManifest)
  ...
}

function configureBar(target, manifest) {
  if ("omarchyPath" in target) target.omarchyPath = shell.omarchyPath
  if ("barWidgetRegistry" in target) target.barWidgetRegistry = shell.barWidgetRegistry
  if ("barConfig" in target) target.barConfig = shell.barConfig
  ...
}
```

By the time `onLoaded` fires, construction has already failed. Assignment after the fact cannot satisfy a `required property`.

### Suggested fix

Use `Loader.setSource(url, initialProperties)`, which supplies properties during construction:

```qml
pluginBarLoader.setSource(shell.activeBarSourceUrl, {
  omarchyPath: shell.omarchyPath,
  barWidgetRegistry: shell.barWidgetRegistry,
  barConfig: shell.barConfig,
  shell: shell,
  manifest: shell.activeBarManifest
})
```

`configureBar()` can stay for the non-required properties.

## Bug 2 — the failure is silent

`shell/shell.qml:256` throws while trying to report the load error:

```qml
var detail = errorString && errorString() ? errorString() : ""
```

`errorString` is not defined in that scope, so the `Loader.Error` handler raises `ReferenceError` before it can log which bar failed or set `failedBarId`. The intended fallback to the default bar therefore never happens either — the user gets no bar and no diagnostic. `Loader` in this context has no `errorString()`; the message needs to come from elsewhere (e.g. `sourceComponent.errorString()`), and the whole block wants a guard.

Fixing this alone would turn the bug above into a graceful fallback plus a clear log line.

## Bug 3 — `omarchy plugin clone` leaves the clone disabled

`omarchy plugin clone omarchy.bar` writes `"id": "<user>.bar"` into `bar` in `~/.config/omarchy/shell.json` and reports `Now using <user>.bar as the bar`, but the plugin is left `disabled`:

```
$ omarchy plugin list | grep '\.bar'
omarchy.bar      enabled   first-party  bar  Bar
<user>.bar       disabled  third-party  bar  My Bar
```

So even with bugs 1 and 2 fixed, the freshly cloned bar would not load until the user separately runs `omarchy plugin enable <user>.bar`. `clone` should enable what it switches to, or not switch until enabled.

## System details

| | |
|---|---|
| Omarchy | 4.0.0.alpha (`4.0.0.r1744.gf002044-1`) |
| Kernel | 7.1.8-arch1-3 |
| Hyprland | 0.56.2 |
| Quickshell | 0.3.0.r20.g28771c7-1 |
| CPU | AMD Ryzen 9 7940HS w/ Radeon 780M |
| GPU | AMD Phoenix1 (rev c1) |
| Monitors | 3 (2x 3840x2160 @1.5, 1x 2560x1440 @1.6) |

Reproduced on a multi-monitor setup, but nothing in the failure path looks monitor-dependent.

## Context

I was cloning the bar to give each monitor its own bar font size — `Style` is a singleton, so `font.base-size` is global, and a bar that reads well on a 1600x900 logical screen is small on a 2560x1440 one. Per-screen scaling in a cloned bar is a reasonable way to do that, and the plugin system looks designed to allow it; it's just that no clone of a `bar`-kind plugin can load today.

---

Possibly related: #6913 (cloning a plugin from Setup → Plugins fails with `unknown clone option: <id>`). That one is a CLI invocation bug; this is a runtime load failure after a successful clone.

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 04:06 UTC