Skip to content

Manifest compile order

Each guide’s compile order comes from markdown links in its manifest file: index.md by default, or shards.md when configured under guides[].compile.manifest. Merlon Docs collects every link to a .md file in document order and stitches those shards in that sequence. A same-document #slug link also adds slug.md when that file exists in the guide directory. Those shards compile after the shards the manifest links by path. The rule skips #table-of-contents: the [Guide title](#table-of-contents) self-link that opens the manifests in this repository doesn’t add a shard.

Guide directories are human source only (index.md, shard files). Under outputDir, compile writes a per-guide {name}.md for each guide that has no compile.outputFile, the optional monolith and .caches/refs.json. A publish output goes where its compile.outputFile points, which can be outside outputDir. Path layout gives the rules.

A minimal manifest is a table of contents — only section links, no stray .md links in preamble prose:

# Admin guide
- [Getting started](./chapter-1-getting-started.md)

Compile order: chapter-1-getting-started.md first (and only). No extra config needed.

When manifests mix policy prose and section lists

Section titled “When manifests mix policy prose and section lists”

Some guides use index.md as both policy prose (how authors should work) and section manifest (ordered shard list). A common pattern:

# Compound glossary
## Acronyms and new terms
When you introduce an acronym… spell out the term and link it — e.g.
Content-Security-Policy ([CSP](04-security-sync.md#glossary-csp)).
## Sections
- [Product surfaces](01-product-surfaces.md)
- [Tenancy](02-tenancy.md)
- [Data model](03-data-model.md)
- [Security and sync](04-security-sync.md)
- [Review vocabulary](05-review-vocabulary.md)

Merlon Docs collects all .md links in file order:

Order Link Author intent
1 04-security-sync.md Example in policy prose — “link CSP like this”
2 01-product-surfaces.md Section shard
3 02-tenancy.md Section shard
… … …

Compile stitches 04-security-sync.md first, then 01, 02, … — wrong order. The CSP link is documentation, not a directive to lead with that shard.

Set guides[].compile.sectionsHeading to the ## heading that starts the real section list (without the # marks):

{
"name": "glossary",
"path": "glossary",
"compile": {
"title": "Compound glossary",
"sectionsHeading": "Sections",
"outputFile": "glossary.md"
}
}

Merlon Docs only considers links at or after ## Sections. Preamble example links are ignored for compile order. Order becomes 01 → 02 → 03 → 04 → 05.

04-security-sync.md still compiles because it appears under ## Sections, not because it is mentioned in the policy paragraph.

Situation sectionsHeading
Manifest is a TOC — every .md link is a section Omit
shards.md lists cross-tree shards only (compiled review guides) Usually omit
Preamble has inline .md links that are examples or cross-references, plus a separate ordered section list under a ## heading Set to that heading text

sectionsHeading matches a ## line whose text equals it, ignoring case: "Sections" matches ## Sections and ## SECTIONS, not ## Section list. When no ## line matches, compile reads every link in the manifest, as it does without sectionsHeading.

Compile also follows inline .md links inside the shards it stitches. A guide compiles its manifest’s shards plus every shard it finds by following links from shard to shard, a set the code calls linkedSectionFiles. Each link resolves from the directory that contains its shard, and the walk keeps a target that exists in the guide directory or under compile.scopeRoot. Those shards compile after the manifest’s shards, in the order the walk finds them. Guide link index says which shards in the set get an entry in the guide link index.

Authoring form Walk follows it
Inline link [label](path.md) or [label](path.md#fragment) Yes
Linked image [![alt](img.png)](path.md), or a label with balanced brackets such as [arr[0]](path.md) Yes
Image ![alt](path.md) Yes
Link after a backslash, \[label](path.md) No
Reference-style link [label][ref] with [ref]: path.md No
File path in backticks, such as `path.md` No

The walk reads a label and a target as the link passes do. It reads each shard’s raw text, so it also follows an inline link written in a code span or a fenced code block. The walk skips a reference-style link and a path in backticks, so either one can refer to a shard that the guide doesn’t compile. No link pass rewrites either form, and the path stays as written in the compiled output.

That walk serves shards in guide subdirectories and under compile.scopeRoot. The manifest must link every top-level shard in the guide directory directly, because the orphan check reads only the manifest. A top-level shard that only another shard links still compiles, and merlon check reports it as an orphan.

When the manifest links no shards, compile takes the other top-level .md files in the guide directory in file-name order, leaving out any shards.md.

The orphan check compares each guide directory in compileOrder with the shards its manifest links, read the way compile reads them, from compile.sectionsHeading on when that is set. It reports:

  • a top-level .md file in the guide directory that the manifest doesn’t link, other than the manifest and shards.md
  • a manifest link to a file that doesn’t exist
  • a guide directory that doesn’t exist, or a manifest that is missing or can’t be read

The check doesn’t follow links from shard to shard, and it doesn’t read guide subdirectories or compile.scopeRoot. When the manifest links no shards, every top-level file compiles through the file-name fallback, and the check reports none of them for that guide. merlon check runs it first and stops on any issue, as Check gate stages says. Relationship to the orphan check says which unlinked shards neither the orphan check nor the coverage scan reports.

  1. Edit shard files and index.md link order as needed.
  2. Run merlon compile — there is no separate manifest sync step.
  3. Run merlon check — orphan validation uses the same manifest rules as compile.

Code: manifestTextForSections and sectionFiles in packages/merlon-docs-core/src/compile/section-manifest.ts.