- the Gateway itself, and
- clients connected to the Gateway (mac app, WebChat, CLI, etc.)
Presence fields (what shows up)
Presence entries are structured objects with fields like:instanceId(optional but strongly recommended): stable client identity (usuallyconnect.client.instanceId)host: human-friendly host nameip: best-effort IP addressversion: client version stringdeviceFamily/modelIdentifier: hardware hintsmode:ui,webchat,cli,backend,node,probe,testlastInputSeconds: seconds since last user input, if knownreason: free-form client-supplied string; the Gateway itself only emitsself,connect, anddisconnectdeviceId,roles,scopes: device identity and role/scope hints from the connect handshakets: last update timestamp (ms since epoch)
Producers (where presence comes from)
Presence entries are produced by multiple sources and merged.1) Gateway self entry
The Gateway always seeds a “self” entry at startup so UIs show the gateway host even before any clients connect.2) WebSocket connect
Every WS client begins with aconnect request. On successful handshake the
Gateway upserts a presence entry for that connection.
Why one-off CLI commands do not show up
The CLI often connects for short, one-off commands. To avoid spamming the Instances list,client.mode === "cli" is not turned into a presence entry.
3) system-event beacons
Clients can send richer periodic beacons via the system-event method. The mac
app uses this to report host name, IP, and lastInputSeconds.
4) Node connects (role: node)
When a node connects over the Gateway WebSocket withrole: node, the Gateway
upserts a presence entry for that node (same flow as other WS clients).
Merge + dedupe rules (why instanceId matters)
Presence entries are stored in a single in-memory map, keyed case-insensitively
by the first available of, in order: a paired device id, connect.client.instanceId,
or the per-connection id as a last resort.
CLI clients are excluded from tracking entirely (see above), so their
connection id never becomes a key. For every other client, the connection id
fallback means a client that reconnects without a stable instanceId shows up
as a duplicate row.
TTL and bounded size
Presence is intentionally ephemeral:- TTL: entries older than 5 minutes are pruned
- Max entries: 200 (oldest dropped first)
Remote/tunnel caveat (loopback IPs)
When a client connects over an SSH tunnel / local port forward, the Gateway may see the remote address as127.0.0.1. To avoid recording that tunnel
address as the client’s IP, connect handling omits ip entirely for
detected-local (loopback) clients rather than writing the loopback address
into the entry.
Consumers
macOS Instances tab
The macOS app renders the output ofsystem-presence and applies a small status
indicator (Active/Idle/Stale) based on the age of the last update.
Debugging tips
- To see the raw list, call
system-presenceagainst the Gateway. - If you see duplicates:
- confirm clients send a stable
client.instanceIdin the handshake - confirm periodic beacons use the same
instanceId - check whether the connection-derived entry is missing
instanceId(duplicates are expected)
- confirm clients send a stable
Related
Typing indicators
When typing indicators are sent and how to tune them.
Streaming and chunking
Outbound streaming, chunking, and per-channel formatting.
Gateway architecture
Gateway components and the WebSocket protocol that drives presence updates.
Gateway protocol
The wire protocol for
connect, system-event, and system-presence.