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

Bar: custom command module with empty "text" renders the raw JSON — falsy fallback makes conditional widgets impossible

Reported by raetsch-hue · filed Sep 5, 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

Bar: custom command module with empty "text" renders the raw JSON — falsy fallback makes conditional widgets impossiblerevision 1 · captured 2026-09-28 21:23 UTC via poll

What happens

A custom type: "command" bar module cannot render as empty. When the script prints Waybar-style JSON with an empty text, the bar displays the raw JSON string instead of nothing:

{"text":"","tooltip":"","class":"idle"}

This makes the documented "print JSON" contract unusable for any widget that should be conditionally visible — a printer queue, a VPN indicator, an update counter. Anything that is idle most of the time.

Why

CustomCommandModule.update() in shell/plugins/bar/Bar.qml uses || to fall back, so an empty string (falsy in JS) takes the fallback branch:

// Bar.qml:1799 (main)
outputText = data.text || String(raw || "").trim()

With data.text === "" the expression falls through to raw — the entire JSON line — and that is what gets rendered.

The same falsy pattern repeats one binding later:

// Bar.qml:1805 (main)
text: outputText || String(setting("text", ""))

The irony is that the hide mechanism already exists and works correctly — it is just unreachable through JSON:

// Ui/WidgetButton.qml
property bool hasVisualContent: text !== ""
visible: hasVisualContent || keepSpace

A module that emits no output at all does reach it: Util.parseModuleJson("") returns {}, outputText stays "", and the widget correctly disappears. So the empty state is reachable by printing nothing, but not by the documented JSON contract.

Expected

{"text":""} hides the widget, exactly as empty output does. An explicitly empty text is a value, not an absent one, and should not be replaced by the raw line.

Steps to reproduce

  1. Create ~/.config/omarchy/bar/scripts/demo:
   #!/usr/bin/env bash
   echo '{"text":"","tooltip":"","class":"idle"}'
   chmod +x ~/.config/omarchy/bar/scripts/demo
  1. Add it to bar.layout.right in ~/.config/omarchy/shell.json:
   { "id": "demo", "type": "command", "exec": "~/.config/omarchy/bar/scripts/demo", "interval": 3 }
  1. Save. The bar shows the literal text {"text":"","tooltip":"","class":"idle"}.

Changing the script to print nothing instead makes the widget correctly invisible, which isolates the fallback as the cause.

Suggested fix

Distinguish absent from empty:

outputText = data.text !== undefined ? String(data.text) : String(raw || "").trim()

and correspondingly for the text: binding, so an explicit "" is honoured while a missing key still falls back.

Workaround

Emit no output at all in the idle state rather than JSON with an empty text.

System details

Omarchy4.0.2-1
Kernel7.1.9-arch1-2
Hyprland0.56.2
CPUIntel Core i5-4670K (Haswell)
GPUNVIDIA GA106 [GeForce RTX 3060], nvidia 610.57.04
MachineASUS H87-PRO, desktop

Verified against main (shell/plugins/bar/Bar.qml lines 1799 and 1805 at time of filing), not just the packaged 4.0.2 copy.

Note

While reproducing this I also hit the moduleName read-only TypeError, which is already tracked in #9701 with a fix in #9972. This report is a separate defect in the same component: #9701 is log noise, this one is visible wrong output.

View raw text
### What happens

A custom `type: "command"` bar module cannot render as empty. When the script prints Waybar-style JSON with an empty `text`, the bar displays **the raw JSON string** instead of nothing:

```
{"text":"","tooltip":"","class":"idle"}
```

This makes the documented "print JSON" contract unusable for any widget that should be conditionally visible — a printer queue, a VPN indicator, an update counter. Anything that is idle most of the time.

### Why

`CustomCommandModule.update()` in `shell/plugins/bar/Bar.qml` uses `||` to fall back, so an empty string (falsy in JS) takes the fallback branch:

```qml
// Bar.qml:1799 (main)
outputText = data.text || String(raw || "").trim()
```

With `data.text === ""` the expression falls through to `raw` — the entire JSON line — and that is what gets rendered.

The same falsy pattern repeats one binding later:

```qml
// Bar.qml:1805 (main)
text: outputText || String(setting("text", ""))
```

The irony is that the hide mechanism already exists and works correctly — it is just unreachable through JSON:

```qml
// Ui/WidgetButton.qml
property bool hasVisualContent: text !== ""
visible: hasVisualContent || keepSpace
```

A module that emits **no output at all** does reach it: `Util.parseModuleJson("")` returns `{}`, `outputText` stays `""`, and the widget correctly disappears. So the empty state is reachable by printing nothing, but not by the documented JSON contract.

### Expected

`{"text":""}` hides the widget, exactly as empty output does. An explicitly empty `text` is a value, not an absent one, and should not be replaced by the raw line.

### Steps to reproduce

1. Create `~/.config/omarchy/bar/scripts/demo`:

   ```bash
   #!/usr/bin/env bash
   echo '{"text":"","tooltip":"","class":"idle"}'
   ```

   ```bash
   chmod +x ~/.config/omarchy/bar/scripts/demo
   ```

2. Add it to `bar.layout.right` in `~/.config/omarchy/shell.json`:

   ```json
   { "id": "demo", "type": "command", "exec": "~/.config/omarchy/bar/scripts/demo", "interval": 3 }
   ```

3. Save. The bar shows the literal text `{"text":"","tooltip":"","class":"idle"}`.

Changing the script to print nothing instead makes the widget correctly invisible, which isolates the fallback as the cause.

### Suggested fix

Distinguish absent from empty:

```qml
outputText = data.text !== undefined ? String(data.text) : String(raw || "").trim()
```

and correspondingly for the `text:` binding, so an explicit `""` is honoured while a missing key still falls back.

### Workaround

Emit no output at all in the idle state rather than JSON with an empty `text`.

### System details

| | |
|---|---|
| Omarchy | 4.0.2-1 |
| Kernel | 7.1.9-arch1-2 |
| Hyprland | 0.56.2 |
| CPU | Intel Core i5-4670K (Haswell) |
| GPU | NVIDIA GA106 [GeForce RTX 3060], nvidia 610.57.04 |
| Machine | ASUS H87-PRO, desktop |

Verified against `main` (`shell/plugins/bar/Bar.qml` lines 1799 and 1805 at time of filing), not just the packaged 4.0.2 copy.

### Note

While reproducing this I also hit the `moduleName` read-only TypeError, which is already tracked in #9701 with a fix in #9972. This report is a separate defect in the same component: #9701 is log noise, this one is visible wrong output.

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 10:51 UTC