Skip to content

feat(a2a): cross-device relay ingress with pairing gate#85

Merged
bahadirarda merged 1 commit into
mainfrom
a2a-relay-endpoint
May 25, 2026
Merged

feat(a2a): cross-device relay ingress with pairing gate#85
bahadirarda merged 1 commit into
mainfrom
a2a-relay-endpoint

Conversation

@bahadirarda
Copy link
Copy Markdown
Contributor

Second cross-device-messaging PR (after the pairing store in #84). Adds the receive side of the LAN relay — the endpoint a remote daemon POSTs to, gated by the operator's chosen trust model (circle key + first-contact pairing approval).

What

  • POST /v1/relay (circle-aware, same circleOrBearer gate as /v1/agents): a paired peer relays a message over the LAN. Unknown sender → 202 pairing_required + 4-digit code, refused until the receiving operator approves; approved sender → delivered. Enqueues into local inboxes (not code execution), so circle auth + pairing approval are the trust boundary.
  • a2a.InstallID / InstallDisplayName — stable per-install fingerprint (persisted UUID) the relay presents as sender identity; peer_ids churn per session and can't anchor a pairing decision.
  • Registry.DeliverToLocal — enqueues into every LOCAL agent inbox (source != mdns), so a relayed message reaches whatever agent is live here without looping back out to remote peers.
  • a2a.GlobalPairingStore — lazy process-wide store; corrupt-file-safe (re-prompts rather than wedging delivery).

Tests

relay first-contact→202+code (nothing delivered), approve→200 delivered into local inbox, missing-field rejects; InstallID stability; DeliverToLocal skips mdns peers. internal/a2a + internal/server suites green.

Next (PR 3)

Send side: peer send to an mdns target relays to the remote's /v1/relay (instead of writing the local inbox) and surfaces the pairing-required response; clawtool peer pair list/approve/deny CLI; app approval prompt + liveness re-announce.

Second of the cross-device messaging PRs (after the pairing store in
#84). Adds the receive side of the LAN relay: the endpoint a remote
daemon POSTs to, gated by the operator's chosen trust model.

- POST /v1/relay (circle-aware, same circleOrBearer gate as
  /v1/agents): a paired peer relays a message here over the LAN. The
  handler runs the first-contact pairing gate — an unknown sender is
  recorded pending (202 + a 4-digit code) and refused until the
  receiving operator approves; an approved sender's message is
  delivered. Not a code-execution surface (it enqueues into local
  inboxes), so circle auth + pairing approval are the trust boundary.
- a2a.InstallID / InstallDisplayName: a stable per-install fingerprint
  (persisted UUID) the relay will present as the sender identity —
  peer_ids churn per session and can't anchor a pairing decision.
- Registry.DeliverToLocal: enqueues a relayed message into every LOCAL
  agent's inbox (source != mdns), so it reaches whatever agent is live
  here without looping back out to other remote peers.
- a2a.GlobalPairingStore: lazy process-wide store the handler reads;
  corrupt-file-safe (re-prompts rather than wedging delivery).

Tests: relay first-contact→202+code (nothing delivered), approve→200
delivered into the local inbox, missing-field rejects; InstallID
stability; DeliverToLocal skips mdns peers.

Send side next: `peer send` to an mdns target relays to the remote's
/v1/relay (instead of writing the local inbox) and surfaces the
pairing-required response.
@bahadirarda bahadirarda merged commit 4bf264a into main May 25, 2026
5 checks passed
@bahadirarda bahadirarda deleted the a2a-relay-endpoint branch May 25, 2026 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant