NAI OS
One run, one target, one deliverable — staged to a run folder, promoted only when every citation and every publish check holds.
You type /nai-document <target>. The command
“document[s] this workspace from its own files” — resolving that one slug
to a lane by five tests applied in order, where “First match wins”;
assembling the source list that lane calls for; then running three waves. doc-scoper
inventories the sources and writes the scoping brief “the rest of the run is grounded
in”. One generator writes a staged page — doc-surveyor in the survey
lane, doc-renderer in the blog lane, and in the editorial lane
“no generator runs”. Then doc-checker re-opens every cited file
and verdicts each claim. Generators “write to
12 Documentation/runs/<target>/proposed/”, never to docs/;
promotion — “copying 12 Documentation/runs/<target>/proposed/<file>
to the page path” — is “the only publishing act in this
system”.
%%{init: {'theme':'neutral', 'flowchart':{'htmlLabels':false,'nodeSpacing':45,'rankSpacing':55}}}%%
flowchart TD
H["Human types<br/>/nai-document <target>"] --> C
subgraph L1 ["1 - Orchestrator (.claude/commands)"]
C["/nai-document<br/>5 ordered tests, first match wins<br/>then assembles the source list"]
end
C -->|"no match"| E1["STOP<br/>missing: no target named <target>"]
C -->|"more than one test matches"| E3["STOP<br/>ask the human which they meant"]
C -->|"Wave 1"| S["doc-scoper<br/>inventory + create/update mode"]
S -.->|"working/scope.md"| C
subgraph L2 ["2 - Wave 2: one generator, chosen by lane"]
G1["doc-surveyor<br/>survey lane"]
G2["doc-renderer<br/>blog lane"]
G3["editorial lane<br/>no generator runs"]
end
C -->|"survey"| G1
C -->|"blog"| G2
C -->|"editorial"| G3
G1 -.->|"proposed/ page + claims.json"| K
G2 -.->|"proposed/ page + claims.json"| K
G3 -.->|"scoper's claims.json"| K
subgraph L3 ["3 - Wave 3: every lane, every run"]
K["doc-checker<br/>re-opens each cited file<br/>CONFIRMED / UNSUPPORTED, terminal"]
end
K -.->|"working/verdicts.json"| GD
GD["Publish guard<br/>orchestrator itself, no subagent<br/>serve path / reachable / links resolve"]
GD -->|"create + all CONFIRMED + all ✓"| P["Promote: copy proposed/ file<br/>to the page path"]
GD -->|"otherwise"| ST["Staged, not published<br/>STOP and tell the human which condition failed"]
GD ==> R["12 Documentation/runs/<target>/report.md"]
classDef orch fill:#dcefe9,stroke:#0f6f63,stroke-width:2px
classDef tool fill:#f4f1ea,stroke:#8a7a5a
classDef human fill:#fdf3e0,stroke:#8a5a00,stroke-width:2px
classDef agent fill:#fff,stroke:#555
class C,GD orch
class S,G1,G2,G3,K agent
class H,E1,E3,P,ST,R human
create, every verdict CONFIRMED, every
guard line ✓.The command applies its five tests in order, and “First match wins”.
Test 1: “11 Blog/<target>.md exists → lane blog,
page docs/blog/<target>.html”. Test 2: “<target>
is a key in the system map below → lane survey, page as
mapped”. Test 3: “docs/architecture/concept-<target>.html
exists → lane survey, page is that file”. Test 4:
“<target> is in the editorial list below → lane
editorial, page none”. Test 5:
“No match → STOP. Report
missing: no target named <target>. Write nothing.”
“If more than one test matches, STOP and ask the human which they meant.
Do not take the first.” cohort-census is a system-map key like the others:
“| `cohort-census` | `docs/architecture/system-cohort-census.html` |”.
That page was created by hand on 2026-08-06; until then nai-cohort-census was the
one command with no page and this orchestrator told you to STOP on it. It no
longer does. The reasoning behind that old STOP still stands for any future command
with no page: add the page first, then the map row.
The system map is a table, not a rule: “Page names do not derive from command names. This
table is the truth; never construct a filename from a slug.” This page is one of its rows
— | `document` | `docs/architecture/system-document.html` |. The map also
carries a deliberate mismatch: “system-monthly-tax.html is stale naming left
from the 2026-07-31 rename of the command to nai-tax-theo. The map records reality. Do
not rename the file — renaming a live URL is a deletion by another name.”
The editorial lane has no pattern fallback either: “Exactly these targets, and no pattern
fallback: index, features, user-guide,
claude-md, verification-patterns, agent-conventions, and
readme-<NN> for each numbered section folder (e.g. readme-06).”
| Lane | Sources, verbatim from the command file |
|---|---|
| editorial | “the file checked, plus every file under .claude/commands/
and .claude/agents/. Those are what settle a factual claim.” |
| survey | “the command file for the system, plus every agent file it dispatches. Read the command file first to find out which those are — do not guess from names.” |
| blog | “11 Blog/<target>.md alone.” |
Each row's tools: column is copied exactly from that agent file's frontmatter.
No agent in this system has a web tool: “It uses no web tools, and neither does any agent it
dispatches.”
| Subagent | Wave / lane | tools: grant | What it does |
|---|---|---|---|
| doc-scoper | Wave 1 — every lane | Read, Write, Glob, Grep | “Inventories the source files behind one documentation target, detects whether its page is being created or updated, and in the editorial lane extracts the page's checkable factual claims.” It “never write[s] a documentation page.” |
| doc-surveyor | Wave 2 — survey lane | Read, Write, Glob | “Regenerates one architecture page as an as-built survey of the agent and command files it documents, anchoring every factual assertion to a verbatim quote. Writes a staged page only; never publishes, and never writes prose it cannot cite.” |
| doc-renderer | Wave 2 — blog lane | Read, Write | “Renders one markdown blog draft into a styled, self-contained HTML page in the site's design language. A view only — it computes nothing, adds nothing, and every sentence on the page appears verbatim in the markdown.” |
| doc-checker | Wave 3 — every lane | Read, Write, Grep | “Adversarially checks every claim in a documentation run — re-opens the cited file, hunts for the quoted evidence, and verdicts CONFIRMED or UNSUPPORTED with a reason. Never edits, adds, or drops a claim; never rewrites a page.” |
The scoper decides the run's mode: “Determine mode: update if
page names a file that exists, create if it does not, and
update is never assumed for page: none — the editorial lane is
always mode update, because its page always already exists.” And the checker runs
regardless of what came before it: “The checker runs in every lane, every run, including when
there are zero claims. Its absence is never silent.”
| Enforced in | The rule, verbatim |
|---|---|
| .claude/commands/nai-document.md | “It never creates or edits a file under .claude/agents/ or
.claude/commands/. Documentation follows the system. If the docs and the agents
disagree, either could be wrong, and only the human decides which.” |
| .claude/commands/nai-document.md | “It never runs an agent system to find out what it does. Everything comes from reading files.” |
| .claude/commands/nai-document.md | “It never deletes or renames a page. A stale page is reported; a dead URL is forever.” |
| .claude/commands/nai-document.md | “It never authors prose. It renders drafts the human wrote and surveys files the human wrote.” |
| .claude/commands/nai-document.md | “Generators write to 12 Documentation/runs/<target>/proposed/.
Never dispatch a generator with a path under docs/.” |
| .claude/commands/nai-document.md | “If it returns missing:, STOP and report that line verbatim.
Do not continue on a partial source list.” |
| .claude/agents/doc-scoper.md | “Never substitute a similar file for a missing one, and never proceed on a partial source list.” |
| .claude/agents/doc-scoper.md | “Editorial judgment is not checkable and must not become a claim” — “When unsure, leave it out — a missed claim costs nothing, a bogus UNSUPPORTED verdict costs trust.” |
| .claude/agents/doc-scoper.md | “source is always a file, never a directory — the
checker opens it and searches it, and a directory has no text to search.” |
| .claude/agents/doc-surveyor.md | “Never survey a system from a partial source list. A page that documents three of four subagents is worse than no page, because nothing on it says which one is absent.” |
| .claude/agents/doc-surveyor.md | “Anything you cannot anchor to a quote becomes an open question, never a sentence on the page. A page that says less and cites all of it beats a page that reads well and cannot be checked.” |
| .claude/agents/doc-renderer.md | “You never author, edit, shorten, expand, correct, or reorder the author's prose. Not for grammar, not for clarity, not for length. Every sentence on the page appears verbatim in the markdown.” |
| .claude/agents/doc-renderer.md | “Nothing else is added. No summary, no table of contents, no “further reading”, no author bio, no date you were not given.” |
| .claude/agents/doc-checker.md | “A quote that appears only in a different file than the one cited is UNSUPPORTED. The citation is part of the claim.” |
| .claude/agents/doc-checker.md | “A quote matching except for wording, tense, or number is UNSUPPORTED. Verbatim means verbatim. Differences in surrounding whitespace or line wrapping are not differences in wording and may be ignored.” |
| .claude/agents/doc-checker.md | “You never widen a search to make a claim pass.” — “You never mark a claim CONFIRMED because it is obviously true. You are checking the citation, not the fact.” |
Why there is no redraft loop
“Your verdict is terminal: a claim you mark UNSUPPORTED is reported to the human, never sent back to be redrafted. Iterating would let the generator reword a claim until it slipped past you, which would destroy the citation discipline you exist to enforce.”
The publish guard is the orchestrator's own work: “You do this yourself. No subagent.
Record each line as ✓ or ✗ in the report.” Three lines.
“Serve path — is the page's path re-included in
.vercelignore? Read the file and check.”
“Reachable — for a page being created, is it linked from
docs/index.html, docs/architecture.html, or another page already
reachable? If not, ✗ with the reason.”
“Links resolve — for every relative href and
src in the staged page, does the target file exist? List each broken one.” In the
editorial lane, “there is no page, so record all three lines as n/a.”
Promotion is conjunctive — “Promote automatically only if all three
hold: mode is create (the page does not already exist), and every verdict is
CONFIRMED, and every publish-guard line is ✓.” Otherwise:
“Otherwise do not promote. Report what is staged and STOP, telling the human
exactly which of the three conditions failed and how to promote it afterwards.” The editorial
lane is outside this entirely: “The editorial lane never promotes anything — it has no
page. Its report is the deliverable.”
| Artefact | Written by | Lanes |
|---|---|---|
| 12 Documentation/runs/<target>/working/scope.md | doc-scoper | “Always write” — every lane |
| 12 Documentation/runs/<target>/working/claims.json | doc-scoper (editorial), doc-surveyor (survey), doc-renderer (blog) | “Editorial lane only, additionally write” for the scoper; the two generators each write it in their own lane |
| 12 Documentation/runs/<target>/proposed/<file> | doc-surveyor or doc-renderer | survey, blog |
| 12 Documentation/runs/<target>/working/verdicts.json | doc-checker | every lane |
| 12 Documentation/runs/<target>/report.md | the orchestrator | every lane |
The staged page differs by lane. The surveyor's must cover “what it does, in one
paragraph”, “the flow, as a <pre class="mermaid"> block
whose source is editable text, never a pre-rendered SVG”, “a table of every subagent
with its exact tools: grant, copied from the agent file”,
“the guardrails, each one quoted from the file that enforces it”, and “what the
output looks like” — matching a sibling's house style rather than inventing one:
“Match the house style; do not invent a new one.” The renderer's is
“a complete, self-contained HTML document, styles inline in a <style> block,
no external stylesheet, no external script”, taking its design language from
docs/index.html.
verdicts.json is strict about shape: “Every id in
claims.json appears exactly once, in the same order. verdict is exactly
CONFIRMED or UNSUPPORTED; there is no third value.” An empty run is
still a run — “An empty claims array is not missing.
Process it normally and produce an empty verdicts array.”
report.md carries the lane, the mode, the outcome
(“<promoted|staged, not published>”), a verdicts table, a
publish-guard table, the open questions (“Anything the generator could not anchor to a quote,
verbatim as it reported it”), and what to do next. The last instruction in the command is
about honesty in the summary: “Never claim a page is published when it was only
staged.”