RFC-001 — koder_pair_kit: SDK architecture

Author: Koder Engineering Date: 2026-04-29 Status: Accepted Module: enginessdkkoderpairkit + productshorizontalpair Origin: koder-stack ticket #034 (OpenClaw analysis 2026-04-29) Spec: meta/docs/stack/specs/pair/handshake.kmd


1. Summary

A peer-to-peer pairing SDK + flagship Pair app for binding multiple devices owned by the same human into a single Kode session — desktop ↔ phone ↔ tablet ↔ Koder Konsul-equipped headset, etc. Reuses the Talk crypto stack (Noise + QUIC) so we add zero new audit surface.

Engine + product split per project memory engine_product_pattern remains optional here — Pair could ship as a standalone app or as a screen inside Kode. We adopt the standalone app path (§7).

2. Problem

OpenClaw ships a "node" model where the desktop assistant federates with mobile devices: the phone is a roaming microphone, a notification mirror, a co-pilot screen for long-running tasks. Today the Koder Stack has Talk (between people) and Kode (single-device sessions) but nothing bridges devices of one owner.

3. Goals

  • Pairing once, session for life. QR or PIN at first contact;

    Noise IK rehandshake automatically on every reconnect.

  • One SDK consumed by Kode, Kanvas, Pass, future apps. They open

    Pair sessions; Pair handles transport + identity + presence.

  • Cross-platform: Flutter (mobile + desktop) for the SDK + app;

    Go binding for backend tools; KL binding for kode CLI.

  • Cross-network via thin relay at pair.koder.dev/relay (§5 of

    the spec) — never decrypted, just forwards Noise frames.

4. Non-Goals

  • Multi-user mesh — that's Talk's job.
  • File-transfer protocol — Pair carries app-defined protobuf; chunking

    rides on top.

  • Synchronous co-presence (Google Docs-style cursors) — out of v1.

5. Architecture

┌────────────┐                ┌────────────┐
│  Kode CLI  │                │   Kanvas   │
│ (desktop)  │  ┌──────────┐  │  (mobile)  │
└─────┬──────┘  │  Pair    │  └─────┬──────┘
      │         │   App    │        │
      └─via SDK→│ (UI for  │←via SDK┘
                │  user)   │
                └──┬───────┘
                   │
          ┌────────┴─────────┐
          │  koder_pair_kit  │
          │  (SDK — Flutter, │
          │   Go, KL)        │
          └────────┬─────────┘
                   │ Noise XX/IK
        ┌──────────┼──────────┐
        │          │          │
   LAN QUIC    Hub Relay   LAN QUIC
                   │
            pair.koder.dev
            (Hub-hosted, never decrypts)

The SDK is the canonical surface; the Pair app is the human-facing front-end (QR scanner, paired-devices list, revocation UI). All session state lives in the SDK; the app is mostly a view.

6. SDK Surface

Dart (enginessdkkoderpairkit)

final pair = KoderPair();
final invite = await pair.prepareInvite();      // QR-bound
print('show: ${invite.qrUri}');                  // pair://...

final remote = await pair.joinInvite(qrUri);     // on the responder
remote.send(myProtobufBytes);                    // app-defined payload
remote.messages.listen((msg) => handle(msg));

Go (enginessdkgo-koder-pair-kit) — future

Same shape; consumed by Kode CLI and any backend tool that wants to participate in a Pair mesh.

KL (engineslangkodarpairkit) — future

Native KL binding for kode CLI.

7. Standalone App vs Kode Screen

Decision: ship Pair as a standalone app (products/horizontal/pair/).

Rationale:

  • Discoverability: users who want to pair their phone don't already

    have Kode mobile installed. A purpose-built Pair app downloads from the Hub independently.

  • Surface area: the QR scanner + paired-device list is enough UI

    to merit its own product.

  • Sub-feature in other apps: Kode and Kanvas import the SDK and

    expose "Pair a device" entry points; users follow them to the Pair app for the actual flow.

8. Scope of Change

  • meta/docs/stack/specs/pair/handshake.kmd — handshake spec (landed)
  • engines/sdk/koder_pair_kit/ — Dart SDK (this RFC + scaffold)
  • products/horizontal/pair/ — Flutter app (scaffold + landing)
  • Future: Go and KL bindings; Kode integration (kode pair add,

    kode device list)

  • Future: Hub relay (pair.koder.dev/relay) — separate ticket

9. Execution Plan

Phase Deliverable
F1 Spec + this RFC + scaffolds (DONE)
F2 Dart SDK: Noise XX over QUIC (delegate to Talk's transport)
F3 Pair app v0.1: QR generate + scan + paired-device list
F4 Hub relay endpoint pair.koder.dev/relay
F5 Kode integration (kode pair add, kode device list)
F6 Cross-app demo: phone microphone → Kode desktop session
F7 Go + KL bindings

10. Alternatives Considered

  • Skip Pair entirely; users open Talk between two of their devices.

    Rejected: Talk's UX is multi-user mesh — bloated for the same-owner case. Pairing semantics, revocation, and discovery differ.

  • Build Pair as a Kode-only screen. Rejected per §7.
  • Use WebRTC instead of Noise+QUIC. Rejected: would introduce a

    separate crypto stack to audit, contradicting the spec §3 "no new primitives" goal.

11. References

  • meta/docs/stack/specs/pair/handshake.kmd — handshake details
  • products/horizontal/talk/docs/rfcs/RFC-001-quic-transport.md — transport stack inherited
  • Memory koder_talk — Talk module status and crypto choices
  • Memory engine_product_pattern — engine+product split convention

    (Pair is SDK+app, not engine+product, because Pair is not a multi-tenant service)