Page source #

View this page as Markdown

This page lists the rules a Markdown source page follows: its slug, its front matter, its order, its links, the images and other files beside it, its callouts, and its diagrams. Add a page is the guide that shows how to apply them.

Slugs #

A page's slug is its URL path within the site. By default the slug comes from the file path:

  • guides/first_guide.md becomes /guides/first-guide: underscores become hyphens, and .md is removed.
  • guides/index.md becomes /guides.
  • The root index.md becomes /.

A file name therefore sets the slug, and a folder containing an index.md sets the section. A slug key in the front matter takes precedence over the derived slug. The check reports a declared slug that puts the page in a different folder from its source file, because the navigation follows the source folders.

Slug rules #

A slug is /, or a path that starts with / and has no empty segment. A slug must not contain:

  • repeated slashes, or a trailing slash other than / itself;
  • a . or .. segment;
  • a backslash, a query string, or a fragment;
  • a control character, or any of <, >, :, ", |, ?, *.

A segment must also not end in a dot or a space. It must not be a reserved device name in any letter case, with or without an extension: CON, NUL, PRN, AUX, COM1 through COM9, or LPT1 through LPT9.

The tool refuses a malformed percent encoding. It decodes each segment once for these rules, so an encoded slash or backslash is refused too. The tool keeps the slug as written and changes nothing in it.

Path collisions #

The tool compares generated paths in lower case on every platform, so /Guide and /guide collide. A file cannot also be a folder: /guide/index.html collides with the HTML written for /guide.

The root names docs.css, site.css, docs.json, llms.txt, llms-full.txt, sitemap.xml, 404.html, and mermaid.min.js are reserved for the build's own files. Each is reserved even when the build does not write it, site.css when the build is given no stylesheet for example.

A file beside the pages follows the same rules. Its path must be a safe slug, and it collides with a page, a redirect, or a reserved name as a page does. A source file guide/index.html, for example, collides with the HTML written for a page at /guide.

Front matter #

Front matter is the metadata block between two --- lines at the start of the file. The parser accepts seven keys, and only title is required.

---
title: First guide
description: What the guide lets the reader do, in one sentence.
slug: /guides/first
order: 2
visibility: public
redirects_from: [/old/first-guide]
---
Key Required Default Notes
title yes — The page's title, in the navigation, the page head, the index, and the manifest.
description no empty One sentence, in the page head, the index line, and the manifest row.
slug no derived from the file path Tree-relative, with a leading slash. A declared slug takes precedence over the derived one.
order no by slug among siblings An unquoted decimal integer from -9007199254740991 through 9007199254740991. Order gives the sort rules.
visibility no public Any other value leaves the page out of the build, the navigation, and every machine file, unless the build passes --include-hidden.
redirects_from no empty A one-line inline list of old slugs. The build writes a redirect stub for each.
section no the first slug segment, or home for the home page The section word the manifest records for the page, which a page kept at the root can set to its section's word; the check reports a word that names no top-level section.

The block #

  • The block opens on the first line with --- and closes on a later line that contains exactly ---.
  • Blank lines inside the block are allowed.
  • Every other line is an unindented key: value entry.

The build refuses an unknown key, a duplicate key, a multiline value, or a structured value. The tool parses every file's front matter before it applies visibility, so malformed front matter in a hidden page also fails the default check or build.

Values #

Form Rule
Plain Trimmed. A # inside it stays literal text.
Single-quoted An apostrophe inside it is doubled, as in title: 'It''s a guide'.
Double-quoted JSON string escapes apply.

