Why Backlinks Matter for AI
- The ID an agent already has is the link.
findandsearchhand back document IDs; embedding one in the prose is the whole authoring step. There is no URL to construct and no path to keep in sync. - Reading a document reveals its neighbors. A
readwithreferencesorbacklinksturns any document into a starting point for traversal, so an agent can follow the graph instead of re-searching the workspace. - The graph cannot drift from the prose. Rows are derived from committed content, so a link that no longer appears in the text no longer appears in the graph.
Two Ways to Link, One Graph
An inline link and a sidecar reference (add_reference) are the same concept at different grains. They both produce rows in the same reference graph and both show up in the same panels — they differ in whether the link lives in the content.
Reach for an inline link when the link belongs in a sentence — that is the default. Reach for a sidecar when you want to relate two documents without touching the body, which is also the only option for
file-kind documents (a PDF or an image has no prose to embed a tag in).
The Syntax
Markdown bodies
section attribute pins the link to one section of the target. The display text between the tags is ordinary content that you choose — it is stored, searchable, and yours to edit.
Report and slide HTML
data-moxn-doc (plus optional data-moxn-section). No href is needed and no client JS — Moxn paints the click affordance and opens the target in a new tab. Put the attribute on the element a reader should click rather than wrapping it in extra markup.
Where the IDs Come From
find and search are where link targets come from. This is the pipeline: discover the document, take its ID, embed the ID.
find returns { id, path, name, description, defaultBranch } per document and { id, documentId, name, position } per section.
search matches on content and returns items that each carry a documentId (section matches also carry a sectionId).
find({type: "section", ...}), or a read with forEdit: true, which keeps the {#id} anchor suffix on each H2 line of the returned markdown.
find is anchor-based — names and paths always reflect the document’s default branch. That is fine for grabbing an ID (the ID is branch-independent), but use read with branchName when you need branch-correct metadata.Worked Example: A Team Directory Report
A report where every person’s card links to that person’s document — the motivating case fordata-moxn-doc.
1
Find the documents you want to link
id you need:2
Put the ID on the element you want clickable
documents tool — action: "create" or action: "update" with kind: "report" and the html field. Every write auto-commits.3
Verify the links landed
derived: true. Reading Jane Doe’s document with backlinks: true now shows the report’s path among her incoming links.edit tool like any other content. There is no separate “create link” call.
Reading Links Back
Aread carries the graph in its front-matter when you ask for it:
references: true— outgoing: the documents and sections this one links to.backlinks: true— incoming: the documents that link to this one, as a deduped list of source paths.
Backlinks are current-state only. They reflect who links here right now, and they are omitted entirely on historical (
commitId) reads. Outgoing references do work point-in-time — a historical read returns the references as of that commit.<moxn:ref> tags themselves also come back verbatim in the markdown body of a read, so an agent editing prose sees the links it is editing around.
Managing Links
documents with action: "list_references" is the only source of a referenceId:
direction is outgoing (the default), incoming, or both. Each row carries:
From the CLI:
How to Reason About Backlinks
These five rules cover almost every question people have about link behavior.
doc names the document anchor, so renaming or moving the target leaves the link working. The display text is content you wrote, and deliberately stays as written — hovering the chip in the editor reveals the target’s current name when it has since changed.
Rows appear only after commit. Until the commit that carries the tag lands, the link is in no panel, no list_references listing, and no read. An uncommitted link is not yet part of the graph.
A dead section pin degrades; only a deleted document breaks. If a section pin names a section that no longer exists, the link still opens the target document — the fragment is simply ignored. Only a deleted target document is genuinely broken: the chip renders in an amber degraded state and stops being clickable, and the listing shows a null path for that end.
Grain is not provenance. A link in a document’s preamble derives a document-grain row; a section can equally own a hand-authored section-grain sidecar. So “can I remove this row?” is answered by derived, never by grain.
Links are branch-scoped, because content is. A link is asserted by content, and content belongs to a branch. A link committed on a feature branch is visible on that branch, and reaches the default branch when the branch merges — the same lifecycle as the words around it. See Branching & Merging.
In the Web Editor
Two ways to insert a link while writing:- Type
@— a picker opens, searching documents by name and path. Choose one and Moxn inserts the chip with the document’s name as the display text, which you can then edit like any other text. - Paste a document URL — pasting a
…/knowledge-base/<uuid>link converts it into a chip. If the ID names nothing you can read, the paste stays an ordinary link rather than guessing.
A link to a document you don’t have permission to read renders as plain text — no chip, no title, no navigation. Access is checked when the link is resolved, so a document you cannot see never leaks its name through someone else’s prose.
Related
documents—list_references,add_reference,remove_referencefind— discover documents and sections, and their IDssearch— full-text search returning document IDsread—references,backlinks, andforEditsection anchors- Documents & Sections — the structure links point into