feat(connect): Node local relay for Relay Connect guests (paused, backup)

Draft
KH
7d ago
+6254-44

Status: paused, kept as a backup (Khaliq, 2026-10-12). Implements the design in #1966. Julian's root cause was that a permission check blocked npx, and a plain terminal is not a session. This would not have fixed that. Work stopped here. Do not merge as-is.

This branch is stacked on #1967 (fix/connect-installer-unidentified-session), so its first commit is #1967's.

Done

  • src/relay/: per-user Node relay daemon.
    • Started detached under the Node already running npx, from a stable runtime copy.
    • IPC handshake: start failures print the daemon's reason plus the end of its log, at once.
    • Single-instance lock, idle exit, private 0700/0600 state.
  • Connect client: join (idempotency key reuse on 5xx/429/timeout), send (per-recipient Idempotency-Key), status, leave.
    • Leave calls the Cloud participant leave from cloud#4865, falling back to Relaycast disconnect.
    • Distinct error codes, logged without secrets.
  • Delivery ledger ported from the probe:
    • persist before inject, ack only when delivered;
    • in-doubt messages are failed and never resent;
    • head-of-line backoff (5→30 s), a 1 h unaccepted TTL;
    • accepted items are only observed;
    • expired or ended notices.
  • Injection routes: the Claude Code inbox socket, Codex codex queue confirmed from the rollout, and Codex app ipc.sock.
  • The CLI identifies its own session: CODEX_THREAD_ID, then CLAUDE_CODE_SESSION_ID with a live record, then a parent-process walk.
  • Backend selection: the session's existing Node relay, then an eligible desktop probe, then the Node relay. AGENT_RELAY_CONNECT_BACKEND forces one.
  • 103 tests pass (6 files).
  • Live proof on macOS, real Cloud, throwaway Connect (since ended). A real Claude Code 2.1.296 session joined through the Node relay in 1.4 s, including daemon start. The host's message was injected into the live session in the probe's exact format, with a working reply command. The ledger recorded delivered and acked it. The reply reached the host. status and leave worked.

Remaining

  • Presence bug. status shows "unknown presence" because GET /v1/agents?status=all needs a workspace key, and Relaycast rejects the participant token with 401 "Workspace key required". The desktop probe has the same bug: sdk_gaps::list_agents is built with the participant token. It needs a participant-scoped roster from Cloud or Relaycast.
  • Not yet proven live: a Codex session (terminal and app), a fresh spawned guest, and the cross-machine run on linuyc.
  • Not ported yet: the Codex app-server proxy route, the Conductor Stop-hook hold, attachment downloads, and queue cleanup (Codex databases are opened read-only).
  • The relay-connect skill's error list and the new codes from relay-desktop#421 still need adding.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Agent Relay sessions

  • claude session 290d4dce · opened via gh pr create · last active 2026-10-12