Omahub
← All plugins
A

My Notifications

by Apurva Saraiya

Notification daemon, popups, DND, history, and notification center

Security review

Potentially dangerous behavior detected · 8 findings

Deterministic scan — not a security guarantee

High
Risk level
High
Analyzed commit
5ec65b0
Scanned
1 month ago
  • high destructive_filesystem Service.qml:694

    Low-level disk manipulation or write command.

    dd of=\"$tmp\" bs=65536 oflag=nofollow conv=excl,fsync status=none 2>/dev/null; then\n" +
  • high destructive_filesystem Service.qml:768

    Low-level disk manipulation or write command.

    dd of=\"$tmp\" bs=65536 oflag=nofollow conv=excl,fsync status=none 2>/dev/null || { rm -f -- \"$tmp\"; exit 0; }\n" +
  • high destructive_filesystem Service.qml:1113

    Low-level disk manipulation or write command.

    dd of=\"$tmp\" bs=65536 oflag=nofollow conv=excl,fsync status=none 2>/dev/null; then\n" +
  • Docs destructive_filesystem docs/upstream-diff.patch:390

    Low-level disk manipulation or write command.

    dd of=\"$tmp\" bs=65536 oflag=nofollow conv=excl,fsync status=none 2>/dev/null; then\n" +
  • Docs destructive_filesystem docs/upstream-diff.patch:416

    Low-level disk manipulation or write command.

    dd of=\"$tmp\" bs=65536 oflag=nofollow conv=excl,fsync status=none 2>/dev/null || { rm -f -- \"$tmp\"; exit 0; }\n" +
  • Docs destructive_filesystem docs/upstream-diff.patch:609

    Low-level disk manipulation or write command.

    dd of=\"$tmp\" bs=65536 oflag=nofollow conv=excl,fsync status=none 2>/dev/null; then\n" +
  • Docs destructive_filesystem AGENTS.md:28

    Low-level disk manipulation or write command.

    dd of=… oflag=nofollow conv=excl,fsync` under an unpredictable
  • Docs external_hosts README.md:149

    Downloads or connects to an external HTTP(S) host.

    git clone https://github.com/apurvasaraiya/omarchy-notification-center.git ~/dev/omarchy-notification-center

Automated analysis only — not a security guarantee.

AI advisory review

No obvious issues detected

Language-model assessment · ~deepseek/deepseek-v4-flash-latest — advisory only

Low
AI risk level
Low
Recommendation
install
Model
~deepseek/deepseek-v4-flash-latest
Analyzed commit
5ec65b0
Reviewed
1 month ago

The plugin is a cloned and extended notification daemon with careful file-handling safeguards (O_NOFOLLOW, exclusive temp files, size caps). The deterministic scan's high-risk findings are false positives: the `dd` invocations are defensive atomic writes to unpredictable temp names, not destructive disk manipulation, and the README git clone is documentation only. No obfuscation, hidden persistence, or credential theft was found.

  • The service executes sender-provided `execArgv` commands (e.g. from `omarchy-exec-argv`), which is inherent to the notification protocol and structurally validated, but still grants same-uid code execution to any session-bus process.
  • The plugin replaces the stock notification daemon via `clonedFrom`; users should be aware that enabling it disables the built-in notifications plugin until removal.
How this check works

This review combines the deterministic scan (the rule-based results above) with an independent look at the plugin's code by a language model. The model reads a trimmed sample of the repository's files, the manifest, and the README, then gives a plain-language risk level and a recommendation: install (no notable danger), review (look closer first), or avoid (clearly dangerous).

It runs on the same analyzed commit as the deterministic scan and is strictly advisory — it is not a security guarantee and never blocks a plugin by itself. A human moderator still reviews plugins before they are listed.

AI advisory only — automated analysis, not a security guarantee.

Install
$ omarchy plugin add https://github.com/apurvasaraiya/omarchy-notification-center --enable
Desktop #bar #quickshell #system

omarchy-notification-center

A notification center for the Omarchy shell: a bell in the bar that opens a panel of notification history, with per-entry delete and a clear-all button. History stays until you remove it by hand — clicking an entry jumps to the sending app (relaunching it if it's closed) and clears it.

Notification center panel

Built and verified against omarchy 4.0.0.r1849.g83881e9-1 (August 2026).

What it is, honestly

This is not a standalone widget. It is a clone of Omarchy's built-in omarchy.notifications plugin (made with omarchy plugin clone, the supported customization path) with the notification center added on top. The clone replaces the built-in notification daemon at runtime.

That shape was forced by the requirements. The stock daemon owns the history store and trims it to 10 entries on every write. A separate widget could only ever read those 10 files and could not stop the trimming, so "preserve history until I clear it" required changing the daemon itself. Cloning is how Omarchy says to do that: the packaged copy in /usr/share/omarchy/ is never edited, and deleting the clone restores stock behavior.

What this touches on the system

Nothing in /usr/share/omarchy/ (core, package-owned) is modified. The full footprint:

  • ~/.config/omarchy/plugins/apurva.notifications — a symlink to this repo. The shell discovers the plugin here.
  • ~/.config/omarchy/shell.json — three additions, all plain config:
    • {"id": "apurva.notifications"} in bar.layout.right (the bell),
    • {"id": "apurva.notifications"} in plugins[] and "omarchy.notifications" in disabledPlugins[] (written by omarchy plugin clone; this is what swaps the daemon),
    • cloneSourceRestores bookkeeping, also written by the clone tool.
  • ~/.local/state/omarchy/notifications/ — runtime data the stock daemon already used (history files, image copies). Not config, survives either way.

Using it

  • Left-click the bell: open or close the panel.
  • Hover a card, click the ✕: delete that one entry (file, image copies, row).
  • Clear all: empty the whole history.
  • Click a card: jump to the sending app's window, relaunching the app if it was closed. The entry leaves history only when that worked; when the app can't be found at all, the entry stays put.
  • Clicking a toast behaves the same way (default action, else focus, else relaunch) and archives the toast to history as before.
  • Right-click the bell: toggle Do Not Disturb. The bell shows a slashed glyph while DND is on. The stock silence button in the middle of the bar keeps working too (see "Changes vs stock").
  • The panel refreshes itself while open when new notifications get archived.

How much history is kept is configurable on the widget's shell.json bar entry (default: the stock 10):

{ "id": "apurva.notifications", "historyLimit": 50 }

The shell picks up shell.json edits live. Lowering the limit trims the on-disk history as soon as the new value lands; raising it applies to new notifications from then on.

Toasts, DND rules, and the stock keybindings (Super+comma family) behave exactly as before. Super+Shift+Alt+comma still replays the last 10 entries as toasts; the panel is where the full history lives.

CLI:

omarchy-shell notification-center toggle          # open/close the panel
omarchy-shell notifications clear                 # clear all history
omarchy-shell notifications removeHistory <stem>  # delete one entry;
                                                  # stem = file name without .json,
                                                  # e.g. 1787848508512-2

Optional keybinding, in ~/.config/hypr/bindings.lua:

o.bind("SUPER + N", "Notification center", "omarchy-shell notification-center toggle")

Changes vs stock

The stock plugin already persisted every notification to ~/.local/state/omarchy/notifications/history/, one JSON file each. This clone keeps all of that machinery and changes:

  • Service.qml
    • historyLimit is writable now (still defaulting to the stock 10); the bar widget pushes the user's historyLimit setting over it, and a lowered limit trims the history directory right away instead of waiting for the next archive.
    • New replayLimit: 10 so the toast replay keeps its old size even when the user raises the history cap.
    • A small DND bridge object is registered under the stock omarchy.notifications service id. The bar's silence indicator resolves its service with firstPartyServiceFor("omarchy.notifications"), which — unlike summon/toggle/call — does not route through PluginRegistry.resolveEnabledId(), so enabling the clone left that button dead. The bridge only exposes doNotDisturb/setDoNotDisturb and re-registers itself whenever a plugin rescan sweeps it away. (The real fix belongs upstream: serviceFor should resolve clones like the other entry points do.)
    • focusApp falls back to launching the sender's desktop entry (resolved via DesktopEntries.heuristicLookup from the app name, then the icon name) when no window matches, using the same uwsm-app -- gtk-launch path as the app launcher. It also reports back whether focus-or-launch worked, which is what lets the panel keep unactionable entries.
    • New historyModel (a ListModel on the service, shared by every monitor's panel), filled by a directory read that goes through the same serialized file-job queue as all other history mutations, so reads are always ordered after the writes that made them necessary.
    • New historyMutated() signal, emitted when a toast archives or a DND-silenced notification is written. Open panels listen and re-read.
    • New deleteHistoryEntry(timestamp, originalId): removes the model row and deletes the entry's JSON file and image copies.
    • New IPC method removeHistory(stem) on the existing notifications target, calling the same function.
  • NotificationCenter.qml (new file, the barWidget entry point): bell button plus the panel. Reuses the stock NotificationCard for rendering, adds a quiet received-at label per card (time today, day+time this week, date older).
  • manifest.json: adds the bar-widget kind and entry point.

docs/upstream-diff.patch is the full diff against /usr/share/omarchy/shell/plugins/notifications/ at build time.

Install

omarchy plugin add https://github.com/apurvasaraiya/omarchy-notification-center.git --enable

Enabling asks where in the bar the bell should go, and — because the manifest declares clonedFrom: omarchy.notifications — the registry swaps the stock notification daemon out automatically (disabledPlugins plus the restore bookkeeping in shell.json). Disabling or removing the plugin restores the stock daemon the same way.

For development, install as a symlink instead so edits land live:

git clone https://github.com/apurvasaraiya/omarchy-notification-center.git ~/dev/omarchy-notification-center
ln -s ~/dev/omarchy-notification-center ~/.config/omarchy/plugins/apurva.notifications
omarchy plugin enable apurva.notifications
omarchy restart shell

Uninstall

rm ~/.config/omarchy/plugins/apurva.notifications
omarchy restart shell

Then remove the three shell.json additions listed above (or run omarchy plugin disable apurva.notifications, which restores the clone source). The stock daemon takes over again, including its 10-entry trim, so history beyond 10 entries disappears at the next archive.

Development notes

Both of these cost a debugging round; don't repeat them:

  • The shell hot-reloads plugin files on save, but a running keepLoaded service instance is not re-created. Edits to Service.qml (including new IPC methods) silently don't apply until omarchy restart shell. The restart is cheap: live toasts and history survive via the popup persistence files.
  • Adding a brand-new file to a plugin directory makes the widget fail to load with Qt's "File name case mismatch" error. The file name is fine; the QML type loader cached the directory listing from before the file existed. omarchy restart shell fixes it.

When Omarchy updates change the stock notifications plugin, this clone keeps running the old code. To rebase: diff the new stock plugin against docs/upstream-diff.patch's base, re-apply the change list above, and regenerate the patch:

diff -ru --exclude=.git --exclude=docs \
  /usr/share/omarchy/shell/plugins/notifications . > docs/upstream-diff.patch

License

MIT — see LICENSE. Substantial portions are derived from Omarchy (MIT, © David Heinemeier Hansson): the plugin is a clone of the built-in omarchy.notifications plugin with the notification center added on top.