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

4.0.3 bar-widget sandbox scopes _moduleWidgets to the caller, silently breaking bar-organiser plugins

Reported by PeterHennesey · filed Sep 9, 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

4.0.3 bar-widget sandbox scopes _moduleWidgets to the caller, silently breaking bar-organiser pluginsrevision 1 · captured 2026-09-28 21:23 UTC via poll

Same class as #10929 (bar drag API dropped from PluginBarApi) and #10888 (no way to enumerate plugins): the 4.0.3 bar-widget sandbox removes a capability with no replacement, and the plugin fails silently rather than erroring.

This one is _moduleWidgets, and it takes out an entire category of plugin: anything whose purpose is to organise or reveal other plugins' bar widgets.

The change

usr/share/omarchy/shell/plugins/bar/Bar.qml:262:

_moduleWidgets: function(requestedId) {
  return String(requestedId || "") === String(moduleName || "")
    ? root.moduleWidgets(moduleName) : []
},

A plugin may now ask only about its own widgets. Any other id returns [].

Why that removes a category rather than narrowing one

A bar organiser exists precisely to ask about widgets it does not own. Concretely, Westy47/omarchy-hidden-bar (a drawer that hides chosen widgets and reveals them on hover) does:

// HiddenBar.qml:45-48
if (!root.bar || typeof root.bar.moduleWidgets !== "function") return out
for (var i = 0; i < root.hiddenIds.length; i++) {
  var items = root.bar.moduleWidgets(root.hiddenIds[i])
  ...
}

root.hiddenIds is, by definition, ids the user assigned to the drawer — never the plugin's own. So every call returns [], liveItems() is empty, no HoverHandler is attached, and nothing is ever hidden or revealed. The plugin loads, enables and logs nothing.

Requested on Omarchy 4.0.3-1, stock package.

Why the usual 4.0.3 workaround does not apply here

The other regressions in this cluster have a fallback, and third-party authors have already shipped it: read from disk instead of asking the shell. data-goblin/fileblade and fross100/omaplug both now enumerate ~/.config/omarchy/plugins/*/manifest.json directly.

That works because a list also exists on disk. This case needs the live QML objects the bar has already instantiated, so that their visible can be set and a HoverHandler parented to them. There is no on-disk equivalent of a running object.

barWidgetRegistry is not a substitute either. services/PluginBarWidgetRegistryApi.qml describes itself as a "detached widget-catalogue snapshot for third-party full-bar implementations", and states that "mutating this local view cannot replace a registration in the host registry". It hands out components and metadata for a plugin to render its own copies — it cannot reach the instances the standard bar is already showing.

So the only remaining route is for the plugin to reimplement the whole bar as a bar-kind plugin. That is a different product, not a port.

Suggested direction

The isolation goal seems to be that a plugin should not silently inspect or mutate things the user never pointed it at. A bar organiser is compatible with that goal, because the ids it manipulates come from the user's own configuration.

A minimal API that keeps the guarantee could scope by user grant rather than by ownership: a plugin may reach moduleWidgets(id) only for ids the user has listed in that plugin's own settings entry in shell.json. The shell already reads that entry, so the check is local and needs no new trust surface.

Failing that, an explicit refusal would at least save the next author the investigation — right now the call returns [], which is indistinguishable from "that widget has no items".

What I did not verify

I have not tried to build a replacement API or patch the shell, and I have not surveyed how many published plugins fall into this category — I found this one because it is installed here. There may be others with the same shape.

View raw text
Same class as #10929 (bar drag API dropped from `PluginBarApi`) and #10888 (no way to enumerate plugins): the 4.0.3 bar-widget sandbox removes a capability with no replacement, and the plugin fails silently rather than erroring.

This one is `_moduleWidgets`, and it takes out an entire category of plugin: anything whose purpose is to organise or reveal *other* plugins' bar widgets.

## The change

`usr/share/omarchy/shell/plugins/bar/Bar.qml:262`:

```js
_moduleWidgets: function(requestedId) {
  return String(requestedId || "") === String(moduleName || "")
    ? root.moduleWidgets(moduleName) : []
},
```

A plugin may now ask only about its own widgets. Any other id returns `[]`.

## Why that removes a category rather than narrowing one

A bar organiser exists precisely to ask about widgets it does not own. Concretely, `Westy47/omarchy-hidden-bar` (a drawer that hides chosen widgets and reveals them on hover) does:

```qml
// HiddenBar.qml:45-48
if (!root.bar || typeof root.bar.moduleWidgets !== "function") return out
for (var i = 0; i < root.hiddenIds.length; i++) {
  var items = root.bar.moduleWidgets(root.hiddenIds[i])
  ...
}
```

`root.hiddenIds` is, by definition, ids the user assigned to the drawer — never the plugin's own. So every call returns `[]`, `liveItems()` is empty, no `HoverHandler` is attached, and nothing is ever hidden or revealed. The plugin loads, enables and logs nothing.

Requested on Omarchy 4.0.3-1, stock package.

## Why the usual 4.0.3 workaround does not apply here

The other regressions in this cluster have a fallback, and third-party authors have already shipped it: read from disk instead of asking the shell. `data-goblin/fileblade` and `fross100/omaplug` both now enumerate `~/.config/omarchy/plugins/*/manifest.json` directly.

That works because a *list* also exists on disk. This case needs the **live QML objects** the bar has already instantiated, so that their `visible` can be set and a `HoverHandler` parented to them. There is no on-disk equivalent of a running object.

`barWidgetRegistry` is not a substitute either. `services/PluginBarWidgetRegistryApi.qml` describes itself as a "detached widget-catalogue snapshot for third-party full-bar implementations", and states that "mutating this local view cannot replace a registration in the host registry". It hands out components and metadata for a plugin to render *its own* copies — it cannot reach the instances the standard bar is already showing.

So the only remaining route is for the plugin to reimplement the whole bar as a `bar`-kind plugin. That is a different product, not a port.

## Suggested direction

The isolation goal seems to be that a plugin should not silently inspect or mutate things the user never pointed it at. A bar organiser is compatible with that goal, because the ids it manipulates come from the **user's own configuration**.

A minimal API that keeps the guarantee could scope by *user grant* rather than by *ownership*: a plugin may reach `moduleWidgets(id)` only for ids the user has listed in that plugin's own settings entry in `shell.json`. The shell already reads that entry, so the check is local and needs no new trust surface.

Failing that, an explicit refusal would at least save the next author the investigation — right now the call returns `[]`, which is indistinguishable from "that widget has no items".

## What I did not verify

I have not tried to build a replacement API or patch the shell, and I have not surveyed how many published plugins fall into this category — I found this one because it is installed here. There may be others with the same shape.

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 11:16 UTC