RST Standards

This page is the canonical specification for how reStructuredText files are authored across every Documentation System repo. It governs section hierarchy, overline and underline formatting, blank-line spacing, and the per-file structure that every .rst file must follow.

The rules below originated in ~/docker/CLAUDE.md; that file remains their origin-of-record, but this page is now the authoritative specification. Repo-level CLAUDE.md files defer here.

Section Hierarchy

Every .rst file uses the following six-level hierarchy, in strict top-down order. A file must start at the top level (# with overline) and descend in order. Levels may be omitted at the bottom of the hierarchy — a section may terminate at any depth — but a file must never skip a level at the top.

Levels

# with overline — parts

The top-level of every document. A file contains exactly one part, which is the document title.

* with overline — chapters

Major divisions within a part.

= underline — sections

The most common authored level. Most content is organized in sections.

- underline — subsections

Children of sections. Use when a section has distinct subtopics.

^ underline — subsubsections

Rare but permitted. Use only when subsections have their own distinct subtopics that each need a header.

" underline — paragraphs

The deepest level. Used sparingly, typically for numbered steps or formally-labelled items within a subsubsection.

Example — single level

A file may use only parts and sections if that matches its content:

.. _my-repo-my-page:


######################################################################
My Page
######################################################################

Introductory paragraph.

Installing
======================================================================

Step-by-step instructions.

Verifying
======================================================================

How to confirm the install worked.

Example — mixed depth

Within a single document, different sections may descend to different depths. A section about a multi-part process might use subsections for each step; a sibling section with no subtopics may contain only prose:

Configuring the Service
======================================================================

The service is configured in three steps.

Step 1 --- Create the Config File
----------------------------------------------------------------------

...

Step 2 --- Edit the Values
----------------------------------------------------------------------

Most values use the defaults, but two require attention.

Database URL
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Must point at the production replica, not the primary.

Retry Count
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Set this to at least 3 for production.

Step 3 --- Restart the Service
----------------------------------------------------------------------

...

Troubleshooting
======================================================================

If the service fails to start, check the log file.

The Configuring the Service section descends to subsubsections for two specific values inside Step 2; Troubleshooting stops at the section level because it has no subtopics. Both are valid — the rule is only that levels must not be skipped at the top.

Full hierarchy capstone

The complete six-level hierarchy in one example:

.. _my-repo-complete-example:


######################################################################
Complete Example
######################################################################

Document introduction.


**********************************************************************
First Chapter
**********************************************************************

Chapter introduction.

First Section
======================================================================

Section body.

First Subsection
----------------------------------------------------------------------

Subsection body.

First Subsubsection
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Subsubsection body.

First Paragraph
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

Paragraph body.

Overline and Underline Rules

The underline (and overline, where applicable) beneath a header is built from the character assigned to that level. Two rules govern its length.

Minimum length rule

The underline (and overline, where applicable) must extend to at least column 70. When the title is shorter than 70 characters — which it almost always is — pad the underline out to 70 characters. When the title is longer than 68 characters, extend the underline to match the title’s length exactly.

Examples:

Short Title
======================================================================

A Slightly Longer Title With Several Words
======================================================================

Configuring The Advanced Multi-Node Kubernetes Rolling Upgrade Procedure
========================================================================

The first two underlines are padded to exactly 70. The third is extended to match the title length (72 characters). The second rule (below) enforces equal lengths for overlined titles.

Overlined titles — equal lengths rule

Where both an overline and an underline are used — that is, for parts (#) and chapters (*) — the overline and underline must be exactly the same length. If the title is long enough to force an extension past 70, both lines are extended by the same amount.

Blank-Line Spacing

Blank-line spacing around headers is fixed so that diffs stay quiet and visual weight matches structural weight.

  • Before an overlined header (# parts, * chapters): exactly 2 blank lines.

  • Before a non-overlined header (=, -, ^, "): exactly 1 blank line.

  • After any header, before the next body element: exactly 1 blank line.

The larger vertical break before overlined headers makes parts and chapters feel like major divisions when reading the source directly.

Required Per-File Elements

Every .rst file in every repo must include the following:

Top-of-file label

The very first non-blank line of every file is a label of the form .. _{slug}-{filename-slug}:. The slug is the repo’s canonical project slug (see Label Prefix Convention). The filename-slug normalizes the file’s path within source/ by replacing directory separators and underscores with hyphens.

Example — the file source/conventions/rst-standards.rst in this repo (slug docs-system) opens with:

.. _docs-system-conventions-rst-standards:

This label lets any other repo’s content link to the page by filename alone, without needing to know its H1 title.

Exactly one H1 per file

Every file contains exactly one top-level header (a #-overlined part). The H1 is the document title; everything else is nested beneath it. Multiple H1s in one file are forbidden — split the content into separate files instead.

:orphan: on non-toctree files

Any file that is intentionally standalone — not listed in any toctree — must carry the :orphan: file-wide metadata marker immediately after its top-of-file label. The marker silences the Sphinx warning “document isn’t in any toctree” for files where that is the intended state.

.. _my-repo-changelog:

:orphan:


######################################################################
Changelog
######################################################################

Common orphan-worthy files: README.rst, CHANGELOG.rst, TODO.rst, standalone meta pages.

Per-section labels

Every section header at every level must carry a label directly above it, following the semi-structured format described in Label Prefix Convention. Inline hyperlink targets and footnote labels are exempt; RST scopes those to the file automatically.

Linting

Every .rst file is linted with rstcheck before commit. The canonical command is:

rstcheck --report-level warning <file>

Each repo carries a .rstcheck.cfg at its root that ignores the Sphinx-specific directives and roles (toctree, :ref:, code-block, mermaid, youtube, and so on) that rstcheck’s docutils core does not recognize natively. With that config in place, the bare command above runs cleanly on compliant files.

Warnings about unreferenced labels in standalone files are expected; the --report-level warning flag filters them out. A fuller treatment of rstcheck workflow, edge cases, and CI integration lives in tooling/rstcheck.rst (forthcoming).

Committing

Every commit touching RST files follows the Verify –> Document –> Commit workflow inherited from ~/docker/CLAUDE.md:

  1. Verify. Run rstcheck --report-level warning <file> on every changed file. Confirm make html succeeds locally if the change could affect the build.

  2. Document. Update CHANGELOG.rst, TODO.rst, and any other affected meta files in the same commit as the content change.

  3. Commit. Use the repo’s conventional commit-message format (type: brief description; see repo CLAUDE.md for the allowed type prefixes). Do not include Co-Authored-By or Authored-by trailers.

One page equals one commit. Do not batch unrelated page changes.

Origin

The rules on this page were first codified in ~/docker/CLAUDE.md for the Docker Compose parent directory. They are reproduced and extended here because the Documentation System repo is the canonical public specification that every other repo — Tier 1 standalone doc repos, Tier 2 aggregation hubs, and the Docker Compose parent — now defers to.