Exact binary protocols, defined as types
Vexil is my attempt to make binary protocol decisions explicit, reviewable, and portable. A Vexil schema defines both the shape of the data and its exact representation on the wire: bit widths, field ordinals, integer encodings, bounds, and evolution rules live together instead of being scattered across handwritten codecs.
From one contract, the toolchain generates codecs for Rust, TypeScript, Go, and Python. The goal is not merely smaller messages. It is to make the same value produce the same bytes everywhere—and to make protocol drift visible before it ships.
Why I am building it
Binary formats often begin as a few reasonable encoding choices and gradually become an undocumented agreement between implementations. The hard part is rarely encoding a number. It is preserving the contract as languages, teams, and versions diverge.
Vexil treats that agreement as a language of its own. Schemas carry a canonical hash, and the compatibility checker classifies changes before they become production surprises. That makes the wire format something a person can inspect and reason about, not just an incidental result of code.
What the project includes
- A schema language with exact-width integers, enums, messages, collections, imports, and explicit wire encodings.
- A compiler and CLI for checking schemas, generating codecs, and evaluating compatibility.
- Generated runtimes for Rust, TypeScript, Go, and Python.
- A normative language specification and binary wire-format specification.
- Shared conformance vectors, cross-language examples, and an emerging language-server surface.
The interesting constraint
The wire format is deliberately not self-describing. Both peers compile the schema they intend to use and can compare its hash. This trades runtime flexibility for compactness and an exact, inspectable contract—a useful constraint for telemetry, embedded systems, and other protocols where representation matters.
Current state
Vexil is pre-1.0. Rust and TypeScript currently have the broadest generated-code evidence; Go and Python cover a representative shared wire matrix but do not yet have the same breadth. The language server on the main branch reports compiler diagnostics, while richer editor capabilities remain future work.
That boundary is part of the project rather than a footnote. I want the documentation to say not only what works, but how strongly each claim is supported.
Where to explore
Start with the project website for the documentation and specifications, or inspect the source and examples on GitHub. The quickstart follows one schema through generation, exact bytes, and a round trip; the cross-language example exercises the same fixture in all four generated targets.