Agent Editing Guide

This guide is the operational playbook for agents editing Noma documents. The rule is simple: discover IDs, patch the smallest stable block, validate the result, and never rewrite a whole file unless the user explicitly asks for a migration.

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. Patchnoma patch file.noma --ops ops.json --inplaceApply a transaction of targeted operations.
5. Re-checknoma check file.nomaConfirm the edit did not introduce errors.
6. Rendernoma render file.noma --to html --strict --out artifact.htmlProduce a safe published artifact.

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
Insert evidence, a task, or a new cardadd_block
Remove obsolete materialdelete_block
Change confidence, status, owner, or sourceupdate_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"
    }
  ]
}

Guardrails for agents

  • 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

You are editing a Noma document. First discover IDs with noma ids. Choose the smallest patch operation. Apply edits with noma patch --ops. 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.

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.