Authoring Documentation

Documentation lives as markdown files under src/MeshWeaver.Documentation/Data/ and is served as mesh nodes under the Doc partition. The file system maps 1:1 to node paths β€” and links resolve against node paths at render time, not against the file system. Getting that one idea right is most of this page.

Files β†’ node paths

File Node path
Data/Architecture.md Doc/Architecture
Data/Architecture/AsynchronousCalls.md Doc/Architecture/AsynchronousCalls
Data/GUI/ContainerControl/Stack.md Doc/GUI/ContainerControl/Stack
Data/GUI/ContainerControl/index.md Doc/GUI/ContainerControl (an index.md is its folder's node)
Data/ReleaseNotes/3_0_0.md Doc/ReleaseNotes/3_0_0 β€” a flat file on purpose, see below

🚨 A folder name must be a C# identifier; a file name need not. The embedded-resource name MSBuild gives a file makes every folder segment an identifier β€” a folder starting with a digit is prefixed (3_0_0/ β†’ _3_0_0), a hyphen becomes an underscore β€” while the file name is kept verbatim. So Data/ReleaseNotes/3_0_0/index.md is served at /Doc/ReleaseNotes/_3_0_0, and every link to the documented path is broken with nothing in the build to say so (DocumentationLinkIntegrityTest is what caught it). Version pages are therefore flat files, Data/ReleaseNotes/3_0_0.md, and no doc folder starts with a digit or carries a hyphen.

Note the pairing: Architecture.md is the index node and the folder Architecture/ holds its children. Agent definitions follow the same scheme under the Agent partition (content/ai/Agent/Researcher.md β†’ Agent/Researcher), and skills under the Skill partition (content/ai/Skill/code.md β†’ Skill/code).

At render time, LinkUrlCleanupExtension resolves every markdown link with PathUtils.ResolveRelativePath against the page's full node path. The page is treated as a container, so:

You want to link… Write Resolves to
Anywhere (the robust default) [CQRS](/Doc/Architecture/CqrsAndContentAccess) exactly that path
A sibling page [CQRS](../CqrsAndContentAccess) up one from Doc/Architecture/ThisPage, then down
Your own child page (from an index) [Stack](Stack) Doc/GUI/ContainerControl/Stack
Another area [Data Binding](/Doc/GUI/DataBinding) absolute β€” immune to moves of this page
An agent definition [Researcher](/Agent/Researcher) the Agent partition
A built-in skill [/code](/Skill/code) the Skill partition

And the three forms that never resolve:

[X](SiblingPage)          ❌ from a leaf page this resolves to ThisPage/SiblingPage
[X](xref:Architecture/X)  ❌ there is no xref: handler in the pipeline
[X](../SiblingPage.md)    ❌ node paths have no .md suffix

DocumentationLinkIntegrityTest (in test/MeshWeaver.Documentation.Test) resolves every link in every doc, agent, and skill page with the real PathUtils and fails the build naming the page, the literal URL, and the bad target β€” so a broken link never reaches the portal.

Two more link rules:

Frontmatter

---
Name: Human-readable page title          # shown in catalogs and the TOC
Category: Architecture                   # grouping hint
Description: One-line summary β€” lands on the node's Description column and search.
Icon: <svg …/>                           # inline SVG, content:file.svg, or an absolute URL
---

Thumbnail, Authors, and Tags are also supported. Abstract is the canonical name for the summary and Description is accepted as its legacy alias β€” both land on the node's Description. Title is likewise a legacy alias of Name. See MarkdownFileParser.MarkdownFrontMatter (src/MeshWeaver.Hosting/Persistence/Parsers/MarkdownFileParser.cs). Icon falls back to Thumbnail when omitted.

Images and diagrams

Code samples are executable

When a doc page brings a code example, the example is executable. A real, runnable sample is written as an executable fenced block, never a static fence β€” the reader sees the code, a Run button on the cell's toolbar, and the result directly below the code (the notebook-cell shape). Blocks auto-execute on page load and Run re-executes them on demand.

The fence syntax:

    ```csharp --render MyDemo --show-code
    MeshWeaver.Layout.Controls.Stack
        .WithView(MeshWeaver.Layout.Controls.Markdown("**live!**"))
    ```

A plain fence is the explicit marker for a non-runnable fragment β€” pseudo-code, wire shapes, framework source excerpts (handlers, layout-area methods, service registrations), bash. If a fence shows real, self-contained runnable code, make it executable.

Every executable block is enforced by CI: DocExecutableBlocksTest (in test/MeshWeaver.Persistence.Test) extracts every --render/--execute block from every embedded doc page and executes it through a real kernel session β€” a block that stops compiling fails the build naming the page and the block. The same test carries a coverage ratchet, so silently converting an executable block back to a prose-only fence is visible.

Use executable blocks for every UI claim a page makes β€” if the doc says a control renders, the doc should render it. Pages that define sample models back them with real code in src/MeshWeaver.Documentation/ and tests in test/MeshWeaver.Documentation.Test (see Business Rules for the canonical example).

Style

Reconnecting…
The server was updated. Reloading the page to pick up the latest version.