The Sourcebook dialect
Status: normative. This page is the authoring guide AND the contract the parser is tested against. If the two disagree, this page is right and the parser is wrong.
It is also the engine describing itself — this page lives in a git repository and is pulled in by the engine it documents.
The one rule
A Sourcebook file is a valid Markdown file first. Everything below is either plain CommonMark, or a fenced block whose info string we understand. Open any file in MkDocs Material or Docusaurus and it builds; the reader may lose a player or a live table, never the content.
That rule has a consequence worth stating plainly: we never write raw HTML
with class=. MDX (Docusaurus) requires className, so an HTML block
styled for MkDocs breaks a Docusaurus build. Fenced blocks are the only
extension mechanism, because an engine that does not know ```video shows
its body as a code block and builds fine.
Front matter
---
title: Setting up the i550 inverter # page title; falls back to the first H1
slug: i550-setup # THE address segment; falls back to the title
sidebar_position: 3 # order among siblings (Docusaurus spelling)
sidebar_label: i550 # short label for the menu
description: Wiring, parameters, first run.
tags: [inverters, commissioning] # becomes TERMS, see Taxonomy
draft: true # not published; still fetched
---
Every key above is a key MkDocs Material or Docusaurus already uses. We add none of our own. An unknown key is kept and reported, never dropped.
slug is the page's identity
The address comes from the slug, not from the title. Rename the page, edit its heading, translate it — the address does not move.
Never let a title decide an address
Titles get edited; addresses get printed in manuals and pasted into e-mails. A page whose address follows its wording moves every time somebody improves a sentence, and every link written down before that breaks.
A page declaring no slug keeps taking its address from the title, so nothing already published moves.
A slug of index or readme means the page IS its section. It
contributes nothing to the address, so the landing page of a documentation
set lives at /docs/ and a section's index at that section's own address —
not one segment below it. The same holds when such a page is somebody's
parent: it adds no segment to the paths beneath it either.
Admonitions — both spellings
Write whichever your team prefers; both render identically here.
!!! warning "Disconnect the mains"
The DC link stays charged for five minutes.
:::warning[Disconnect the mains]
The DC link stays charged for five minutes.
:::
Types: note, tip, info, warning, danger, example, quote,
success.
Three of them are MkDocs-only
example, quote and success exist in MkDocs Material and have no
Docusaurus directive of any of those names. Written as :::success,
Docusaurus renders a stray directive rather than an admonition — so write
those three in the !!! spelling, where they degrade to plain content
everywhere.
The other five behave identically in all three engines, in both spellings. This was found by the conformance build and by nothing else: the block looked perfect here and in MkDocs, and only the third engine disagreed.
Video with an outline
The block a machine manual is written around. Everything inside is DATA — it becomes fields on the page, so Views and search can process it.
```video
src: https://www.youtube.com/watch?v=XXXXXXXXXXX
title: Commissioning the i550
transcript: ./captions.vtt # optional: WebVTT or SubRip
outline:
- at: 0:00
text: What you need before starting
- at: 1:24
text: Wiring the mains and the motor
- at: 4:12
text: Setting the ramp time
- at: 7:45
text: First run and what to watch
```
srcmay be a YouTube URL or a path to a video committed to the repository (../assets/i550.mp4).atacceptsM:SS,MM:SSorHH:MM:SS. Write it unquoted; YAML reads1:24as a sexagesimal number and the parser expects that.- Clicking an outline entry seeks the player to that second.
transcript:points at a caption file beside the page — WebVTT or SubRip, the two formats a caption file is already in. It becomes searchable and seekable.
The transcript never overwrites the outline. The outline is what a person wrote about the video; the transcript is what a machine heard in it. A reader navigates by the first and a search finds the second, and merging them would destroy the authored half on the first re-sync — the half that took effort.
The captions are yours. Nothing is fetched from the video host — you put the file in the repository, where it is reviewed in a pull request like everything else, translated like everything else, and works for a video that never went near a hosting service. A transcript pulled from somewhere else would be somebody else's text, changing when they change it. - In MkDocs or Docusaurus the block shows as a readable list of times and descriptions. The content survives; only the player is ours.
Cards
A grid of links — the shape a landing page usually wants.
```cards
- title: Quick start
href: ./quickstart.md
icon: rocket
text: From install to a running program in minutes.
- title: Troubleshooting
href: ./troubleshooting.md
icon: alert
text: The messages the system prints, and what is behind them.
```
MkDocs Material's own spelling is read too, unchanged:
<div class="grid cards" markdown>
- **Quick start**
---
From install to a running program in minutes.
[Quick start](quickstart.md)
</div>
A bold first line is the card's title, --- is the rule MkDocs draws under
it, the prose is the text, and the link is where the card goes. A grid that
does not read as cards is left exactly as written.
It would not have degraded gracefully
The natural assumption is that an unsupported grid still shows a readable
list of links. It does not: the <div> is raw HTML, so the Markdown inside
is never processed — the bullets and the [text](target) links would sit on
the page as literal markup, unrendered and unrewritten, pointing at files
instead of addresses. Which is why it is read rather than tolerated.
Tables
Three kinds, because "a table" means three different things.
Small tables — ordinary GFM. Use these for anything a person typed.
| Parameter | Default | Range |
|-----------|---------|-----------|
| P100 | 5.0 s | 0.1–3600 |
Large data — a table nobody wants in the body:
```table
src: data/parameters.csv
caption: All i550 parameters
searchable: true
```
The CSV lives in the repository next to the page, so it is reviewable in a pull request like anything else.
Live data — what the platform itself holds:
```view
name: error_codes
argument: term # the page's own term; or a literal value
```
This renders a real listing through the existing embed door, with its existing guarantees. If the listing does not exist or refuses to be embedded, the page renders without it and the sync says so.
Layout
Presentation, and therefore the one thing that legitimately stays as markup in the body.
```layout
gap: large
columns:
- |
Left column, ordinary Markdown with **emphasis** and lists.
- |
Right column.
```
Every block keeps its content inside its own fence. An earlier draft let the layout's content follow the fence — it degrades more prettily, and there is no honest way to say where the layout stops. One shape for all five blocks means an unambiguous end and a degradation that still shows the content in order.
```cards
- title: Wiring
href: ./wiring.md
icon: plug
text: Mains, motor and braking resistor.
- title: Parameters
href: ./parameters.md
icon: sliders
text: Every parameter with its default.
```
Taxonomy
tags: in front matter become terms, not text.
- A vocabulary or term that does not exist is created, in your organisation, and the sync tells you it did.
inverters,InvertersandINVERTERSare ONE term. Case, diacritics and surrounding space do not create duplicates.tags: [products/inverters/i550]creates the whole branch in order.- A term whose last use disappears is reported as unused, never deleted — deleting it would silently break every other link to it.
- Every vocabulary a documentation set creates carries that set's GROUP, so an administrator sees which taxonomy belongs to which documentation without opening either.
Links and images
Write them relatively, the way both other engines expect:
See [wiring](./wiring.md) and the [glossary](../reference/glossary.md).

Links to .md files are rewritten to the page's address here and left alone
for the other engines. Images are fetched into the file store, in a folder
tree mirroring the repository, and identical bytes are stored once.
Versions
A version is a tag on main — a photograph of the documentation on the
day it shipped:
git tag docs/3.4 && git push origin docs/3.4
Tags matching docs/* become released versions. main itself is always the
current version. This keeps one rule intact: nothing is ever published
from a branch that was not merged. A version is not somewhere else — it is
this documentation, earlier.
If your repository is already laid out the Docusaurus way, that works too:
docs/ → current
versioned_docs/version-3.4/ → released 3.4
versioned_sidebars/
Both live on main, so both are legitimate.
Until you tag or create a versioned directory, nothing changes: no chooser appears, and you write exactly as you do now. Versioning costs nothing until you use it.
Readers stay inside the version they chose. A page that does not exist in their version says so and offers the current one — it is never shown to them as though it were theirs.
Languages
Write translations either way; both are accepted, because both are what the other engines expect:
docs/i550.md docs/en/i550.md i18n/en/…/i550.md
docs/i550.sk.md docs/sk/i550.md i18n/sk/…/i550.md
A translation is the same page in another language, not a second page. It shares the original's tags, its version, its weight and its place in the tree, and it joins the platform's existing language machinery — so everything that already works in eleven languages works here without a special case.
What a translation may say differently
The title, the body and the video outline. Everything else — the tags, the sidebar order, the version, the address — belongs to the page, and every language of it shares one answer. Letting a translation set its own tags would let two languages of one page drift into different categories, and the drift would be invisible until somebody browsed in the other language.
A language directory is only a language directory if the platform actually
has that language installed. docs/cs/index.md is Czech; docs/api/index.md
is a directory called api. Nothing in the path can tell them apart, so the
installed languages decide — guessing would file an API reference as a
translation.
A page you have not translated yet is shown to that reader in the original language, with a note saying so. Silence would be worse: an untranslated page that does not admit it is indistinguishable from a bad translation.
Version and language are independent. Any version may exist in any language; a missing combination falls back by language first, then by version.
What is fetched, and from where
Only main. Only main is fetched, and only main is published. There
is no staging branch that quietly appears on the site, because a reader
seeing an unmerged branch is the one failure a documentation system cannot
explain away.
A change made in the browser becomes a branch and a pull request. It is
reviewed on GitHub like any other change and appears on the site when it is
merged. The platform cannot write to main, by design.
What you edit there is the Markdown, not the rendered page — each page
keeps its source file byte for byte, so a commit is exactly what you typed,
blocks included. If main moved since the page was imported, the change is
refused and reported rather than forced over somebody else's work.