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

Bar: an extra bar built for Qt's placeholder screen stacks on a real monitor after all outputs reconnect; bars are built one at a time (KVM switch)

Reported by dreed47 · filed Sep 24, 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: an extra bar built for Qt's placeholder screen stacks on a real monitor after all outputs reconnect; bars are built one at a time (KVM switch)revision 1 · captured 2026-09-28 21:23 UTC via poll

What happens

When every output disconnects and reconnects at the same time (switching a KVM away and back), one monitor briefly shows two bars stacked, and the other monitor shows no bar at first. It settles to one bar per monitor after 5–15 s on this machine.

Expected

One bar per monitor at all times, and no bar built for a screen Hyprland doesn't have.

What I recorded

I polled hyprctl layers -j / hyprctl monitors -j every 0.5 s. The sequence was the same on every switch (every bar belongs to the single omarchy-shell PID):

t after switch backHDMI-A-1 (Samsung)HDMI-A-2 (Philips)
0 soutput back, no baroutput back, no bar
+1.6 s1 omarchy-bar at y=0none
+6.3 s2 omarchy-bar: y=0 and y=261 omarchy-bar
+10 s11

At the same moment the shell logs:

INFO qt.qpa.wayland: There are no outputs - creating placeholder screen
WARN: Layershell screen does not correspond to a real screen. Letting the compositor pick. (x2)

Timing measurements

