Adding a lesson¶
The conventions are few, and most of them exist to keep one promise: a page never claims something a program has not actually printed — on both standard libraries.
The shape of a lesson¶
NN_Chapter/
topic_name/
README.md the lesson
examples/
topic_name.cpp a program that demonstrates it
topic_name.out its recorded output (generated — do not hand-edit)
A folder's overview page is named exactly README.md: GitHub renders it in the folder view and MkDocs turns it into the section's landing page, so the descriptive title goes in the page's # H1.
The one rule¶
Mark where output belongs and let the tool fill it:
Then run python3 tools/run_examples.py. It compiles every examples/*.cpp with $CXX (default c++) as -std=c++20 -O2 -Wall -Wextra -Wpedantic, runs it, compares its stdout with the sibling .out, and rewrites every block. Inside the markers is generated; outside is yours. A source: block pastes the program itself, for a page where the code is the lesson. CI runs --check, which writes nothing and fails if the code, the answer key and the page have drifted apart.
For a brand-new example, record the key — and scope it to your own stem:
Read what it recorded before committing: --update accepts whatever the program printed, so it will enshrine a bug. Stems are unique repo-wide, because a block names a bare stem.
One answer key, two standard libraries¶
CI compiles every example on Ubuntu, where c++ is GCC with libstdc++, and on macOS, where c++ is Apple clang with libc++ — and both runs must match the one .out. Before you record a key on a Mac, hold it against libstdc++ yourself. Docker's gcc:13 image matches the Ubuntu runner's GCC 13 and ships python3, so the runner itself runs there:
docker run --rm -v "$PWD:/w:ro" gcc:13 sh -c 'cd /w && CXX=g++ python3 tools/run_examples.py --check'
So the rule for what may go in a key is: only what the standard pins down. What a vendor chooses — which clock high_resolution_clock is, how long a system_clock tick is, sizeof(long) — goes in a dated fence on the page, titled with the date, the compiler, the library and the machine, and ending not an answer key. The two CI runners are also two architectures, x86-64 and arm64, so nothing the hardware decides goes in a key either.
Time makes the determinism rule sharper¶
An example may read a clock — clocks are half of this library — but it must never print a reading. A measured time differs on every run and every machine. Print a verdict the standard guarantees instead: after std::this_thread::sleep_for(20ms), a steady_clock measurement is at least 20ms, because the standard says _for functions wait at least that long and should measure it with a steady clock (timing specifications ↗). So elapsed >= 20ms prints true everywhere.
For a page whose subject is a measurement, give the example a flag the runner never passes — --times — and paste a dated run of it into a labelled fence. The optimizer deletes your benchmark does this: the key holds the sums every compiler agrees on, the table holds the times no two agree on.
Showing code that does not compile¶
GCC and Clang word the same refusal differently, so a failed compile can never be an answer key — the runner treats one as an error. Two honest ways to show a refusal instead:
- Ask the compiler a question. A C++20
requires-expression turns "would this compile?" intotrueorfalse, and prints identically on both libraries:
template <class A, class B>
concept subtractable = requires(A a, B b) { a - b; };
// subtractable<system_clock::time_point, steady_clock::time_point> is false
- Quote the transcript, labelled. Put the compiler's own output in a
textfence whose title names the compiler, its version and the file. Name the scratch file what the transcript says. If you cut lines, say so in the title — abridged: the first 7 of 51 lines.
Either way, never open a page with the code that fails. Lead with the version that works; show a refusal as a // comment inside a snippet that compiles, and the transcript lower down.
Stubs¶
A stub is a lesson page with no example behind it yet: an H1, a **Level:**, the notice below, a **One line:**, and the questions the finished page has to answer. It gives a chapter its shape and a permanent URL before the prose exists.
> **Stub — an outline, not a lesson.** There is no runnable example behind this page yet, so nothing on it has been through [the check that backs every other claim in this library](../../CONTRIBUTING.md). The bullets below are the questions the finished page has to answer.
A stub has no <!-- output: --> block — there is no answer key to fill it from. It graduates by gaining an examples/ program and losing the notice.
Writing the prose¶
- One idea per page.
- Lead with the shortest true statement —
**Level:**, then a**One line:**summary — then earn it. The level is101,201,301orreference, then·and the audience. - Lead with the working answer. The first block on a page is the one that gets pasted.
- Expected output goes in a trailing comment on the printing line —
std::cout << d; // 1500ms— never as a bare line under the code, which gets pasted too. - Say which trap you are describing. The mistake is usually the valuable half.
- Bridge to a language the reader already speaks, under If you are coming from another language: Rust (link the twin page in the Rust library), Python, and ABAP where a real counterpart exists — what transfers, and what C++ enforces or does not. Mark anything you could not run as not machine-checked.
- No padding — no sentence explaining why the previous one matters, no announcing structure, no prose restating a table.
- Don't hard-wrap paragraphs. One paragraph, one line.
Linking¶
- A link that leaves the library ends its label with
↗; an internal link never does.python3 tools/check_link_style.py --fixadds and removes the marker; CI runs it without--fix. Keep square brackets out of link labels — the checker cannot see a link whose label contains one. - Link a folder by naming its README:
[label](some_folder/README.md), never[label](some_folder/). MkDocs ships the bare form unrewritten, and it 404s. - A repo path in backticks must be a link, with a real relative href.
- Link a term on first meaningful use, once per page.
Other people's material¶
The first chapter follows a talk whose slide source is published under the BSD 2-Clause licence (© 2026 Hudson River Trading LLC). Quote a slide's code or wording with attribution and a link to the slide source; write every example from scratch; and copy no image without checking its own licence first — several of the deck's photographs carry separate credits.
Reading order¶
Set it in NAV_ORDER in mkdocs_hooks.py ↗ — never by renaming folders, which are permanent URLs. A page missing from NAV_ORDER still ships, alphabetically at the bottom of its chapter, with no warning. A section's sidebar label is its README's # H1, backticks and all; when the H1 carries a subtitle ("Three clocks, and the one in the trenchcoat"), give it a shorter one in LABELS in the same file.
Before you commit¶
python3 tools/run_examples.py # examples verified, pages refilled
python3 tools/check_link_style.py # every external link carries its ↗
uv run --group docs mkdocs build --strict
Take each verdict from the exit status, never from output piped through tail. When several sessions work on the library at once, give each its own worktree: