The Notification Inbox
The persistent notification inbox: its four tabs, how it survives a restart, threads and Needs Attention, grouping by context, per-thread snooze, keyboard navigation, per-entry actions, and the events that reach it from outside the agent loop.
The Notification Inbox
Click the bell in the toolbar to open the inbox. It lists everything that has fired, newest first, and it keeps recording while delivery is paused.
It survives a restart
The inbox is persisted to disk and restored on launch, with age-based retention:
- Read entries age out after 7 days.
- Archived entries persist for 30 days, so looking up how something was resolved still works days later.
- Unread entries are kept regardless of age. Losing a missed error to a clock is the failure this model exists to prevent.
A 200-entry cap still exists as a backstop, but it is no longer the model. Pruning runs on a tick and is a no-op when nothing has expired, so the persistence write does not fire every cycle. The unread count is recomputed on load rather than trusted from disk.
Four tabs
- All: everything that is not archived and not currently snoozed.
- Unread: the same, filtered to entries you have not seen.
- Archived: the "done" surface.
- Snoozed: the "deferred" surface. It appears only while something is actually snoozed, and if the last snooze expires while you are looking at it, the view snaps back to All rather than stranding you on a tab that vanished.
Archived and Snoozed are deliberately not the same idea. An archived entry belonging to a still-snoozed thread stays in Archived: you finished with that one, and finishing is not deferring.
Threads, needs attention, and new-since
Related notifications from one run share a thread and collapse into a single expandable entry with a count chip. When a thread's worst-severity icon disagrees with its most recent entry (an error thread whose latest event is a successful recovery), the preview is prefixed with Latest: so the mismatch reads as deliberate.
Unread threads whose worst entry is an error or warning are pinned to a Needs attention section at the top, sorted by severity then recency, up to five at a time. When more than five qualify, the section says +N more below rather than silently dropping them: the overflow threads are still in the chronological list underneath, and the count tells you to keep scrolling. There is no manual pinning; snoozed threads drop out of the rail entirely, because snoozing is an explicit statement that a thread does not need attention right now.
Reopening the inbox puts a New since you last looked divider above the first entry that arrived after you closed it, with an inline Mark these N read button. Scroll the divider out of view and a floating Jump to new pill brings you back to it. Both are hidden on Archived and Snoozed.
The list carries scroll shadows at its top and bottom edges: soft fades that make it obvious when there is more above or below rather than leaving the list looking like it ends at the panel edge. Scroll-into-view targets are inset by the fade height, so a row the keyboard just focused, or the jump-to-new divider, never lands underneath the gradient.
Grouping by context
The Group by context toggle in the header splits the list by project and worktree. Each section gets its own header and its own Mark read button, which is the fast way to clear one project's noise while leaving another's alone. The setting persists.
Per-thread snooze
Snooze defers a whole thread, not a single entry: a thread is the unit you actually care about. Four durations, matching the Linear inbox model:
| Option | Resolves to |
|---|---|
| For 1 hour | One hour from now |
| For 4 hours | Four hours from now |
| Until tomorrow | Tomorrow, 8:00 local |
| Until next week | Next Monday, 8:00 local |
Sub-hour options are deliberately absent: development happens in deep-work blocks, and a 30-minute defer is too granular to be useful. Durations resolve with local date arithmetic, so a daylight-saving transition lands on the wall-clock hour you expected rather than a UTC offset.
A snoozed thread is hidden from All and Unread until it un-snoozes, shows a clock badge in the Snoozed tab, and, as covered above, resurfaces early if it escalates into an error. Deferring a warning does not defer the failure it turns into.
Keyboard navigation
The inbox is fully keyboard-driven while it has focus. Navigation is suppressed while a row's kebab menu is open so the keys do not fight the menu.
| Key | Action |
|---|---|
| j / ↓ | Next notification |
| k / ↑ | Previous notification |
| Home / End | First / last |
| Enter | Run the entry's primary action |
| e | Archive the focused row. In the Archived tab, delete it permanently. |
| u | Toggle the focused row between read and unread |
| h | Open the snooze menu on the focused row (correlated rows only) |
u and h are lowercase only. The shifted forms are reserved for future bulk actions, and h is offered only on rows that belong to a thread, because snooze is a thread-level concept.
Per-entry actions
Each row's kebab menu carries, depending on what the entry is: Snooze or Unsnooze, Copy correlation ID, Go to source, Report on GitHub, Silence {event kind} (optionally "from this project") and Mute project notifications. The last two are the same actions offered on a toast's kebab; see Muting & Silencing.
Timestamps stay relative while recent and grow specific with age: just now, Nm ago, Nh ago, Yesterday HH:MM, Mon D, then Mon D, YYYY. The full date is always on the tooltip.
Other Events That Reach the Inbox
Agent finished with changes
When an agent finishes having touched more files than the session started with, Daintree drops a quiet entry: Agent finished with changes, with an Open review hub action that jumps to the diff. Inbox-only, no toast, no OS alert, and only when the working tree actually changed. It does not replace the completion notification: a single finish can produce both, one telling you the agent is done and one pointing at what changed. See Review Hub.
Park released
Parking a run in Pilot can gate it on another terminal. When that gate comes free (or closes) the park is released and a Park released entry names the run, why it was released, and the note you left on it: "api-refactor: its gate came free. 'rerun the migration first'". An Open action jumps straight to the run.
This is the notification the whole feature exists to earn. A parked run usually lives in a different project, so the row reappearing in Pilot's waiting band is invisible from wherever you have moved on to. The wording stays neutral about the run's own state on purpose: the release says the gate finished, not that the parked run is idle. Re-parking and re-releasing the same run retires the older entry rather than stacking near-duplicates.
Update available and update ready
The Update available toast is informational and deduplicates itself: dismissing it suppresses that version for 24 hours, though a newer version always breaks through and a manual Check for Updates always shows its result.
The Update ready toast, raised once a download completes, carries two actions: Restart to update and View release notes, which opens that version's release notes in your browser. It is urgent, so it breaks through a quiet window: an install genuinely being ready outranks a scheduled mute. Two details follow from that:
- Dismissing the "Update ready" toast does not start the 24-hour cooldown. A pending install should keep reminding you.
- If a newer download starts while an "Update ready" toast is still on screen, the toast regresses to the downloading state and both its restart action and its release-notes link are cleared, so it cannot restart you into a stale build or link to the wrong version's notes.
See Updates.
Deleted worktree cleanup
Deleted worktrees keep their agent terminals alive for a while on a deleted-worktree card. When that grace expires and the terminals are swept, a burst of deletions produces one summary row and one inbox entry ("3 deleted worktrees still had 7 terminals open, so they moved to trash and close shortly.") rather than one entry per worktree. A burst is armed with the same expiry at the same moment, so all its rows expire on one tick; writing N entries describing one event was noise. The title switches between the singular and plural form, and a multi-worktree sweep carries no worktree attribution at all, because pinning one member's identity would make the entry navigate somewhere arbitrary. It is a low-priority inbox record: the event is unattended by definition, so a toast would interrupt whatever you moved on to.
Idle terminals
Daintree checks background projects periodically and records an entry when every terminal in a project has been idle past the threshold. "Idle" means no terminal input and no output for longer than the threshold; a terminal with an agent in the working, running, waiting or directing state is not idle even when it is silent.
This is an inbox-only signal: no toast. An idle background terminal is an ignorable, self-recovering state you can keep working through, so it belongs in the durable record rather than in your way. One row per project, and a re-fire retires that project's previous row instead of accumulating near-duplicates. Each row carries two actions: Close them, which closes every terminal in the project and terminates any running processes, and Mute project, which snoozes the project for a while.
On by default, with a 60-minute threshold. Configure it under Settings > General > Hibernation, not under Settings > Notifications. Presets are 30m, 1h, 2h and 4h; the valid range is 15 minutes to 24 hours.