Parser
Hand-written recursive descent. Tracks fence depth by counting leading colons. Never throws on malformed input — produces a best-effort AST and lets the validator complain.
The noma CLI parses, renders, and validates .noma source files. This page is itself written in Noma — the same source produces the rendered HTML you're reading and the deterministic LLM context an agent would consume.
npm install -g @ferax564/noma-cli@latest
# or one-off
npx @ferax564/noma-cli render path/to/file.noma --to html
Hand-written recursive descent. Tracks fence depth by counting leading colons. Never throws on malformed input — produces a best-effort AST and lets the validator complain.
Discriminated union in src/ast.ts. Single source of truth. Adding a node type is a one-line change that the TypeScript compiler propagates to every renderer's switch.
Pure functions. AST → string. No I/O, no globals. Three in core today (HTML, LLM, JSON); PDF is a wrapper around the HTML renderer + Puppeteer.
.noma source
│
▼
┌──────────┐
│ Parser │ src/parser.ts (line-based, recursive descent)
└─────┬────┘
│ typed AST (src/ast.ts)
▼
┌──────────────────────────────────┐
│ Renderers (pure) │
│ ├── renderer-html.ts → HTML │
│ ├── renderer-llm.ts → LLM ctx │
│ └── renderer-json.ts → JSON │
└──────────┬───────────────────────┘
│
▼
artifact
import { parse, renderHtml, validate } from "@ferax564/noma-cli";
const source = await fs.readFile("doc.noma", "utf8");
const ast = parse(source, { filename: "doc.noma" });
const diagnostics = validate(ast);
if (diagnostics.some(d => d.severity === "error")) {
throw new Error("invalid Noma document");
}
const html = renderHtml(ast, { standalone: true });
Agents should not rewrite full files. They propose block-level operations that the CLI applies safely.
{
"op": "replace_block",
"id": "asml-euv-moat",
"content": "ASML's moat rests on EUV optics, mechanics, and supply chain — not just exclusivity."
}
Operations: add_block, replace_block, delete_block, move_block, update_attribute, add_evidence, add_comment, resolve_comment, rename_id. See docs/agent-protocol.noma for the full schema.
flowchart LR A[.noma source] --> B[parser] B --> C[AST] C --> D[validator] C --> E[renderer-html] C --> F[renderer-llm] C --> G[renderer-noma] G --> H[noma fmt / patch]
docs/spec.noma for the full block reference.docs/agent-protocol.noma for the patch protocol.docs/direction.noma for the product positioning.examples/research-thesis.noma for a reasoning-heavy demo.