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-602GitHub issuePublicFixed

Universal Fix for Wedged-Style Popup Panels in Third-Party Plugins

Reported by M0VO · filed Sep 13, 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

Universal Fix for Wedged-Style Popup Panels in Third-Party Pluginsrevision 1 · captured 2026-09-28 21:23 UTC via poll

System details

System: Omarchy 4.0.3-1 / Quickshell 0.3.1 / Hyprland

What's wrong?

Supersedes: omarchy-popup-fix-report-2026-09-13.md (previous per-plugin fix)


Problem

Third-party Omarchy bar plugins that use a popup panel exhibit stuck overlays:
the popup opens but refuses to close. The panel stays mapped on screen and
swallows all mouse input on that monitor. The only recovery is killing the
shell with the emergency SUPER + SHIFT + ESC binding.

This affects every third-party plugin that was written against the older
Omarchy bar plugin API where centerHoverRevealSuppressed was a plain
writable property. It recurs identically whenever such a plugin is installed
or updated.

Confirmed affected plugins:

PluginStatus
io.github.calebhat.weather (Detailed Weather)Fixed in previous session
yooneskh.omaniclean (OmaniClean)Fixed in previous session
omargram (OmarGram)Reproduced bug (journal evidence below), then removed by user at 13:53:30

Root Cause

The Omarchy bar plugin API (PluginBarApi.qml:25-26) now exposes the
bar's hover-reveal state to plugins as a read-only property, with a
dedicated setter function:

// /usr/share/omarchy/shell/Ui/PluginBarApi.qml
readonly property bool centerHoverRevealSuppressed: _centerHoverRevealSuppressed

function setCenterHoverRevealSuppressed(value) {
  if (_setCenterHoverRevealSuppressed) _setCenterHoverRevealSuppressed(!!value)
}

Third-party plugins copied an older Omarchy panel template that assigned
directly to the property:

function setCenterHoverRevealSuppressed(value) {
  if (root.bar && "centerHoverRevealSuppressed" in root.bar)
    root.bar.centerHoverRevealSuppressed = value   // ← QML TypeError: read-only
}

The read-only assignment throws a QML TypeError, which aborts close()
before root.controller.hide() runs. The panel stays mapped and keeps
grabbing input — the "wedged overlay" effect.

Journal evidence (omargram, 2026-09-13):

WARN scene: .../omargram/Panel.qml[171:-1]:
  TypeError: Cannot assign to read-only property "centerHoverRevealSuppressed"

This pattern occurs because every third-party plugin author copied the same
older Omarchy template. The API change (read-only + setter function) is
documented in the built-in first-party panels, but no migration path was
provided for third-party plugins.

Why It Recurs

The root cause is not in the user's configuration files (shell.json,
Hyprland, etc.). It is a latent API compatibility issue between the packaged
bar's plugin interface and third-party plugin code. Any plugin written against
the older template will hit it identically on first open+close cycle.


Files Changed

Previous session (per-plugin fix)

  • ~/.config/omarchy/plugins/io.github.calebhat.weather/Panel.qml
  • ~/.config/omarchy/plugins/yooneskh.omaniclean/Panel.qml

Both already carry the safe pattern (verified this session):
weather/Panel.qml:69-73, omaniclean/Panel.qml:92-96.

This session (universal auto-patch script)

  • `~/.config/omarchy/fix-plugin-popups.sh` — new universal scan + patch script

Fix: Universal Auto-Patch Script

