aontu documentation
Rendered from
docs/index.md
in the engine repository, where a correction belongs, and where the
test suite executes every example on this page.
aontu is a JSON structure unifier: a small language (a purpose-specific dialect inspired by CUE) and an engine that merges partial structures into one consistent result, or reports exactly where they conflict. The same source can describe data, the schema that constrains it, and the defaults that fill it in: all in one notation, all combined by a single operation: unification.
This repository ships two implementations kept in parity:
- TypeScript in
ts/: the canonical implementation, published to npm asaontu. - Go in
go/: a port (github.com/aontu-lang/aontu/go) that mirrors the core semantics.
Both are checked against one language-agnostic test suite in
test/spec/, and every example in these pages is
executed by that machinery too: the outputs come from the engine, not
from the author’s memory.
How this documentation is organised
The documentation is split by what you are trying to do when you open it. Reach for the part that matches your need:
| If you want to… | Read |
|---|---|
| Learn aontu from zero by building something, step by step | Tutorials |
| Accomplish a specific task you already have in mind | How-to guides |
| Look up exact syntax, semantics, options, or API surface | Language reference · API reference, with three supplements below |
| Understand unification itself: meet, top, bottom, the lattice | Unification |
| Understand how and why the engine works the way it does | Explanation |
| See whole systems defined, each with its checks runnable | Use cases |
There are four tutorials, each building one thing and showing the output of every step: a config that is schema, defaults, and data at once; the graph layer of identity, relations, and reachability; sharing a model as a versioned package; and computing source files from a model. The index says what each one assumes.
The how-to guides are one page per task, grouped six ways: run, embed and integrate; templates, defaults and composition; schemas and constraints; query, explain and change; validate and evolve; modules and multi-file.
Three capabilities have doorways of their own:
- Declare and check relations. Entities carry identity, the edges
between them are declared in the model, and the engine checks both.
The recipe is check relations; the live
version is
use-cases/12-relations; the normative rules are under Declared relations. - Write a recursive schema. A schema can name itself, so trees and
nested structures validate to any depth. The recipe is
define a recursive schema;
the live version is
use-cases/13-recursive-schema; the semantics are under Recursive references. - Generate code from a model. The field names, types and
optionality a Go struct or a TypeScript interface needs are already
in the model, and the unifier computes the file: a rule set over the
records,
matchfor the type mapping, a backtick string to carry the target text, and a component tree of files and lines that a generator runtime writes to disk and holds against its golden. The recipe is generate code from a model; the live version, with three targets in one document and a check that both ports build identical trees, isuse-cases/15-code-generation. The rules for the tree itself are the Generation reference.
Six reference sections sit beside the two above. Each is a surface that cuts across the language reference rather than a part of it, which is what the language reference, organised by topic, cannot show at once:
- Generation reference. The component tree:
every component node, the props it carries, the children it admits,
and what
aontu renderandaontu tracedo with a tree. - Functions reference. The call surface of every built-in: arity, argument modes, accepted kinds and result words, as one table and as slices through it.
- Error reference. Every registered error code, by class, with what raises it and what a report carries.
- Packages reference. The files the package
system keeps, every field
pkg.aontudeclares, the name rules, the caps, what an archive may hold, and every refusal code. - Grammar reference. The published grammar rule by rule, the spellings the parser accepts beyond it, and what holds the four grammar files to the engine.
- Agent and editor reference. Every door a machine comes in by, the one answer shape they share, what none of them does, and the posture each takes towards includes.
Tooling:
-
The
aontucommand. One binary, nineteen verbs, both implementations. Each verb has its own reference section:- validate:
vet, wrapped for CI as a GitHub Action - evolve a schema:
subsume,breaking - ask and change:
get,why,set,trim - identity and relations:
relations,reaches,view - export and pin:
jsonschema,hash - generate:
template,trace(the guide: Generate code from a model) - depend and publish:
sync,add,get,remove,why,publish,pkg - hand over:
agentsmd - keep in the agreed form:
fmt(the form: The formatted form; the guide: Format a document)
With no file at all,
aontustarts a REPL. - validate:
-
Language Server (LSP). The
aontu-lspdiagnostics server (TypeScript and Go), how to wire it into an editor, and the reusable LSP library API. -
The MCP server.
aontu mcp, a Model Context Protocol server over stdio, answering with the identical reports the CLI prints.
For agents:
- The aontu skill. An agent-facing teaching pack: the grammar card, a worked example ladder whose documents the test suite executes, and the error-code index.
- The published
grammar:
grammar/aontu.abnfto read, with railroad diagrams;aontu.gbnfandaontu.larkfor constrained decoding.
Contract:
- The trust contract. Hermeticity, termination, determinism, and sandboxing: what a host may rely on when evaluating an aontu document, and where each guarantee is conditional.
For contributors:
- The style guide. How these pages are written: Diátaxis placement, the voice, the banned-phrase list, and the snippet directives under which every example runs.
Why the split?
The four kinds of document answer four different questions and are kept separate on purpose. A tutorial holds your hand and is allowed to omit detail; a how-to assumes you know the basics and just need the recipe; a reference is exhaustive and dry so you can trust it as the source of truth; an explanation is discursive and is the only place that argues about trade-offs. Mixing them (a reference that teaches, a tutorial that digresses into design rationale) serves none of those needs well, so each lives in its own file.
The rule applies to the toolkit as much as to the language, which is
why a verb can appear in all four kinds without any of them repeating
another: met once, in passing, while a tutorial builds something; given
as a recipe for one goal in a how-to guide; specified exhaustively
(every flag, every exit code) in the API reference; and argued for,
never merely listed, in the explanation. The use cases stand alongside
as whole worked systems, each holding a check.sh that CI runs.
A 30-second taste
# A schema, a default, and data — unified into one result.
port: *8080|integer
host: string
host: "localhost"
Unifying the three lines above yields:
{ "host": "localhost", "port": 8080 }
The port is constrained to be an integer, defaults to 8080, and,
because nothing overrode the default, 8080 is what comes out. host
is constrained to a string and pinned to "localhost". Conflicting
facts (a second port: "high", say, or a port: 1.5) are refused
with a precise error rather than silently resolved: the preferred
branch keeps the kind it names, which is
argued in the explanation.
Try it without writing a file: both implementations ship an aontu
command that evaluates a file, reads stdin, or starts a REPL:
$ echo 'port: *8080 | integer' | aontu
{
"port": 8080
}
Start with build a config that checks itself, the first of four tutorials.