Skip to content

Overview

Merlon Docs, a documentation system delivered as a toolchain and an Agent Skill, helps teams maintain large documentation in small shard files, compile them into canonical outputs, and validate before merge. It is built for LLM-assisted authoring, human review, and compiled output for agents and end-user readers.

This page is the mental model for the whole system. Use it to orient yourself before diving into command details, API modules, or config fields.

Large Markdown guides are hard to edit, diff, and link correctly. A single README.md or guides.md with dozens of headings invites merge conflicts, broken cross-references, and orphan sections that no longer appear in the table of contents.

Merlon Docs inverts the workflow:

  1. Authors edit shards: one file per section, listed in the manifest (index.md or shards.md) of their guide.
  2. Compile stitches shards: it normalizes heading levels and rewrites links.
  3. Validation catches drift: orphans and broken internal links or # anchors, plus optional prose and style linters.
  4. Compiled output serves consumers: compiled guides (some as publish outputs) and the optional monolith.

You never hand-maintain the compiled file. Shards are the source of truth. Each compiled guide is generated, whether it is {name}.md under outputDir or a publish output such as README.md.

The glossary defines the core terms:

  • Shard: one .md file that becomes part of a guide (such as 01-intro.md).
  • Guide: a directory of shards plus a manifest, named in compileOrder.
  • Compiled guide: the file compile writes for one guide.
  • Publish output: a compiled guide at its own compile.outputFile, such as a package README.
  • Monolith: the optional single file that stitches the guides without compile.outputFile.
  • Refs registry: GitHub-style heading slugs from compile output.

Paths and config: shards live under the docs root (--docs-root), one subdirectory per guide. Generated paths are relative to outputDir, which defaults to _build and is safe to delete. --config resolves from the directory you run the command in, not from the docs root (--config vs --docs-root). Path layout in Config essentials has every other path rule and default, and loadConfig(path, configBase) in the config API follows the same rules.

flowchart TB
  subgraph author["Authoring layer"]
    shards["Shard .md files"]
    index["index.md / shards.md"]
  end

  subgraph merlon["Merlon Docs"]
    cli["@merlon-docs/merlon-docs-cli"]
    core["@merlon-docs/merlon-docs-core"]
    presets["@merlon-docs/merlon-docs-presets"]
    config["merlon.config.json"]
  end

  subgraph outputs["Generated outputs"]
    compiled["Compiled guides under outputDir"]
    publish["Publish outputs"]
    monolith["Optional monolith (outputFile)"]
    refs["refs.json"]
  end

  subgraph validate["Validation"]
    orphans["Orphan / manifest checks"]
    peers["Peer linters optional"]
  end

  config --> cli
  cli --> core
  presets -.-> peers
  shards --> core
  index --> core
  core --> compiled
  core --> publish
  core --> monolith
  core --> refs
  compiled --> validate
  publish --> validate
  monolith --> validate
  shards --> validate
Package Role
@merlon-docs/merlon-docs-cli Command-line entry point: compile, check, review, shard, refs, peer linter wrappers.
@merlon-docs/merlon-docs-core Library behind the CLI: compile/assemble, refs, validation, shard orchestration, hooks.
@merlon-docs/merlon-docs-presets Starter markdownlint configs and the MerlonDocs Vale style (opt-in via config / .vale.ini).

The CLI is a thin wrapper over core. Integrators (CI, editors, agents) can call core directly or shell out to the CLI.

Understanding this sequence explains why most commands exist:

[optional] merlon shard Split a source document into guide shards (md-tree)
↓
Edit shards + index.md
↓
merlon compile Assemble outputs, rewrite links, write refs.json
↓
merlon check Run the validation gate

Split (merlon shard) is the inverse path. Use it to bootstrap shards from an existing source document, not on every edit cycle.

For each guide in compileOrder, core:

  1. Reads section files: from link order in the manifest (index.md / shards.md). See Manifest compile order when the manifest mixes preamble example links with a ## Sections list (compile.sectionsHeading).
  2. Transforms each shard: demotes headings to fit the guide level and handles the preamble shard (compile.preambleSection) as Project layout says. Then it runs the compile hooks (stripAnchors, codeEvidence, inlineInserts) by default. See Default compile hooks. Cross-guide link rewrite runs at assembly. See Cross-guide link rewriting.
  3. Assembles the guide body: injects optional compile.title as a ## heading followed by a blank line, then concatenates sections in order. When the first shard’s top heading matches the title, that duplicate heading is stripped.
  4. Rewrites links: the link passes turn a shard’s links to other shards into #slug targets, in the same document or in another output. They rewrite a ./ or ../ link to any indexed shard, and a bare link to a shard the guide stitches. A link to a guide that compile.crossGuideLinks.ignoreGuides names keeps a path to the shard instead, except where a link to a shard the compiling guide stitches takes its in-document anchor. The passes then rebase the shard’s ../ paths, kept ones included, relative to the guide’s link base, except the ones Publish-relative exclusions lists, such as a path that leads to no file.
  5. Marks broken links and re-aligns tables: by default, a BROKEN LINK marker replaces each #fragment link that matches no heading or section slug in the compiled guide. A link to a missing file stays a link, and link lint reports it. Then core re-aligns each aligned table whose links changed width. See Tables after link rewriting.
  6. Writes outputs: one compiled guide per guide (at compile.outputFile or the default path), plus the monolith when top-level outputFile is set and at least one guide has no compile.outputFile.

Guides with compile.outputFile are excluded from the monolith so you can publish npm READMEs, DEVELOPERS.md, or compiled review guides side by side.

merlon check runs a fixed order of stages, from the orphan check to the coverage scan. A failure in one of the first three stops the run at once, while most later stages report a failure and let the run go on. Check gate lists the stages and when each one runs.

merlon.config.json is the single contract between your repo layout and every command:

  • compileOrder: which guides exist and in what order they appear in the monolith.
  • guides[].compile: per-guide manifest name, hooks, publish path, title, scope root, etc.
  • outputFile: optional monolith path.
  • refs: registry file path and slug algorithm.
  • lint / vale: peer linter config paths and scan globs.

This repository uses Merlon Docs on its own docs under docs/, and its docs/merlon.config.json is an example of a multi-output layout. Guide directories lists the output each of its guides compiles to.