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.
Theme change can leave one monitor on the old wallpaper, and `background refresh` cannot recover it (multi-GPU, multi-monitor)
Reported by nicolasbadano · filed Aug 27, 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
System details
Intel i7-12700 + two GPUs (NVIDIA Quadro T400 driving DP-1, Intel UHD 770 driving HDMI-A-1), Omarchy 4.0.1-1, Hyprland 0.56.2, quickshell 0.3.1-1, Qt 6.11.2, mesa 26.2.1, kernel 7.1.9-arch1-2, Lenovo ThinkStation P360.
Two monitors, both scale 1.25: DP-1 2560x1440 at 0,864 (NVIDIA, primary DRM device) and HDMI-A-1 1920x1080 at 256,0 (Intel, secondary DRM device — aquamarine logs Starting backend for /dev/dri/card0, with driver i915 with primary /dev/dri/card1 and GBM: Buffer is marked as multigpu, forcing linear).
What's wrong?
omarchy theme set kanagawa retinted everything correctly and updated the wallpaper on DP-1, but HDMI-A-1 kept displaying the previous theme's wallpaper indefinitely. The bar on that same monitor kept updating normally (clock ticking, new theme colors), so only the background surface was stale.
What I verified
- Shell state was correct.
~/.local/state/omarchy/current/background->.../current/theme/backgrounds/1-kanagawa.jpg, andtheme.namesaidkanagawa. - Only the pixels were wrong. Sampling the visible wallpaper strip on each output with
grim+ ImageMagick:
HDMI-A-1:#58206F(previous theme's purple)DP-1:#C0C1B4(matches1-kanagawa.jpg, which averages#A1A09A)
hyprctl layersshowed exactly oneomarchy-backgroundlayer per monitor, both from the shell's pid, both correctly sized/positioned. No stacking or leftover-surface problem.omarchy restart shellfixed it immediately — HDMI-A-1 then sampled#C0C1B4, matching DP-1.
Since every panel binds its image to the same shared root properties, correct state plus wrong pixels means that output's background surface simply never committed a new frame after the source changed, and the compositor kept scanning out its last buffer. A wallpaper is static, so nothing ever forces another redraw and it stays stale forever.
The stale output is precisely the one behind the cross-GPU blit path, so the stale surface itself may well be an aquamarine/Hyprland multi-GPU issue rather than an Omarchy one. But there are two things in the shell that turn a one-frame glitch into an unrecoverable one, and both look fixable here:
1. `omarchy-shell background refresh` cannot recover this state (the obvious user fix silently does nothing).
In shell/plugins/background/Background.qml, refreshBackground() -> readlinkProc -> setBackground(path, false) -> transitionBackground(...), which early-returns:
if (!path || (!force && finalPath === currentBackground)) returnThe shell already believes it is showing the new wallpaper, so refresh is a guaranteed no-op exactly when you need it. The same applies to the set and setInstant IPC calls. Only themeTransition passes force: true, and calling that by hand also overwrites the palette. It would help a lot if refresh forced a re-set (or if there were any IPC entry point that re-commits the current background without touching colors).
2. The theme reveal only ever runs on one monitor.
maybeStartReveal() is gated on root.revealProgress !== 0, both immediately and again inside its Qt.callLater:
function maybeStartReveal() {
if (!root.incomingBackground || root.revealProgress !== 0 || maskReady) return
...
}revealProgress is a single shared root property driven by a single shared revealAnimation. Whichever panel's incomingFrame loads first calls startReveal(), which starts the animation and immediately moves revealProgress off 0 — so every other panel's queued callLater re-checks the gate, bails, and never gets maskReady = true. Its incomingLayer therefore stays hidden for the whole transition, and that monitor is left depending entirely on the single revealAnimation.onFinished -> displayedBackground -> base reload to pick up the new image, with no repaint of its own along the way.
So on a multi-monitor setup the cross-fade is only ever seen on one monitor (cosmetic), and the other monitors take a code path with strictly fewer chances to repaint (how this became visible).
Steps to reproduce
- Two monitors, ideally driven by different GPUs.
omarchy theme set <some-theme>with a shell that has been running a while.- Watch: the reveal animation plays on one monitor only; occasionally the other monitor keeps the old wallpaper.
omarchy-shell background refreshdoes nothing.omarchy restart shellfixes it.
I could not make step 3 fire on demand — it happened once after ~45 h of shell uptime, during which HDMI-A-1 had been disconnected and reconnected once (aquamarine logged Deinitializing secondary renderer on /dev/dri/card0, no enabled outputs and later reinitialized it). That hotplug is a plausible trigger for the output's render path getting into a state where it no longer repaints on its own.
Possibly related: #8024 (bar foreground stuck at old opacity on one monitor after a shell-wide toggle) looks like the same shape — shared root state updated, one monitor's panel not reflecting it.
Workaround
omarchy restart shell
View raw text
### System details
Intel i7-12700 + **two GPUs** (NVIDIA Quadro T400 driving DP-1, Intel UHD 770 driving HDMI-A-1), Omarchy 4.0.1-1, Hyprland 0.56.2, quickshell 0.3.1-1, Qt 6.11.2, mesa 26.2.1, kernel 7.1.9-arch1-2, Lenovo ThinkStation P360.
Two monitors, both scale 1.25: `DP-1` 2560x1440 at `0,864` (NVIDIA, **primary** DRM device) and `HDMI-A-1` 1920x1080 at `256,0` (Intel, **secondary** DRM device — aquamarine logs `Starting backend for /dev/dri/card0, with driver i915 with primary /dev/dri/card1` and `GBM: Buffer is marked as multigpu, forcing linear`).
### What's wrong?
`omarchy theme set kanagawa` retinted everything correctly and updated the wallpaper on DP-1, but **HDMI-A-1 kept displaying the previous theme's wallpaper indefinitely**. The bar on that same monitor kept updating normally (clock ticking, new theme colors), so only the background surface was stale.
**What I verified**
1. Shell state was correct. `~/.local/state/omarchy/current/background` -> `.../current/theme/backgrounds/1-kanagawa.jpg`, and `theme.name` said `kanagawa`.
2. Only the pixels were wrong. Sampling the visible wallpaper strip on each output with `grim` + ImageMagick:
- `HDMI-A-1`: `#58206F` (previous theme's purple)
- `DP-1`: `#C0C1B4` (matches `1-kanagawa.jpg`, which averages `#A1A09A`)
3. `hyprctl layers` showed exactly one `omarchy-background` layer per monitor, both from the shell's pid, both correctly sized/positioned. No stacking or leftover-surface problem.
4. `omarchy restart shell` fixed it immediately — HDMI-A-1 then sampled `#C0C1B4`, matching DP-1.
Since every panel binds its image to the same shared root properties, correct state plus wrong pixels means **that output's background surface simply never committed a new frame** after the source changed, and the compositor kept scanning out its last buffer. A wallpaper is static, so nothing ever forces another redraw and it stays stale forever.
The stale output is precisely the one behind the cross-GPU blit path, so the stale surface itself may well be an aquamarine/Hyprland multi-GPU issue rather than an Omarchy one. But there are two things in the shell that turn a one-frame glitch into an unrecoverable one, and both look fixable here:
**1. `omarchy-shell background refresh` cannot recover this state (the obvious user fix silently does nothing).**
In `shell/plugins/background/Background.qml`, `refreshBackground()` -> `readlinkProc` -> `setBackground(path, false)` -> `transitionBackground(...)`, which early-returns:
```qml
if (!path || (!force && finalPath === currentBackground)) return
```
The shell already believes it is showing the new wallpaper, so `refresh` is a guaranteed no-op exactly when you need it. The same applies to the `set` and `setInstant` IPC calls. Only `themeTransition` passes `force: true`, and calling that by hand also overwrites the palette. It would help a lot if `refresh` forced a re-set (or if there were any IPC entry point that re-commits the current background without touching colors).
**2. The theme reveal only ever runs on one monitor.**
`maybeStartReveal()` is gated on `root.revealProgress !== 0`, both immediately and again inside its `Qt.callLater`:
```qml
function maybeStartReveal() {
if (!root.incomingBackground || root.revealProgress !== 0 || maskReady) return
...
}
```
`revealProgress` is a single shared root property driven by a single shared `revealAnimation`. Whichever panel's `incomingFrame` loads first calls `startReveal()`, which starts the animation and immediately moves `revealProgress` off 0 — so every other panel's queued `callLater` re-checks the gate, bails, and never gets `maskReady = true`. Its `incomingLayer` therefore stays hidden for the whole transition, and that monitor is left depending entirely on the single `revealAnimation.onFinished` -> `displayedBackground` -> `base` reload to pick up the new image, with no repaint of its own along the way.
So on a multi-monitor setup the cross-fade is only ever seen on one monitor (cosmetic), and the other monitors take a code path with strictly fewer chances to repaint (how this became visible).
### Steps to reproduce
1. Two monitors, ideally driven by different GPUs.
2. `omarchy theme set <some-theme>` with a shell that has been running a while.
3. Watch: the reveal animation plays on one monitor only; occasionally the other monitor keeps the old wallpaper.
4. `omarchy-shell background refresh` does nothing. `omarchy restart shell` fixes it.
I could not make step 3 fire on demand — it happened once after ~45 h of shell uptime, during which HDMI-A-1 had been disconnected and reconnected once (aquamarine logged `Deinitializing secondary renderer on /dev/dri/card0, no enabled outputs` and later reinitialized it). That hotplug is a plausible trigger for the output's render path getting into a state where it no longer repaints on its own.
Possibly related: #8024 (bar foreground stuck at old opacity on one monitor after a shell-wide toggle) looks like the same shape — shared root state updated, one monitor's panel not reflecting it.
### Workaround
`omarchy restart shell`
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
- Related PRpr/9312· confirmed
- Related PRpr/9313· confirmed
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 09:40 UTC