Koder Pair — peer-to-peer device pairing handshake
Protocolo de handshake para pareamento peer-to-peer entre dispositivos do mesmo dono na Koder Stack (Kode CLI, Kanvas, Talk, Drive, etc.). Define discovery via mDNS/bluetooth, key exchange (Noise XX), confirmação visual cross-device e armazenamento da relação no Koder Keys.
Quando esta spec se aplica
Todos os triggers
- Implementar pairing entre dois dispositivos Koder do mesmo owner
- Adicionar surface de pareamento em app Koder novo
- Editar engines/sdk/koder_pair_kit/ ou products/horizontal/pair/
Corpo da especificação
Spec — Koder Pair: peer-to-peer device pairing handshake
Status: Normative (Draft)
Applies to: engines/sdk/koder_pair_kit/, products/horizontal/pair/,
any Koder app that wires same-owner device pairing (Kode CLI, Kanvas,
future).
Origin: KSTACK-34 (OpenClaw analysis 2026-04-29).
Crypto reuse: Noise Protocol Framework — same primitives as
products/horizontal/talk (RFC-001 QUIC transport). Do NOT introduce
new cryptographic primitives.
1. Scope
This spec defines the handshake that establishes a Koder Pair session between two devices owned by the same human (e.g. desktop ↔ phone). Once established, the session reuses the Talk transport (Noise-encrypted streams over QUIC).
Out of scope: application-level message formats (Pair owns one per app: audio relay, notification mirror, co-pilot). Each consumer defines its own protobuf on top of the Pair session.
2. Pairing Modes
Two modes, both producing the same end state:
2.1 QR + Out-of-band
Default for casual setups (phone ↔ laptop in the same room).
- Initiator (e.g. desktop) calls
pair.PrepareInvite()→ returns:pair_token: 256-bit random, expires in 5 minutesinitiator_pubkey: Ed25519 public keyendpoint:host:portreachable on LAN, plus optionalrelay_urlfor cross-network pairing via Koder Hub-hosted relay (see §5)
- Initiator displays a QR encoding
pair://{token}@{endpoint}?pk={pk_b64}. - Responder scans the QR with the Pair app, calls
pair.JoinInvite(uri). - Responder generates its Ed25519 keypair, opens a Noise XX handshake
over QUIC to
endpoint, presentspair_tokenin the handshake prologue. - Initiator verifies token, completes Noise XX, returns its long-term identity in the final handshake message.
- Both sides write the peer's identity to local keystore — future sessions skip the QR step (use Noise IK directly).
2.2 PIN fallback
When the QR camera is unusable (server pairing, wearable, accessibility):
- Initiator calls
pair.PreparePIN()→ returns:- 6-digit human PIN (displayed)
pair_token(same as 2.1)
- Responder enters PIN manually; SDK derives
pair_tokenfrom PIN + shared discovery channel context (so PINs alone don't authorize — the discovery channel proximity is part of the proof).
PIN mode requires both devices on the same LAN OR both authenticated to the same Koder ID v2 account (the relay validates both auth tokens).
3. Cryptographic Choices
| Property | Value |
|---|---|
| Identity keys | Ed25519 (matches Talk) |
| Handshake | Noise XX (mutual auth, forward secrecy) |
| Session keys | Derived via Noise XX → ChaCha20-Poly1305 |
| Transport | QUIC (matches Talk RFC-001) |
| Identity persistence | Per-device keystore via OS keychain (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows, KeyStore on Android, Keychain on iOS) |
Re-uses every primitive from products/horizontal/talk/RFC-001 — no new
crypto reviewed. New auditing surface is limited to the prologue
(token+PIN handling).
4. Session Lifetime
- Each Pair session is per-device-pair, not per-app. Multiple Koder apps share the same underlying Noise session via the Pair daemon.
- Session is persistent across restarts (re-handshake on first message after reboot using cached identities — Noise IK pattern).
- Revocation: the user can revoke a paired peer in any Koder app's Settings → Paired Devices. Revocation broadcasts a tombstone via the Hub-hosted relay (see §5) so all this user's devices update their trust list.
5. Relay (cross-network pairing)
When devices aren't on the same LAN, the Hub hosts a thin relay at
pair.koder.dev/relay:
- Initiator and Responder both authenticate to the relay with their Koder ID v2 token (so the relay can confirm same-owner).
- Relay forwards Noise frames byte-for-byte; never decrypts (it has no key material).
- Relay is rate-limited per Koder ID account (10 active sessions, 100 pairings/day).
6. Validation
- Smoke test: pair desktop+phone via QR; verify
kode device listshows both; revoke from desktop; verify phone no longer in the list. - Property test: handshake with corrupted
pair_tokenMUST fail before any session key derivation. - Audit: cryptographic review limited to §2 prologue handling — Noise primitives below are inherited from Talk and don't need re-audit.
7. Non-Goals
- Multi-user mesh. Pair is for same-owner device sets only. Talk handles multi-user.
- File transfer protocol. Pair sessions carry app-specific protobuf streams; large transfers ride on top via app-level chunking.
8. References
products/horizontal/talk/docs/rfcs/RFC-001-quic-transport.md— Noise + QUIC stack inheritedservices/foundation/id— Koder ID v2 auth used by §5 relayengines/sdk/koder_pair_kit/docs/rfcs/RFC-001-pair-architecture.md— implementation spec
Referências
specs/koder-app/behaviors.kmdspecs/ipc/protocol.kmdspecs/voice/wake-word.kmd