Everything on this page is the implemented grammar — cross-checked against
compiler/src/lex.rs, compiler/src/parse.rs, and the .mz files CI gates on every
push. Where RFC-0001’s illustrative examples differ, Status
records the divergence.The method: design against named failure modes
RFC-0001 does not open with a syntax proposal. It opens with a table of nine things that go wrong when a language model writes code, and then justifies every decision against one of them. Its own rule: “If a decision doesn’t trace to a failure mode, it doesn’t belong in the language.”A whole component
This isexamples/connectivity_bar.mz verbatim — a hand port of a real registry component
(n7-shell/nyuchi-connectivity-bar) whose TypeScript and Rust implementations both exist, so
every line is checkable against known ground truth. RFC examples come from the benchmark
corpus, never invented.
examples/connectivity_bar.mz
use statements for the button it renders, no
lifetimes, no &, no .to_string(), no #[derive], no pub, no braces, no semicolons.
end, with the name echoed back — FM-2
Blocks close with end. Top-level declarations close with end <kind> <name>, and the
parser cross-checks the echo. A mismatched or missing closer produces one precisely located
diagnostic rather than a cascade.
RFC-0001 originally justified this as parser-side error localisation and then criticised
itself for it. RFC-0002 withdrew the self-criticism and supplied the real reason:
The echo is an error-correcting code for weak long-range attention. A parameter-constrained model cannot reliably track nesting depth across 200 lines; the closer hands it the answer locally instead of requiring it to reconstruct the stack.Indentation is canonical but not significant — the parser reads
end, not whitespace, so
whitespace mangling in transit cannot change meaning.
One construct per intent — FM-1
There is no statement/expression duality. Logic is statements; only
view and contract
have their own declarative sub-grammars.
The keyword vocabulary is 23 common English words, each a single token in every mainstream
tokenizer:
text is also a view attribute, so lexing
it as a keyword made a valid view line unparseable. Types resolve by position.
Variant data lives on the variant — FM-1, FM-4
enum connection_state carries label and color as columns on the variants. The
TypeScript corpus kept these in parallel Record maps, and porting that corpus to Rust
found exactly the drift you would predict: nodes missing from a map, a wrong fallback
colour. In Mzizi the enum is the table, a missing cell is a compile error, and
state.label is total by construction.
alert.mz shows the version of this that is not about styling at all:
primitives/alert.mz (excerpt)
Props, events and defaults are declarations — FM-6
prop name: type [= default], one per line. Events are props of type event(payload), and
emit is the only way to fire one. No destructuring ceremony, and no
interface-plus-signature double declaration — the TypeScript pattern declares every prop
twice, which is pure ceremony and a real drift site.
The view grammar is native, not a macro — FM-7
view … end is part of the language grammar. Elements are words (strip, row, button,
control, notice, busy, rule); attributes are name = value lines; children are
nested blocks. Every diagnostic inside a view points at source the author actually wrote.
Interpolation is {expr} inside strings, and it is the only string-building mechanism.
Attributes the corpus proved load-bearing are first-class and checked: slot (the
data-slot identity contract), role (ARIA — and an explicit role replaces implicit
semantics, which is a real corpus defect class), and class (statically scanned, so
dynamic class construction is impossible).
Capabilities are declared at the top — FM-9
use motion, use net, use storage, use ml. An agent reading the first five lines of
any component knows its blast radius. use ml is the Phase 3 Candle seam: it parses today
and is specified to error as “not yet available”.
No ownership at the surface — FM-3
Mzizi lowers to Rust, but no borrow, lifetime or ownership concept exists in the surface language. Values have value semantics; the compiler owns theRc/signal plumbing in
lowered code. The class of non-local-fix errors that makes Rust hard for agents is spent
once, by the compiler authors, instead of on every generation.
This is a design commitment, not a demonstrated one — there is no lowering yet. See
Status.
Canonical form — FM-8, FM-4
There is meant to be exactly one rendering of any Mzizi program: two-space indent, one attribute per line past two, fixed column alignment in enum tables, and a fixed declaration order inside a component (doc → use → enum/type → prop → view → fn → contract). No
configuration. The point is that diffs are always semantic and any unique line is a unique
edit anchor — and that the benchmark’s token counts are measured against one canonical
surface rather than a formatting lottery.
Still open
Local state —state count: int = 0 plus assignment semantics that lower to signals — is
unresolved. It was open in RFC-0001 §7, still open in RFC-0002 §6, and RFC-0003 §8 adds a
constraint to it: signal semantics must survive content addressing. state is not a keyword
in the lexer today.