Shoalrun documentation framework
For agents
Start with https://www.shoalrun.com/llms.txt for the documentation index, then read the Markdown pages it links. Skip to article. Documentation index. Read this page as Markdown.
How to

Reuse prose across pages

Share validated prose across pages with typed variables.

Updated
Read as Markdown

A snippet is a shared Markdown or MDX fragment that the build expands into each page that includes it. Use one when the wording must stay in sync across pages. A template creates a draft once; editing a template does not change existing pages.

Register a snippet

Import a snippets mapping in project config. Snippet IDs are dot-separated names, such as authoring.build-check. Each entry points to a plain .md or .mdx file and declares its variables:

docs/config/snippets.yaml
authoring.build-check:
  file: ../snippets/build-check.mdx
  variables:
    command: { type: string, required: true }

The snippet file uses <Var name="command" /> in prose:

docs/snippets/build-check.mdx
<Callout label="Check the result">Run <Var name="command" /> after editing. Confirm the HTML page and Markdown twin contain the same resolved snippet text.</Callout>

A page includes it with literal values:

docs/content/snippets.mdx
<Snippet id="authoring.build-check" values={{ command: "npm test" }} />

See a variable resolve

The example project has a second snippet with two variables:

example/config/snippets.yaml
payment.request-prep:
  file: ../snippets/request-prep.mdx
  variables:
    product: { type: string, required: true }
    header: { type: string, default: Idempotency-Key }

Its source file contains ordinary MDX prose:

example/snippets/request-prep.mdx
For <Var name="product" /> requests, choose a unique
<Var name="header" /> and provide the amount in minor currency units.

The guide supplies product and leaves header at its declared default:

example/content/create-payment-guide.mdx
<Snippet id="payment.request-prep" values={{ product: "Payments" }} />

Readers and agents get resolved text in their respective page formats:

For Payments requests, choose a unique Idempotency-Key and provide the amount in minor currency units.

The real snippet also includes a nested retry note. It inherits product from the outer snippet. See example/snippets/request-prep.mdx and example/content/create-payment-guide.mdx in the repository.

This page uses that snippet below, so the published HTML and Markdown exercise the same expansion.

Check the result: Run npm test after editing. Confirm the HTML page and Markdown twin contain the same resolved snippet text.

Values can be strings, numbers, or booleans. A variable can also list allowed values with enum, such as tier: { type: string, enum: [free, pro] }; its default must be one of them.

Snippet defaults, project variables, page variables, and invocation values apply in that order. Set project variables in the top-level variables mapping of docs.config.yaml, and page variables in a page's variables frontmatter:

docs.config.yaml
variables:
  product: Payments

Unknown names, missing required values, wrong types, and recursive includes stop the build. The document manifest lists snippet IDs used by each page.

For this slice, snippets use inline <Var /> in prose. Code blocks are never changed by string replacement. Put headings in the page, and use absolute or doc: links inside snippets. These limits avoid ambiguous anchors and broken relative links until their adapters are built.

Component attributes

<Snippet> is a standalone empty element in a page or registered snippet. <Var> is an inline empty element inside a snippet file; using it directly in a page fails the build.

Element Attribute Required Meaning
<Snippet> id Yes Registered snippet ID.
<Snippet> values No Literal mapping of invocation values.
<Var> name Yes Variable declared for that snippet.

The included Markdown and supported MDX components render in both HTML and Markdown. Nested snippets work, but recursive includes fail. API embeds need page-level headings and cannot be placed inside snippets. Keep headings in the page, and use absolute or doc: links in snippets.

Check the shared text

Build your project and open each page that includes the snippet. Confirm that HTML and Markdown both contain the resolved text and that no variable tags remain. Change the snippet source and rebuild; every including page should receive that change. If validation fails, correct the named variable, include, or type before publishing.

Reference while working

Often confused with