Canary for Omarchy
Know when an application starts or stops using your microphone, camera, or screen capture. Canary lives in the Omarchy bar, stays hidden while idle, and opens into a local activity panel with app attribution, device details, and recent history.

Features
- Live microphone, camera, and screen-sharing indicators from PipeWire
- Direct V4L2 and ALSA device monitoring for apps that bypass PipeWire
- Application icons, physical-device names, access duration, and confidence details in a native Omarchy popup
- Optional Chromium companion that distinguishes Google Meet, Slack, Zoom, Teams, Discord, and Webex instead of reporting every tab as Chromium
- Separate cards for web apps sharing one browser capture process, with tabs from the same web app grouped together
- Start and stop desktop notifications, controlled by a persistent master switch in the panel header
- Reversible per-application exclusions and a bounded, scrollable recent list
- Seven days or 100 entries of local history, whichever limit is reached first
- Visible degraded state if PipeWire or direct-device monitoring becomes unavailable
- No captured media, telemetry, accounts, or network requests
Install
omarchy plugin add https://github.com/melonamin/omarchy-canary.git --enable
The shell discovers Canary and adds it to the right side of the bar. The widget appears only while capture is active or monitoring is degraded.
If Omarchy's stock microphone widget is enabled, hide it to avoid two mic indicators:
omarchy plugin disable omarchy.microphone
To remove Canary without the optional browser companion:
omarchy plugin remove melonamin.canary
If you installed the companion, uninstall it first as described below.
Requirements
Omarchy 4 (Quattro) or newer, running omarchy-shell with PipeWire and
WirePlumber. Python 3.11 or newer is required for the direct-device helper;
Canary has no Python package dependencies and installs no system service.
Canary 1.0.4 includes compatibility fixes for Omarchy 4.0.3's scoped plugin APIs, restoring direct-device monitoring, browser-companion detection, settings persistence, and application icons after the shell update.
Direct monitoring reads the current user's /proc/<pid>/fd links and watches
V4L2 and ALSA device nodes with inotify. It needs neither root nor membership
in an extra system group.
Browser companion
PipeWire identifies Chromium's shared media process, not the tab that requested capture. When Chromium first uses your microphone or camera, open Canary and select Enable under Identify browser tabs. Fully quit and reopen Chromium when prompted. Canary then identifies supported web apps instead of showing the generic browser process.
The optional companion is a local Manifest V3 extension and native-messaging bridge. Capture detection continues to work without it.
The companion installer checks ownership and permissions before accessing Chromium configuration. It refuses symlinked configuration directories or files, hard-linked files, and paths writable by other users. Writes use exclusively created temporary files and atomic replacement inside the checked directories; existing Chromium flags and their permissions are preserved. Uninstall and status use the same path checks. The installer does not change the bridge script's permissions.
If you manage Chromium configuration through symlinks, automatic companion setup will report an unsafe path. Manage that configuration manually or use regular files in owner-controlled directories; Canary's capture monitoring still works without the companion.
Canary independently verifies that Chromium is accessing a microphone, camera, or screen through PipeWire or direct-device monitoring. The companion's specific web-app name is a best-effort tab hint: scripts running on a supported page can spoof or suppress it. Canary marks these hints with an information icon and keeps the verified Chromium identity visible alongside the web-app icon.
The companion runs only on these HTTPS origins:
- Google Meet
- Slack
- Zoom
- Microsoft Teams
- Discord
- Webex
It sends active media kinds, local device labels, tab origin/title, and related
browser process IDs through Chromium's local native-messaging channel. Records
expire after 15 seconds, remain under $XDG_RUNTIME_DIR/canary, and are never
sent over the network.
The dropdown is the recommended setup path. These commands provide the same operations from a terminal:
python3 ~/.config/omarchy/plugins/melonamin.canary/install_browser_companion.py install
python3 ~/.config/omarchy/plugins/melonamin.canary/install_browser_companion.py status
Remove the companion before removing Canary:
python3 ~/.config/omarchy/plugins/melonamin.canary/install_browser_companion.py uninstall
omarchy plugin remove melonamin.canary
</details>
Without the companion, capture detection remains intact and safely falls back to the browser's application name.
What “in use” means
Canary reports an established capture session, not whether non-silent samples or visible frames are flowing at a particular instant. An app can keep a stream open while muted or paused so it can resume immediately; Canary correctly leaves the indicator active until that session closes.
Launching an application is not enough to trigger Canary. For example, a dictation app appears only while it actually holds a microphone device.
PipeWire infrastructure such as WirePlumber, desktop portals, and media filters is correlated through the graph rather than shown as if it were the requesting application. Persistent processors such as noise suppression may legitimately hold a mic open; use Ignore once you have identified one you trust.
Controls and settings
Click the bar indicator to open Canary. The header switch enables or disables all desktop notifications. Active cards can be ignored individually; every ignored application remains visible above Recent and can be restored one at a time or all at once. Only the history list scrolls, so controls stay in place.
Settings live inline on Canary's entry in ~/.config/omarchy/shell.json and are
written through Omarchy's scoped plugin-settings API.
| Key | Values | Default |
|---|---|---|
notificationsEnabled |
desktop start/stop notifications | true |
historyEnabled |
retain local recent activity | true |
directDeviceMonitoring |
watch direct V4L2 and ALSA access | true |
ignoredApps |
normalized application keys managed by the panel | [] |
State and privacy
History lives in Quickshell's per-shell state directory under
canary/history.json. Each entry contains application and device metadata plus
start/end timestamps. It never contains audio, video, screen frames, or browser
content. Turning history off clears the stored records.
The direct helper scans only same-user processes. Canary makes no network requests, collects no telemetry, and sends no media anywhere.
Canary is a privacy indicator for ordinary desktop applications, not an anti-malware sandbox. A root process, compromised kernel, hidden device implementation, or process deliberately attacking Canary can evade or disable it. Browser site labels are unverified local attribution hints correlated with independent OS-level evidence that the Chromium application is capturing.
How it works
PipeWire graph ──────────────────────────────────────┐
│
/proc file descriptors + inotify ─▶ device_watch.py ├─▶ Service.qml
│ │
Chromium extension ─▶ native bridge ─▶ runtime state┘ ▼
CanaryModel.js
│
▼
bar + popup + history
Service.qmlowns monitoring, session lifecycle, settings, history, and IPC.CanaryModel.jsperforms dependency-free classification, grouping, attribution, migrations, sorting, and formatting; the same file runs in QML and Node tests.BarWidget.qmlandSessionIcon.qmlrender the bar indicator and popup.device_watch.pyobserves direct camera and ALSA capture handles.browser-extension/chromium/,browser_bridge.py, andinstall_browser_companion.pyimplement the optional Chromium integration.tests/contains headless model/helper tests and a read-only live smoke test.
IPC
omarchy-shell canary status # health, settings, attribution, active sessions
omarchy-shell canary pipewireNodes # raw capture-stream summary
omarchy-shell canary pipewireSessions
omarchy-shell canary rescan
omarchy-shell canary clearHistory
omarchy-shell canary clearIgnored
Tests
Run the headless suite from the repository root:
node --test tests/model.test.mjs
uv run -m unittest discover -s tests -p 'test_*.py'
uvx ruff check browser_bridge.py device_watch.py install_browser_companion.py tests
qmllint -I /usr/share/omarchy/shell -I . Service.qml BarWidget.qml SessionIcon.qml
omarchy plugin validate .
On a running Omarchy install with Canary enabled, exercise the service and both monitoring paths without changing settings or opening devices:
tests/integration.sh
License
MIT