ADR-195: nikaia describe Is a Nikaia Program, Because This Language Has To Be Written In

Status: Superseded by ADR-290 — its D1-D5 are D11-D15 there Date: September 22, 2026 Target Version: Nikaia 0.0.155 Answers: open-decisions.md’s is nikaia describe written in Nikaia? — option A, and the owner’s reason is not the one that page led with Narrows: ADR-193 D4’s second step, a real parser (syn) replaces the scraper — the parser is a grammar Related: ADR-002 D4 (the pre-lowering this ships by), ADR-104 D4 and D5 (what the command reads, and that its draft is reviewed), ADR-194 D1 (the subtraction that puts an OS resource in std), ADR-009 D4 (measure before choosing a shape — and where that rule does not apply)

1. Context

nikaia describe reads a Rust crate’s pub signatures and writes a draft ledger. It is 843 lines, and the half that reads is a hand-written character scanner — split_top_level, items_of, fields_at, line_starts, signature_at, matching — which its own module header apologises for: a signature scraper and not a Rust parser.

ADR-193 D4 said the answer was syn. The owner asked whether the command should be written in Nikaia instead, where the reading half is a grammar — which is this language’s headline feature.

And the page that carried the question got the shape of the decision wrong. It recommended writing a grammar first as a measurement that would settle the question. That was a category error, and correcting it is D5.

2. Decisions

D1 — nikaia describe is written in Nikaia, and the reason is that this language has to be written in.

Eat your own dog food. Not as a slogan: a language whose own toolchain is written in another one has no user who is forced to live with its gaps, and every gap this tree has found was found by running something. describe is the first tool that can be written in Nikaia without anything else moving, so it is the one that gets written in it.

This is a decision about the project and not about the shape, which is why no number stands behind it.

D2 — Nothing bootstraps through it, and it ships the way std’s own Nikaia half does.

The compiler compiles without describe: NK2504 names the command and a person runs it. So there is no cycle to break.

It ships by ADR-002 D4’s route, unchanged — the .nika kept beside the .rs, pre-lowered at release, so a binary install compiles the .rs and needs no compiler to do it. nikaia lower-std is the release step that already does this for std; describe rides the same one.

D3 — The reading half is a grammar, and ADR-193 D4’s syn step is replaced by it.

Everything else in that record’s five steps stands: the column, the note, the unsafe impl Send/Sync flag, the call graph, the use table. What changes is which parser.

And the grammar removes the class rather than the instance. All three of the scraper’s named limits come from its being a scanner; the one that survives a real parser — an item a macro generates — survives syn too, and for a reason that is neither parser’s (ADR-001 D1, the same wall that keeps rustdoc-JSON out).

D4 — std gains a directory walk and a subprocess.

A crate is read by reading its .rs files, and ADR-193 D4’s first step wants cargo metadata. std has neither today.

Both are operating-system resources of exactly the kind ADR-194 D1 just put the socket in std for, so ADR-069 D2’s subtraction covers them without a new argument: what was pushed out of std was the protocol and the framework, and a directory is no more HTTP-shaped than a socket is.

D5 — A measurement decides between options; where the choice rests on a project principle, a number is a diagnosis.

The entry this record answers proposed writing the grammar first, as a measurement that would settle the question. It would not have. ADR-009 D4’s measure before choosing a shape applies where two shapes are genuinely on the table — Rc against Arc, a match against a perfect hash, a boxed future against impl AsyncFn. Here the choice is made on a reason about the project, and no number could have moved it.

So what a number would mean here is different, and it is worth saying once for every record that comes after. If the Nikaia describe turns out slower than the scraper, that is a finding about this compiler and an amount of work owed — not a reason to go back. A measurement that cannot change the decision is still worth taking; calling it the reason for the decision is what this record refuses.

3. Consequences

4. What this does not decide

5. What is built

Nothing yet. The order of work, and the first step is usable on its own:

  1. the grammar, over the crates examples/foreign-runtime/ already has, against the scraper’s own output — not as a gate, but because a parser is worth having before the program around it;
  2. fs gains a directory walk, and a subprocess beside cli;
  3. the command rewritten in .nika, in the sysroot, pre-lowered at release by nikaia lower-std’s own step;
  4. ADR-193 D4’s remaining steps on top of it — the use table, the call graph, the unsafe impl flag.

#124 carries it.

This site is open source. Improve this page.