Appearance
Background Notifications (Android)
Hive's in-app notifications only fire while the app is open and connected. On Android, background notifications close that gap: the app briefly wakes on a timer, connects to your cluster, and raises a native notification for anything that happened while it was closed or backgrounded - a finished agent, a scheduled task that succeeded or failed, or a session waiting on you.
This is opt-in and battery-friendly. Hive does not hold a constant connection; it connects for a moment roughly every 15 minutes, checks for missed alerts, and disconnects.
Turning it on
Open Settings -> Notifications on the Android app. Under Background notifications (this device), enable Check for missed notifications while the app is closed.
The toggle only appears on Android, where the native scheduling support exists. On desktop and in the web client the app relies on the normal in-app / OS alerts while it is running (see Agent Waiting Marker), so there is no equivalent toggle there.
What you get notified about
While the app is closed, a background check surfaces the same events the app would have alerted you to live:
- An agent finished - a session went idle after doing work.
- A scheduled task succeeded or failed - honouring the per-task Notify on success / Notify on failure opt-ins (see Tasks). A task with neither flag set stays silent.
- A session is waiting for you - the same "needs input" signal that drives the
?marker (see Agent Waiting Marker).
Each notification carries a title and body and, where relevant, targets the session it relates to so a tap can open it.
Timing: expect up to ~15 minutes
The ~15 minute cadence is a floor imposed by Android, not a setting. Hive uses an inexact repeating alarm, which Android is free to delay and batch, especially under Doze (the OS's idle power-saving mode). So a missed alert can arrive up to about 15 minutes late, sometimes more if the device has been idle for a long stretch.
This is a deliberate trade-off: a constant push connection would drain the battery, while a periodic wake keeps power use negligible. If you need to-the-second alerts, keep the app open in the foreground, where in-app notifications fire immediately.
Cluster-wide coverage
The background check polls a single node - whichever one your app's active profile points at. That node aggregates missed notifications from the whole cluster before answering, so a task failure or an idle agent on any node still reaches your phone through the one node you poll. You do not need to poll every node individually.
How it works
The feature has two halves: a durable notification log the daemon keeps, and a native Android poller that reads it.
Daemon: durable notification log
Every alert the daemon fires is appended to a durable log (a SQLite notifications table, added in schema migration v28) so a client that was offline when the alert fired can still see it on its next poll. The log is bounded: rows older than 7 days, or beyond the newest 500, are pruned after each insert.
Each record carries a stable id (clients dedupe on it across polls), the firing time in Unix milliseconds, a machine-readable kind, an optional session_id (tap-to-open target), the firing node_id, and a title / body.
The kind is one of:
kind | Meaning |
|---|---|
agent_idle | An agent went idle / a session finished a turn of work |
attention | A session is waiting for the user (the ? state) |
task_success | A scheduled task completed with exit 0 |
task_failure | A scheduled task failed (non-zero exit or timeout) |
HTTP endpoint
The Android poller reads the log over a small authenticated HTTP endpoint:
GET /notifications?since_ms=<unix_ms>- Authenticate with the daemon token, either as
Authorization: Bearer <token>or as a?token=<token>query parameter. The cluster token is also accepted. - The response is
{ "now_ms": <server_time>, "items": [ ...NotificationRecord ] }, whereitemsare the notifications fired aftersince_ms, aggregated across the cluster. - The client persists the returned
now_msas its nextsince_mscursor, so each poll only returns what is new since the previous one.
The same aggregation is available over the WebSocket protocol via ClientMessage::GetNotifications { since_ms } -> ServerMessage::Notifications { items, now_ms }, which the polled node uses to fan out to its peers (see Protocol).
Android native side
The native scheduling is generated into the Android project at build time by crates/hive-app/scripts/patch-android-keyboard.mjs. It wires up:
- An AlarmManager inexact-repeating alarm that wakes the app roughly every 15 minutes.
- A BroadcastReceiver (
HiveBackgroundNotifyReceiver) that runs on each alarm: it does theGET /notificationsrequest with the stored cursor and posts a native notification for each new item. - A boot receiver that re-arms the alarm after the device reboots, so the feature keeps working across restarts without reopening the app.
Configuration (enabled flag, base URL, token, and the since_ms cursor) lives in Android SharedPreferences, written when you toggle the setting and read by the receiver on each wake.