Protocol specification v0.1

One Protocol.
Three Patterns.

FLUXAR unifies RPC, Streaming, and PubSub in a single binary envelope. Seven message types. One connection. Zero compromises.

FLUXAR ENVELOPECBOR · 7 fields
{ type: 2, // call
  id: 0xa3f1…, // binary UUID
  ref: null, // new request (no ref = request)
  target: "user.getProfile",
  meta: { trace_id: "…" },
  payload: { id: 42 },
  error: null }
7
Message Types
7
Envelope Fields
~500
Lines for Core
4
Transports
// The problem

Why FLUXAR Exists

Modern applications communicate in three fundamentally different patterns: request-response for APIs and queries, streaming for LLM token generation and real-time analytics, and publish-subscribe for chat messages and notifications.

Today, if your application needs all three, you wire together multiple protocols — gRPC for RPC, MQTT or NATS for pub/sub, custom WebSocket framing for streaming. Each has its own connection, its own serialisation, its own error model, its own auth flow. The glue between them is your problem.

The idea

What if one protocol handled all three?

Not by being the largest common denominator — but by finding the smallest set of primitives that naturally compose into all three patterns.

FLUXAR is built on one observation: every message interaction is either a one-shot (I send, you reply) or a continuation (this belongs to an ongoing exchange). If you can express "this message is a response to that message", you can build everything else. That is the ref mechanism.

Principles

Symmetry

After the handshake, both sides are equal. No "client" and "server" — only two peers. A mobile app can receive server-initiated RPC calls. Two backend services can subscribe to each other's events on the same connection.

Asynchrony

Sending and receiving are completely independent. Fire ten requests without waiting for the first response. The ref field correlates them. No head-of-line blocking at the protocol level.

Transport Agnosticism

FLUXAR doesn't care how bytes travel. The protocol defines a message format and processing pipeline; the transport is pluggable. Your application code stays the same — only the connection setup differs.

One Envelope

Every message — handshake, RPC call, stream chunk, subscription, event — uses the same seven-field envelope. No second wire format for "control frames". Parsers are simple. Debuggers work on everything.

Binary by Default

CBOR, not JSON. Binary UUIDs (16 bytes) instead of strings (36 bytes). Integer type codes instead of names. ~50 bytes saved per message — matters at scale and on constrained devices. IETF standard (RFC 8949) with libraries in every language.

What FLUXAR is not
Not a message broker. FLUXAR is a wire protocol between two peers. It provides PubSub semantics, but routing, persistence, and fan-out are the implementation's responsibility.
Not a replacement for HTTP. Browsers need HTTP for loading pages, REST APIs, CDN caching. FLUXAR is for persistent connections where bidirectional, asynchronous communication matters.
Not opinionated about your data model. The payload field carries any CBOR value. No prescribed schemas or validation — optional introspection is available if you want it.
// The difference

One Protocol Instead of Three

Stop gluing protocols together. One connection, one format, one auth flow.

Today's stack
gRPCRPC
MQTT / NATSPubSub
Custom WSStreaming
3 connections 3 serialisation formats 3 auth flows 3 error models Glue code = your problem
FLUXAR
FLUXAR RPC + Streaming + PubSub
1 connection 1 envelope (CBOR) 1 auth flow 1 error model Zero glue code
// Core concept

The ref Mechanism

One field turns any message from request into response. That's the entire trick.

Request
id: 0xA1  ref: null  target: "user.get"
Response
id: 0xB2  ref: 0xA1  payload: {…}
Stream open
id: 0xC3  target: "ai.generate"
Stream data
ref: 0xC3  payload: "Hello"
Stream data
ref: 0xC3  payload: " world"
Stream end
ref: 0xC3  target: "end"

Messages, not methods

Every message has an id. If it also carries a ref, it's a response to that id. No ref — it's a new request. Same type, same envelope.

From this single primitive, three communication patterns emerge naturally — no special-casing, no separate wire formats.

RPC = request + response Stream = open + data* + end PubSub = subscribe + messages
// Async model

Send Now, Receive Whenever

Requests don't wait for responses. No head-of-line blocking. Ever.

Traditional (HTTP / gRPC)
REQ 1RES 1
REQ 2blocked
REQ 3waiting…
Each request blocks until its response arrives. Slow query on REQ 1 delays everything behind it.
FLUXAR
REQ 1REQ 2REQ 3→ all sent
RES 3ref: 3
RES 1ref: 1
RES 2ref: 2
Fire all requests immediately. Responses arrive in any order — ref correlates them. A slow database query on one request doesn't delay the others.
// Symmetry

Peers, Not Client & Server

After the handshake, both sides are equal. Either can call, stream, subscribe, publish.

Handshake (asymmetric)
Initiator
hello →
← response
Responder
handshake complete
After handshake (symmetric)
Peer A
call ⇄ call
stream ⇄ stream
subscribe ⇄ publish
Peer B
Mobile app receives server-initiated RPCs Two services subscribe to each other's events Browser and server as equal peers
// Wire format

