Every case. Zero unsafe. One version.
406/406
Every official test case. No skips.
The whole YAML test suite runs on every change, through every product in the family. The same document gives the same answer in Rust, in the shell, in your editor, in the browser and in an agent.
0
Lines of unsafe code. Ever.
The compiler enforces it in every crate. Miri checks for what the compiler cannot see. Fifteen fuzzers throw hostile documents at it on every push. A malicious file is an error, never a crash.
6×1
Six products. One version number.
The library, the drop-in, the command line, the language server, the agent server and the browser build release together. Which version you have has one answer.
The family
One parser. Six ways to reach it.
Every product below is the same engine, wrapped for the place you meet YAML.
noyalib
The library. Typed, lossless, fast.
noyalib-serde-yaml
serde_yaml, without the archive notice.
noya-cli
Format. Validate. Fail the build, not the deploy.
noyalib-lsp
Diagnostics as you type. In any editor.
noyalib-mcp
YAML edits by an assistant. Byte-faithful.
noyalib-wasm
The same parser, in the browser tab.
What it does
Lossless editing
Change one value. Keep every byte you did not touch.
The lossless tree reproduces your file exactly. Comments, blank lines, quoting, indentation. A tool that bumps a version rewrites one span and nothing else. Your reviewer sees a one-line diff. Your auditor sees the same.
let mut doc = parse_document(text)?;
doc.set("version", "0.0.43")?;
// Everything else: untouched.Hostile input
Refuses the wrong thing. Fast.
A billion-laughs alias bomb. A hundred thousand levels of nesting. A two-thousand-link merge chain. Each one is refused in milliseconds with a line and a column. The limits are on by default and yours to tune.
error: alias expansion limit exceeded
--> config.yaml:12:5
= limit: 1000 expansionsStrict by design
A misspelt key is an error. Not a default.
Strict mode names the field it thinks you meant. Schema validation reports every violation with the exact path. A schema can be generated from your own types. Nothing is guessed on your behalf.
error: unknown field `retires`
did you mean `retries`?
--> limits.yaml:4:3Where it runs
Built for the configuration that runs the business.

Financial services
Routing tables, limits and scheme profiles. Read strictly. Edited without touching a neighbouring line.

Platform and Kubernetes
Multi-document manifests, parsed in parallel and validated on every commit.

CI and build pipelines
Pipeline definitions checked before they run. A non-zero exit the moment something is wrong.

Agents and automation
Version bumps and policy edits made by assistants. Every other byte left alone.
Ready for 2027
The evidence your buyers will ask for. Already in every release.
A bill of materials
A CycloneDX SBOM ships with every release, the artefact the EU Cyber Resilience Act requires from December 2027.
Memory safety, proven by the compiler
No unsafe code in any crate. The roadmap regulators asked software makers for is already the whole codebase.
Signed and attested
Every binary carries a sigstore signature and SLSA level 3 provenance. Every commit on main is signed.
Vetted dependencies
Twelve runtime crates in the library, each audited or exempted on record, checked on every push.
Coming from serde_yaml
One line. Zero source changes.
The crate most Rust services depend on was archived in 2024. Rename the package and keep every call site. Same functions. Same error text. Same behaviour, pinned by a contract suite captured from the original.
[dependencies]
serde_yaml = { package = "noyalib-serde-yaml", version = "=0.0.43" }About noyalib
Why noyalib
Configuration is code that nobody tests. It is read at start-up, trusted, and acted on. When the parser gets it wrong, the failure looks like a business decision. So the parser has to be right, every time, everywhere.
That is the whole idea behind noyalib. Start from the YAML 1.2 specification, not from a fork. Run every official test case on every change, through every product. Forbid unsafe code and let the compiler enforce it. Cap every limit a hostile document could exploit. Sign, attest and inventory every release.
Then take that one parser everywhere people meet YAML. A Rust service. A build pipeline. An editor. A browser tab. An AI assistant. Six products, one engine, one version number.
Two APIs. One parser.
The data-binding API reads YAML into typed Rust values through serde and writes them back. It is the fast path, and what most services need.
The tooling API reads YAML into a tree that reproduces the source byte for byte. Change one value and every other byte stays. The language server, the agent server and every formatter in the family are built on it.
Both share one scanner and one set of limits. Coming from serde_yaml? The one-line migration keeps your source unchanged. Starting fresh? The developer docs show the native API in ten lines.
Start with one line.
Add the crate, or rename the one you already depend on. Either way, the parser under your configuration becomes one you can audit.
