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.
Feature request: per-monitor workspaces by default, with a bar widget that shows each monitor's own block
Reported by rsd · 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
Summary
Make workspaces per-monitor by default (hyprsplit semantics: each monitor owns its own block of 10 workspaces) and teach the omarchy.workspaces bar widget to show each monitor's own block. On a single screen nothing changes. On two or more screens this fixes the two things every docked user hits first: SUPER+N stealing a workspace from another monitor, and the bar being wrong on every screen but one.
Problem with the current default
Hyprland treats workspaces as one global pool. Workspace 3 is a single object that lives on whichever monitor last showed it. Pressing SUPER+3 on an external display pulls workspace 3 over from the laptop panel, and the laptop falls back to whatever is left. Layouts drift with every keypress.
The stock bar widget assumes that same model:
- It only lists ids 1–10, so a monitor that ended up with workspace 11 or 12 shows nothing for it.
- It highlights the single global
Hyprland.focusedWorkspace, so every bar except the one on the focused monitor highlights either nothing or the wrong slot.
macOS, GNOME, KDE and Windows all bind virtual desktops to a display. New Omarchy users bring that expectation and assume they misconfigured something when the second monitor behaves differently.
Proposal
- Compositor side: ship per-monitor workspaces as the default in the Quattro Lua config. Monitor
i(by Hyprland id) owns idsi*10+1 .. i*10+10, andSUPER+1..0always means "this monitor's slot 1..10". With one monitor this is exactly stock behaviour, so single-screen users see no regression. This is what the hyprsplit plugin does; the same logic can be expressed in the Lua pipeline without a compiled compositor plugin (I have it running that way on 0.56.2).
- Bar side: make
omarchy.workspacesresolve the monitor each bar instance lives on, show that monitor's block labelled 1–10, and highlightmonitor.activeWorkspaceinstead of the global focused workspace.
Reference implementation of the widget change
I have been running a clone of plugins/bar/widgets/Workspaces.qml with these changes for a few weeks on a three-monitor setup (laptop + 4K + portrait), at home and at a second desk with different panels. The diff against stock is small:
// one instance per screen, so the window tells us which monitor we are
readonly property var barWindow: root.QsWindow.window
readonly property var monitor: barWindow && barWindow.screen
? Hyprland.monitorFor(barWindow.screen)
: null
readonly property int perMonitor: 10
readonly property int offset: monitor !== null ? monitor.id * perMonitor : 0
// highlight this monitor's own active workspace, not the globally focused one
readonly property int activeId: {
if (monitor !== null && monitor.activeWorkspace !== null) return monitor.activeWorkspace.id
if (monitor === null && Hyprland.focusedWorkspace !== null) return Hyprland.focusedWorkspace.id
return -1
}
function workspaceIds() {
var ids = [1, 2, 3, 4, 5]
var values = Hyprland.workspaces.values
for (var i = 0; i < values.length; i++) {
var slot = values[i].id - root.offset
if (slot > 0 && slot <= root.perMonitor && ids.indexOf(slot) === -1) ids.push(slot)
}
ids.sort(function(left, right) { return left - right })
return ids
}and in the Repeater delegate:
readonly property int absoluteId: modelData + root.offset
readonly property var workspace: root.workspaceById(absoluteId)
readonly property bool focused: root.activeId === absoluteId
onPressed: function() { root.focusWorkspace(absoluteId) }Two implementation notes that cost me time and may save someone else's:
Hyprland.monitorFor(window.screen)is the reliable way to get the monitor. MatchingHyprland.monitors.valuesby name returns null at widget-completion time, and the binding never re-fires.- Use
monitor.activeWorkspace.idfor the highlight, notHyprland.focusedWorkspace. The focused monitor is not necessarily the one this bar is on.
With stock workspace config (one global pool, ids 1–10) offset is always 0 and the widget behaves exactly as today, so the widget change alone is safe to land ahead of the compositor default.
Why this should be the default rather than an opt-in
- Most Omarchy machines are laptops that dock. The multi-monitor case is not an edge case; it is the daily case for a large share of users.
- Single-screen users see no behaviour change.
- The bar widget can currently only ever be correct on one screen at a time. A workspace indicator that is wrong on every other screen is not a finished feature.
- Layouts survive docking and undocking. Windows stay on the screen the user put them on.
- No new binary dependency: the split is expressible in the existing Lua config, and the widget change is a few lines of QML.
Happy to turn the widget part into a PR if there is interest. Tested on Quattro 4.0.x, Hyprland 0.56.2.
Drafted with Claude Code assistance; the implementation and testing are mine.
View raw text
## Summary
Make workspaces per-monitor by default (hyprsplit semantics: each monitor owns its own block of 10 workspaces) and teach the `omarchy.workspaces` bar widget to show each monitor's own block. On a single screen nothing changes. On two or more screens this fixes the two things every docked user hits first: `SUPER+N` stealing a workspace from another monitor, and the bar being wrong on every screen but one.
## Problem with the current default
Hyprland treats workspaces as one global pool. Workspace 3 is a single object that lives on whichever monitor last showed it. Pressing `SUPER+3` on an external display pulls workspace 3 over from the laptop panel, and the laptop falls back to whatever is left. Layouts drift with every keypress.
The stock bar widget assumes that same model:
- It only lists ids 1–10, so a monitor that ended up with workspace 11 or 12 shows nothing for it.
- It highlights the single global `Hyprland.focusedWorkspace`, so every bar except the one on the focused monitor highlights either nothing or the wrong slot.
macOS, GNOME, KDE and Windows all bind virtual desktops to a display. New Omarchy users bring that expectation and assume they misconfigured something when the second monitor behaves differently.
## Proposal
1. **Compositor side:** ship per-monitor workspaces as the default in the Quattro Lua config. Monitor `i` (by Hyprland id) owns ids `i*10+1 .. i*10+10`, and `SUPER+1..0` always means "this monitor's slot 1..10". With one monitor this is exactly stock behaviour, so single-screen users see no regression. This is what the hyprsplit plugin does; the same logic can be expressed in the Lua pipeline without a compiled compositor plugin (I have it running that way on 0.56.2).
2. **Bar side:** make `omarchy.workspaces` resolve the monitor each bar instance lives on, show that monitor's block labelled 1–10, and highlight `monitor.activeWorkspace` instead of the global focused workspace.
## Reference implementation of the widget change
I have been running a clone of `plugins/bar/widgets/Workspaces.qml` with these changes for a few weeks on a three-monitor setup (laptop + 4K + portrait), at home and at a second desk with different panels. The diff against stock is small:
```qml
// one instance per screen, so the window tells us which monitor we are
readonly property var barWindow: root.QsWindow.window
readonly property var monitor: barWindow && barWindow.screen
? Hyprland.monitorFor(barWindow.screen)
: null
readonly property int perMonitor: 10
readonly property int offset: monitor !== null ? monitor.id * perMonitor : 0
// highlight this monitor's own active workspace, not the globally focused one
readonly property int activeId: {
if (monitor !== null && monitor.activeWorkspace !== null) return monitor.activeWorkspace.id
if (monitor === null && Hyprland.focusedWorkspace !== null) return Hyprland.focusedWorkspace.id
return -1
}
function workspaceIds() {
var ids = [1, 2, 3, 4, 5]
var values = Hyprland.workspaces.values
for (var i = 0; i < values.length; i++) {
var slot = values[i].id - root.offset
if (slot > 0 && slot <= root.perMonitor && ids.indexOf(slot) === -1) ids.push(slot)
}
ids.sort(function(left, right) { return left - right })
return ids
}
```
and in the `Repeater` delegate:
```qml
readonly property int absoluteId: modelData + root.offset
readonly property var workspace: root.workspaceById(absoluteId)
readonly property bool focused: root.activeId === absoluteId
onPressed: function() { root.focusWorkspace(absoluteId) }
```
Two implementation notes that cost me time and may save someone else's:
- `Hyprland.monitorFor(window.screen)` is the reliable way to get the monitor. Matching `Hyprland.monitors.values` by name returns null at widget-completion time, and the binding never re-fires.
- Use `monitor.activeWorkspace.id` for the highlight, not `Hyprland.focusedWorkspace`. The focused monitor is not necessarily the one this bar is on.
With stock workspace config (one global pool, ids 1–10) `offset` is always 0 and the widget behaves exactly as today, so the widget change alone is safe to land ahead of the compositor default.
## Why this should be the default rather than an opt-in
- Most Omarchy machines are laptops that dock. The multi-monitor case is not an edge case; it is the daily case for a large share of users.
- Single-screen users see no behaviour change.
- The bar widget can currently only ever be correct on one screen at a time. A workspace indicator that is wrong on every other screen is not a finished feature.
- Layouts survive docking and undocking. Windows stay on the screen the user put them on.
- No new binary dependency: the split is expressible in the existing Lua config, and the widget change is a few lines of QML.
Happy to turn the widget part into a PR if there is interest. Tested on Quattro 4.0.x, Hyprland 0.56.2.
---
*Drafted with Claude Code assistance; the implementation and testing are mine.*
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:53 UTC