Inbox alerts (how an agent gets your attention) (part 6)
An alert can also appear on screen the moment it is created: a toast in the corner, a full-width bar across the top of the app, or a small OS window that pops over whatever you are doing. Each alert declares which of those it wants, and you can silence or add any of them per alert type. All three fire once — a re-raised alert never pops again.
What it is
Every alert has always landed in the inbox. This part covers the alerts that can ALSO appear on screen the moment they are created: as a toast in the corner, as a full-width warning bar across the top of the app, or as a small OS window that pops over whatever the person is doing — including when Omniscio is not the front window.
Where to find it
The surfaces arrive on screen by themselves. Where you choose them is Settings → Inbox → Alert pop-ups, which lists every alert that offers an on-screen surface, with one checkbox per surface.
How it behaves
What the person sees
- Toast — the ordinary in-app toast, in the alert's own colour and icon, with an Open button that jumps to the alert's card in the inbox.
- Banner — one full-width strip at the top of the app, in the alert's colour, carrying the alert title, the alert card's own primary action button, and a dismiss cross. There is ONE banner component for every alert that wants one; it is not hand-built per alert. It disappears on its own the moment the underlying alert is archived or otherwise leaves the active list.
- Popup — a small, always-on-top window that never steals keyboard focus. It shows the alert's title and body, with View (brings the main window forward and opens that alert's card) and Dismiss.
Each surface fires ONCE, when the alert is first created. An alert that is re-raised and merges onto its existing card — the normal dedup behaviour — does not pop again, and neither does any background refresh of the inbox.
Turning them off
The choice is stored per alert type in the alertSurfaceOverrides setting, and it REPLACES what that alert declared — so a person can silence a surface an alert asked for, and can also add one an alert did not ask for. Only alerts that declare a loud surface are listed; an alert that says nothing about surfaces stays inbox-only.
How it is wired
- The renderer listens for the
ALERT_CREATEDpush (payload{ id, sourceKind, projectId }).ALERT_CHANGED— the dedup-bump / archive / re-surface channel — is deliberately NOT a trigger, which is what makes "never re-pop" structural rather than a guard someone has to remember. dispatchAlertSurfaces(renderer,features/alerts/alert-surface-dispatch.ts) reads the alert's definition throughreadAlertSurfaceDefinition, resolves which surfaces are enabled, and calls one effect per surface. It is pure and takes its effects by injection, so every branch is unit-tested without a running app.resolveExtraSurfaces(shared,src/shared/alert-surfaces.ts) is the one place the priority rule lives: an override for the alert's dedup key wins, otherwise the definition's own list applies, otherwise nothing.- The popup is a real
BrowserWindow(src/main/services/alerts/alert-popup-window.ts) withcontextIsolation: trueandnodeIntegration: false, showing its own minimal renderer entry (alert-popup-window.html) rather than the whole app shell. It is shown through the typed, zod-validatedalert:popup-showchannel, reads its content back overalert:popup-get, and its View button comes back throughalert:popup-view-request, which focuses the main window and asks it to open the card over thealert/popup-openpush. Nothing about the popup is reachable from a web page.
Where the definition comes from
An alert's surfaces, style and icon come from its own definition file under src/shared/alert-definitions/ — the file shape and its rules are in alert-definition-contract.md. The renderer reads them through ONE seam, src/renderer/src/features/alerts/alert-surface-definition.ts, which calls resolveAlertDefinition for a fired dedup key and ALERT_DEFINITIONS for the list the Settings card shows. Nothing else in the surface system knows where definitions live, and the tests inject definitions through that same seam.
So adding an alert that toasts, sits in the top banner and pops a window is ONE new file declaring surfaces: ['inbox', 'toast', 'banner', 'popup'] — no edit to the dispatcher, the banner, the popup, the Settings card or any list. on-screen-surfaces-demo.alert.ts is that one-file example.
Proving each surface
Raise the demo alert with its own dedup key and each declared surface appears once:
curl -s -X POST http://127.0.0.1:19519/alert \
-H "Authorization: Bearer $AMC_CLI_TOKEN" \
-H "X-AMC-Source-Session-Id: $AMC_SESSION_ID" \
-H 'Content-Type: application/json' \
--data '{"dedupKey":"on-screen-surfaces-demo","title":"Surface check","text":"toast, banner and popup"}'
Related
- Inbox alerts — the parent page: what an alert is and where it lands.
- Inbox alerts (part 5) — starting a session from an alert, and the daily digest.
Last verified 2026-10-19