0027: Notifications come from leashd
On this page
Status: accepted
Context
Short Leash already knows when a queue worker stops, a port is taken, mail arrives, a webhook delivery is held or a share drops, but only showed it on the screen concerned. People want to hear about some of these with Short Leash's window in the background, and not about others. The CLI and the app both read the same daemon, and the desktop shell holds no domain logic.
Decision
- The daemon decides.
leash_core::notificationsholds the store and the wording; the rules live in the engine, fed by what it already watches: supervisor states (a process that stops, or keeps crashing so keep-running is paused after five quick crashes), busy ports when they first become busy, terminal attention, new mail (one per burst per site), held, refused or failed webhook deliveries, queries of 500 ms or more and logged errors, and shares connecting, moving, dropping or failing. - Six categories, three levels. Processes, terminals, mail, webhooks, dumps and sharing are each "off" (not kept), "app" (listed in Short Leash) or "system" (also a desktop notification). Processes, terminals and sharing default to "system"; mail, webhooks and dumps to "app". The settings, with
menuBarCount, are inconfig.toml; the defaults are inconfig::defaults. - Repeats fold. A notification with the same key within two minutes, or while it's unread, replaces the last one at the top with a count, instead of adding another. The newest 200 are kept, in memory, with their read state.
- Each one says what happened and what to do, and carries actions (open, restart, start, logs, copy, fix) with a target the app understands, such as
proc:shop:queue-worker. - The app only shows. Each
notificationevent carries its level. The Tauri shell shows a desktop notification (tauri-plugin-notification, MIT/Apache-2.0, used from Rust only) for "system" ones while the main window isn't in front, at most once per notification every two minutes, and puts the unread count from/v1/statebeside the menu bar icon and on the Dock icon whenmenuBarCountis on.
Alternatives
- Rules in the app would let each window decide, but the menu bar popover, the main window and the CLI would each need them, and nothing would be raised while the app is closed.
- Saving notifications to disk would keep them across restarts, but they're about what's happening now; after a restart the screens show the current state anyway.
Consequences
- A burst (a crash loop, a flood of mail) is one notification with a count, not dozens.
- Notifications raised while the app is closed are listed when it opens, but their desktop notifications aren't shown late.
- A new kind of event needs a rule in the engine and its wording in
notifications::rules, with a test.