~/.config/omarchy/fix-plugin-popups.sh scans every plugin panel under
~/.config/omarchy/plugins/*/Panel.qml and, where it finds the broken
helper, rewrites it in place to the safe first-party pattern:

// Before (broken):
function setCenterHoverRevealSuppressed(value) {
  if (root.bar && "centerHoverRevealSuppressed" in root.bar)
    root.bar.centerHoverRevealSuppressed = value
}

// After (safe):
function setCenterHoverRevealSuppressed(value) {
  if (root.bar && typeof root.bar.setCenterHoverRevealSuppressed === "function")
    root.bar.setCenterHoverRevealSuppressed(value)
  else if (root.bar && "centerHoverRevealSuppressed" in root.bar)
    root.bar.centerHoverRevealSuppressed = value
}

Already-fixed files (containing typeof root.bar.setCenterHoverRevealSuppressed)
are skipped. Plugins without the helper at all are also skipped.

Usage

# Scan and patch all broken plugins, then restart the shell:
~/.config/omarchy/fix-plugin-popups.sh

# Dry-run — report only, change nothing:
~/.config/omarchy/fix-plugin-popups.sh --check

# Patch but don't restart the shell (if you plan to do it separately):
~/.config/omarchy/fix-plugin-popups.sh --no-restart

Git-Managed Plugin Workflow

Patching a git-cloned plugin creates an uncommitted working tree change,
which blocks omarchy plugin update (it uses git merge --ff-only). The
recommended workflow is:

# 1. Stash the local fix before updating
git -C ~/.config/omarchy/plugins/<id> stash

# 2. Update the plugin
omarchy plugin update <id>

# 3. Re-run the fix script to re-apply the patch to the updated code
~/.config/omarchy/fix-plugin-popups.sh

This is idempotent — the script won't re-patch files that already have
the safe pattern.

When to Run

Run the script after:
- omarchy plugin add (new plugin install)
- omarchy plugin update (after the stash → update → re-run workflow above)


Verification

Script check (current state)

$ ~/.config/omarchy/fix-plugin-popups.sh --check
No broken plugin panels found — every panel already uses the safe pattern.

Live toggle (weather + omaniclean, after shell restart)

$ omarchy-shell shell toggle io.github.calebhat.weather   # open
$ omarchy-shell shell toggle io.github.calebhat.weather   # close — no error
$ omarchy-shell shell toggle yooneskh.omaniclean          # open
$ omarchy-shell shell toggle yooneskh.omaniclean          # close — no error

Journal (5-minute window): no TypeError / Cannot assign to read-only
entries.

omargram note

At 13:53:30 the user removed omargram via omarchy-plugin-remove omargram
while debugging the wedged overlay. The journal confirms the same read-only
TypeError before removal:

Sep 13 13:38:23 WARN scene: .../omargram/Panel.qml[171:-1]:
  TypeError: Cannot assign to read-only property "centerHoverRevealSuppressed"
Sep 13 13:38:33 WARN scene: ...
  (repeated ~10 times while panel was wedged)

Upstream Recommendation

The underlying fix should be applied in the packaged bar API
(/usr/share/omarchy/shell/Ui/PluginBarApi.qml) to preserve backward
compatibility with existing third-party plugins. A single change would make
all current and future plugins work without per-plugin patching:

// Suggested change in PluginBarApi.qml:
// Make centerHoverRevealSuppressed a writable property that
// delegates to the setter on assignment.
property bool centerHoverRevealSuppressed: false
onCenterHoverRevealSuppressedChanged: {
  if (_setCenterHoverRevealSuppressed)
    _setCenterHoverRevealSuppressed(centerHoverRevealSuppressed)
}

// Keep _centerHoverRevealSuppressed as the authoritative binding target
// (read from bar), with the public property as a compat shim.

This would allow old plugins to assign directly while new plugins
use the setter function — both paths produce the same effect. Consider
filing this as a backward-compatibility enhancement in the Omarchy
issue tracker: https://github.com/basecamp/omarchy/issues


Summary

ActionResult
Previous per-plugin fix✅ weather + omaniclean fixed and verified
Universal auto-patch script✅ created at ~/.config/omarchy/fix-plugin-popups.sh
Script dry-run (all plugins)✅ "No broken plugin panels found"
Live toggle test (weather, omaniclean)✅ open+close, no QML errors
Journal check (5-minute window)✅ clean — no TypeError / Cannot assign entries
Shell restart (post-fix)✅ clean startup (PID 3352702), no errors
omargramRemoved by user; same bug confirmed in journal
Remaining broken pluginsNone installed
View raw text
### System details

System: Omarchy 4.0.3-1 / Quickshell 0.3.1 / Hyprland  

### What's wrong?

**Supersedes:** `omarchy-popup-fix-report-2026-09-13.md` (previous per-plugin fix)

---

## Problem

Third-party Omarchy bar plugins that use a popup panel exhibit **stuck overlays**:
the popup opens but refuses to close. The panel stays mapped on screen and
swallows all mouse input on that monitor. The only recovery is killing the
shell with the emergency `SUPER + SHIFT + ESC` binding.

This affects every third-party plugin that was written against the older
Omarchy bar plugin API where `centerHoverRevealSuppressed` was a plain
writable property. It recurs identically whenever such a plugin is installed
or updated.

**Confirmed affected plugins:**

| Plugin | Status |
|--------|--------|
| `io.github.calebhat.weather` (Detailed Weather) | Fixed in previous session |
| `yooneskh.omaniclean` (OmaniClean) | Fixed in previous session |
| `omargram` (OmarGram) | Reproduced bug (journal evidence below), then removed by user at 13:53:30 |

---

## Root Cause

The Omarchy bar plugin API (`PluginBarApi.qml:25-26`) now exposes the
bar's hover-reveal state to plugins as a **read-only** property, with a
dedicated setter function:

```js
// /usr/share/omarchy/shell/Ui/PluginBarApi.qml
readonly property bool centerHoverRevealSuppressed: _centerHoverRevealSuppressed

function setCenterHoverRevealSuppressed(value) {
  if (_setCenterHoverRevealSuppressed) _setCenterHoverRevealSuppressed(!!value)
}
```

Third-party plugins copied an older Omarchy panel template that assigned
directly to the property:

```js
function setCenterHoverRevealSuppressed(value) {
  if (root.bar && "centerHoverRevealSuppressed" in root.bar)
    root.bar.centerHoverRevealSuppressed = value   // ← QML TypeError: read-only
}
```

The read-only assignment throws a **QML TypeError**, which aborts `close()`
**before** `root.controller.hide()` runs. The panel stays mapped and keeps
grabbing input — the "wedged overlay" effect.

**Journal evidence (omargram, 2026-09-13):**

```
WARN scene: .../omargram/Panel.qml[171:-1]:
  TypeError: Cannot assign to read-only property "centerHoverRevealSuppressed"
```

This pattern occurs because every third-party plugin author copied the same
older Omarchy template. The API change (read-only + setter function) is
documented in the built-in first-party panels, but no migration path was
provided for third-party plugins.

### Why It Recurs

The root cause is **not** in the user's configuration files (`shell.json`,
Hyprland, etc.). It is a latent API compatibility issue between the packaged
bar's plugin interface and third-party plugin code. Any plugin written against
the older template will hit it identically on first open+close cycle.

---

## Files Changed

### Previous session (per-plugin fix)

- `~/.config/omarchy/plugins/io.github.calebhat.weather/Panel.qml`
- `~/.config/omarchy/plugins/yooneskh.omaniclean/Panel.qml`

Both already carry the safe pattern (verified this session):
`weather/Panel.qml:69-73`, `omaniclean/Panel.qml:92-96`.

### This session (universal auto-patch script)

- **`~/.config/omarchy/fix-plugin-popups.sh`** — new universal scan + patch script

---

## Fix: Universal Auto-Patch Script

`~/.config/omarchy/fix-plugin-popups.sh` scans every plugin panel under
`~/.config/omarchy/plugins/*/Panel.qml` and, where it finds the broken
helper, rewrites it in place to the safe first-party pattern:

```js
// Before (broken):
function setCenterHoverRevealSuppressed(value) {
  if (root.bar && "centerHoverRevealSuppressed" in root.bar)
    root.bar.centerHoverRevealSuppressed = value
}

