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.
Notification actions are advertised in GetCapabilities but never rendered: action buttons are silently dropped
Reported by fooblahblah · filed Sep 2, 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 happened
The notification server advertises the freedesktop actions capability, but the
shell never renders action buttons. Senders are told actions are supported, send
them, and every one is silently dropped — only the default action (the
whole-card click) is reachable.
$ busctl --user call org.freedesktop.Notifications /org/freedesktop/Notifications \
org.freedesktop.Notifications GetServerInformation
ssss "quickshell" "quickshell" "" "1.2"
$ busctl --user call org.freedesktop.Notifications /org/freedesktop/Notifications \
org.freedesktop.Notifications GetCapabilities
as 6 "persistence" "body" "body-markup" "body-hyperlinks" "actions" "icon-static"The actions do arrive. A dbus-monitor trace of a Chromium extension
notification carrying two buttons:
array [
string "0" string "Delete"
string "1" string "Mark as read"
string "default" string "Activate"
]The toast rendered from that payload has no buttons.
Expected
Actions other than default render as buttons on the toast and invoke the
sender's action when clicked — the behaviour of every other daemon that
advertises actions (mako, swaync, dunst, KDE's Plasma daemon).
Alternatively, if this is deliberate, actions should be dropped fromGetCapabilities and actionsSupported set to false, so senders can fall
back instead of emitting controls that go nowhere.
Steps to reproduce
notify-send -A "delete=Delete" -A "read=Mark as read" "Test" "Any buttons?"The toast shows title and body only, and notify-send exits on timeout without
printing an action id. Real-world equivalent: any Gmail/Facebook web
notification in Chromium, which ship "Delete" / "Mark as read" / "Settings"
buttons that are visible on other desktops and absent here.
Where it comes from
plugins/notifications accepts the actions but has no path to draw them:
Service.qml:935setsactionsSupported: true, andGetCapabilities
advertises actions accordingly.
- Service.qml:360 invokePopupDefault() walks ref.actions looking only for
identifier === "default" (line 380), ignores every other action, and falls
back to focusApp(entry) (line 395).
- components/NotificationCard.qml has a single card-wide MouseArea and no
repeater over actions — there is nowhere for a button to be drawn.
- NotificationLogic.js:206 POPUP_ROLES carries no actions role, so the
action list never reaches the model in the first place.
The live Notification objects are already retained in Service.liveRefs, so
the invocable action objects are present at render time. This looks like a
missing UI layer rather than a protocol gap.
Fix confirmed locally
Cloning the plugin (omarchy plugin clone omarchy.notifications) and adding
roughly 60 lines makes it work end to end:
NotificationLogic.js— serializenotification.actions(skipping
default and label-less entries) into a new actions role, added to
POPUP_ROLES.
2. Service.qml — invokePopupAction(index, identifier) resolves the row
through liveRefs, calls action.invoke(), and dismisses. Restored and
replayed rows have actions cleared before append, since their sender died
with the previous server generation and their originalId may since have
been reused.
3. NotificationCard.qml — a right-aligned Repeater of Ui.Buttons,
declared after the card-wide MouseArea so buttons take their own clicks
instead of falling through to the default action. History rows leave the
property empty and are unchanged.
Verified with notify-send -A, which returned the action id delete on click,
and with a live Facebook notification in Chromium whose "Settings" button
correctly opened Chromium's per-site notification settings.
Happy to open a PR if the approach looks right.
System
- Omarchy 4.0.2-1
- quickshell 0.3.1-1, hyprland 0.56.2-1
- Linux 7.1.9-arch1-2
- Intel Core Ultra 9 285H / Intel Arc Pro 130T/140T (Arrow Lake-P)
- Chromium 151.0.7922.173-1 (one affected sender;
notify-sendreproduces it
with no browser involved)
View raw text
## What happened
The notification server advertises the freedesktop `actions` capability, but the
shell never renders action buttons. Senders are told actions are supported, send
them, and every one is silently dropped — only the `default` action (the
whole-card click) is reachable.
```
$ busctl --user call org.freedesktop.Notifications /org/freedesktop/Notifications \
org.freedesktop.Notifications GetServerInformation
ssss "quickshell" "quickshell" "" "1.2"
$ busctl --user call org.freedesktop.Notifications /org/freedesktop/Notifications \
org.freedesktop.Notifications GetCapabilities
as 6 "persistence" "body" "body-markup" "body-hyperlinks" "actions" "icon-static"
```
The actions do arrive. A `dbus-monitor` trace of a Chromium extension
notification carrying two buttons:
```
array [
string "0" string "Delete"
string "1" string "Mark as read"
string "default" string "Activate"
]
```
The toast rendered from that payload has no buttons.
## Expected
Actions other than `default` render as buttons on the toast and invoke the
sender's action when clicked — the behaviour of every other daemon that
advertises `actions` (mako, swaync, dunst, KDE's Plasma daemon).
Alternatively, if this is deliberate, `actions` should be dropped from
`GetCapabilities` and `actionsSupported` set to `false`, so senders can fall
back instead of emitting controls that go nowhere.
## Steps to reproduce
```bash
notify-send -A "delete=Delete" -A "read=Mark as read" "Test" "Any buttons?"
```
The toast shows title and body only, and `notify-send` exits on timeout without
printing an action id. Real-world equivalent: any Gmail/Facebook web
notification in Chromium, which ship "Delete" / "Mark as read" / "Settings"
buttons that are visible on other desktops and absent here.
## Where it comes from
`plugins/notifications` accepts the actions but has no path to draw them:
- `Service.qml:935` sets `actionsSupported: true`, and `GetCapabilities`
advertises `actions` accordingly.
- `Service.qml:360` `invokePopupDefault()` walks `ref.actions` looking only for
`identifier === "default"` (line 380), ignores every other action, and falls
back to `focusApp(entry)` (line 395).
- `components/NotificationCard.qml` has a single card-wide `MouseArea` and no
repeater over actions — there is nowhere for a button to be drawn.
- `NotificationLogic.js:206` `POPUP_ROLES` carries no `actions` role, so the
action list never reaches the model in the first place.
The live `Notification` objects are already retained in `Service.liveRefs`, so
the invocable action objects are present at render time. This looks like a
missing UI layer rather than a protocol gap.
## Fix confirmed locally
Cloning the plugin (`omarchy plugin clone omarchy.notifications`) and adding
roughly 60 lines makes it work end to end:
1. `NotificationLogic.js` — serialize `notification.actions` (skipping
`default` and label-less entries) into a new `actions` role, added to
`POPUP_ROLES`.
2. `Service.qml` — `invokePopupAction(index, identifier)` resolves the row
through `liveRefs`, calls `action.invoke()`, and dismisses. Restored and
replayed rows have `actions` cleared before append, since their sender died
with the previous server generation and their `originalId` may since have
been reused.
3. `NotificationCard.qml` — a right-aligned `Repeater` of `Ui.Button`s,
declared after the card-wide `MouseArea` so buttons take their own clicks
instead of falling through to the default action. History rows leave the
property empty and are unchanged.
Verified with `notify-send -A`, which returned the action id `delete` on click,
and with a live Facebook notification in Chromium whose "Settings" button
correctly opened Chromium's per-site notification settings.
Happy to open a PR if the approach looks right.
## System
- Omarchy 4.0.2-1
- quickshell 0.3.1-1, hyprland 0.56.2-1
- Linux 7.1.9-arch1-2
- Intel Core Ultra 9 285H / Intel Arc Pro 130T/140T (Arrow Lake-P)
- Chromium 151.0.7922.173-1 (one affected sender; `notify-send` reproduces it
with no browser involved)
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:32 UTC