Just Another LLM Introspective
Contents

The ground floor

How this book is written

The conventions every chapter follows, and a working demonstration of everything the build supports.

Last updated 2026-08-27

This chapter is two things at once. It is the style guide I hold myself to, and it is a live test of the build – every formatting feature the site supports appears below, so if something renders wrong here, it is broken everywhere.

The conventions#

A chapter is one technique. If it needs two, it is two chapters.

The opening should be readable on its own. Someone who arrives from a search result and reads only the first paragraph should come away with the point, even if they leave immediately.

Claims get a boundary. “This works” is not useful without “and here is where it stops working”. The boundary is usually the most valuable sentence in the chapter.

Dates are honest. The updated field in each chapter’s frontmatter is shown at the top of the page and drives the sitemap. When a chapter is revised in a way that changes its advice, the date moves. Fixing a typo does not count.

Writing a chapter#

Every chapter is a Markdown file in src/content/, opening with a frontmatter block:

---
title: How this book is written
summary: The conventions every chapter follows, and a working demonstration.
updated: 2026-08-27
---

The body starts here. No `# ` heading - the title above becomes the h1.

The file is then listed in src/content/book.json, which is the only place the book’s order lives:

{
  "parts": [
    {
      "title": "The ground floor",
      "summary": "What this book is and how to get around it.",
      "chapters": ["introduction", "how-this-book-is-written"]
    }
  ]
}

The build refuses to run if those two ever disagree. A chapter listed with no file is an error, and so is a file that no part lists – an unreachable chapter is worse than a missing one, because nothing tells you it is there.

Why the build is strict

Every check is a fail-closed one: the build exits non-zero and writes nothing. deploy.sh runs under set -e, so a broken book never reaches the web root. The live site keeps serving the last good version.

What the formatting supports#

Headings#

Second- and third-level headings become sidebar entries and search anchors, so they should read as labels rather than sentences. Fourth-level headings are for grouping inside a section and do not appear in the contents.

Like this one#

Below h4, use a paragraph in bold instead. The outline stops being useful past four levels.

Text can be italic, bold, or inline code. Links to another chapter are written root-relative – the introduction – and the build checks that every one of them resolves before it will deploy. A link to a chapter that does not exist is a build failure, not a 404 discovered later.

External links work as normal: the CommonMark spec.

Lists#

Ordered lists for steps that must happen in order:

  1. Write the chapter.
  2. List it in book.json.
  3. Run sudo /root/docs/deploy.sh.

Unordered for everything else:

  • Short items do not need full stops.
  • Longer items that run to a full sentence do.
  • Nesting works, but two levels is the practical limit:
    • like this
    • and this

Quotations#

A language model is not a program you instruct. It is a system you steer.

Blockquotes are for actual quotations and for stating a principle you are about to spend a chapter defending. They are not for emphasis – bold is for that.

Code#

Fenced blocks take a language tag, and highlighting is rendered at build time by Pygments. Nothing ships to the browser to make this work, which is why the site’s content security policy never needs to allow anything beyond its own origin:

def parse_frontmatter(text: str, where: str) -> tuple[dict[str, str], str]:
    """Split a leading `key: value` block from the Markdown body."""
    lines = text.replace("\r\n", "\n").split("\n")
    if not lines or lines[0].strip() != "---":
        fail(f"{where}: must open with a '---' frontmatter block")
    return meta, body

Shell, JSON, JavaScript and plain text all work too:

# Build locally without deploying anything.
.venv/bin/python tools/build_site.py
python3 -m http.server 8080 --directory build

A block with no language tag is rendered without highlighting, which is the right choice for output, logs, and anything you do not want coloured:

build_site: 2 chapter(s) in 1 part(s), 14 search record(s), index 3.1 KB

Tables#

Tables are for genuine three-column data. Two-column tables read badly on a narrow screen – use a list of **key** -- value bullets instead.

Check When it runs What it catches
Unit tests Before build Regressions in the generator itself
Structure validate During build Missing, duplicated or orphan chapters
Link check During build Internal links that go nowhere
Index budget After build A search index that has grown too big

Callouts#

Two kinds, and they should stay rare. A note adds context that is genuinely optional:

Note

The search index holds one record per section heading, so a result links straight to the part of the chapter that matched rather than to the top of the page.

A warning marks something that will cost you if you ignore it:

This one bites

Do not put a # heading in a chapter body. The title from the frontmatter is already the page’s h1, and a second one breaks the document outline for screen readers. The build rejects it rather than letting it through.

Footnotes#

Footnotes are for the aside that would otherwise derail a sentence.1 They collect at the bottom of the chapter with a link back to where you were.

Publishing#

One command, run as root:

sudo /root/docs/deploy.sh

That runs the generator’s unit tests, builds the site, checks the structure and every internal link, rsyncs the result to the web root, stamps cache-busting hashes onto the CSS and JS, and reloads nginx. Any failure stops the whole thing before the live site is touched.


  1. Like this. If the aside is longer than a couple of sentences, it probably wants to be its own section instead. return