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.
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
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
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 || keepSpaceA 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
- Create
~/.config/omarchy/bar/scripts/demo:
#!/usr/bin/env bash
echo '{"text":"","tooltip":"","class":"idle"}' chmod +x ~/.config/omarchy/bar/scripts/demo- Add it to
bar.layout.rightin~/.config/omarchy/shell.json:
{ "id": "demo", "type": "command", "exec": "~/.config/omarchy/bar/scripts/demo", "interval": 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:
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.
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