Agent Editing Guide

This is the operational playbook for agents editing Noma documents. The rule is simple: read scoped context, discover IDs, choose the smallest stable patch, prove the edit, apply it only after the proof passes, validate the result, and never rewrite a whole file unless the user explicitly asks for a migration.

Agent contract

If you are an agent, treat the .noma source as the artifact's audit log. Your job is to preserve surrounding bytes, keep block IDs stable, and make the next human review smaller.

The safe editing loop

StepCommandPurpose
1. Readnoma render file.noma --to llm --budget 12000Get deterministic context without HTML noise.
2. Discover IDsnoma ids file.nomaFind canonical IDs and aliases before patching.
3. Validatenoma check file.nomaRecord the pre-edit diagnostic state.
4. Provenoma proof file.noma --ops ops.json --out proof.htmlDry-run the patch and render diagnostics, hashes, diff, source preservation, LLM context, ID registry, and a post-patch preview.
5. Patchnoma patch file.noma --ops ops.json --inplaceApply the same transaction after the proof is accepted.
6. Re-checknoma check file.nomaConfirm the edit did not introduce errors.
7. Rendernoma render file.noma --to html --strict --out artifact.htmlProduce a safe published artifact.

Use noma proof file.noma --ops ops.json --inplace --out proof.html when the proof artifact and source update should be one guarded operation. The command writes the source only if the simulated post-patch document has no validation errors.

Browser proof surface

The web workbench exposes the same product contract for no-install review:

  1. paste one patch op or an ops array into Agent Proof
  2. click Review -> Prove
  3. inspect hashes, diagnostics, source preservation, ops, and post-preview in

the Proof output tab

  1. click Apply only when the proof is writable
  2. copy Share Proof when a reviewer needs proof metadata without the source

Workbench table and dataset edits also travel through this path. The visual grid generates granular patch ops, runs a proof, and only writes the browser draft when post-validation has no errors.

Space maintenance

For multi-page documentation, books, papers, or agent memory packs, treat the book manifest as the project boundary:

noma ids docs/book.noma.yml
noma check docs/book.noma.yml
noma render docs/book.noma.yml --to site --out dist/docs

The generated Noma Space is reader-facing, but it also gives agents useful orientation: _assets/search-index.json lists page titles, paths, tags, status, owners, updated dates, summaries, and plain text; page sidebars expose related pages and backlinks; cross-chapter [[id]] links use the same scoped ID/alias map as validation. Edits still go through source patches against .noma files, not HTML rewrites.

Choose the smallest operation

User intentPreferred op
Replace an entire semantic blockreplace_block
Change only the prose/bodyreplace_body
Rename a section title but keep links stableupdate_heading
Add or resolve a review noteadd_comment / resolve_comment
Add a Word-compatible footnote or endnoteadd_footnote / add_endnote
Propose a tracked Word review editadd_change_request
Change one body cell in an ID-bearing ::tableupdate_table_cell
Change one header cell in an ID-bearing ::tableupdate_table_header_cell
Add or remove one body row in an ID-bearing ::tableinsert_table_row / delete_table_row
Add or remove one column in an ID-bearing ::tableinsert_table_column / delete_table_column
Change one body cell in an ID-bearing ::datasetupdate_dataset_cell
Add or remove one data row in an ID-bearing ::datasetinsert_dataset_row / delete_dataset_row
Add or remove one data column in an ID-bearing ::datasetinsert_dataset_column / delete_dataset_column
Reorder or re-home an existing semantic blockmove_block
Insert evidence, a task, or a new cardadd_block
Remove obsolete materialdelete_block
Change confidence, status, owner, or sourceupdate_attribute
Clear stale metadataremove_attribute
Change a canonical ID and retarget referencesrename_id

Transaction shape

Patch files should use the transaction wrapper when an edit has more than one operation or when validation should guard the write.

{
  "prevalidate": true,
  "postvalidate": true,
  "ops": [
    {
      "op": "update_attribute",
      "id": "launch-decision",
      "key": "status",
      "value": "accepted"
    }
  ]
}

Book-wide transactions

noma patch book.noma.yml --ops tx.json --inplace routes each op to the chapter that owns its target block ID. Chapter-scoped section IDs (chapter/heading), their unscoped aliases, and directive IDs all resolve, so an agent addresses blocks exactly as it discovered them via noma ids. All chapters patch in memory first; the re-assembled book is validated; files are written all-or-nothing. An ID that exists in more than one chapter is rejected with id_conflict — switch to the chapter-scoped form. baseHash preconditions verify against the owning chapter file, so the concurrency contract is identical to single-file patching.

