v__VERSION__

One language, three problems resolved.

ANVL — Attributed · Node · Variadic · Language

Most stacks solve this with three separate tools. Config, structured messaging, and — eventually — embedded scripting: one grammar, one parser, no exceptions. Anvil Native, the reference implementation, is a single C parser with no runtime dependencies; bindings — currently Node.js and WebAssembly — wrap it directly, so a document parses identically no matter which one reads it.

Download → Read the docs Sandbox

AML and AMP are real today. AnvilScript (ASL) is still design-only — not implemented yet.

Why ANVL?

JSON exists so that ANVL could live.

JSON was never designed — it was lifted out of a subset of JavaScript's own object literals and standardized after the fact, because it had already won on convenience. Nobody ever got to ask "is this good enough?" The answer was assumed. That's the whole problem: good enough to ship is exactly the kind of decision that costs you later, quietly, after everyone's already built on top of it.

Anvil started from the opposite direction — out of frustration with Makefile's own DSL, a look at CMake that made the climb steeper instead of easier, and a JSON experiment that ended before it began. What started as "can this be a config language" turned out to be an Object Modeling Language. Restrict a few features, and it's also a stable, deterministic messaging protocol. Anvil's dialects aren't three separate designs bolted together — they're the same grammar with different amounts of it turned on.

There's a lot more to it than a couple of paragraphs can give credit for. Read the full story →

Your Stack Needs ANVL

Anvil doesn't mince words when it comes to configuration and messaging safety. It is designed to get it right, or fail fast with clear errors and information about where things went wrong. It never silently assumes correctness, and doesn't depend on etiquette or implicit conventions. The parser enforces very few rules around symbols and structure, leaving the rest to be explicitly specified and validated by the consumer.

A bare no in your config silently becomes the boolean false. YAML's own "Norway problem" doesn't announce itself — it just quietly means the wrong thing until something breaks in production, maybe months later. ANVL's grammar never guesses: a literal is only true, false, or null if it's exactly that word. A mistake fails to parse instead of silently meaning something else.

A message schema starts as five scalar fields and quietly grows a nested object. Nobody reviews that kind of drift until a downstream consumer breaks on structure it was never built to handle. AMP, Anvil's restricted dialect, forbids objects, attributes, inheritance, and includes outright — rejected at parse time, not by convention or code review. The payload can't grow arbitrary structure even by accident.

A fuzzer or a heap dump can only expose what a parser actually held. Anvil Native's internal state is integers — byte offsets and lengths into the buffer you hand it. No string is copied during parsing, and blob payloads are skipped entirely. Under adversarial conditions, the parser can't leak payload data, because it never held any.

A look at AML

#!aml
server @[env = production] := {
    host := localhost;
    port := 8080;
    tags := [edge, cache];
};

// variables can be defined and referenced
var_ref    := 42;
derived_var := $var_ref;

/*
  Base object fields, overrides and inheritance.
*/
endpoint:server {
  host := 234.55.78.90;
};

Real throughput

Not a synthetic microbenchmark — a realistic, hand-authored-style AML config (inheritance, attributes, nested objects, arrays, mixed scalar kinds), parsed end to end (anvil_load_buffer: parse and resolve, the real cost a caller pays) by the exact release library this site ships for download. Reproducible yourself: bench/throughput.c in the repo.

1.6 KB

A small app's config, 5 services.
103 MB/s

30 KB

A moderate microservice fleet, 100 services.
123 MB/s

308 KB

A large generated environment config, 1,000 services.
125 MB/s

Throughput holds steady across two orders of magnitude of document size — no scaling cliff between a small hand-written config and a large generated one.

Why not just JSON?

JSON earned its win honestly — simple enough to hold in your head, human-readable, and by now nearly universal. Every language parses it, every API speaks it, nobody has to be taught it. That's real, hard-won success, and ANVL isn't here to take that away from it.

But JSON was built to be a wire format — one JS object literal a browser could evaluate. Config files, schemas, templated builds, structured messages: all of that got handed to JSON after the fact, not designed into it from day one. No comments. No way to reference a value you already defined. No restricted subset for contexts where a payload shouldn't be able to grow arbitrary structure. It was good enough — right up until it wasn't, and by then everyone had already built on top of it. Nobody wants to be the one who tells the senior citizen it's time to retire.

JSON ANVL
Comments Not allowed // and /* */
Reference a value you already defined Copy-paste, or a non-standard $ref convention Native $identifier, resolved once at parse time
Extend or override a template Not supported Single inheritance — Child : Base := {...}
A restricted subset for untrusted-ish payloads None — any valid JSON is valid JSON AMP dialect: scalars and flat arrays/tuples of them, no nesting, no objects — rejected otherwise at parse time
Metadata attached to a field Invent your own convention Native @[key=value] attributes
Bare identifiers as values Always quoted strings Unquoted wherever unambiguous

None of this is exotic on its own — TOML and YAML each solve pieces of it too. ANVL's bet is doing all of it under one strict, unambiguous grammar, plus a second, deliberately restricted dialect for when you want structure but not arbitrary structure.

Try it now

Download the native library or the WebAssembly bundle and parse real source in minutes — see the Bindings guide for a runnable example in each. A live in-browser sandbox is in progress.