ZAP Protocol

Transports

ZAP is the native wire between services; HTTP is a bridge for the edge. How the transport layer is organized, and the one law that governs it.

Transports

ZAP is the wire, not a library you bolt onto TCP. The transport layer answers one question — how do two peers exchange ZAP frames — and it answers it the same way for a native RPC service, an HTTP bridge, and a full zip application, because they all sit on the same wire.

The law: ZAP inside, HTTP/WS only at the edge

There is one architectural rule, and everything below follows from it:

Internal service ↔ service traffic is ZAP. HTTPS and WebSocket appear only at the edge — the single point where the system talks to something it does not control. The edge is the only place a translation happens.

Inside a cluster, a mesh, or an agent-to-tool boundary, both peers are trusted and both speak ZAP: zero-copy framing, capability-based authority, and a post-quantum handshake at the transport layer instead of a bearer token minted per call. At the edge — a browser, a third-party client, a partner API — you terminate ZAP and translate to the classical protocol the outside world expects. Nothing internal carries HTTP semantics just to be reachable from outside.

Outside world ──HTTPS / WSS──▶ [ edge: the only translator ] ──ZAP──▶ services ──ZAP──▶ services

Three ways onto the wire

You rarely construct a socket directly. Pick the surface that matches what you're building; all three ride the same ZAP transport.

SurfacePackageUse it when
Native ZAP RPCzap-proto/goGreenfield service ↔ service — you define .zap interfaces, generate code, and want ZAP's full capability model. See Native ZAP RPC.
HTTP over ZAPzap-proto/httpYou have net/http handlers or http.Client code and want the ZAP wire underneath, unchanged. See HTTP over ZAP.
zipzap-proto/zipA full web framework — Sinatra-style routes, typed handlers, OpenAPI + MCP — with ZAP primary and HTTP extra from one Listen. See zip.

Native ZAP RPC

The Go runtime's transport package is the low-level surface. A server binds a network and address to a generated Dispatch; a client dials the same address. The network is a value (tcp, unix), with TLS and QUIC as variants:

import "github.com/zap-proto/go/transport"

// Server: serve a generated Dispatch over TCP.
srv, err := transport.Listen("tcp", ":9000", dispatch)

// Client: dial and get a Conn.
conn, err := transport.Dial("tcp", "svc.internal:9000")

transport also provides DialServe / Serve / ListenStream for bidirectional streaming, NewPool for connection pooling, ListenTLS / DialTLS for classical TLS, and a transport/quic subpackage for QUIC. In practice you use the client and server that zapgen generates from your schema, which wrap these primitives — see Native ZAP RPC.

HTTP over ZAP

zap-proto/http is a drop-in for net/http when both peers are inside the trusted boundary. Existing handlers and http.Client code work unchanged; only the wire underneath changes to ZAP, and the transport handshake uses an X-Wing hybrid post-quantum KEM (X25519 + ML-KEM-768) instead of a JWT minted per request:

zaphttp.ListenAndServe(":9999", nil)                         // server: same http.Handler
c := &http.Client{Transport: zaphttp.NewTransport("svc:9999")} // client: same http.Client

zip

zip turns the wire into a full web framework. One Listen verb takes any number of addresses, and the address scheme selects the transport — a bare address is ZAP, http:// is the HTTP bridge, and zip.RegisterTransport adds any future protocol:

app.Listen(":9653", "http://:8080") // ZAP primary + HTTP extra, one call

In the browser and at the edge

Browser → server is TLS 1.3. Chrome and Safari handle the KEM (recent versions ship X25519MLKEM768), and the application runs over wss://. The ZAP wire is fine over TLS, but the X-Wing handshake described in post-quantum terminates at the server, not in the browser. End-to-end PQ ZAP between a browser and an origin requires a server-side terminator; the browser hop is TLS.

The pattern that works today:

Browser ──(wss:// + TLS 1.3 hybrid KEM)──▶ Edge Worker ──(ZAP over X-Wing)──▶ Origin

The Edge Worker (Cloudflare Workers / Deno / Bun — any V8 isolate runtime) is the ZAP terminator: the browser sees fetch, and the Worker holds the persistent X-Wing-authenticated ZAP connection upstream. This is the edge from the law above — the one place a translation happens.

A first-class browser/WASM SDK is on the roadmap; see the per-language status on post-quantum. Today, talk to your origin via a thin Worker-side adapter using zap-proto/js or zap-proto/wasm; the X-Wing/KEM hop happens server-side.

Next steps

  • Native ZAP RPC — ZAP as your application protocol
  • HTTP over ZAP — the net/http drop-in
  • zip — the web framework over the wire
  • Post-quantum — the X-Wing handshake and per-language status
  • Gateway — the edge translator in front of a ZAP fleet

On this page