Notifications
An agent that finished four minutes ago while you were looking elsewhere has cost you four minutes. Notifications are how Offsite gives that time back.
What fires
Section titled “What fires”Four events, each switchable per device:
| Event | Default | Fires when |
|---|---|---|
| Turn completed | on | the agent finished and is idle again |
| Input requested | on | the agent is waiting for you — a question, a permission prompt |
| Session ended | off | the session’s process exited |
| Errors | off | something went wrong |
The two events that mean you are now the bottleneck are on by default; the noisier two wait until you ask for them.
Per device, not per account
Section titled “Per device, not per account”Every device you have paired carries its own settings. Your Watch can tap you while your phone stays silent, or the Mac can stay quiet while you are sitting in front of it.
They name the session
Section titled “They name the session”A notification carries the session’s name, so you know which agent wants you before you unlock anything. Tapping one opens exactly that session.
“waiting for input” is noise; “api-refactor is waiting for input” is information. You do not have to arrange that yourself — agent sessions name their own cards, and your own rename overrides theirs.
Not screen scraping
Section titled “Not screen scraping”Offsite does not watch the terminal for phrases like “waiting for input”. It subscribes to the CLIs’ own lifecycle interfaces — hooks, where the CLI has them — so the signal is the agent actually reporting its state.
A CLI update changes its wording all the time. Its hook contract stays put, so the signal survives the next release.
What a push actually contains
Section titled “What a push actually contains”A lock-screen notification has to be readable text, so this part is not encrypted end-to-end. When your device is not currently attached, the host sends the event to a Firebase function we run, which hands it to Firebase Cloud Messaging and Apple’s push service:
| Travels | Example |
|---|---|
| The session’s name | api-refactor needs your input |
| The workspace’s name | …is waiting for approval or instructions in offsite. |
| Event type, timestamp, and ids for host, workspace and session | — |
Nothing else does: no prompt, no agent output, no file, no diff, no path, no command.
Two things keep this small by default. A push is only sent to a device that is not connected in the foreground — with the app open, the same event arrives over your own encrypted connection and Firebase is not involved. And with notifications off for a device, nothing leaves the host for it at all.
Since agent sessions name themselves, that name is usually a description of the work — which is exactly what makes the notification useful, and something to keep in mind if a project name is sensitive. The full picture is in Security and privacy.
Details
Section titled “Details”- For Claude, Offsite registers hooks for
SessionStart,UserPromptSubmit,Stop,Notificationmatchingpermission_prompt, andPreToolUsematchingAskUserQuestion|ExitPlanMode. Each one reports the event back to the host, which decides whether it is worth a notification. - For Codex, Offsite uses Codex’s
notifycommand plus its lifecycle hooks (SessionStart,UserPromptSubmit,PermissionRequest,Stop). Codex only runs a hook it has been told to trust; Offsite normally passes the hook and its trust to each session it starts, so nothing is written to your Codex configuration and Codex never asks. If that per-session path is unavailable on a host, a Codex card shows a Codex hook chip: allow it, and Offsite adds one entry to~/.codex/hooks.json— Codex then asks you once, on its next start, to trust it (“Trust all and continue”). Decline, and Codex sessions keep working on thenotifysignal alone.offsite-host codex-hooks uninstallremoves the entry; resetting the host removes it too. - Push delivery to phones and Watch rides Firebase Cloud Messaging, via a function we run. The payload is the event, the session and workspace names, and the ready-made title and body built from them — never the content of your session.
- The title and body are templates, not anything the agent wrote: “name needs your input” / “name is waiting for approval or instructions in workspace”. The agent’s recap is not part of them.
- Our function stores no notification text; it logs a push-token id, a status, a hashed IP and a timestamp. Transport past that point is Google’s and Apple’s.
- The Watch complication is refreshed by a separate silent push that carries no text — it only prompts the app to fetch state over your own connection.
- Attention resolves when a device that is actually looking at the session acks it; a background app does not silently clear a notification you never saw.
- Notification settings live per registered device in the host’s
devices.json. - Attention is per session, so a busy board still resolves to one tap on the card that actually wants you.