Native OS desktop notifications for herdr agent status changes — get pinged by your system's real notification center when an agent needs you or finishes a task, instead of having to keep an eye on the terminal.
- Cross-platform: Linux, macOS, and Windows via
notify-rust(also builds and runs on the BSDs, though herdr's own plugin manifest schema doesn't have a platform value for them yet). - Only notifies when it matters: toasts on
working → blocked(needs input),working → done/blocked → done(finished). Unchanged status never re-notifies; ablocked → working → blockedcycle still pings again. First sight of a pane seeds silently, and restore churn throughidle/unknowndoes not toast — so restartingherdr serverafter a laptop reboot no longer floods notifications for every restored agent. - Click to focus: clicking a status-change notification focuses the
originating pane back in herdr. On Linux, set
HERDR_NOTIFICATIONS_RAISE_HOST=1to also raise the terminal window that hosts the Herdr UI (KDE, GNOME, XFCE/X11, Hyprland, Sway — best-effort). - Location in the toast: body shows
workspace · tab(and the agent title when present) so you can tell which project fired, not only which agent binary. - Zero runtime config required: works out of the box; the dedup state lives under herdr's own per-plugin state directory (or a per-user local data directory as a fallback), never a shared/world-writable location.
herdr plugin install quinnjr/herdr-notificationsherdr builds the plugin (cargo build --release) on install, then wires up
the pane.agent_status_changed event automatically.
Nothing to configure — once installed and enabled, notifications just happen. To confirm your OS notification permissions/backend are working without waiting for a real agent-status change, run the bundled smoke-test action from herdr's command palette or:
herdr plugin action invoke test-notification --plugin quinnjr.herdr-notificationsherdr fires a pane.agent_status_changed event (idle / working / blocked /
done / unknown) for every agent pane whenever its status changes. This
plugin's binary is invoked once per event:
- Every status transition is recorded to a small on-disk dedup table (one entry per pane), written atomically (temp file + rename) and guarded by a short-lived exclusive lock, so concurrent status changes across multiple panes can't corrupt or race on it. The first time a pane is seen the entry is seeded without notifying.
- A toast fires only when live work stops:
working → blocked,working → done, orblocked → done. Transitions throughidle/unknown(common whenherdr serverrespawns panes on laptop boot) update the table but do not notify. - For ~90 seconds after
herdr serverstarts (API socket age, or the parentherdrprocess age on Linux), even those “live work” transitions are suppressed. That covers boot restore storms where agents briefly lookworkingthen settle onblocked/donebefore anyone opened the TUI. Override withHERDR_NOTIFICATIONS_STARTUP_QUIET_SECS(0disables). Every status decision is appended totransition-debug.logunder the plugin state dir (previous→next, whether the transition looked notify-worthy, server age, quiet window, final notify) so the next reboot is diagnosable. - The notification is shown on a background thread with a bounded wait, so
a stuck notification daemon can never hang the process indefinitely.
Summary is
{agent} is done/{agent} needs you; body islocation · tabplus a shortClick to openhint. Labels come fromherdr pane/workspace/tablist for the event pane, falling back toHERDR_PLUGIN_CONTEXT_JSON, then cwd basename / tab id. - Actionable toasts show a single Close button where the platform
supports notification actions (Linux/BSD, Windows, macOS). Clicking the
notification body runs
herdr agent focus <pane_id>to bring that pane back into view. On Linux, opt in withHERDR_NOTIFICATIONS_RAISE_HOST=1to also raise the host terminal window via desktop-specific APIs (KWin on KDE, GNOME Shell Eval on GNOME,hyprctl/swaymsgon those compositors,wmctrlplusxdotoolactivate/raise/focus on X11 — needed when the WM focuses without raising, e.g. XFCEraise_on_focus=false). If the plugin process has noDISPLAY(common whenherdr serveris started by systemd), it importsDISPLAY/ desktop vars from the Herdr UI client's/procenviron before raising. The toast stays up for 60 seconds, and the plugin process exits with it. - Closing a notification is not a click. The one exception is
xfce4-notifyd, where a body click emits only
NotificationClosed(Dismissed)and neverActionInvoked; the plugin detects that daemon viaGetServerInformationand reads a dismissal as a click there alone. xfce4-notifyd also emits an immediate post-showDismissedas replace churn; the plugin re-subscribes through that and treats the next dismissal as the body click. SetHERDR_NOTIFICATIONS_CLICK_ON_DISMISS=1to force that reading on another daemon that behaves the same way, or=0to turn it off.
Herdr 0.8+ delivers HERDR_PLUGIN_EVENT_JSON as
{"event":"…","data":{…}}; this plugin unwraps data and still accepts
older bare payloads (Herdr 0.7.x), so min_herdr_version stays 0.7.0.
agent, display_agent and title are typed ["string", "null"] by herdr
and are accepted missing, null, or empty; workspace_id is accepted
missing. An unrecognized agent_status is ignored rather than treated as a
parse failure, so a future herdr status will not break the plugin.
- herdr ≥ 0.7.0
- A working OS notification backend: a D-Bus session + notification daemon on Linux/BSD (present on virtually every desktop environment), or the native notification center on macOS/Windows.
- Optional (Linux host-window raise): one or more of
wmctrl,xdotool,qdbus/qdbus6(KDE),gdbus(GNOME),hyprctl(Hyprland), orswaymsg(Sway), depending on your desktop.
cargo build --release
cargo test
herdr plugin link . # develop against a local checkout instead of installingMIT — see LICENSE.