Getting Started
Install the public CLI, render a readable artifact, export clean agent context, discover stable block IDs, prove a small patch, apply it, and validate the result.
The first loop
Start here before learning the full directive surface. This path uses the published npm package, so it is the same first loop a new user runs outside this checkout.
npm install -g @ferax564/noma-cli@latest
noma --version
noma init my-spec
noma check my-spec/demo.noma
noma render my-spec/demo.noma --to html --strict --out my-spec/demo.html
noma render my-spec/demo.noma --to llm --budget 12000
noma ids my-spec/demo.noma
noma prove my-spec/demo.noma --op '{"op":"replace_body","id":"first-risk","content":"The first risk is now tracked without rewriting surrounding source."}' --out my-spec/proof.html
noma patch my-spec/demo.noma --op '{"op":"replace_body","id":"first-risk","content":"The first risk is now tracked without rewriting surrounding source."}' --inplace
noma check my-spec/demo.noma
That loop proves six things:
- the source stays readable in Git
- the artifact renders for humans
- the LLM export is clean enough for agents
- IDs give agents stable patch targets
- the proof artifact shows the proposed patch, diff, hashes, diagnostics, and post-patch preview before the source changes
- validation catches broken structure before shipping
Use noma render --to html --strict for team-visible artifacts. Use noma render --to llm --select ... --budget ... when an agent should see only the relevant block types.
Install
Install the CLI when you want to author documents outside this checkout:
npm install -g @ferax564/noma-cli@latest
noma --version
noma init my-spec
noma render my-spec/demo.noma --to html --out my-spec/demo.html
Install the VS Code extension for syntax highlighting, folding, embedded YAML / JSON / LaTeX / Mermaid / DOT scopes, and warning scopes for raw escape hatches:
ext install ferax564.noma-language
For contributor work, clone the repo and install dependencies:
git clone https://github.com/ferax564/noma.git
cd noma
npm install
Use the web workbench
The static site includes a browser workbench for editing .noma source, checking diagnostics, previewing safe HTML, proving patch ops, editing ID-bearing tables/datasets, inspecting the AST, and copying LLM context. Its ribbon covers the main Word-like workflows that fit Noma's source-first model: file open/new/export, selection formatting, headings, lists, links, tables, figures, layout blocks, comments, change requests, footnotes, proof controls, find, and print:
npm run build:site
open dist/workbench.html
For persistent cloud documents, run the hosted server instead:
npm run build:cloud
PORT=3000 npm start
open http://localhost:3000/workbench.html
The hosted workbench can save source through /api/documents, reopen it from workbench.html?doc=<id>, and share the rendered artifact at /d/<id>.
For screenshots and the full command map, read the web workbench guide.
The fastest no-install product test is:
- open the published workbench
- load the agent-plan example
- click Review -> Prove
- inspect the Proof output tab
- click Apply only after the proof passes
- switch to the research-thesis example and use Tables & Data on a dataset
That path demonstrates the source/artifact/agent loop without installing the CLI first. The CLI remains the release and CI path for repository work.
Render an example
The repo ships working examples in examples/: five main demos, starter templates, original intro files, and a multi-file book:
npm run noma -- render examples/agent-plan.noma --to html --out dist/agent-plan.html
npm run noma -- render examples/research-thesis.noma --to html --out dist/research-thesis.html
npm run noma -- render examples/tech-doc.noma --to html --out dist/tech-doc.html
Open any of the produced files in a browser — they are fully self-contained and include the default theme inline.
Export to Markdown
Use Markdown when the recipient needs a lightweight handoff rather than the full Noma source or a Word review package:
npm run noma -- render examples/agent-plan.noma --to markdown --out dist/agent-plan.md
The Markdown target keeps ordinary Markdown prose, headings, lists, code, quotes, and pipe tables readable. It converts [[id]] links to [id](#id), emits hidden anchors for IDs and aliases, renders ::agent_task / ::todo as checkboxes, ::figure as Markdown images, callouts as GitHub-style admonitions, and directive tables as Markdown pipe tables. Noma-specific blocks degrade to readable labels and hidden noma:block comments so exported .md files remain useful in GitHub, Slack, email, docs imports, and agent handoffs without replacing .noma as the source of truth.
Export to Word
Use DOCX when a document needs to enter a Word, Google Docs import, or committee review workflow:
npm run noma -- render examples/agent-plan.noma --to docx --out dist/agent-plan.docx
npm run noma -- docx-data dist/agent-plan.docx --out dist/agent-plan.controls.json
npm run noma -- docx-sync examples/agent-plan.noma dist/agent-plan.docx --out synced-agent-plan.noma --report synced-agent-plan.report.json
npm run noma -- docx-review-data dist/agent-plan.docx --out dist/agent-plan.review.json
npm run noma -- docx-review-sync examples/agent-plan.noma dist/agent-plan.docx --out reviewed-agent-plan.noma --report reviewed-agent-plan.report.json
The DOCX target preserves frontmatter as Word package metadata, headings, prose, lists, page-aware pipe tables, ::table directives and field-numbered captions, ::dataset tables, metric KPI blocks, static computed metric/plot/table handoffs, technical API/reference blocks, addressable code snippets, code-cell/output computation blocks, page-aware ::grid / ::columns layouts, framed card panels, memory profile panels, flattened hero/tabs/accordion sections, titled tab panels, framed sidebars, code blocks, abstract/callout/note/warning/tip blocks, Office Math blocks and inline equations, native checkbox action items, native text/dropdown/date/checkbox control fields with custom XML data bindings, action blocks, section-level page setup, form document-protection settings, rich native Word headers/footers with page-number fields and part-local hyperlinks, generated tables of contents and caption lists with Word page-reference fields, page breaks, targeted/threaded native Word comments with rich inline body content and resolved-state metadata, review-view settings for comments and revisions, target-anchored rich tracked review revisions, state-change deltas, target-anchored rich native footnotes/endnotes, generated bibliographies, semantic directive labels, styled review blocks and metadata, review/provenance/confidence metadata blocks, embedded PNG/JPEG/GIF/SVG figures, field-numbered figure/plot captions, static SVG plots for resolvable data, diagram/Plotly source fallbacks, clickable citations, block-ID bookmarks, internal wikilinks, external hyperlinks with rich Markdown labels including combined bold+italic spans, and readable fallback labels for custom directives. Unresolved web-first blocks degrade to labeled placeholders so the handoff document stays readable.
noma docx-data reads the urn:noma:controls custom XML part behind bound ::control fields plus visible noma-control:<id> fields and native checkbox content controls behind ::agent_task / ::todo in the document body, headers, and footers, emitting JSON for workflows that need .noma -> .docx -> data handoff loops. noma docx-sync uses that value layer to update matching source ::control default= attributes plus task done / status attributes while preserving the rest of the .noma file, giving fillable Word review cycles a source return path; visible text controls preserve leading/trailing spaces from Word instead of trimming them before source sync. Pass --report <file.json> to record applied control/task changes and unmatched DOCX IDs without duplicating the patched source. noma docx-review-data extracts native Word comment/note bodies, author/date metadata, resolved state, reply links, tracked revisions and tracked moves, footnotes, endnotes, bookmarked headings, prose block bodies, and bookmarked tables as JSON so review loops can inspect what came back from the DOCX package before turning it into patches; bold, emphasis, inline code, internal wikilinks, and external hyperlinks in comments, notes, accepted heading titles, accepted caption titles, accepted metric/control/action/block-title labels, accepted block body edits, tracked revision text, and bookmarked table cells return as lightweight Noma Markdown, with adjacent same-style Word runs coalesced before Markdown rendering, including inside internal and external hyperlink labels. Word HYPERLINK fields, including complex fields and fldSimple, return through the same Markdown link path. Formatted or custom internal #id hyperlink labels return as [label](#id) when the visible anchor text or a verified Noma-generated bookmark identifies the target, generated complex or fldSimple Word REF fields for Noma caption cross-references return as [[id]], intentional spaces inside hyperlink labels are preserved, literal brackets inside returned external hyperlink labels are escaped, and whitespace or parentheses inside returned external hyperlink targets are percent-encoded. DOCX return readers preserve Word w:cr / w:br line breaks, tabs, hyphen tokens, symbol glyphs, and leading/trailing spaces in comment, note, and table-cell text even when those empty run-token elements are serialized as paired XML elements, keep nested native table rows inside their parent table cell, merge adjacent same-ID tracked revision fragments, and group multiple adjacent delete/insert pairs in one paragraph as separate replacements before syncing change requests. Header/footer comments, tracked revisions, and wrapper or range-marker tracked moves use the same bookmark return path as body content, and table-cell comments, notes, tracked revisions, and tracked moves inherit the table's Noma bookmark when the table was exported from a bookmarked block. noma docx-review-sync uses native anchors to apply accepted heading-title edits with update_heading, add new source ::comment, ::footnote, and ::endnote blocks after matching target blocks, add threaded replies with reply_to=, update/resolve/delete existing source comments and replies from Word state, update existing source-position and matched targeted note bodies when those note bodies have no tracked revisions, mark missing sibling targeted notes deleted, add/update/delete source ::change_request blocks from Word revisions and moves, apply accepted prose-like body-only directive edits with replace_body, apply simple accepted ::table edits with granular header/cell/row/column patch ops, apply simple inline ::dataset cell/row/column edits with update_dataset_cell, insert_dataset_row, delete_dataset_row, insert_dataset_column, or delete_dataset_column, and import unmatched tracked insert/delete/replace revisions or wrapper/range-marker tracked moves as source ::change_request blocks. It treats alias and canonical targets as the same source reference, so Word's canonical bookmark return does not rewrite unchanged alias-authored wikilinks, internal links with escaped labels, generated caption cross-reference fields, table/dataset cell links, or target attributes; equivalent escaped/raw backslash spellings inside hyperlink labels and source \| escapes versus Word-returned literal pipes also compare unchanged, and target-only comment markup removals match source links whose visible labels contain escaped brackets. Its --report <file.json> output records applied changes plus skipped comments, revisions, notes, tables, headings, block bodies, labels, metric values, metric metadata, and block metadata, including revision-bearing comments, notes, tables, and block bodies plus table/dataset cell edits whose multiline or nested Word content cannot be represented source-preservingly, so reviewers can audit what the source sync did not apply.
When Word Track Changes markup appears inside a native comment, footnote, or endnote body, review sync still uses the anchor to avoid false deletion and can still sync native comment resolution state, but it leaves the review-body text unchanged in source and reports the item as skipped.
Technical prose DOCX block bodies use the same return path for body-only ::api, ::endpoint, ::parameter, ::instruction, ::changelog, and non-language-backed ::query / ::example blocks.
Code-style DOCX block bodies use the same return path in code mode: accepted edits to ::code, ::code_cell, ::output, and language-backed ::query / ::example bodies keep monospace line breaks when they patch source.
Custom fallback DOCX panels use that return path too: body-only unknown or namespaced directives remain readable in Word and accepted body edits patch the original directive body.
Local figure files are embedded when rendering through the CLI:
::figure{id="chart" src="assets/chart.png" alt="Revenue chart" caption="Revenue by quarter" width="5in"}
::
Use ::page_setup when a Word handoff needs explicit page geometry:
::page_setup{size="A4" orientation="landscape" margin="12mm" margin_left="20mm"}
::
The first ::page_setup sets the initial Word section. Later ::page_setup blocks start a native Word section break, so wide tables can switch to landscape and then continue with section-local widths.
Use ::header and ::footer when a Word handoff needs document chrome, live links, or page numbers:
::header
Committee **draft** — [source room](https://example.com)
::
::footer{page_numbers total_pages}
Confidential
::
Use ::toc when a report needs a linked table of contents in Word, HTML, or PDF. DOCX entries include Word page-reference fields that update when the document opens:
::toc{title="Contents" depth=3}
::
Use normal wikilinks for figure, table, or plot cross-references. In DOCX, [[scenario-table]] becomes a Word REF field when the target has a numbered caption, and DOCX review extraction turns that generated field back into [[scenario-table]] on return whether Word stores it as a complex field or fldSimple:
See [[scenario-table]] for the scenario summary.
Use ::pagebreak when a report needs a hard page boundary in Word or PDF:
::pagebreak
::
Use ::doc_protection when a Word form should open in a fillable editing mode:
::doc_protection{edit="forms"}
::
::control{id="review-date" type="date" default="2026-05-24" locked}
::
This writes native Word document-protection metadata in the DOCX settings part. The locked flag on ::control maps to Word's content-control lock metadata so reviewers can edit the value without accidentally deleting the field. ID-bearing controls also bind to a urn:noma:controls custom XML part in the DOCX package, giving downstream tools a structured form-data layer to inspect after Word review. noma docx-data also reads the visible noma-control:<id> fields themselves from the document body, headers, and footers, so text, date, dropdown, and checkbox edits can return even when an editor leaves the custom XML part stale or strips it. It is not password protection; treat it as an editing-mode hint for Word review and form workflows.
Use ::comment for review notes that should arrive as real Word comments attached to a target block:
::comment{id="comment-core-claim" parent="core-claim" author="Research"}
Verify the latest source before committee review.
::
A comment can reply to another comment by ID:
::comment{id="comment-core-claim-reply" reply_to="comment-core-claim" author="Research"}
Verified and updated.
::
Agents can close that review loop with resolve_comment, which adds status="resolved" and optional resolved_by= / resolved_at= metadata to the comment block. DOCX handoffs keep that status both as visible comment text and as native Word resolved-state metadata, preserve reply_to= as a native Word comment thread, and skip orphaned replies whose parent comment is missing, deleted, or withdrawn without forcing Word review-view settings. noma docx-review-data <file.docx> reads those native comments back out as JSON, including resolved state and reply relationships, plus native footnote/endnote bodies, bookmarked Word headings/table rows, prose block bodies, and tracked revisions. Comment, note, accepted heading-title, accepted block-body, and bookmarked table-cell extraction reconstruct lightweight Noma Markdown for bold, emphasis, inline code, internal wikilinks, and external hyperlinks, and nested native tables inside returned table cells remain in the parent cell text. noma docx-review-sync <file.noma> <file.docx> applies the source return path: accepted Word heading edits update source headings with update_heading, accepted prose-like block body edits update source directive bodies with replace_body, anchored Word comments become source ::comment blocks, table-cell comments, notes, and tracked revisions on bookmarked native tables become source review blocks on the matching table or dataset block, Word replies become ::comment{reply_to="..."} blocks, edited source-position Word comments and matched replies update existing ::comment bodies when their bodies have no tracked revisions, source-bookmarked replies count as returned thread state for missing sibling deletion, source comments that Word marks done become resolved source comments, reopened Word comments clear stale source resolution metadata with remove_attribute, deleted/withdrawn source comments, replies, notes, and change requests stay as audit history instead of matching returned Word artifacts, even when an older DOCX still carries their source bookmarks, missing sibling comments on a reviewed target, including previously resolved source comments, become status="deleted", anchored notes become ::footnote / ::endnote blocks, edited source-position or matched targeted notes update existing note bodies when their bodies have no tracked revisions, missing sibling targeted notes become status="deleted", edited source or unambiguous Noma-generated change requests update existing ::change_request attributes, target-anchored tracked revisions count as returned review state, missing sibling native-tracked change requests become status="deleted" while malformed fallback requests are left alone, simple accepted table edits update matching ::table blocks with granular header/cell/row/column patch ops, simple accepted inline dataset cell/row/column edits use update_dataset_cell, insert_dataset_row, delete_dataset_row, insert_dataset_column, or delete_dataset_column before falling back to full dataset-body replacement, and unmatched tracked revisions become new ::change_request blocks. Comments, notes, tables, headings, and block bodies with tracked revisions are not accepted as direct source edits; their changes stay in the skipped report or return as ::change_request proposals where the source model can represent them.
When multiple source comments, footnotes, or endnotes share the same reviewed Word anchor, review sync matches them by visible body and metadata instead of trusting the first source bookmark on that anchor. Generated empty Comment, Footnote, and Endnote fallback labels are treated as render-time placeholders, not accepted edits back into an empty source block.
Accepted Word edits to rendered monospace directive bodies, including ::code, ::code_cell, ::output, and language-backed ::query / ::example blocks, also return through replace_body while preserving code line breaks.
Accepted Word edits to body-only technical prose directives, including ::api, ::endpoint, ::parameter, ::instruction, ::changelog, and non-language-backed ::query / ::example blocks, return through that same source-preserving body path.
Accepted Word edits to body-only custom fallback panels, including future community-pack directives such as ::finance::position, also return through replace_body.
Accepted Word edits to custom fallback panel headings add or update title= while keeping rendered directive names and attribute summaries out of the stored title.
Accepted Word edits to custom fallback heading attribute summaries update, add, or remove matching directive attrs, including when the whole rendered summary is removed or when an attr value itself contains commas, so metadata-only edits do not become noisy titles.
Metadata values may contain Word's visible · separator too. Values such as source="CRM · status: stale" and owner="Ops · Q1: Finance" return unchanged unless a reviewer edits that actual value, even when Word serializes the value separator as a separate run.
Use ::change_request for proposed wording changes that should arrive as tracked review revisions:
::change_request{target="core-claim" action="replace" from="old wording" to="new wording" author="Research"}
Reason for the requested edit.
::
When the target resolves and the request has valid revision text, DOCX output marks that reviewed block with a native Word comment range and places the tracked revision block next to it, preserving bold, emphasis, inline code, wikilinks, and external links inside the proposed from= / to= text. If the target is missing or the tracked revision is malformed, the change request still renders at its source position; malformed requests keep visible action, target, revision-text, author, and date metadata without creating native Word review parts, and review sync does not treat them as missing native tracked-revision siblings. status="deleted" or status="withdrawn" keeps the source audit trail but suppresses native DOCX tracked-revision export.
DOCX files with native comments or valid change-request revisions also include Word review-view settings so comments and insert/delete revisions are advertised as review markup.
Use ::footnote for context that should become a native Word footnote. Add for=, parent=, or target= when the superscript reference should attach to a specific block; unresolved targets fall back to the footnote's source position. Inline emphasis, wikilinks, and external links remain live inside the footnote part. status="deleted" or status="withdrawn" keeps the source audit trail but suppresses native DOCX note export:
::footnote{for="core-claim"}
This **caveat** should travel with the Word handoff. See [source](https://example.com).
::
Use ::endnote the same way when the note belongs at the end of the Word document instead of at the bottom of the page:
::endnote{target="core-claim"}
This note should stay out of the page flow but remain linked to the claim.
::
Use ::bibliography near the end of a report to collect every ::citation block into a references section:
::bibliography
::
Understand the split
Noma is easiest to use when you keep three surfaces separate:
| Surface | Command or file | What to check |
|---|---|---|
| Source | file.noma | Is the text readable in a normal editor? Are important blocks named with stable IDs? |
| Artifact | noma render file.noma --to html, --to markdown, or --to docx | Does the rendered page, Markdown handoff, or Word package carry the layout, table, plot, or review surface people need? |
| Agent | noma ids, noma check, noma render --to llm, noma patch | Can an agent discover targets, validate facts, get scoped context, and patch only the block that changed? |
This is the core wedge: Markdown is still great source for simple prose, HTML is still the right browser artifact, and Noma is the durable layer when a document needs both rich output and safe future edits.
Choose a starter template
Copy a template when you want a known-good document shape before adding project-specific content:
cp examples/templates/research-memo.noma my-research-memo.noma
cp examples/templates/decision-record.noma my-decision.noma
cp examples/templates/technical-spec.noma my-spec.noma
cp examples/templates/agent-refresh.noma my-refresh-pack.noma
The rendered template guide explains when to use each one: templates.noma.
Render to LLM context
npm run noma -- render examples/thesis.noma --to llm
npm run noma -- render examples/thesis.noma --to llm --select claim,evidence,risk
npm run noma -- render examples/thesis.noma --to llm --exclude dataset,plot --budget 12000
The output is deterministic plain text designed for LLM input: typed blocks become [CLAIM], [EVIDENCE], [RISK] tags with attributes preserved. --select and --exclude match AST node types or directive names; --budget trims at a line boundary when possible.
List IDs for agents
npm run noma -- ids examples/thesis.noma
npm run noma -- ids examples/book/book.noma.yml
The registry includes canonical IDs in document order, alias-to-canonical mappings, source line numbers, and basic block metadata. On book manifests it uses the same scoped IDs and aliases as validation and rendering.
Use Noma from agents
The CLI is the stable contract, but two public packages make agent integrations easier:
npm install @ferax564/noma-mcp-server@latest
npm install @ferax564/noma-agent-sdk@latest
Use the MCP server from any stdio-capable MCP host:
{
"mcpServers": {
"noma": {
"command": "npx",
"args": ["-y", "@ferax564/noma-mcp-server"]
}
}
}
Use the TypeScript SDK when you want a small client wrapper and retry-aware patch workflow:
import { NomaTools, NomaWorkflow } from "@ferax564/noma-agent-sdk";
const tools = await NomaTools.spawn();
try {
const workflow = new NomaWorkflow(tools);
const result = await workflow.safePatch("memo.noma", {
op: "update_attribute",
id: "launch-decision",
key: "status",
value: "accepted",
});
if (!result.ok) throw new Error(result.error);
} finally {
await tools.close();
}
The server exposes read_doc, list_ids, validate_doc, and patch_block. The SDK remains experimental during v0.x; the patch schemas and CLI behavior are the stable surface.
Validate
npm run noma -- check examples/thesis.noma
npm run noma -- check examples/research-thesis.noma --stale-days 30
The validator catches duplicate IDs, broken references (including [[wikilink]] targets across all chapters of a book), plots missing data, plots referencing unknown datasets or unknown columns, figures without alt text, claims missing evidence, risks without owners, decisions without status, agent tasks without scope, state_change blocks missing block/from/to, citations older than the staleness window, untrusted ::html / ::svg / ::script escape hatches, and (when a profile is declared in frontmatter) any directive outside the declared profile. Add the noverify flag attribute to any block to silence rules on it individually.
The staleness window defaults to 365 days. Override it for one document via stale_citation_days: 30 in frontmatter, for one citation via stale_after_days=30 on the citation, or globally with --stale-days 30 on the CLI.
Pick a theme
npm run noma -- render examples/research-thesis.noma --to html --theme dark
Two themes ship with the CLI: default (warm cream paper) and dark. Inside a document, use {variant="important|subtle|success|danger|info"} on a card, callout, or claim/evidence/risk block to switch its emphasis without touching CSS.
Choose the right table shape
Small tables can stay as Markdown-style pipe tables:
| Need | Format |
| ---- | ------ |
| Simple prose | Markdown |
| Agent-editable artifact | Noma |
When the separator row and column padding start dominating the source, switch to the ::table directive:
::table{header align="l,c,r"}
| Vertical | Status | Score |
| Legal | review | 3.4 |
| Healthcare | watch | 2.9 |
::
When values need validation or plots, store them as a dataset and point visual blocks at it:
::dataset{id="vertical-arr"}
schema:
vertical: string
growth: number
rows:
- [legal, 3.4]
- [healthcare, 2.9]
::
::plot{id="arr" type="bar" dataset="vertical-arr" column="growth" xcolumn="vertical"}
::
The rule of thumb: pipe table for readable prose, ::table for compact report tables, ::dataset when the numbers should be reusable or checked.
Render a multi-file book or space
Multi-file projects use a YAML manifest with a .yml / .yaml extension. The CLI auto-detects it:
npm run noma -- render examples/book/book.noma.yml --to html --out dist/book.html
npm run noma -- render examples/book/book.noma.yml --to site --out dist/book-site
npm run noma -- render examples/book/book.noma.yml --to llm
Chapter paths inside the manifest resolve relative to its directory. --to html concatenates the chapters into one continuous artifact. --to site publishes a static Noma Space: one page per chapter, a sidebar, breadcrumbs, search UI, _assets/search-index.json for agents, page metadata from frontmatter (tags, status, owner, updated), related pages, and backlinks discovered from cross-chapter [[id]] references.
Patch a block (without rewriting the file)
npm run noma -- patch examples/thesis.noma \
--op '{"op":"update_attribute","id":"asml-euv-moat","key":"confidence","value":0.95}' \
--inplace
Twenty-five ops cover the common editing flows: replace_block, replace_body, update_heading, add_comment, resolve_comment, add_footnote, add_endnote, add_change_request, update_table_cell, update_table_header_cell, insert_table_row, delete_table_row, insert_table_column, delete_table_column, update_dataset_cell, insert_dataset_row, delete_dataset_row, insert_dataset_column, delete_dataset_column, move_block, add_block, delete_block, update_attribute, remove_attribute, rename_id. The source-preserving patch path rewrites only addressed line ranges, moved blocks, or inserted blocks, so unrelated bytes stay byte-identical. See agent-protocol.noma and compatibility.noma for the schema and compatibility policy.
For multi-op agent edits, use a transaction-shaped --ops file:
{
"ops": [
{ "op": "update_attribute", "id": "asml-euv-moat", "key": "confidence", "value": 0.95 }
],
"prevalidate": true,
"postvalidate": true
}
npm run noma -- patch examples/thesis.noma --ops patch.json --inplace
The CLI writes only after every operation applies to an in-memory candidate. If postvalidate finds errors, the original file is left unchanged.
Print the bundled machine-readable schemas when an agent or CI integration needs to validate payloads before calling the CLI:
npm run noma -- schema patch-op
npm run noma -- schema ast
Render with strict HTML safety
npm run noma -- render examples/tech-doc.noma --to html --strict --out dist/tech-doc-strict.html
--strict blocks raw ::html, ::svg, and browser ::script escape hatches, omits external CDN runtimes for math, diagrams, and Plotly, and disables computed-control interactivity while keeping static default values visible. Use it for review or publishing contexts where the artifact must not execute untrusted markup or generated inline runtime code. For books, trusted_publishing: true in the manifest applies the same strict static posture to manifest-driven HTML/site/PDF renders.
Render in GitHub Actions
Add this workflow to another repository to validate, render, and upload a Noma artifact on every push and pull request:
name: Render Noma docs
on: [push, pull_request]
jobs:
noma:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ferax564/noma@v0.13.0
with:
input: docs/spec.noma
output: dist/spec.html
to: html
strict: true
artifact-name: spec-preview
The action installs the CLI from the checked-out action ref by default, runs noma check, renders the requested target, and uploads the output with actions/upload-artifact. For book manifests, set to: site and point output at a directory. If you need an explicit package source, set cli-package to any npm package spec or cli-version to an @ferax564/noma-cli npm version range.
Re-align tables in source
npm run noma -- fmt examples/research-thesis.noma --inplace
GitHub-style pipe tables get rebuilt to a single column width. Tables inside fenced code blocks are skipped. Pipes inside ` code spans and | escapes are preserved in source; renderers show | as a literal pipe outside code spans. Idempotent — running fmt` twice produces the same output.
Connect a plot to a dataset
Stop authoring numbers twice — link a plot to a sibling dataset by id:
::dataset{id="vertical-arr"}
schema:
vertical: string
growth: number
rows:
- [legal, 3.4]
- [healthcare, 2.9]
::
::plot{id="arr" type="bar" dataset="vertical-arr" column="growth" xcolumn="vertical"}
::
column= selects the y-series. xcolumn= (optional) pulls categorical labels from a string column. The validator emits errors when the dataset id or column name don't resolve.
Declare a profile
Tell downstream tools which directives the document guarantees to use:
---
profile: research
---
Three built-in profiles ship: minimal (markdown-equivalent), technical (product docs, landing pages), and research (theses, ADRs, recap docs). The validator warns on any out-of-profile directive. Omit the field to keep the open surface.
Render to PDF
The PDF target renders through the HTML renderer, then prints with Chromium via Puppeteer:
npm run noma -- render examples/research-thesis.noma --to pdf --out dist/research-thesis.pdf
npm run noma -- render examples/research-thesis.noma --to pdf --out dist/research-thesis.pdf --page-size Letter --margin 12mm
Use --css report.css to append report-specific CSS to the selected theme and --no-print-background when the output must avoid filled backgrounds. On first install, Puppeteer may download a Chromium build.
Write your own
Create mydoc.noma:
---
title: My First Noma Document
---
# Hello, Noma
::callout{tone="tip"}
Plain text in. Structured documents out.
::
::claim{id="my-first-claim" confidence=0.7}
Documents that know their own structure are more useful than documents that don't.
::
Then render:
npm run noma -- render mydoc.noma --to html --out dist/mydoc.html
Where to next
- Read docs/spec.noma for the full format specification.
- Read PLAN.md for the long-term vision.
- Read
CLAUDE.mdif you are an agent contributing to this repo.
Next guides
- Case studies for end-to-end workflow narratives.
- Comparison guide for when to choose Noma over Markdown, MDX, raw HTML, or collaborative docs.
- Research memo for the external Markdown/HTML pain research behind the wedge.
- Agent editing guide for safe patch operations and validation.
- Starter templates for copyable document shapes.