Skip to main content

Notifications & Sound

The declarative routing manifest behind every Daintree notification, the persistent inbox with age-based retention and per-thread snooze, the attention gates, global and pane-local banners, and the event sound system.

Reviewed

Overview

With several agents running at once, the hard part is knowing what needs you. Daintree answers that with four surfaces, in ascending order of interruption: a persistent inbox that records everything, in-app toasts for things worth looking up for, OS-native alerts that reach you when Daintree is in the background, and a sound system that lets you track progress without watching the screen. Two more surfaces carry state rather than events: a single global banner slot at the top of the window and pane-local error banners inside individual panels.

What lands where is not decided at each call site. Every notification declares what kind of event it is, and a single declarative policy manifest resolves that into a routing decision. Understanding that manifest is most of understanding this page, so it comes first.

On top of routing sit the attention gates: Do Not Disturb for the session, Quiet Hours on a schedule, awareness of your OS-level Focus state, and per-source muting and silencing. Because those stack, the inbox leads with a plain-language summary of what will actually break through right now.

The Routing Manifest

Every notification carries an event kind, drawn from a closed set of ten. The kind is looked up in a policy manifest at dispatch time, and the manifest fills in any routing decision the caller did not make explicitly. Fields the caller set always win; the manifest only fills gaps.

This replaced a per-call-site checklist (is this urgent, should it toast, should it make a sound, should it page the OS) with one typed source of truth. The practical consequence is that routing is consistent: two different parts of the app raising the same kind of event behave the same way, and changing how a kind is routed is a one-line change in one file rather than an audit of every call site.

Interruption levels

Each kind declares a baseline interruption level, which resolves to a priority and from there to a delivery decision:

InterruptionPriorityWhere it goes
passivelowInbox only. Never a toast, never an OS banner.
activehighToast when the window is focused; inbox only when it is not.
time-sensitivehigh + urgentToasts, and bypasses the quiet gates.
criticalwatchToast and an OS-native banner, regardless of focus.

The ten event kinds

Event kindInterruptionUser toggleNotes
completedactivecompletedEnabledAn agent finished.
waitingactivewaitingEnabledAn agent needs you. Pages through the quiet gates at the OS layer.
workingPulsepassiveworkingPulseEnabledSound only.
uiFeedbackpassiveuiFeedbackSoundEnabledSound only.
agentactiveAgent lifecycle events that are not completion or waiting.
gitactiveAuto-dismisses after 6 seconds — git confirmations are briefer than the per-type default.
hosttime-sensitiveBackend and host-process events.
recoveryactiveCrash recovery and session restore.
settingspassiveConfiguration changes.
connectivityactiveConnection lost and regained.

The set is deliberately closed rather than open-ended. It is an internal taxonomy, not a plugin extension point, and keeping it closed means the compiler can prove that every kind has a policy and a label. The per-kind silence toggles are derived from the manifest rather than listed separately, so a kind cannot drift out of sync with its own setting. Kinds without a user-facing toggle simply do not have one.

Re-promotion on escalation

A notification sharing a thread with existing entries normally updates the thread quietly. It breaks through and toasts again in two cases: when it escalates the thread's worst severity (an info thread that turns into an error), or when it un-snoozes a deferred thread. Routine same-severity updates keep updating the inbox row silently, which is what stops a chatty run from re-toasting every few seconds.

Re-promotion is gated on window focus for the same reason toasts are, but the un-snooze half is not: an escalated entry on a snoozed thread clears the snooze whether you are looking or not, so it lands unread and counts toward the badge rather than staying hidden behind a defer you set on a milder version of the same problem.

Go deeper

A routed event can reach more than one surface, so these are three guides rather than three destinations. The rest of the detail is organized across them:

  • The inbox keeps what happened. Tabs, threads, Needs Attention, per-thread snooze, retention, and every event that reaches it from outside the agent loop.
  • Delivery, focus and muting decides what interrupts you now. Toasts, Do Not Disturb, Quiet Hours, OS focus, per-project muting, OS notifications and banners.
  • Sounds and settings covers what you hear and where to change any of it, including the per-project overrides.