Self-repair with fixits

Validator diagnostics carry a fix field when the repair is mechanically unambiguous — today: broken attribute references (for=, target=, block=) whose target has exactly one near-miss ID. The fix payload is a complete patch op; pass it straight to patchSource or patch_block, or let the CLI do it:

noma check report.noma --fix    # applies every available fix, re-validates

Treat fixits as the first repair attempt in a validation loop: apply them, re-check, and only escalate to reasoning about the document when diagnostics remain. Never apply a fixit whose diagnostic you have not read — the patch is mechanical, but whether the near-miss ID is the intended target is a judgment the diagnostic message ("Did you mean …?") asks you to confirm.

Live validation

Two continuous surfaces complement the one-shot CLI loop:

  • noma check <file> --watch re-validates on every change to the document's

directory — useful for a supervising agent that owns a long editing session.

  • @ferax564/noma-lsp serves the same validator over the Language Server

Protocol (diagnostics with full block spans, document symbols, alias-aware go-to-definition for [[wikilinks]] and for= references, [[ completion). Editor-embedded agents get identical diagnostics to the CLI.

Guardrails for agents

  • Do not scrape rendered HTML when --to llm can provide scoped context.
  • Prefer noma proof before noma patch when the edit is user-visible,

multi-operation, or needs an audit artifact.

  • Prefer replace_body over replace_block when attributes and children should survive.
  • Prefer update_heading over text replacement for section titles.
  • Use rename_id only when the user accepts a breaking ID change.
  • Preserve aliases unless the user asks to remove them.
  • Validate fragments before insertion.
  • Use --strict for published/team artifacts.
  • Keep raw ::html, ::svg, and ::script out of agent-generated content unless explicitly requested.

Minimal agent prompt

Code

agent-safe-edit-prompt

language text
You are editing a Noma document. First discover IDs with `noma ids`. Choose the smallest patch operation. Prove the edit with `noma proof --ops --out proof.html`. Apply edits with `noma patch --ops` only after the proof passes. Run `noma check` after the patch. Do not rewrite the whole file unless explicitly requested.

When to ask a human

Ask before editing when:

  • The requested target has no stable ID.
  • Multiple aliases could refer to different sections.
  • A patch would delete evidence, citations, or accepted decisions.
  • The edit requires raw HTML/script escape hatches.
  • Validation fails after a patch and the fix is not mechanical.

MCP and SDK status

The MCP server exposes read_doc, list_ids, validate_doc, and patch_block over stdio. The Agent SDK wraps that server and remains experimental until the protocol annexes graduate. Treat the CLI and schemas as the stable contract; treat SDK ergonomics as subject to change during v0.x.

Concurrency-safe edits

read_doc returns a hash for every ID-bearing block (sha256 of the block's source slice). Pass it back as base_hash on patch_block — or as the op's baseHash field when calling patchSource directly — and the patch is refused with sha_mismatch if the block changed between your read and your write. Preconditions are per block, so concurrent edits to other blocks of the same document do not conflict. Prefer this over the whole-file expected_sha when several actors share a document.

MCP host setup

Use the published stdio server from any MCP host that accepts command-based server definitions:

{
  "mcpServers": {
    "noma": {
      "command": "npx",
      "args": ["-y", "@ferax564/noma-mcp-server"]
    }
  }
}

The server should be pointed at absolute file paths by the caller. It does not invent edits: agents still need to discover IDs, choose a small patch operation, and validate after the patch.

SDK workflow

Use the SDK when an agent integration needs a typed client and retry-aware source patches:

import { NomaTools, NomaWorkflow } from "@ferax564/noma-agent-sdk";

const tools = await NomaTools.spawn();
try {
  const ids = await tools.listIds("/repo/memo.noma");
  console.log(ids.ids);

  const workflow = new NomaWorkflow(tools);
  const result = await workflow.safePatch("/repo/memo.noma", {
    op: "replace_body",
    id: "summary",
    content: "Updated summary text.",
  });

  if (!result.ok) {
    throw new Error(`${result.code}: ${result.error}`);
  }
} finally {
  await tools.close();
}

safePatch reads the current SHA before patching and retries only on sha_mismatch. Same-file patches inside one workflow are serialized so two local agent tasks do not race each other.