// After (safe):
function setCenterHoverRevealSuppressed(value) {
  if (root.bar && typeof root.bar.setCenterHoverRevealSuppressed === "function")
    root.bar.setCenterHoverRevealSuppressed(value)
  else if (root.bar && "centerHoverRevealSuppressed" in root.bar)
    root.bar.centerHoverRevealSuppressed = value
}
```

Already-fixed files (containing `typeof root.bar.setCenterHoverRevealSuppressed`)
are skipped. Plugins without the helper at all are also skipped.

### Usage

```bash
# Scan and patch all broken plugins, then restart the shell:
~/.config/omarchy/fix-plugin-popups.sh

# Dry-run — report only, change nothing:
~/.config/omarchy/fix-plugin-popups.sh --check

# Patch but don't restart the shell (if you plan to do it separately):
~/.config/omarchy/fix-plugin-popups.sh --no-restart
```

### Git-Managed Plugin Workflow

Patching a git-cloned plugin creates an uncommitted working tree change,
which blocks `omarchy plugin update` (it uses `git merge --ff-only`). The
recommended workflow is:

```bash
# 1. Stash the local fix before updating
git -C ~/.config/omarchy/plugins/<id> stash

# 2. Update the plugin
omarchy plugin update <id>

# 3. Re-run the fix script to re-apply the patch to the updated code
~/.config/omarchy/fix-plugin-popups.sh
```

This is idempotent — the script won't re-patch files that already have
the safe pattern.

### When to Run

Run the script after:
- `omarchy plugin add` (new plugin install)
- `omarchy plugin update` (after the stash → update → re-run workflow above)

---

## Verification

### Script check (current state)

```
$ ~/.config/omarchy/fix-plugin-popups.sh --check
No broken plugin panels found — every panel already uses the safe pattern.
```

### Live toggle (weather + omaniclean, after shell restart)

```
$ omarchy-shell shell toggle io.github.calebhat.weather   # open
$ omarchy-shell shell toggle io.github.calebhat.weather   # close — no error
$ omarchy-shell shell toggle yooneskh.omaniclean          # open
$ omarchy-shell shell toggle yooneskh.omaniclean          # close — no error
```

Journal (5-minute window): **no** `TypeError` / `Cannot assign to read-only`
entries.

### omargram note

At 13:53:30 the user removed omargram via `omarchy-plugin-remove omargram`
while debugging the wedged overlay. The journal confirms the same read-only
TypeError before removal:

```
Sep 13 13:38:23 WARN scene: .../omargram/Panel.qml[171:-1]:
  TypeError: Cannot assign to read-only property "centerHoverRevealSuppressed"
