Architecture & Cross-Repo Contracts
This page is the canonical reference that every Consensus repository syncs against. When a change crosses a repo boundary — a request/response shape, a header, a tunnel frame, the ticket format — update it here first, then in the affected repos.
Repositories
Section titled “Repositories”| Repo | Role |
|---|---|
consensus | Orchestrator / proxy (server/, port 8080). Routing, payment, node registry, tunnels, paid WebSockets. |
consensus-client | @canister-software/consensus-cli — TypeScript SDK + TUI/CLI used to interact with the network. |
consensus-node | Bun worker-node runtime that registers with the orchestrator and serves proxied requests. |
consensus-docs | This site (Astro Starlight). Hosts this canonical architecture/contracts reference. |
consensus-facilitator | x402 payment facilitator — verifies and settles payments across ICP, EVM (mainnet + Base + testnets), and SVM (mainnet + devnet). Backs the orchestrator’s FACILITATOR_URL. |
The
instance/directory inside theconsensusmonorepo is a stale reference implementation, not the node — the node isconsensus-node.
Architecture
Section titled “Architecture”All proxy and tunnel traffic is relayed through the orchestrator. Nodes dial out to the server and hold a long-lived encrypted control tunnel (/node/tunnel); the server pushes work down it and reads responses back up. Every byte crosses the orchestrator.
Direction (in progress): control plane / data plane split
Section titled “Direction (in progress): control plane / data plane split”The data path is being migrated so the orchestrator becomes a control plane only:
- Client asks the orchestrator to route a request.
- Orchestrator authenticates, charges (x402), selects a node, and issues a short-lived Ed25519-signed ticket.
- Client connects directly to that node for the actual request/stream.
- Orchestrator serves a request itself only when no other node is available (server-as-node fallback).
Supporting decisions:
- Per-node cache. Each node (including the server-as-node) owns its cache. The orchestrator keeps sticky-by-dedupe-key routing so repeat requests reuse the same node. Free cache hits are preserved via a node-side
402challenge (hit → free; miss →402→ client pays orchestrator → ticket → retry). - SSRF enforcement moves into the node runtime (the node now fetches client-supplied URLs directly). The
consensusSSRF guard (server/utils/ssrf.ts) is being ported intoconsensus-node.
Cross-repo contracts
Section titled “Cross-repo contracts”/proxy request & response
Section titled “/proxy request & response”consensus ⇄ consensus-client. Change both sides together.
- Request:
POST /proxywith{ target_url | target_ref, method, headers, body }. - Response:
{ status, statusText, data }by default, or the full{ status, statusText, headers, data, meta }(ProxyResponse) when the request carriesx-verbose: true. - Client-controlled headers that influence routing/caching, all stripped before the upstream call:
x-cache-ttl,x-verbose,x-api-key,x-idempotency-key,x-node-region,x-node-domain,x-node-exclude.
Node control tunnel
Section titled “Node control tunnel”consensus (server/features/node-tunnel/) ⇄ consensus-node (src/tunnel/, src/crypto/). The handshake, frame format, and MESSAGE_TYPE union must stay byte-compatible:
- Versioned JSON handshake; init signed with the node’s Ed25519 identity; X25519 exchange → ChaCha20-Poly1305 keys via HKDF over the canonical-JSON transcript.
- Public-tunnel mux uses a 5-byte frame header (
type: u8+streamId: u32 BE) with opcodesSTREAM_OPEN/DATA/END/RESET/PING/PONG.
Routing tickets (in progress)
Section titled “Routing tickets (in progress)”The new primitive for the direct data plane. Shared across consensus (issuer), consensus-node (verifier), and consensus-client (bearer):
- Signing: Ed25519. The orchestrator holds the signing key; nodes learn its public key at registration and verify against it.
- Claims:
{ node_id, dedupe_key | tunnel_id, paid, exp, jti }. Node verifies signature,exp, thatnode_idis itself, that the request hashes todedupe_key, and thatjtiis unused (replay protection).
x402 facilitator
Section titled “x402 facilitator”consensus (and consensus-client, which constructs payments) ⇄ consensus-facilitator. The facilitator verifies and settles x402 payments; the orchestrator reaches it via FACILITATOR_URL. The scheme/network identifiers must match across all three — EVM (eip155:*), SVM (solana:*), and ICP (icp:*) — as registered on the server’s x402ResourceServer and accepted by the facilitator.
Keeping repos in sync
Section titled “Keeping repos in sync”When you touch a contract above:
- Update this page first.
consensus+consensus-client:/proxyshapes and routing/caching headers move together.consensus+consensus-node: tunnel handshake/frames/messages and the ticket format move together.- Note the change in each affected repo’s
CLAUDE.mdif it changes day-to-day guidance.