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 — partsThe top-level of every document. A file contains exactly one part, which is the document title.
*with overline — chaptersMajor divisions within a part.
=underline — sectionsThe most common authored level. Most content is organized in sections.
-underline — subsectionsChildren of sections. Use when a section has distinct subtopics.
^underline — subsubsectionsRare but permitted. Use only when subsections have their own distinct subtopics that each need a header.
"underline — paragraphsThe 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:
Verify. Run
rstcheck --report-level warning <file>on every changed file. Confirmmake htmlsucceeds locally if the change could affect the build.Document. Update
CHANGELOG.rst,TODO.rst, and any other affected meta files in the same commit as the content change.Commit. Use the repo’s conventional commit-message format (
type: brief description; see repoCLAUDE.mdfor the allowed type prefixes). Do not includeCo-Authored-ByorAuthored-bytrailers.
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.