3.5 KiB
3.5 KiB
summary, read_when
| summary | read_when | |||
|---|---|---|---|---|
| Gateway-owned node pairing (Option B) for iOS and other remote nodes |
|
Gateway-owned pairing (Option B)
Goal: The Gateway (clawd) is the source of truth for which nodes are allowed to join the network.
This enables:
- Headless approval via terminal/CLI (no Swift UI required).
- Optional macOS UI approval (Swift app is just a frontend).
- One consistent membership store for iOS, mac nodes, future hardware nodes.
Concepts
- Pending request: a node asked to join; requires explicit approve/reject.
- Paired node: node is allowed; gateway returns an auth token for subsequent connects.
- Bridge: LAN transport that forwards between node ↔ gateway. The bridge does not decide membership.
API surface (gateway protocol)
These are conceptual method names; wire them into src/gateway/protocol/schema.ts and regenerate Swift types.
Events
node.pair.requested- Emitted whenever a new pending pairing request is created.
- Payload:
requestId(string)nodeId(string)displayName?(string)platform?(string)version?(string)remoteIp?(string)ts(ms since epoch)
node.pair.resolved- Emitted when a pending request is approved/rejected.
- Payload:
requestId(string)nodeId(string)decision("approved" | "rejected" | "expired")ts(ms since epoch)
Methods
node.pair.request- Creates (or returns) a pending request.
- Params: node metadata (same shape as
node.pair.requestedpayload, minusrequestId/ts). - Result:
requestIdstatus("pending" | "alreadyPaired")- If already paired: may include
tokendirectly to allow fast path.
node.pair.list- Returns:
pending[](pending requests)paired[](paired node records)
- Returns:
node.pair.approve- Params:
{ requestId } - Result:
{ nodeId, token } - Must be idempotent (first decision wins).
- Params:
node.pair.reject- Params:
{ requestId } - Result:
{ nodeId }
- Params:
CLI flows
CLI must be able to fully operate without any GUI:
clawdis nodes pendingclawdis nodes approve <requestId>clawdis nodes reject <requestId>
Optional interactive helper:
clawdis nodes watch(subscribe tonode.pair.requestedand prompt in-place)
Storage (private, local)
Gateway stores the authoritative state under ~/.clawdis/:
~/.clawdis/nodes/paired.json~/.clawdis/nodes/pending.json(or~/.clawdis/nodes/pending/*.json)
Notes:
- Tokens are secrets. Treat
paired.jsonas sensitive. - Pending entries should have a TTL (e.g. 5 minutes) and expire automatically.
Bridge integration
The macOS Bridge is responsible for:
- Surfacing the pairing request to the gateway (
node.pair.request). - Waiting for the decision (
node.pair.approve/reject) and completing the on-wire pairing handshake to the node. - Enforcing ACLs on what the node can call, even after paired.
The macOS UI (Swift) can:
- Subscribe to
node.pair.requested, show an alert, and callnode.pair.approveornode.pair.reject. - Or ignore/dismiss (“Later”) and let CLI handle it.
Implementation note
If the bridge is only provided by the macOS app, then “no Swift app running” cannot work end-to-end.
To support headless pairing, also add a clawdis bridge CLI mode that provides the Bonjour bridge service and forwards to the local gateway.