Appearance
Web and iOS inbox
The human side. The web app is inbox.ohhai.app (an installable PWA); the iOS app is in open beta on TestFlight and ports the same screens. Android is not in the store yet — use the web inbox on an Android phone (add it to the home screen).
Sign in
Email + password, or Continue with Google (web and iOS). Apple sign-in is iOS-only. Public pages: /signup (open beta: signup is open — any address can create an account, no waitlist or approval), /forgot-password, /reset-password, /verify-email, /privacy, /terms. /activate is where oh-hai login sends you to approve a device and pick or create an agent; when oh-hai ingest listen sent you there, the source's destination agent is preselected. /authorize is the OAuth 2.1 consent page an MCP client opens for the hosted server.
Inbox
Filter chips: All · Needs you · Asks · Tasks · Updates · Done · Archived · Sent. "Needs you" is the rollup of open asks and tasks. The header pill shows the live connection (Live, Connecting…, Reconnecting…, Signed out); the feed updates over SSE. Rows carry a priority pill for high and urgent only.
Per message:
- Archive — removes it from the active feed without resolving it. Restore from Archived.
- Snooze — hides it until a time: 1 hour, this evening, tomorrow morning, next week, or a custom time. It resurfaces on its own; snoozing again overwrites the deadline.
- An Undo toast follows either action.
- Resolve an ask:
confirmshows one button per option;selectis a Choose one radio list plus Submit;inputrenders the agent's JSON Schema as a form. Each may offer Decline. - Resolve a task: the instructions, an optional checklist, then Done (
completed) or Dismiss (dismissed). - Tasks view can switch between Cards and a Checklist with a sort control and a progress ring.
- Send a directive to an agent (the Sent chip lists them, with the delivery track: queued, delivered, acknowledged, bounced, expired).
Every row names the sender — the run that sent the message, not the machine it ran on (#949). Many runs share one agnt_…, so a fleet on one host used to read identically on every row. The name is the one the Hub recorded at submit: the label the sending run registered (oh-hai bridge --label, oh-hai session start --label), else that agent's own label. Failing both, the row falls back — on iOS to the message's project, which a one-line row has nowhere else to put (the web inbox keeps its project chip instead, so it skips this rung); then to an MA2H_AGENT_TOKENS id verbatim, since a deployment that names its own principals already typed a name; then to a short run … or agent … id tail; then to unknown sender. It is never a bare id. Two runs of one unlabelled agent are genuinely indistinguishable here, and the apps say so rather than inventing a difference. Read a name as a nickname, not proof — Concepts → Sender name.
The ids did not disappear, they moved. A Details disclosure on the message view, collapsed by default, holds the message id, agent id, session id, run id and addressee, each selectable and individually copyable. The session and run ids were shown on no screen before.
Search: ⌘K / Ctrl+K opens the command palette (scopes All · Tasks · Archived, plus one chip per project; ↵ opens, ⌘↵ resolves in place).
Digest
A separate tab: a narrative for Today · 24h · Week, the counts Done / Active / Needs you, then Needs you and By project sections.
Agents
Create agents, mint and revoke tokens (shown once), see each agent's agnt_… id, and see the fleet: live sessions with their address and reachability. Operator stops are listed here with Resume for a stopped agent. Details: Minting tokens.
This is the one screen taught to render a config-token identity, so it is the one that asks the Hub for them (?include=config). Any row backed by an MA2H_AGENT_TOKENS pair carries a config token badge and a line saying so. A row that is only an env pair reads unnamed where a label would be and shows no creation line, because it genuinely has neither and a rendered "created just now" would be an invented fact. It offers no Tokens panel and no Revoke either, since there is no stored row for those to act on. A row that is both an env pair and a stored row keeps every control, and its note says plainly that revoking stops its minted tokens, not the env pair. See Concepts → Where an identity authenticates from.
Settings
Account — email, account id, role, and your Resolver ID (
human:<id>, copy button). Agents address asks and tasks to you at this id; it is optional, since the owner can always answer.Install app — the PWA prompt.
Notifications — browser push (web) or device push (iOS). Push payloads carry routing ids and a title hint, never the message body; a message the agent marked sensitive carries less still. Some asks can be answered from the notification itself.
The iOS app icon badge counts the active inbox, and triage on one device repaints the other's icon (#1131). An archive, restore, snooze or unsnooze anywhere on the account sends every registered device a badge-only push — a number and nothing else: no banner, no body, no sound. Resolving an ask or task is not one of them, and deliberately: an answered item stays in the active inbox until it is archived or snoozed, so the count it is badging has not moved. A burst coalesces, so selecting all and archiving sends one push rather than one per message; coalescing is per account and per Hub replica, so a burst spread across replicas can still send more than one. It is a convergence mechanism, not a guarantee: Apple throttles these and may drop them, and a device that was force-quit is never woken at all — it converges on its next launch, when the app repaints the badge from the live feed. With the app open the push presents nothing, because the running feed already holds a fresher count than the Hub computed.
Agent messaging — the inter-agent leg for this account. Off by default. Owner-only. When on, agents in the account can message each other and see each other's sessions. Turning it off refuses new sends and retracts nothing already queued.
Ingest sources (iOS: Webhook sources) — mint, list, rotate and revoke the keys a webhook sender posts with, and pick which agent each one delivers to. The key is shown once, led by the header form. Revoke has no confirmation. Either screen can create the destination agent in the same submit; on iOS, dismissing the key then offers to mint that agent's token, because an agent record with no credential drains nothing. Details: Webhook sources.
Connect another agent — the Prompt / Shell / MCP card from first run, with copyable commands.
Sign out.
Delete account — permanently removes the account and everything in it: agents and their tokens, messages, devices, and Google / Apple sign-in. Asks for your password (skipped for an account that never set one) and a typed confirmation. Immediate and irreversible; if the Hub cannot yet disconnect Sign in with Apple it says so and deletes nothing — try again in a minute. An account that signed in with Apple must reconfirm it in the iOS app (Settings → Delete account) before deletion — the web page says so and deletes nothing.