> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mzizi.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# The mz compiler

> The commands (check, fix, contract, outline and build, plus hash and ir), an exit-status contract, an exact-fix pass, contract evaluation, the lowering of a service to Rust and axum, and an NDJSON diagnostic protocol written for a reader holding zero file context.

`mz` is the compiler that implements the Mzizi language: toolchain, not the language itself.
Today it is the Phase 0 front end: lex → parse → resolve → lower → IR, plus a contract
evaluator ("lower" here means into the IR for a component). One thing lowers to Rust: a
`service`, which [`mz build`](#mz-build-lower-a-service) turns into a local Rust + axum
package. No component lowers to Rust yet. It is the centre of the
[toolchain](/toolchain/overview). It is a single Rust binary with
**no dependencies at all**, which is a deliberate house convention rather than an oversight
— a compiler whose check loop must stay sub-second on a modest laptop should not start life
with a dependency tree to build first, and the small things it needs (JSON emission,
SHA-256) are fully specified and therefore hand-rollable with verifiable correctness.

## Getting it

There is no release, no published crate, and no installer. The crate is `version = "0.0.0"`
with `publish = false`.

```bash theme={null}
git clone https://github.com/mzizi-dev/mzizi.git
cd mzizi/compiler
cargo test                                                          # the compiler's tests
cargo run --bin mz -- check    ../primitives/button.mz              # does it compile
cargo run --bin mz -- contract ../primitives/button.mz              # does it do what it says
cargo run --bin mz -- fix      path/to/file.mz                      # apply every exact fix, check again
cargo run --bin mz -- check --agent ../examples/connectivity_bar.mz # NDJSON for an agent
cargo run --bin mz -- outline  ../primitives/alert.mz               # the interface, as valid Mzizi
cargo run --bin mz -- ir       ../primitives/card.mz                # nodes, hashes, structural paths
cargo run --bin mz -- build    ../examples/registry.mz --out out    # a service, lowered to Rust + axum
```

Run `cargo test --workspace` from the repository root for the whole suite: 425 tests in 18
suites at `6da2170`, 294 of them in the compiler crate and the rest in the benchmark harness,
runner and probe crate. `compiler/src` is 12,644 lines.

## The commands

| Command | What it does |
| - | - |
| `mz check <file.mz>` | Human-readable diagnostics, one per line, plus a summary |
| `mz check --agent <file.mz>` | The same diagnostics as NDJSON, plus a summary object |
| `mz fix <file.mz>` | Applies every `exact` fix in place, in one pass, then checks again |
| `mz contract <file.mz>` | Evaluates the `contract` block; `--agent` gives NDJSON with a tally |
| `mz outline <file.mz>` | The component's interface only, emitted as valid Mzizi |
| `mz hash <file.mz>` | The root hash and the stored node count |
| `mz ir <file.mz>` | Every node with its hash and structural path |
| `mz build <file.mz> --out <dir>` | A service only: writes a local Rust + axum package ([below](#mz-build-lower-a-service)) |

With no command given, the first positional argument is treated as a file and `check` is
assumed.

<Note>
  **Documented elsewhere, not implemented here.** RFC-0003 §5 lists `mz refs`, `mz path`,
  `mz patch` and `mz diff` under *"designed here, next in implementation order"*. They are
  not built, and neither are `mz run`, `mz test` or `mz fmt` ([what still has to be
  built](/tracker)). The binary dispatches exactly the commands in the table above: `check`,
  `fix`, `contract`, `outline` and `build`, plus `hash` and `ir` for the IR. Asking for anything
  else prints the usage line and exits 2. `mz outline`, `mz hash` and `mz ir` refuse a service
  with exit status 2, because services have no IR yet.
</Note>

### Exit status is a contract

So the loop can branch on status without parsing output:

| Status | Meaning |
| - | - |
| `0` | No errors. Warnings do not fail. |
| `1` | Errors present, a contract clause failed, or an IR command had no tree. |
| `2` | Usage or I/O problem. |

## `mz check --agent`: the protocol

This is the surface an agent should use. RFC-0001 §4 states it as a versioned contract, and
four properties define it.

<Steps>
  <Step title="Whole-program, all at once, deterministic order">
    Statement-per-line plus `end`-anchored blocks let the parser resynchronise at every
    line. The recovery target is **at most one diagnostic per true author error** — never a
    cascade, and never "fix one to see the next". That is the direct answer to FM-5: a
    compiler that stops at the first parse error turns one mistake into five agent turns.
  </Step>

  <Step title="NDJSON, one diagnostic per line">
    Each line is a complete JSON object carrying `code`, `severity`, `file`, `span` as
    `[start_line, start_col, end_line, end_col]`, `say`, and an optional `fix`.
  </Step>

  <Step title="`say` is written for a reader with zero file context">
    It quotes the offending source inline, so the agent needn't re-read the file to
    understand the error. The stated target is ≤ 200 characters — density is the budget.
  </Step>

  <Step title="Fixes are data">
    Every diagnostic carries a machine-applicable `fix` when one is unambiguous, tagged
    `exact`, `guess` or `none`. [`mz fix`](#mz-fix-apply-every-exact-fix) applies every
    `exact` fix in one pass, which takes a whole class of mechanical error out of the loop.
  </Step>
</Steps>

The shape RFC-0001 specifies:

```json theme={null}
{"code":"MZ0412","file":"connectivity_bar.mz","span":[38,10,38,17],
 "say":"`emit on_state_change(sync)` — `sync` is not a variant of `connection_state`; nearest is `syncing`",
 "fix":{"span":[38,10,38,17],"replace":"syncing"},"confidence":"exact"}
```

The emitter in `compiler/src/diagnostic.rs` writes the same fields with `severity` added and
`confidence` nested inside the `fix` object:

```text theme={null}
{"code":…,"severity":…,"file":…,"span":[…],"say":…,"fix":{"span":[…],"replace":…,"confidence":…}}
```

Every run ends with a summary line, so a consumer always has a terminator:

```json theme={null}
{"summary":true,"errors":3,"warnings":1,"exact_fixable":2,"ms":480}
```

The human-readable mode ends with the same information as prose:
`mz: 3 errors (2 exact-fixable), 480ms`.

### Diagnostic codes

Codes are grouped by phase, and the ranges are stable:

| Range | Phase |
| - | - |
| `MZ01xx` | Lexical |
| `MZ02xx` | The component header, `use`, and block closing — including every `end` echo mismatch |
| `MZ03xx` | Enum variants and `prop` declarations |
| `MZ04xx` | Lines that cannot start where they appear, and the view grammar |
| `MZ05xx` | The contract block's presence and shape |
| `MZ06xx` | Contract clauses, from `mz contract` (RFC-0006) |
| `MZ07xx` | Names and types, from the resolver (RFC-0008) |

Two are worth quoting because they show what the messages are trying to be. `MZ0402`, when
something that cannot start a view line does:

```text theme={null}
… cannot start a view line — expected an element, `name = value`, `nothing`, or `end`
```

It names the whole set of valid continuations rather than only what was wrong — the
Elm-derived expected-vs-found discipline RFC-0002 §3 names as the most valuable borrow in
compiler-error UX, on the grounds that a small model cannot infer from an indirect hint.

And `MZ0501`, which is a warning rather than an error, and is how RFC-0001 §1.6's rule
("a component without a `contract` block compiles with a warning") is actually enforced:

```text theme={null}
`component button` has no `contract` block — behaviour is unverified (RFC-0001 §1.6)
```

The `end`-echo diagnostics (`MZ0206`–`MZ0208`) are the payoff for the name echo: they can
say *which* block on *which* line an `end` actually closes, and hand back the exact text to
write instead. Each fix rewrites the whole closer, not only the `end` word.

### Codes added after pilot 2

Pilot 2's 7B model brought React habits the compiler did not name, and several view mistakes
gave a cascade instead of one error on the right line. These codes are the fixes, audited in
[`benchmarks/READINESS.md`](https://github.com/mzizi-dev/mzizi/blob/main/benchmarks/READINESS.md).
Each message below is quoted from `compiler/src/lex.rs` or `compiler/src/parse.rs`.

| Code | Severity | What it catches | Fix |
| - | - | - | - |
| `MZ0106` | error | A spread, `...props` or `{...props}`. Mzizi has none: a component names each prop it reads | `exact`: delete the spread, or its whole line when it stands alone |
| `MZ0312` | warning | A prop named `as_child`, React's `asChild`. Mzizi elements are not polymorphic | `exact` (delete the prop) when nothing reads it; otherwise names the branch |
| `MZ0313` | error | A variant row whose `height` disagrees with the `h-N` or `size-N` class that renders it | `exact`: the rendered number |
| `MZ0406` | error | An attribute written without its `=`, such as `class "flex"` | Insert `=`: `exact` for a known attribute word, `guess` otherwise |
| `MZ0407` | error | `if` in a view. The one conditional is `when` | `exact`: `when` |
| `MZ0408` | error | Attributes directly under `view`, which holds one element tree | None |
| `MZ0409` | error | Anything after an element word on its line, such as `span class="x"`. Before, the tail was silently kept | None |

`MZ0313` quotes both numbers, so the agent needn't work out the scale itself:

```text theme={null}
`icon` declares `height 48` but its class `size-14` renders 56px (N × 4) — write `height 56`, or drop the column and let the class say it once
```

## `mz fix`: apply every exact fix

`mz fix <file.mz>` checks the file, applies every `exact` fix to it in place, then checks the
result again. The output and the exit status describe the file as it now is.

```text theme={null}
$ mz fix button.mz
mz: applied 1 exact fixes; 0 errors (0 exact-fixable) remain, 0ms
```

* **One pass.** It applies the `exact` fixes the first check reported, once. It does not loop
  until nothing changes. The second check says what is left.
* **`guess` fixes are never applied.** Where two `exact` fixes would overlap, the checker keeps
  one as `exact` and demotes the other to `guess`, so the edits never collide. A demoted fix
  may come back as `exact` on the next run.
* **`--agent` works here too.** `mz fix --agent <file.mz>` prints the second check as NDJSON,
  exactly as `mz check --agent` would.
* **The exit status is the second check's:** `0` with no errors left, `1` with errors left, `2`
  if the file could not be read or written.

RFC-0001 §4.3 described this command before it existed. It landed after pilot 2, whose 7B
model resubmitted a byte-identical file in 15 of 16 Mzizi repair attempts. `READINESS.md`
records that applying `mz fix` to any Mzizi candidate from either pilot never raised its
error count. Whether it helps an agent converge is for the benchmark to measure, and it has
not been measured.

## `mz contract`: does it do what it says

`check` and `contract` are separate on purpose. The charter measures two different things:
*"a syntax/compile error is not itself a defect for this metric… the defect rate measures
what gets past the compiler wrong."* One exit code covering both would make the Phase 0
defect metric unreadable.

`mz contract <file>` evaluates the component's own `contract` block against its own
declarations: enum variants and their data columns, defaults, slots and the view. A failed
clause exits 1, exactly as a compile error does, so a harness can branch on status alone.
Across the nine primitives there are 29 clauses, and CI evaluates every one.

```text theme={null}
mz: 0 errors (0 exact-fixable), 5 contract clauses, 0 failed, 0ms
```

What it does **not** do: it checks nothing rendered, and it does not compare a component
with a reference implementation. That comparison is the benchmark harness's job
(`benchmarks/harness`).

**For a service, `mz contract` runs it in process** ([RFC-0011](/rfcs) §6–§7). Each `example`
clause is one request, and each `ensure` clause is tested over a generated set of requests:
tested, not proven. Over the example service:

```text theme={null}
$ mz contract examples/registry.mz
mz: 0 errors (0 exact-fixable), 22 contract clauses, 0 failed, tested over 61 generated requests, 1ms
```

**A size's height is now read from its class.** Pilot 2's 7B buttons wrote
`icon class "size-14" height 48`: the class renders 56px, the contract read the 48, and
`mz contract` passed. Now a variant row may leave `height` out, and the evaluator takes the
height its first plain `h-N` or `size-N` class token renders (`N × 4` pixels). A row that
writes a `height` which disagrees with its class fails `mz check` with `MZ0313`. The rule is
the one the benchmark harness scores with, and both test suites check it on the same
examples. Tokens with a prefix or an arbitrary value, such as `md:h-10` or `h-[56px]`, are not
read. See [the pilot results](/pilots).

## `mz build`: lower a service

`mz build <file.mz> --out <dir>` lowers a `service` to Rust ([RFC-0011](/rfcs) §8). It is
the first thing in Mzizi that lowers to Rust, and the only one: it takes a service, and refuses
a component or a file with errors.

```text theme={null}
$ mz build examples/registry.mz --out out/registry
mz: built `service registry` into out/registry (3 routes, 1 fixtures); run it with `cargo run --release --manifest-path out/registry/Cargo.toml`
```

The output is an ordinary local Cargo package: the runtime (RFC-0011 §6 as one Rust function),
the generated route table and handlers, and one `#[tokio::test]` per `example`. It pins
`axum =0.8.9` and `tokio =1.53.1`. CI's `lowering` job builds the example service, runs its 18
generated tests, starts the server and sends a request over a socket.

What it is **not**: there is no Workers, Containers or WebAssembly target, no `mz run`, and no
component lowering. A generated package runs locally as a native server. See
[what still has to be built](/tracker).

## `mz outline`: the representation for dependencies

When editing component A that uses B, an agent needs B's *interface*, not B's body. Reading
the file gets both, plus comments and unrelated functions — RFC-0003's barrier RB-2.

The outline carries: the first doc line, the component name, declared capabilities, every
prop with its type and default, every enum with its variant **names** only, the names of
`fn` declarations, and a marker for whether a contract exists. It drops variant column data,
view bodies and function bodies — which is where the bulk of a component's bytes are.

It is emitted as **valid Mzizi**, deliberately: a reader who can read the language can
already read this, so there is no second format to learn and no second parser to keep in
step.

Measured over the nine primitives and the two component examples, the worst case is **38% of source**
(`spinner.mz`); the test in `compiler/tests/ir_measured.rs` fails above 75%.

## Compile speed is a protocol property

RFC-0001 §4.6 makes this explicit: *"A slow compiler fails Phase 0 no matter how good its
errors are."* The stated budget is sub-second incremental for a single-component change, and
the benchmark is specified to record it per iteration.

What has been measured so far is much narrower: parse and lower of all eleven component `.mz` files in
the repository takes about 10 ms in a debug build, against a 400 ms test budget. That is a
floor on a tiny corpus, not the incremental-compile figure the charter asks for. See
[Status](/status).

## Paths in the agent output

`mz check --agent` prints each diagnostic's `file` exactly as it was given. In pilot 2 the
benchmark runner passed absolute paths, so the 7B model read about 13,500 tokens of path
strings. That was the first fix pilot 2 listed, and it is fixed in the runner rather than the
compiler: the runner's default `file-name` normaliser replaces the candidate's path with its
bare file name before the model sees it, for every arm. If you drive `mz` from your own
loop, pass a relative path.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.