The parser-free core
Reading source code is the most dangerous thing vidi does. Nineteen tree-sitter grammars, all of them generated C, run over whatever happens to be in your repository.
So the code that decides whether you pass never does it.
The one-way edge
The workspace manifest states the doctrine in its own header: six crates whose dependency edges point one way, into a parser-free trusted core. Nothing the core trusts ever sees a parser.
vidi-lang 19 tree-sitter grammars + a Markdown profile ─┐
vidi-graph significance scoring, advisory only ─┼─→ vidi-core
vidi-cli filesystem and CLI glue ─┘ decides
vidi-core holds everything that produces a verdict: addressing and digests,
in-toto records, the ledger, trust policy, signature and notary verification. It depends
on no internal crate, not one path dependency in its manifest.
The mechanism is that simple, and Cargo checks it on every build. Doctrine in a comment is a wish; doctrine as a dependency edge is enforced.
Why parsers specifically
A parser’s input is untrusted by definition. The scan reads whatever is
committed, and a generated, minified, or deliberately hostile file can nest
arbitrarily deep: a 20,000-level parenthesis chain, a 50,000-segment qualified
name. Every recursive descent in vidi-lang carries a depth cap for exactly
that reason.
Keeping the grammars out of the deciding path bounds what a bad file can do. It can crash the scanner, produce nonsense units, or refuse to parse. It cannot forge a verdict, because nothing it touches is trusted by the code that computes one.
What the name overstates
vidi-core is not literally free of parsing. It depends on seven external
crates, and two of them decode formats:
| Crate | Why it is there |
|---|---|
blake3 | the sole content-addressing hash |
serde · serde_json | the exact bytes a record is hashed from, and the ledger line format |
toml | .vidi/policy.toml, with Spanned byte offsets for diagnostics |
ed25519-dalek · sha2 | signature verification and the keyid fingerprint |
libc | O_NOFOLLOW for the ledger custody seam, Unix targets only |
So the core does parse, but only its own small, controlled formats. What it never parses is a programming language. That claim is narrower than the name suggests.
The cost, in hand-written code
Adding a dependency to the core is expensive, so small things get written rather
than imported. The policy glob matcher is 186 hand-rolled lines, and its module
docs say why plainly: a vendored glob engine would be far more attack surface
than these few lines. Errors are hand-rolled too, with no thiserror.
Every dependency in the core’s manifest carries a comment arguing for its existence, and the workspace catalog is grown at first use, never ahead of a consumer, so the tree never carries an unused edge.
What sits outside, and why
Two crates are excluded on purpose, and neither is a parser:
vidi-graph computes significance, meaning how much a change matters. It is
advisory and never feeds a content hash. Ranking is allowed to be clever,
heuristic, and wrong; it orders a queue rather than deciding an outcome, so it
does not need to be trusted.
vidi-interop binds the engine’s output for renderers and never re-derives
a verdict. Clients display what the core decided; they do not recompute it.
The line is not “parsers outside, everything else inside”. It is: anything that could be wrong without being dangerous stays out.
No unsafe anywhere
All six crates carry #![forbid(unsafe_code)], the core included. The compiler
rejects hand-written unsafe, so memory-safety review has no surface to cover.
The tree-sitter grammars are still C, linked in. The forbid applies to vidi’s
own Rust, not to what it links.
Where it frays
The core still decodes untrusted input. Ledger lines, policy files, and signature envelopes all arrive from outside and all go through a decoder. Parsing is reduced to small controlled formats, not eliminated, which is why those paths fail closed on any doubt rather than trusting a successful parse.
Hand-rolled means fewer eyes. A bespoke glob matcher has bespoke bugs, and 186 lines maintained here get far less scrutiny than a widely used crate. The trade buys a smaller, auditable surface at the price of shared maintenance. That is a trade rather than a free win.
The grammars still ship. They are excluded from the deciding path, not from the product. A parser bug is still a bug you experience; the guarantee is only that it cannot become a forged verdict.