I ran a copy of $OMARCHY_PATH/shell with console.warn timestamps added: in BarPanel Component.onCompleted/onDestruction, on Quickshell.onScreensChanged, and in ModuleSlot (slot completion plus each Loader's onLoaded). Two switch-backs:

EventSwitch 1Switch 2
Bar for the placeholder screen (screen.name == "") done12:27:20.312:28:01.2
HDMI-A-1 bar done12:27:26.3 (+6.0 s)12:28:04.5 (+3.3 s)
HDMI-A-2 bar done12:27:36.5 (+10.3 s)12:28:09.3 (+4.8 s)

What this shows:
1. A complete bar is built for Qt's placeholder screen. Variants { model: Quickshell.screens } in plugins/bar/Bar.qml has no filter, so while no outputs exist the placeholder gets a full BarPanel with every widget. Quickshell can't map it to an output, so Hyprland places it on the first monitor that returns. That's the extra bar.
2. The bars are built one after another on the GUI thread. onScreensChanged only fires after each BarPanel finishes, so HDMI-A-2's bar can't start until HDMI-A-1's is done. That's why the second monitor has no bar at first.
3. The placeholder build costs a full bar's worth of time before the real bars even start, and the placeholder bar stays visible for that whole time.

Build cost per bar, averaged over 6 builds (gaps between events, credited to the widget that finished next, so approximate):

ms / barwidget
630omarchy.indicators
481othavi0.agent-bar
238crmne.hyprmoncfg
221tmn73.calendar
216robzolkos.github
175omarchy.tray
60–170every other widget, including trivial ones (omarchy.menu 78, omarchy.power 71)

34 widgets per bar gives 3–10 s per bar on this CPU. The ~60–80 ms that every slot costs, however small the widget, suggests ModuleSlot itself is expensive to create.

When it's visible

How visible this is depends on timing:
- Intel N150 (i915), 2× 4K HDMI at scale 1.6, 34 bar widgets: visible on every switch.
- Ryzen 9 6900HX (Radeon 680M), same monitors, same plugins, same package versions: never seen. The bars presumably build fast enough that the placeholder bar is gone before it can be seen.

Possible fixes

  • Skip screens in the bar's Variants (and DragGhostPanel / BarMoveGhostPanel, which use the same model) that don't match a real Hyprland monitor, e.g. an empty name. Or debounce rebuilding until the screen list is stable.
  • Longer term: build bars incrementally or asynchronously, and make ModuleSlot cheaper to create, so N monitors × M widgets doesn't block the GUI thread for seconds on low-end CPUs.

System

  • omarchy 4.0.4-1, quickshell 0.3.1-1, hyprland 0.56.2-2, aquamarine 0.15.0-2, linux-omarchy 7.2.5-3
  • Intel N150 / Alder Lake-N graphics (i915), 4 cores
  • Samsung U32R59x + Philips 328E1, both 3840x2160@60, scale 1.6, via a generic 4-port HDMI/USB KVM

Repro

  1. Two monitors through a KVM, on a slower machine.
  2. Switch the KVM to another computer, wait ~10 s, switch back.
  3. Watch the bars, or poll hyprctl layers -j.

Related, but a different symptom: #12554 (Quickshell abort when no outputs remain), #9975 (IpcHandler registered once per bar).

Filed by Claude Opus 5.5 via Claude Code.

View raw text
## What happens
When every output disconnects and reconnects at the same time (switching a KVM away and back), one monitor briefly shows **two bars stacked**, and the other monitor shows **no bar** at first. It settles to one bar per monitor after 5–15 s on this machine.

## Expected
One bar per monitor at all times, and no bar built for a screen Hyprland doesn't have.

## What I recorded
I polled `hyprctl layers -j` / `hyprctl monitors -j` every 0.5 s. The sequence was the same on every switch (every bar belongs to the single omarchy-shell PID):

| t after switch back | HDMI-A-1 (Samsung) | HDMI-A-2 (Philips) |
|---|---|---|
| 0 s | output back, no bar | output back, no bar |
| +1.6 s | 1 `omarchy-bar` at y=0 | none |
| +6.3 s | **2** `omarchy-bar`: y=0 **and y=26** | 1 `omarchy-bar` |
| +10 s | 1 | 1 |

At the same moment the shell logs:

    INFO qt.qpa.wayland: There are no outputs - creating placeholder screen
    WARN: Layershell screen does not correspond to a real screen. Letting the compositor pick.   (x2)

## Timing measurements
I ran a copy of `$OMARCHY_PATH/shell` with `console.warn` timestamps added: in `BarPanel` `Component.onCompleted`/`onDestruction`, on `Quickshell.onScreensChanged`, and in `ModuleSlot` (slot completion plus each Loader's `onLoaded`). Two switch-backs:

| Event | Switch 1 | Switch 2 |
|---|---|---|
| Bar for the placeholder screen (`screen.name == ""`) done | 12:27:20.3 | 12:28:01.2 |
| HDMI-A-1 bar done | 12:27:26.3 (+6.0 s) | 12:28:04.5 (+3.3 s) |
| HDMI-A-2 bar done | 12:27:36.5 (+10.3 s) | 12:28:09.3 (+4.8 s) |

What this shows:
1. **A complete bar is built for Qt's placeholder screen.** `Variants { model: Quickshell.screens }` in `plugins/bar/Bar.qml` has no filter, so while no outputs exist the placeholder gets a full `BarPanel` with every widget. Quickshell can't map it to an output, so Hyprland places it on the first monitor that returns. That's the extra bar.
2. **The bars are built one after another on the GUI thread.** `onScreensChanged` only fires after each `BarPanel` finishes, so HDMI-A-2's bar can't start until HDMI-A-1's is done. That's why the second monitor has no bar at first.
3. **The placeholder build costs a full bar's worth of time** before the real bars even start, and the placeholder bar stays visible for that whole time.

Build cost per bar, averaged over 6 builds (gaps between events, credited to the widget that finished next, so approximate):

| ms / bar | widget |
|---|---|
| 630 | `omarchy.indicators` |
| 481 | `othavi0.agent-bar` |
| 238 | `crmne.hyprmoncfg` |
| 221 | `tmn73.calendar` |
| 216 | `robzolkos.github` |
| 175 | `omarchy.tray` |
| 60–170 | every other widget, including trivial ones (`omarchy.menu` 78, `omarchy.power` 71) |

34 widgets per bar gives 3–10 s per bar on this CPU. The ~60–80 ms that every slot costs, however small the widget, suggests `ModuleSlot` itself is expensive to create.

## When it's visible
How visible this is depends on timing:
- **Intel N150** (i915), 2× 4K HDMI at scale 1.6, 34 bar widgets: visible on every switch.
- **Ryzen 9 6900HX** (Radeon 680M), same monitors, same plugins, same package versions: never seen. The bars presumably build fast enough that the placeholder bar is gone before it can be seen.

## Possible fixes
- Skip screens in the bar's `Variants` (and `DragGhostPanel` / `BarMoveGhostPanel`, which use the same model) that don't match a real Hyprland monitor, e.g. an empty `name`. Or debounce rebuilding until the screen list is stable.
- Longer term: build bars incrementally or asynchronously, and make `ModuleSlot` cheaper to create, so N monitors × M widgets doesn't block the GUI thread for seconds on low-end CPUs.

## System
- omarchy 4.0.4-1, quickshell 0.3.1-1, hyprland 0.56.2-2, aquamarine 0.15.0-2, linux-omarchy 7.2.5-3
- Intel N150 / Alder Lake-N graphics (i915), 4 cores
- Samsung U32R59x + Philips 328E1, both 3840x2160@60, scale 1.6, via a generic 4-port HDMI/USB KVM

## Repro
1. Two monitors through a KVM, on a slower machine.
2. Switch the KVM to another computer, wait ~10 s, switch back.
3. Watch the bars, or poll `hyprctl layers -j`.

Related, but a different symptom: #12554 (Quickshell abort when no outputs remain), #9975 (IpcHandler registered once per bar).

Filed by Claude Opus 5.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 19:39 UTC