A quoted value must close, with nothing but whitespace after it. A value that starts with [, {, |, >, &, *, or ! must be quoted to be read as text. So must a value that starts with - or ? followed by whitespace. Write title: "{name: Example}", not the bare braces. The parser accepts only these forms and is not a general YAML parser.

The redirects_from list #

redirects_from is a one-line list in brackets. Commas outside quotes separate the entries, and a comma inside quotes stays part of its value. [] is valid, and an empty entry is refused. Each entry follows the slug rules.

Order #

order is read at two scopes:

  • On a folder's index.md, it places the section among its parent's entries.
  • On any other page, it places the page among its siblings.

Entries sort by these rules:

  1. Entries with an order come first, by order.
  2. Entries with the same order sort by slug.
  3. Entries without an order come after, by slug.

Slugs sort in character-code order, so an uppercase letter comes before a lowercase one. The navigation order is therefore the same on every build.

Sections #

A folder containing an index.md is a section. Where the folder also contains other pages or sections, the section is a group in the navigation that the reader opens and closes, and its title is not a link. Its index.md contains only front matter: the title gives the section its name, and the order places it. The build writes no page for it, and it refuses an index that has any text after its front matter.

Where the folder contains only its index.md, that file is a page like any other, at the folder's slug, and the navigation links it.

A folder without an index.md is not a section. Its pages appear among the entries of the nearest folder above it that is a section, or of the root, each placed by its own order. Their slugs still come from their paths, so the folder groups their addresses without adding a group to the navigation.

The check and the build resolve internal links with the same rules. Write a link in one of two forms:

  • a tree-relative path, such as /reference/output/;
  • a path relative to the source page's folder, such as code_blocks.md or ../reference/output.md.

For a relative path, the tool removes .md, replaces underscores with hyphens, and treats index as its folder. Where a page declares a slug that differs from its derived path, link to the declared slug.

The build rewrites a link to a page or a redirect as a relative HTML link. Output says how those links open. An external URL and a link to an anchor alone keep their spelling. A query string does not affect the lookup. A link that matches no page or redirect stops the build, and the check reports it.

A fragment such as #details must match a heading anchor on the destination page. This applies to a link to the current page and to a link through a redirect. A fragment that matches no heading is an advisory finding: the check reports it, and the build proceeds. The check does not read links or images written in raw HTML, or a custom id in raw HTML, and it does not fetch external URLs.

Images and other files #

Every file in the source folder whose name does not end in .md is copied to the same path in the output, byte for byte: an image, a download, or any other file. A file in a folder whose name begins with a dot, or whose own name begins with one, is not copied, so .DS_Store and .git never ship. A file that only hidden pages reference is left out with them, unless the build passes --include-hidden. A file no page references, such as one linked only from raw HTML, is still copied.

A page refers to a file in two ways:

  • an image, such as ![The flow](diagram.png);
  • a link whose target ends in an extension other than .md, such as [the sample](../files/sample.zip).

The tool resolves the path against the source page's folder, or against the source folder for a path that starts with /, as it does for a link to a page. It keeps the file's name as written: underscores stay. The build then writes the copied file's address relative to the built page. A page at guides/add_a_page.md is built at guides/add-a-page/index.html, one folder deeper, so its diagram.png becomes ../../guides/diagram.png.

A query string or a fragment after the path is kept. An external URL, a data: address, and an anchor keep their spelling, and an image or a link written in raw HTML is not rewritten.

A reference to a file the source folder does not have stops the build, and the check reports it. The Markdown copy beside each page keeps the source as written.

Heading anchors #

The build gives each heading an id, its anchor, by these steps:

  1. Take the heading's rendered text: its HTML with the tags removed.
  2. Write it in lower case.
  3. Replace every run of characters other than the ASCII letters a to z and the digits 0 to 9 with one hyphen.
  4. Remove leading and trailing hyphens.

An anchor left empty becomes section, and a duplicate gets the suffix -2, -3, and so on. The rendered text writes &, <, >, ", and ' as &amp;, &lt;, &gt;, &quot;, and &#39;, and the anchor is made from the heading's text as written. So What's new has the anchor what-s-new. The manifest lists each page's anchors.

Callouts #

A block quote whose first line is exactly one of five markers renders as a callout, as on GitHub:

Marker Title
[!NOTE] Note
[!TIP] Tip
[!IMPORTANT] Important
[!WARNING] Warning
[!CAUTION] Caution
> [!WARNING]
> The build replaces the whole output folder.

The marker is read in any letter case, and spaces after it are ignored. The rest of the quote becomes the callout's body, which can hold paragraphs, lists, and code blocks. A first line with text after the marker, such as [!NOTE] Read this, is no marker, so the quote stays a block quote. A bracketed word that is not one of the five, such as [!WARN], stays a block quote too, and the check reports it.

Diagrams #

A fenced block whose language word is mermaid holds a diagram in Mermaid's text syntax:

```mermaid
graph TD
  A[Write] --> B[Build]
```

The build draws it where Mermaid is installed: where mermaid/dist/mermaid.min.js resolves from the folder the command runs in, as npm install mermaid in that folder provides. Otherwise, or with --diagrams-as-code, the block renders as a code block in the language mermaid. A diagram block takes no title and no line set, and the check reports either. Add callouts and diagrams is the guide.