Files
clawdbot/docs/presence.md
2025-12-12 16:57:25 +00:00

4.5 KiB
Raw Blame History

summary, read_when
summary read_when
How Clawdis presence entries are produced, merged, and displayed
Debugging the Instances tab
Investigating duplicate or stale instance rows
Changing gateway WS hello or system-event beacons

Presence

Clawdis “presence” is a lightweight, best-effort view of:

  • The Gateway itself (one per host), and
  • The clients connected to the Gateway (mac app, WebChat, CLI, etc.).

Presence is used primarily to render the mac apps Instances tab and to provide quick operator visibility.

The data model

Presence entries are structured objects with (some) fields:

  • instanceId (optional but strongly recommended): stable client identity used for dedupe
  • host: a human-readable name (often the machine name)
  • ip: best-effort IP address (may be missing or stale)
  • version: client version string
  • mode: e.g. gateway, app, webchat, cli
  • lastInputSeconds (optional): “seconds since last user input” for that client machine
  • reason: a short marker like self, connect, periodic, instances-refresh
  • text: legacy/debug summary string (kept for backwards compatibility and UI display)
  • ts: last update timestamp (ms since epoch)

Producers (where presence comes from)

Presence entries are produced by multiple sources and then merged.

1) Gateway self entry

The Gateway seeds a “self” entry at startup so UIs always show at least the current gateway host.

Implementation: src/infra/system-presence.ts (initSelfPresence()).

2) WebSocket hello (connection-derived presence)

Every WS client must begin with a hello frame. On successful handshake, the Gateway upserts a presence entry for that connection.

This is meant to answer: “Which clients are currently connected?”

Implementation: src/gateway/server.ts (WS hello handling uses hello.client.instanceId when provided; otherwise falls back to connId).

3) system-event beacons (client-reported presence)

Clients can publish richer periodic beacons via the system-event method. The mac app uses this to report:

  • a human-friendly host name
  • its best-known IP address
  • lastInputSeconds

Implementation:

  • Gateway: src/gateway/server.ts handles method system-event by calling updateSystemPresence(...).
  • mac app beaconing: apps/macos/Sources/Clawdis/PresenceReporter.swift.

Merge + dedupe rules (why instanceId matters)

All producers write into a single in-memory presence map.

Key points:

  • Entries are keyed by a “presence key”. If two producers use the same key, they update the same entry.
  • The best key is a stable, opaque instanceId that does not change across restarts.
  • Keys are treated case-insensitively.

Implementation: src/infra/system-presence.ts (normalizePresenceKey()).

mac app identity (stable UUID)

The mac app uses a persisted UUID as instanceId so:

  • restarts/reconnects do not create duplicates
  • renaming the Mac does not create a new “instance”
  • debug/release builds can share the same identity

Implementation: apps/macos/Sources/Clawdis/InstanceIdentity.swift.

displayName (machine name) is used for UI, while instanceId is used for dedupe.

TTL and bounded size (why stale rows disappear)

Presence entries are not permanent:

  • TTL: entries older than 5 minutes are pruned
  • Max: map is capped at 200 entries (LRU by ts)

Implementation: src/infra/system-presence.ts (TTL_MS, MAX_ENTRIES, pruning in listSystemPresence()).

Remote/tunnel caveat (loopback IPs)

When a client connects over an SSH tunnel / local port forward, the Gateway may see the remote address as loopback (127.0.0.1).

To avoid degrading an otherwise-correct client beacon IP, the Gateway avoids writing loopback remote addresses into presence entries.

Implementation: src/gateway/server.ts (isLoopbackAddress()).

Consumers (who reads presence)

macOS Instances tab

The mac apps Instances tab renders the result of system-presence.

Implementation:

  • View: apps/macos/Sources/Clawdis/InstancesSettings.swift
  • Store: apps/macos/Sources/Clawdis/InstancesStore.swift

The store refreshes periodically and also applies presence WS events.

Debugging tips

  • To see the raw list, call system-presence against the gateway.
  • If you see duplicates:
    • confirm clients send a stable instanceId in hello
    • confirm beaconing uses the same instanceId
    • check whether the connection-derived entry is missing instanceId (then it will be keyed by connId and duplicates are expected on reconnect)