Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

How this book is built

Rules for anyone adding a page. They exist because a book is a second copy of the language, and the usual fate of a second copy is to drift until it teaches a version of the language nobody ships.

What a page may contain

Prose, and code that something else already verifies. Nothing else.

You want to showWrite it as
A few lines from a real program{{#include ../path/prog.rk:anchor}}
A small self-contained snippetan inline block with <!-- test: compile --> or <!-- test: run | expected output -->
What the compiler says when you get it wrong{{#include ../../errors/<chapter>/<case>.out}}
What a program prints{{#include ../../../../tests/golden/<name>.out}}

<!-- test: parse --> does not count as verified anywhere in the book. Parsing proves the syntax is current; syntax is not what rots. The front-page snippet passed test: parse while calling fs.open, which the real grep program doesn’t use, and missing both its imports, so a reader copying it got two errors on page one. compile type-checks; run | expected runs it and matches the output. Use one of those.

CI runs the markers in its “Docs snippets parse” step, which has covered docs/ for a while. What it can’t tell you is whether a block has a marker at all, or whether the one it has is strong enough, which is what tests/book_gate.sh is for. It also checks that every include resolves: the file is present and the named anchor really is in it, because mdBook renders a missing anchor as nothing at all and says so quietly.

Errors are content

Chapters teach with real compiler output. Each case is a program under docs/book/errors/<chapter>/ that must not compile, with its rask check output pinned beside it. The gate re-renders and diffs on every run, so improving a diagnostic shows up as a diff on the page that teaches it, which is the review you want. A case that starts compiling is a hard failure, not a stale golden: the page is claiming a rejection the compiler no longer makes.

Regenerate after a deliberate diagnostics change:

tests/book_gate.sh --update

The book teaches the ruling, not just the rule

The specs are normative and say what the rule is. A chapter’s job is the part the spec tables leave out: why it’s that way, and what it would cost to be otherwise. “The marker is required” is a spec line. “A misread move is caught for you and a misread mutation isn’t, so the one that can’t be caught is the one you write down” is a chapter.

specs/RULINGS.md is where those arguments come from. If a chapter can’t say why, it’s restating the spec and should link to it instead.

Size is capped by the language, not by the author

specs/DAY_ONE.md holds the reading set: the concepts you need to read someone else’s Rask, which must fit one page. The guide inherits that budget: roughly one chapter per Day-One concept, and no chapter for something that isn’t in the language yet.

This is the answer to books that grow to a thousand pages: the guide can’t outgrow the language, because its table of contents is the language’s own list. Anything deeper goes to specs/, which is allowed to be long.

What to do when the language changes

Nothing, usually. That’s the point: included code moves with its program, error renderings are regenerated by the gate, program output comes from the goldens. The prose only needs touching when a decision changes, which is rare and deliberate.

If you find yourself keeping a page in step by hand, the page is built wrong.