--- summary: "How Clawdbot presence entries are produced, merged, and displayed" read_when: - Debugging the Instances tab - Investigating duplicate or stale instance rows - Changing gateway WS connect or system-event beacons --- # Presence Clawdbot “presence” is a lightweight, best‑effort view of: - the **Gateway** itself, and - **clients connected to the Gateway** (mac app, WebChat, CLI, etc.) Presence is used primarily to render the macOS app’s **Instances** tab and to provide quick operator visibility. ## Presence fields (what shows up) Presence entries are structured objects with fields like: - `instanceId` (optional but strongly recommended): stable client identity - `host`: human‑friendly host name - `ip`: best‑effort IP address - `version`: client version string - `deviceFamily` / `modelIdentifier`: hardware hints - `mode`: `gateway`, `app`, `webchat`, `cli`, `node`, ... - `lastInputSeconds`: “seconds since last user input” (if known) - `reason`: `self`, `connect`, `node-connected`, `periodic`, ... - `ts`: 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 a `connect` request. On successful handshake the Gateway upserts a presence entry for that connection. #### Why one‑off CLI commands don’t 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 bridge beacons When a node bridge connection authenticates, the Gateway emits a presence entry for that node and refreshes it periodically so it doesn’t expire. ## Merge + dedupe rules (why `instanceId` matters) Presence entries are stored in a single in‑memory map: - Entries are keyed by a **presence key**. - The best key is a stable `instanceId` that survives restarts. - Keys are case‑insensitive. If a client reconnects without a stable `instanceId`, it may show 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) This keeps the list fresh and avoids unbounded memory growth. ## Remote/tunnel caveat (loopback IPs) 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. ## Consumers ### macOS Instances tab 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. ## Debugging tips - To see the raw list, call `system-presence` against the Gateway. - If you see duplicates: - confirm clients send a stable `instanceId` in the handshake - confirm periodic beacons use the same `instanceId` - check whether the connection‑derived entry is missing `instanceId` (duplicates are expected)