Protocol overview
The wire format in detail, frames, vocab handshake, transports, compression. Everything you need to write a fifth implementation.
Start
This is a tour of PROTOCOL.md (https://github.com/wdunn001/Codec/blob/main/spec/PROTOCOL.md), the canonical spec. If you're using one of the six reference implementations you don't need to read it. The bindings already speak the protocol for you.
Layers
Codec is deliberately three thin layers on top of HTTP, not one fat envelope:
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Layer โ What it carries โ What it does NOT carry โ
โโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Token IDs โ 'uint32[]' โ Text, role markers, tool framing โ
โ Frames โ '{ids, done, finish_reason?}' โ Token semantics โ
โ Vocab handshake โ sha256-addressed JSON map โ Frames โ
โโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The handshake binds an ID space to a tokenizer; frames carry IDs in that space; the IDs map back to tokens only when a human edge needs them.
Frame format
Every frame on the wire is:
+---------------------+----------------------------+
| 4-byte BE length | msgpack OR protobuf body |
+---------------------+----------------------------+
The body is one of:
msgpack, a map with three optional keys:
{ "ids": [uint32, uint32, ...], "done": bool, "finish_reason": str (optional) }
protobuf, a 'CodecFrame' message:
code (proto):
message CodecFrame {
repeated uint32 ids = 1 [packed = true];
bool done = 2;
optional string finish_reason = 3;
}
Both bind to identical semantics. Pick msgpack if you want zero schema dependencies; pick protobuf if you want stricter typing or already have a 'protoc' toolchain.
Same payload, different planet
The seven-token request '"What is the capital of France?"' on the wire, both ways:
JSON, ~142 bytes, text:
code (http):
POST /v1/chat/completions HTTP/2
content-type: application/json
{
"model": "gpt-4",
"messages": [
{ "role": "user",
"content": "What is the capital of France?" }
]
}
Codec, 32 bytes, binary:
code (http):
POST /v1/chat HTTP/2
content-type: application/codec
01 00 00 04 // control: vocab=gpt-4 / role=user
00 00 0F A1 // "What"
00 00 09 BE // " is"
00 00 04 21 // " the"
00 00 1C 33 // " capital"
00 00 02 5A // " of"
00 00 1F 90 // " France"
00 00 02 30 // "?"
JSON pays the tokenizer twice, once when the client serializes, once when the server retokenizes the UTF-8. Codec ships the IDs the model already speaks, with one control word at the head naming the vocab and message role. That's the only framing.
Vocab handshake
A dialect map is a JSON document that fully describes a tokenizer:
โข 'vocab', the token-string-to-ID map
โข 'merges', BPE merge rules
โข 'special_tokens', reserved control IDs ('<|im_start|>', '<tool_call>', etc.)
โข 'encoder_type' ('byte_level', 'metaspace', or omitted)
โข 'pre_tokenizer_program' (optional), a small instruction list that replaces the legacy GPT-2 regex; deterministic across languages
Maps are addressed by sha256 of the canonical JSON bytes. 'loadMap({url, hash})' is 'fetch + verify + cache'. A given '(url, hash)' pair always resolves to byte-identical bytes, or 'loadMap' raises.
'github.com/wdunn001/codec-maps' (https://github.com/wdunn001/codec-maps) hosts a starter set of pre-generated maps (Llama, Qwen, Mistral, Phi, Gemma, DeepSeek, Falcon, SmolLM2, Codestral, and more), but the registry isn't a closed list. Any model with a Hugging Face 'tokenizer.json' can have a map: install '@codecai/maps-cli' (https://www.npmjs.com/package/@codecai/maps-cli) and run 'codec-maps generate <tokenizer.json>' to produce a deterministic, sha256-addressable map for your fine-tune, your private model, or anything else, same format, same 'loadMap' call, same wire bytes. The codec-maps repo accepts PRs for new models too, but you don't need to wait on one to use Codec.
Discovery
If you don't want to track URLs and hashes out of band, model maintainers can publish maps at a stable '/.well-known/codec/' path on a domain they control. Clients then resolve a map from '(origin, id)' alone:
code (ts):
import { discoverMap } from "@codecai/web/discover";
const map = await discoverMap({ origin: "https://example.com", id: "qwen2" });
This is the resolution to PROTOCOL.md's old Open Question #3 (decentralised first; a registry remains an option for cross-org and air-gapped use). Full convention: Self-hosted discovery.
HTTP transports
The spec defines three patterns over plain HTTP, in increasing weirdness:
A. Text prompt in, binary stream out
The drop-in upgrade. Same JSON request body as today's '/v1/completions', plus 'stream_format':
code (http):
POST /v1/completions HTTP/1.1
Content-Type: application/json
Accept-Encoding: gzip
{
"model": "Qwen/Qwen2.5-7B-Instruct",
"prompt": "Explain entropy.",
"stream_format": "msgpack",
"max_tokens": 256
}
Response body is a sequence of length-prefixed msgpack frames. 'Content-Type: application/codec+msgpack' (or '+protobuf').
B. Token-ID prompt, binary in, binary out
Skip the server's tokenizer call entirely:
code (json):
{
"model": "Qwen/Qwen2.5-7B-Instruct",
"prompt": [4954, 198, 11, 5234, ...],
"stream_format": "msgpack",
"max_tokens": 256
}
Useful when the client already has the IDs (e.g., during multi-hop agent flows where a previous Codec response is the next prompt).
C. Binary in, binary out: '/v1/completions/codec'
For very large prompts where even the JSON envelope is too big. The whole request body is a Codec frame; the response is a Codec stream. Documented in PROTOCOL.md ยง3.3 (https://github.com/wdunn001/Codec/blob/main/spec/PROTOCOL.md).
Compression
Codec is streaming-safe with gzip. Set 'Accept-Encoding: gzip, identity' on the request; the server compresses if it's worth it. Identity is always a valid response. Brotli was broken in v0.4.0 (per-chunk 'flush()' reset the sliding window, inflating small streams); the v0.4.1 fix in both sglang + vllm forks restores brotli's between-chunk dictionary, and brotli is now Pareto-front for 32-256 token msgpack streams, beating both gzip and dict-zstd in that size band. The server's compression negotiator honours spec preference order 'zstd > br > gzip > identity' and picks the smallest.
zstd is dict-only
zstd without a pre-trained dictionary is a trap on Codec streams: its wire-byte advantage over gzip is essentially zero (both reach โ3.4ย B/token, within noise, see RESULTS.md ยง1f (https://github.com/wdunn001/Codec/blob/main/packages/bench/RESULTS.md)) but the shipped buffered middleware in every gateway eats a 334ร TTFB cliff at 2K tokens (11ย ms โ 3,684ย ms). Same bytes as gzip, much worse first-token latency.
The pre-trained dictionary is the precondition for using zstd at all, not an optimization layered on top. Tokenizer maps now declare zstd dictionaries inline:
code (json):
{
"id": "qwen/qwen2",
"vocab": { ... },
"merges": [ ... ],
"zstd_dictionaries": [
{
"format": "msgpack",
"url": "https://raw.githubusercontent.com/wdunn001/Codec/main/dictionaries/qwen2.5-msgpack-v1.dict",
"hash": "sha256:...",
"size_bytes": 16384
},
{
"format": "protobuf",
"url": "https://raw.githubusercontent.com/wdunn001/Codec/main/dictionaries/qwen2.5-protobuf-v1.dict",
"hash": "sha256:...",
"size_bytes": 16384
}
]
}
A server with a matching dict loaded compresses against it; a client decompresses against the same one (matched by hash). The two formats train against different byte distributions, so dicts are not interchangeable across 'msgpack' / 'protobuf'. Without a loaded dict, servers MUST fall through to gzip. The picker enforces this and the '@codecai/wire-compress' library refuses to advertise zstd unless a matching dict is in place.
With a dict, dict-zstd beats gzip by 16-38% on bytes (RESULTS.md ยง1g (https://github.com/wdunn001/Codec/blob/main/packages/bench/RESULTS.md)) at +0.13ย ms streaming TTFB, sub-millisecond, dwarfed by network. So for a deployment with a dict shipped alongside the model, zstd is the right pick for both interactive and agent traffic.
'Codec-Zstd-Dict' response header
When a server responds with 'Content-Encoding: zstd', it MUST emit the hash of the dictionary it used as a 'Codec-Zstd-Dict' header:
code (http):
Content-Encoding: zstd
Codec-Zstd-Dict: sha256:79b707aea8c2b41c2883ec7913b0c4a0c880044ac844d89a9a03e779eb92db04
Vary: Accept-Encoding
The header value is 'sha256:' followed by the lowercase hex digest of the raw dictionary bytes, same shape as the 'hash' field in 'zstd_dictionaries[]' entries.
Clients check the hash against a dict they have loaded. Hash mismatch is a fatal stream error (wrong-dict zstd decompression yields garbage); a missing header on a zstd response is a server protocol error. Why a header rather than inferring from 'tokenizer_id': a single tokenizer can have multiple dict versions over time (re-trained on fresher corpora, specialised per workload). The header lets a deployment upgrade its dict without bumping the tokenizer-map version, and lets intermediaries identify the active dict by reading headers alone.
Reference dicts ship at 'dictionaries/' (https://github.com/wdunn001/Codec/tree/main/dictionaries) in the main repo; the training pipeline is 'packages/bench/scripts/train-zstd-dict.py' (https://github.com/wdunn001/Codec/blob/main/packages/bench/scripts/train-zstd-dict.py).
Request vs response (where each Codec knob lives)
Codec piggybacks on the OpenAI '/v1/completions' body schema rather than redefining the request envelope. That makes the asymmetry confusing at first. Some Codec configuration is in the request body, some is in HTTP headers (request and response), some only shows up on the response side. The table:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโ
โ Knob โ Where โ Why โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโค
โ 'stream_format: "msgpack" | "protobuf" | "json"' โ request body (next to โ Per-requ โ
โ โ 'model', 'prompt', โ est โ
โ โ 'max_tokens') โ choice โ
โ โ โ that โ
โ โ โ piggybac โ
โ โ โ ks on โ
โ โ โ the โ
โ โ โ OpenAI โ
โ โ โ body. โ
โ โ โ Default โ
โ โ โ '"json"' โ
โ โ โ keeps โ
โ โ โ existing โ
โ โ โ JSON-SSE โ
โ โ โ traffic โ
โ โ โ byte-ide โ
โ โ โ ntical; โ
โ โ โ no Codec โ
โ โ โ presence โ
โ โ โ at all โ
โ โ โ on โ
โ โ โ requests โ
โ โ โ that โ
โ โ โ don't โ
โ โ โ ask for โ
โ โ โ it. โ
โ 'model', 'prompt', 'max_tokens', 'messages', โฆ โ request body โ Standard โ
โ โ โ OpenAI โ
โ โ โ fields. โ
โ โ โ Codec โ
โ โ โ doesn't โ
โ โ โ touch โ
โ โ โ them. โ
โ 'Content-Type: application/json' โ request header โ Standard โ
โ โ โ HTTP for โ
โ โ โ the JSON โ
โ โ โ body. โ
โ 'Accept-Encoding: zstd, br, gzip, identity' โ request header โ The โ
โ โ โ client's โ
โ โ โ compress โ
โ โ โ ion โ
โ โ โ menu. โ
โ โ โ The โ
โ โ โ server's โ
โ โ โ negotiat โ
โ โ โ or picks โ
โ โ โ per spec โ
โ โ โ preferen โ
โ โ โ ce 'zstd โ
โ โ โ > br > โ
โ โ โ gzip > โ
โ โ โ identity โ
โ โ โ ' and โ
โ โ โ picks โ
โ โ โ the โ
โ โ โ smallest โ
โ โ โ valid โ
โ โ โ for the โ
โ โ โ response โ
โ โ โ size. โ
โ โ โ v0.4.1 โ
โ โ โ made โ
โ โ โ brotli โ
โ โ โ usable โ
โ โ โ across โ
โ โ โ all โ
โ โ โ sizes โ
โ โ โ and โ
โ โ โ landed โ
โ โ โ dict-zst โ
โ โ โ d decode โ
โ โ โ in every โ
โ โ โ client. โ
โ โ โ Advertis โ
โ โ โ ing the โ
โ โ โ full โ
โ โ โ menu is โ
โ โ โ now โ
โ โ โ correct โ
โ โ โ for โ
โ โ โ every โ
โ โ โ binding. โ
โ 'Codec-Client-Version: 0.4' โ request header โ v0.4 โ
โ โ โ normativ โ
โ โ โ e. โ
โ โ โ Client โ
โ โ โ advertis โ
โ โ โ es the โ
โ โ โ maximum โ
โ โ โ spec โ
โ โ โ version โ
โ โ โ it can โ
โ โ โ correctl โ
โ โ โ y โ
โ โ โ decode. โ
โ โ โ The โ
โ โ โ server โ
โ โ โ uses โ
โ โ โ this to โ
โ โ โ pick a โ
โ โ โ graceful โ
โ โ โ downgrad โ
โ โ โ e if the โ
โ โ โ deployme โ
โ โ โ nt โ
โ โ โ requires โ
โ โ โ newer โ
โ โ โ features โ
โ โ โ . โ
โ โ โ Omitting โ
โ โ โ it on a โ
โ โ โ v0.4 โ
โ โ โ deployme โ
โ โ โ nt is โ
โ โ โ equivale โ
โ โ โ nt to โ
โ โ โ claiming โ
โ โ โ v0.3. โ
โ โ โ You get โ
โ โ โ the v0.3 โ
โ โ โ wire โ
โ โ โ surface. โ
โ 'Codec-Tokenizer-Map: <id> sha256:<short>' โ response header โ Identifi โ
โ โ โ es + โ
โ โ โ hash-pin โ
โ โ โ s the โ
โ โ โ vocab โ
โ โ โ the โ
โ โ โ server โ
โ โ โ is โ
โ โ โ using. โ
โ โ โ Client โ
โ โ โ verifies โ
โ โ โ before โ
โ โ โ decoding โ
โ โ โ (mismatc โ
โ โ โ h = โ
โ โ โ fail-fas โ
โ โ โ t, stops โ
โ โ โ KV-cache โ
โ โ โ poisonin โ
โ โ โ g). โ
โ 'Codec-Zstd-Dict: sha256:<short>' โ response header โ Identifi โ
โ โ โ es the โ
โ โ โ pre-trai โ
โ โ โ ned zstd โ
โ โ โ dict โ
โ โ โ when โ
โ โ โ 'Content โ
โ โ โ -Encodin โ
โ โ โ g: โ
โ โ โ zstd'. โ
โ โ โ Multiple โ
โ โ โ dicts โ
โ โ โ per โ
โ โ โ tokenize โ
โ โ โ r is โ
โ โ โ allowed; โ
โ โ โ the โ
โ โ โ header โ
โ โ โ is how โ
โ โ โ the โ
โ โ โ client โ
โ โ โ picks โ
โ โ โ the โ
โ โ โ right โ
โ โ โ local โ
โ โ โ copy. โ
โ 'Content-Encoding: zstd | br | gzip | identity' โ response header โ The โ
โ โ โ encoding โ
โ โ โ the โ
โ โ โ server โ
โ โ โ chose โ
โ โ โ from the โ
โ โ โ request' โ
โ โ โ s โ
โ โ โ 'Accept- โ
โ โ โ Encoding โ
โ โ โ '. โ
โ 'Codec-Safety-Policy-Id', 'Codec-Safety-Policy-Hash' โ response header (v0.4) โ Identifi โ
โ โ โ es the โ
โ โ โ safety โ
โ โ โ policy โ
โ โ โ the โ
โ โ โ server โ
โ โ โ enforced โ
โ โ โ . Pairs โ
โ โ โ with the โ
โ โ โ hash-anc โ
โ โ โ hored โ
โ โ โ descript โ
โ โ โ or at โ
โ โ โ '/.well- โ
โ โ โ known/co โ
โ โ โ dec/poli โ
โ โ โ cies/<id โ
โ โ โ >.json'. โ
โ 'Codec-Min-Version', 'Codec-Required-Features' โ response header on 426 โ Server's โ
โ โ (v0.4) โ enforcem โ
โ โ โ ent โ
โ โ โ floor. โ
โ โ โ Returned โ
โ โ โ when the โ
โ โ โ client's โ
โ โ โ 'Codec-C โ
โ โ โ lient-Ve โ
โ โ โ rsion' โ
โ โ โ falls โ
โ โ โ short. โ
โ 'finish_reason: "policy_violation"' โ in-frame field (v0.4) โ Surfaces โ
โ โ โ inside a โ
โ โ โ 'CodecFr โ
โ โ โ ame.fini โ
โ โ โ sh_reaso โ
โ โ โ n' when โ
โ โ โ a โ
โ โ โ server-s โ
โ โ โ ide โ
โ โ โ safety โ
โ โ โ action โ
โ โ โ fired โ
โ โ โ mid-stre โ
โ โ โ am. Not โ
โ โ โ a โ
โ โ โ header. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโ
Why no 'Codec-Stream-Format' header? We considered it. The OpenAI request body already carries 'model' + 'prompt' + 'max_tokens' + 'stream', so making 'stream_format' a sibling field there was the smallest possible patch into upstream sglang / vllm / llama.cpp's request validator, one extra optional field, JSON-Schema-compatible, no header parser changes. The v0.5 plan covers a separate negotiation path (OPTIONS preflight + a persistent 'Codec-Session' token) that would let frequent agent-mesh clients drop most per-request bytes, but the per-request knob staying in the body is by design.
A complete v0.4.1 client request looks like:
code (http):
POST /v1/completions HTTP/1.1
Host: inference.example.com
Content-Type: application/json
Accept-Encoding: zstd, br, gzip, identity
Codec-Client-Version: 0.4
{
"model": "Qwen/Qwen2.5-7B-Instruct",
"prompt": "Explain entropy in one paragraph.",
"stream": true,
"stream_format": "msgpack",
"max_tokens": 256
}
And the response headers that come back:
code (http):
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Encoding: zstd
Codec-Tokenizer-Map: qwen2 sha256:62c2f94f...
Codec-Zstd-Dict: sha256:79b707ae...
Codec-Safety-Policy-Id: lab-vinez-prod
Codec-Safety-Policy-Hash: sha256:4d8a91...
<msgpack frames, zstd-compressed against the pinned dict>
The two halves carry different things: the request-side headers + body declare what the client wants and can decode; the response headers tell the client what it actually got and how to interpret it.
Headers (the full v0.4 / v0.4.1 floor)
Every Codec response carries a small set of HTTP response headers that name the wire-level capabilities the server is using. v0.4 normalised the floor; v0.4.1 closed the cross-client decode gap. The normative table lives in 'spec/versions/v0.4.md' ยง Graceful downgrade (https://github.com/wdunn001/Codec/blob/main/spec/versions/v0.4.md). The short version:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโ
โ Header โ Direction โ Introduced โ Purpose โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโค
โ 'Codec-Tokenizer-Map: <id> โ response โ v0.2 โ Identifi โ
โ sha256:<short>' โ โ โ es + โ
โ โ โ โ hash-pin โ
โ โ โ โ s the โ
โ โ โ โ vocab โ
โ โ โ โ the IDs โ
โ โ โ โ belong โ
โ โ โ โ to. โ
โ โ โ โ Receiver โ
โ โ โ โ verifies โ
โ โ โ โ before โ
โ โ โ โ decoding โ
โ โ โ โ (mismatc โ
โ โ โ โ h is โ
โ โ โ โ fail-fas โ
โ โ โ โ t, stops โ
โ โ โ โ KV-cache โ
โ โ โ โ poisonin โ
โ โ โ โ g). โ
โ 'Codec-Zstd-Dict: โ response โ v0.3 โ Identifi โ
โ sha256:<short>' โ โ โ es + โ
โ โ โ โ hash-pin โ
โ โ โ โ s the โ
โ โ โ โ pre-trai โ
โ โ โ โ ned zstd โ
โ โ โ โ dictiona โ
โ โ โ โ ry used โ
โ โ โ โ to โ
โ โ โ โ compress โ
โ โ โ โ the โ
โ โ โ โ body. โ
โ โ โ โ MUST be โ
โ โ โ โ present โ
โ โ โ โ when โ
โ โ โ โ 'Content โ
โ โ โ โ -Encodin โ
โ โ โ โ g: โ
โ โ โ โ zstd'. โ
โ โ โ โ Multiple โ
โ โ โ โ dict โ
โ โ โ โ versions โ
โ โ โ โ can โ
โ โ โ โ coexist โ
โ โ โ โ per โ
โ โ โ โ tokenize โ
โ โ โ โ r; the โ
โ โ โ โ header โ
โ โ โ โ lets a โ
โ โ โ โ deployme โ
โ โ โ โ nt โ
โ โ โ โ rotate โ
โ โ โ โ dicts โ
โ โ โ โ without โ
โ โ โ โ re-cutti โ
โ โ โ โ ng the โ
โ โ โ โ map. โ
โ 'Content-Encoding: zstd | โ response โ v0.2 (gzip), v0.3 (zstd), v0.4 (br) โ The โ
โ br | gzip | identity' โ โ โ negotiat โ
โ โ โ โ or โ
โ โ โ โ honours โ
โ โ โ โ spec โ
โ โ โ โ preferen โ
โ โ โ โ ce order โ
โ โ โ โ 'zstd > โ
โ โ โ โ br > โ
โ โ โ โ gzip > โ
โ โ โ โ identity โ
โ โ โ โ ' and โ
โ โ โ โ picks โ
โ โ โ โ the โ
โ โ โ โ smallest โ
โ โ โ โ valid โ
โ โ โ โ encoding โ
โ โ โ โ for the โ
โ โ โ โ response โ
โ โ โ โ size. โ
โ โ โ โ v0.4.1 โ
โ โ โ โ fixed a โ
โ โ โ โ brotli โ
โ โ โ โ per-chun โ
โ โ โ โ k-flush โ
โ โ โ โ bug; โ
โ โ โ โ brotli โ
โ โ โ โ is now โ
โ โ โ โ Pareto-f โ
โ โ โ โ ront for โ
โ โ โ โ 32-256-t โ
โ โ โ โ oken โ
โ โ โ โ msgpack โ
โ โ โ โ streams. โ
โ 'Codec-Client-Version: โ request โ v0.4 โ Client โ
โ <major.minor>' โ โ โ advertis โ
โ โ โ โ es the โ
โ โ โ โ maximum โ
โ โ โ โ spec โ
โ โ โ โ version โ
โ โ โ โ it can โ
โ โ โ โ correctl โ
โ โ โ โ y โ
โ โ โ โ decode. โ
โ โ โ โ Used by โ
โ โ โ โ the โ
โ โ โ โ server โ
โ โ โ โ to pick โ
โ โ โ โ a โ
โ โ โ โ graceful โ
โ โ โ โ downgrad โ
โ โ โ โ e path. โ
โ 'Codec-Min-Version: โ response (426) โ v0.4 โ Server's โ
โ <major.minor>' โ โ โ minimum โ
โ โ โ โ supporte โ
โ โ โ โ d spec โ
โ โ โ โ version. โ
โ โ โ โ Returned โ
โ โ โ โ on the โ
โ โ โ โ 426 โ
โ โ โ โ Upgrade โ
โ โ โ โ Required โ
โ โ โ โ response โ
โ โ โ โ when the โ
โ โ โ โ client โ
โ โ โ โ falls โ
โ โ โ โ short. โ
โ 'Codec-Required-Features: โ response (426) โ v0.4 โ Comma-se โ
โ <csv>' โ โ โ parated โ
โ โ โ โ list of โ
โ โ โ โ feature โ
โ โ โ โ names โ
โ โ โ โ the โ
โ โ โ โ deployme โ
โ โ โ โ nt โ
โ โ โ โ requires โ
โ โ โ โ (e.g. โ
โ โ โ โ 'safety- โ
โ โ โ โ policy-e โ
โ โ โ โ nforceme โ
โ โ โ โ nt, โ
โ โ โ โ mandator โ
โ โ โ โ y-classi โ
โ โ โ โ fier'). โ
โ โ โ โ Returned โ
โ โ โ โ with 426 โ
โ โ โ โ alongsid โ
โ โ โ โ e โ
โ โ โ โ 'Codec-M โ
โ โ โ โ in-Versi โ
โ โ โ โ on'. โ
โ 'Codec-Safety-Policy-Id: โ response โ v0.4 โ Identifi โ
โ <id>' โ โ โ es the โ
โ โ โ โ safety โ
โ โ โ โ policy โ
โ โ โ โ the โ
โ โ โ โ server โ
โ โ โ โ enforced โ
โ โ โ โ on this โ
โ โ โ โ response โ
โ โ โ โ (operato โ
โ โ โ โ r-side โ
โ โ โ โ categori โ
โ โ โ โ es, โ
โ โ โ โ action โ
โ โ โ โ types). โ
โ โ โ โ Pairs โ
โ โ โ โ with โ
โ โ โ โ 'Codec-S โ
โ โ โ โ afety-Po โ
โ โ โ โ licy-Has โ
โ โ โ โ h'. โ
โ 'Codec-Safety-Policy-Hash: โ response โ v0.4 โ Hash of โ
โ sha256:<short>' โ โ โ the โ
โ โ โ โ sanitize โ
โ โ โ โ d โ
โ โ โ โ descript โ
โ โ โ โ or โ
โ โ โ โ served โ
โ โ โ โ at โ
โ โ โ โ '/.well- โ
โ โ โ โ known/co โ
โ โ โ โ dec/poli โ
โ โ โ โ cies/<id โ
โ โ โ โ >.json'. โ
โ โ โ โ The โ
โ โ โ โ descript โ
โ โ โ โ or โ
โ โ โ โ publishe โ
โ โ โ โ s the โ
โ โ โ โ shape of โ
โ โ โ โ enforcem โ
โ โ โ โ ent but โ
โ โ โ โ never โ
โ โ โ โ operator โ
โ โ โ โ -interna โ
โ โ โ โ l โ
โ โ โ โ banned-t โ
โ โ โ โ oken โ
โ โ โ โ lists or โ
โ โ โ โ threshol โ
โ โ โ โ ds. Hash โ
โ โ โ โ mismatch โ
โ โ โ โ โ client โ
โ โ โ โ refuses โ
โ โ โ โ the โ
โ โ โ โ stream. โ
โ 'finish_reason: โ response โ v0.4 โ Surfaces โ
โ "policy_violation"' โ โ โ when a โ
โ (in-frame, not a header) โ โ โ server-s โ
โ โ โ โ ide โ
โ โ โ โ safety โ
โ โ โ โ action โ
โ โ โ โ fired โ
โ โ โ โ mid-stre โ
โ โ โ โ am. โ
โ โ โ โ Distinct โ
โ โ โ โ from โ
โ โ โ โ 'length' โ
โ โ โ โ , โ
โ โ โ โ 'stop', โ
โ โ โ โ 'tool_ca โ
โ โ โ โ ll'. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโ
What v0.4.1 changed about the headers
โข No new headers, no header bytes on the wire change. v0.4.1 is wire-additive over v0.4.
โข Brotli per-chunk-flush bug fixed in both sglang + vllm forks. 'Content-Encoding: br' now compresses correctly across chunk boundaries instead of inflating small streams (was 1,159 B on a 975 B identity stream pre-fix; now Pareto-front for 32-256-token msgpack).
โข 'Codec-Zstd-Dict' decode now works across all 6 clients. Pre-v0.4.1 only the Python client decoded the dict-zstd payload correctly; the other 5 either silently returned compressed bytes or threw "Dictionary mismatch". v0.4.1 ships real dict-zstd support in TS/Web, .NET, Rust, Java, and C, gated by a shared cross-client interop fixture. The header was always emitted correctly; the client side just couldn't act on it.
โข llama.cpp gained brotli + zstd. Pre-v0.4.1 the llama.cpp fork only supported identity + gzip. v0.4.1 adds 'codec_brotli_streamer' + 'codec_zstd_streamer' + the 'codec_zstd_dict_registry', so the same 'Content-Encoding' negotiation now works on all three engines. The '/codec/schema' endpoint also lands so the engine-acceptance pytest can probe llama.cpp the same way it probes sglang and vllm.
The 426 dance
A v0.4 server that requires a feature the client can't satisfy returns:
HTTP/1.1 426 Upgrade Required
Codec-Min-Version: 0.4
Codec-Required-Features: safety-policy-enforcement, mandatory-classifier
Content-Type: application/json
{
"error": "codec_version_required",
"client_version": "0.3",
"required_features": ["safety-policy-enforcement", "mandatory-classifier"],
"deployment_id": "lab-vinez-prod" // optional; operator may omit
}
The client can upgrade and retry, or surface the requirement to the user. A v0.3 client that doesn't understand 426 just sees an HTTP error, graceful from the spec's perspective. The body's 'client_version' echoes what the server saw, so a misconfigured 'Codec-Client-Version' shows up at debug time.
Polyglot bit-identical
The six reference implementations (TypeScript, Python, .NET, C, Rust, Java) all produce byte-identical wire output for the same inputs. The CI matrix encodes the same prompt with each binding and asserts a SHA match. If your seventh implementation matches the bytes from any one of those, you're correct.