CBOR, Not JSON

Binary serialisation that's compact, self-describing, and handles raw bytes natively.

JSON — typical approach
{
  "type": "call",
  "id": "0190d4a8-7b3c-7def-8abc-123456789012",
  "ref": null,
  "target": "user.getProfile",
  "meta": { "trace_id": "abc123" },
  "payload": { "id": 42 },
  "error": null
}
~210 bytes · text UUIDs · string keys · base64 for binary
CBOR — FLUXAR
{
  1,                              // type as integer
  h'0190d4a87b3c7def8abc…',      // 16-byte binary UUID
  null,
  "user.getProfile",
  { "trace_id": "abc123" },
  { "id": 42 },
  null
}
~89 bytes · binary UUIDs · integer codes · native binary data
~58%smaller per message
0base64 overhead for binary data
RFC 8949IETF standard · libraries everywhere
Selfdescribing — parser knows boundaries
// Processing pipeline

Message → Wire → Message

Clean transform chain. Extensions plug in without changing the core.

SEND
{ }Message
CBOR encode
Compressoptional
Encryptoptional
Wire
RECEIVE
Wire
Decryptoptional
Decompressoptional
CBOR decode
{ }Message
Extensions are negotiated during the handshake via capabilities. Before handshake completes, messages travel as plaintext CBOR. After — full pipeline activates with all negotiated transforms.
// Patterns

Three Patterns, One Envelope

RPC, Streaming, and PubSub — all built from the same seven message types.

Request / Response

Classic RPC. Send a call — get a call back with ref pointing to your request. Fully async: fire ten requests, receive responses in any order.

call → call(ref) // that's it

Streaming

Open a stream, send data chunks, end or cancel. Full lifecycle state machine: IDLE → ACTIVE → CANCELLING → CLOSED. Backpressure via pause/resume.

stream → stream(ref)* → stream(ref, "end")

Pub / Sub

Subscribe to topics, publish events, receive messages with ack/nack. Three delivery guarantee modes: at-most-once, at-least-once, exactly-once.

subscribe → message(ref)* → unsubscribe
// Architecture

Six Clean Layers

Each layer has one job. Implementations can be swapped independently.

L5PatternsRPC, Streaming, PubSub application patterns
L4SessionHandshake, auth, heartbeat, resume, version negotiation
L3MessageEnvelope structure, 7 types, ref correlation mechanism
L2Wire FormatCBOR serialisation, optional compression & encryption
L1FramingLength-prefixed message boundaries within byte stream
L0TransportWebSocket, TCP, QUIC, Unix socket
// Transport agnostic

Run Anywhere

Same application code, different transports. Only the connection setup changes.

WS

WebSocket

Browsers and web clients. Native frame boundaries, TLS via wss://

TCP

TCP

Backend services. Length-prefixed framing, TLS 1.3

Q

QUIC

Mobile apps. Connection migration, 0-RTT, multiplexed streams

UX

Unix Socket

Local IPC. Zero network overhead, file-system permissions

// Security

Secure by Default

TLS 1.3 approach: few options, strong defaults, forward secrecy.

🔑

4 Auth Schemes

Bearer token, API key, credentials, and custom. Independent PSK peer trust layer for service meshes.

🔒

E2E Encryption

Application-level encryption atop transport TLS. X25519 key exchange with AES-256-GCM or ChaCha20-Poly1305.

🔄

Forward Secrecy

Ephemeral keys per session. Compromise of long-term keys doesn't expose past traffic.

🛡️

DoS Protection

Message size limits, rate limiting, heartbeat timeouts, backpressure controls.

// Use cases

Built For

Real-time Apps

Chat, collaboration, gaming — bidirectional streaming + PubSub on a single connection.

Microservices

RPC + event-driven patterns without gluing together multiple protocols.

Mobile

QUIC with connection migration, session resume on network switch.

IoT & Edge

CBOR compactness, PSK mutual auth, minimal overhead on constrained devices.

AI / LLM

Streaming token delivery with cancel, backpressure, and lifecycle control.

Peer-to-Peer

Symmetric protocol — both sides are equal peers after handshake.

// Conformance levels

Start Small, Grow Complete

Two conformance levels. Adopt incrementally.

FLUXAR Core

~500 lines

Implement in a day. Everything you need to start.

  • RPC (request / response)
  • One transport (WebSocket or TCP)
  • CBOR serialisation
  • Basic handshake
  • Error handling
FLUXAR Complete

Full Power

Everything the protocol offers. Production-grade.

  • Streaming with state machine
  • PubSub with delivery guarantees
  • Session resume
  • E2E encryption
  • Compression (Zstd / Gzip)
  • All four transports

Ready to dive in?

Read the full specification, explore the design decisions, or start implementing.