docs/concepts/presence.md
OpenClaw “presence” is a lightweight, best‑effort view of:
Presence is used primarily to render the macOS app’s Instances tab and to provide quick operator visibility.
Presence entries are structured objects with fields like:
instanceId (optional but strongly recommended): stable client identity (usually connect.client.instanceId)host: human‑friendly host nameip: best‑effort IP addressversion: client version stringdeviceFamily / modelIdentifier: hardware hintsmode: ui, webchat, cli, backend, probe, test, node, ...lastInputSeconds: “seconds since last user input” (if known)reason: self, connect, node-connected, periodic, ...ts: last update timestamp (ms since epoch)Presence entries are produced by multiple sources and merged.
The Gateway always seeds a “self” entry at startup so UIs show the gateway host even before any clients connect.
Every WS client begins with a connect request. On successful handshake the
Gateway upserts a presence entry for that connection.
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.
system-event beaconsClients can send richer periodic beacons via the system-event method. The mac
app uses this to report host name, IP, and lastInputSeconds.
When a node connects over the Gateway WebSocket with role: node, the Gateway
upserts a presence entry for that node (same flow as other WS clients).
instanceId matters)Presence entries are stored in a single in‑memory map:
instanceId (from connect.client.instanceId) that survives restarts.If a client reconnects without a stable instanceId, it may show up as a
duplicate row.
Presence is intentionally ephemeral:
This keeps the list fresh and avoids unbounded memory growth.
When a client connects over an SSH tunnel / local port forward, the Gateway may
see the remote address as 127.0.0.1. To avoid overwriting a good client‑reported
IP, loopback remote addresses are ignored.
The macOS app renders the output of system-presence and applies a small status
indicator (Active/Idle/Stale) based on the age of the last update.
system-presence against the Gateway.client.instanceId in the handshakeinstanceIdinstanceId (duplicates are expected)