Vexil describes both the shape and the wire encoding of data crossing system boundaries. The type u4 occupies exactly 4 bits. The annotation @varint switches a field to LEB128. The schema is the wire contract, not just the shape contract.
Each schema produces a deterministic BLAKE3 hash, embedded in generated code at compile time. If a sender and receiver compile against different schemas, the mismatch is detectable before any data is read.
Quick look
namespace sensor.packet
enum SensorKind : u8 {
Temperature @0
Humidity @1
Pressure @2
Light @3
}
message SensorReading {
channel @0 : u4 # 4 bits, values 0..15
kind @1 : SensorKind
value @2 : u16
sequence @3 : u32 @varint # variable-length encoding
delta_ts @4 : i32 @zigzag # signed, ZigZag-encoded
}
Generated Rust:
use ;
let reading = SensorReading ;
let mut w = new;
reading.pack.unwrap;
let bytes = w.finish; // compact, bit-packed
let mut r = new;
let decoded = unpack.unwrap;
assert_eq!;
The same schema generates TypeScript that produces identical bytes:
import { BitWriter, BitReader } from '@vexil-lang/runtime';
const w = new BitWriter();
encodeSensorReading({
channel: 0, kind: 'Temperature',
value: 2350, sequence: 1, delta_ts: -50,
}, w);
const bytes = w.finish(); // identical bytes as Rust
const r = new BitReader(bytes);
const decoded = decodeSensorReading(r);
// decoded.value === 2350
What Vexil does
u1..u63andi2..i63occupy exactly N bits on the wire, LSB-first@varint(unsigned LEB128),@zigzag(ZigZag + LEB128), and@delta(per-field delta from previous value) are declared in the schema- Six declaration kinds:
message,enum,flags,union,newtype,config - BLAKE3 hash of the canonical schema form, embedded as a compile-time constant in generated code
- Rust and TypeScript backends from the same schema, byte-identical output verified by compliance vectors
- Same data always produces the same bytes, enabling content addressing and replay detection
- Every invalid input yields a distinct error with file, line, column, and a human-readable description
- 83-file conformance corpus (27 valid, 56 invalid) that any implementation must pass
Comparison
| Vexil | Protobuf | Cap'n Proto | FlatBuffers | |
|---|---|---|---|---|
Sub-byte types (u1..u63) |
Yes | -- | -- | -- |
| Encoding annotations in schema | Yes | -- | -- | -- |
| Schema hash (mismatch detection) | BLAKE3 | -- | -- | -- |
| LSB-first bit packing | Yes | -- | -- | -- |
| Self-describing wire format | No | Optional | No | Optional |
| Zero-copy decode | No | No | Yes | Yes |
| Deterministic encoding | Yes | No (maps) | No (padding) | No (vtables) |
| Schema evolution | Partial | Yes | Yes | Yes |
| Language targets | Rust, TS | Many | Many | Many |
Install
Pre-built binaries for Linux, Windows, and macOS are on the Releases page.
To build from source (requires Rust 1.94+):
Usage
CLI
# Check a schema for errors (prints BLAKE3 hash on success)
# Generate code
# Compile a multi-file project
# Schema-driven data tools
Errors render with source spans:
Error: duplicate field name
--> schema.vexil:8:5
|
8 | value: u32,
| ^^^^^ field "value" was already declared on line 5
Library
[]
= "0.2"
use ;
let result = compile;
if result.diagnostics.iter.any
if let Some = result.compiled
Repository layout
spec/
vexil-spec.md # Language specification (normative, S1-S14)
vexil-grammar.peg # Formal PEG grammar
corpus/
valid/ # 27 schemas -- conformant impl must accept all
invalid/ # 56 schemas -- conformant impl must reject all
projects/ # Multi-file integration tests
compliance/
vectors/ # Golden byte vectors (JSON), cross-implementation contract
crates/
vexil-lang/ # Compiler: lexer, parser, IR, type checker, canonical hash
vexil-codegen-rust/ # Rust code generation
vexil-codegen-ts/ # TypeScript code generation
vexil-runtime/ # Rust runtime: BitWriter/BitReader, Pack/Unpack, LEB128, ZigZag
vexilc/ # CLI with ariadne error rendering
vexil-store/ # .vx text and .vxb binary file formats
vexil-bench/ # Encode/decode benchmarks (Criterion)
packages/
runtime-ts/ # @vexil-lang/runtime -- TypeScript BitWriter/BitReader (npm)
examples/
sensor-packet/ # Sub-byte types, encoding annotations, compact enums
command-protocol/ # Unions, flags, limits -- RPC-style protocol
multi-file-project/ # Cross-file imports and project compilation
cross-language/ # Rust <-> Node.js interop via binary files
system-monitor/ # Live dashboard: Rust -> browser via @delta WebSocket
Documentation
- Language Specification
- FAQ
- Examples
- Limitations and Gaps
- API reference: vexil-lang | vexil-runtime | vexil-codegen-rust | vexil-codegen-ts | vexil-store
Contributing
See CONTRIBUTING.md. Language changes and protocol modifications go through the RFC process in GOVERNANCE.md.
License
Licensed under either of MIT or Apache-2.0 at your option.