Sep 13 13:38:33 WARN scene: ...
  (repeated ~10 times while panel was wedged)
```

---

## Upstream Recommendation

The underlying fix should be applied in the packaged bar API
(`/usr/share/omarchy/shell/Ui/PluginBarApi.qml`) to preserve backward
compatibility with existing third-party plugins. A single change would make
all current and future plugins work without per-plugin patching:

```qml
// Suggested change in PluginBarApi.qml:
// Make centerHoverRevealSuppressed a writable property that
// delegates to the setter on assignment.
property bool centerHoverRevealSuppressed: false
onCenterHoverRevealSuppressedChanged: {
  if (_setCenterHoverRevealSuppressed)
    _setCenterHoverRevealSuppressed(centerHoverRevealSuppressed)
}

// Keep _centerHoverRevealSuppressed as the authoritative binding target
// (read from bar), with the public property as a compat shim.
```

This would allow old plugins to assign directly while new plugins
use the setter function — both paths produce the same effect. Consider
filing this as a backward-compatibility enhancement in the Omarchy
issue tracker: https://github.com/basecamp/omarchy/issues

---

## Summary

| Action | Result |
|--------|--------|
| Previous per-plugin fix | ✅ weather + omaniclean fixed and verified |
| Universal auto-patch script | ✅ created at `~/.config/omarchy/fix-plugin-popups.sh` |
| Script dry-run (all plugins) | ✅ "No broken plugin panels found" |
| Live toggle test (weather, omaniclean) | ✅ open+close, no QML errors |
| Journal check (5-minute window) | ✅ clean — no `TypeError` / `Cannot assign` entries |
| Shell restart (post-fix) | ✅ clean startup (PID 3352702), no errors |
| omargram | Removed by user; same bug confirmed in journal |
| Remaining broken plugins | None installed |

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

  • Fixed bypr/11080· 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 12:41 UTC