- split installation.md into installation/deployment/notifications - merge cursor/grok guides into new agents.md with full support matrix - sidebar: grouped sections; add namespace, deployment, notifications, native companion contract - fix license footer (AGPL-3.0), settings schema fields and $id - fix drift in pwa, faq, namespace, how-it-works, voice-assistant, quick-start, native-companion-contract - move mermaid lightbox dogfood doc to localdocs (untracked) - README: complete agent list, replace dead cursor/grok links
3.8 KiB
Native companion API contract (phone + Wear)
Audience: Implementers of native companion apps (Android phone + Wear OS, iOS, etc.) that pair with a hapi hub via FCM.
Auth: Exchange the pairing code / CLI access token with POST /api/auth:
{ "accessToken": "<code>" }. Use the returned JWT as Authorization: Bearer <token>
for device registration and session actions. POST /api/bind is only for Telegram Mini App
binding (requires Telegram initData).
Scope
A companion implementing this contract is a native client to the same hub the PWA talks to, surfacing notifications and reply / approve actions on a phone or wearable. Hub topology is unchanged - the hub still runs on the operator's dev machine.
Device registration (FCM)
Register
POST /api/devices/register
{
"token": "<fcm-registration-token>",
"platform": "phone",
"deviceId": "<stable-install-id>"
}
platform: "phone" | "wear"
deviceId: any string of 1-128 characters chosen by the client (does not have to be a UUID). Must be stable across re-registrations of the same install.
Response: { "ok": true }
Upsert on (namespace, deviceId, platform) - same device re-registering replaces the FCM token.
Unregister
DELETE /api/devices/register
{
"token": "<fcm-registration-token>"
}
Outbound push (hub → device)
Hub sends FCM HTTP v1 whenever a notification event is emitted for a
namespace with registered native devices and FCM is configured. The native
companion is treated as the canonical wrist-first surface, so FCM fires
unconditionally (independent of whether a PWA tab happens to be
foreground / visible via SSE) - that's deliberate, see
FcmNotificationChannel.deliver(). Web Push is suppressed for the same
namespace to avoid duplicate OS notifications.
Data payload (all platforms)
| Key | Example | Purpose |
|---|---|---|
type |
ready |
ready, permission-request, task-notification |
sessionId |
uuid | Target session |
sessionName |
string | Display name (agent - project) |
url |
/sessions/{id} |
Deep link path |
requestId |
uuid | Permission only - approve/deny |
title |
string | Notification title |
body |
string | Notification body |
severity |
info |
info (ready), warning (permission), success / error (task) |
contractVersion |
1 |
Present on every message; see Versioning |
notifySummary |
JSON string | Only on ready: parsed AGENT_NOTIFY_SUMMARY line from agent text, when present |
Native apps must handle data for Wear; notification block is for display.
Client actions (native - not hub)
| User action | Hub API |
|---|---|
| Send text | POST /api/sessions/:id/messages { "text": "...", "localId": "..." } |
| Allow | POST /api/sessions/:id/permissions/:requestId/approve |
| Deny | POST /api/sessions/:id/permissions/:requestId/deny |
localId is optional in the send-message body - an opaque client-generated id for reconciling the locally shown message with the server-echoed one.
sentFrom extension (optional future): android-phone, android-wear.
Environment (hub operator)
FCM_SERVICE_ACCOUNT_PATH=/path/to/service-account.json
FCM_PROJECT_ID=your-firebase-project-id
When unset, hub skips FCM channel (Web Push / Telegram unchanged).
The native push channel is opt-in: operators who don't run a companion app see no behavior change. When at least one device is registered for a namespace, the existing Web Push channel suppresses its fallback for that namespace to avoid double-notifying (one in the native app, one from the PWA service worker). PWA-only operators are unaffected.
Versioning
Contract version 1. Breaking changes require data.contractVersion in FCM payload and doc update.