Sphinx documentation style#


Pigweed’s documentation style guide came after much of the documentation was written, so Pigweed doesn’t entirely conform to our own style guide. When updating docs, please update them to match the style guide.


We are moving to the Google Developer Documentation Style Guide (GDDSG) for the English language conventions (rather than technical style for RST usage, etc). Currently, most of our documentation does not adhere.

Pigweed documentation is written using the reStructuredText markup language and processed by Sphinx. We use the Furo theme along with the sphinx-design extension.


Use headings according to the following hierarchy, with the shown characters for the ReST heading syntax.

Document Title: Two Bars of Equals
Document titles use equals ("====="), above and below. Capitalize the words
in the title, except for 'a', 'of', and 'the'.

Major Sections Within a Doc
Major sections use hyphens ("----"), above and below. Capitalize the words in
the title, except for 'a', 'of', and 'the'.

Heading 1 - For Sections Within a Doc
These should be title cased. Use a single equals bar ("====").

Heading 2 - for subsections
Subsections use hyphens ("----"). In many cases, these headings may be
sentence-like. In those cases, only the first letter should be capitalized.
For example, FAQ subsections would have a title with "Why does the X do the
Y?"; note the sentence capitalization (but not title capitalization).

Heading 3 - for subsubsections
Use the caret symbol ("^^^^") for subsubsections.

Note: Generally don't go beyond heading 3.

Heading 4 - for subsubsubsections
Don't use this heading level, but if you must, use period characters
("....") for the heading.

Do not put blank lines after headings.#

Yes: No blank after heading

Here is a heading
Note that there is no blank line after the heading separator!

No: Unnecessary blank line

Here is a heading

There is a totally unnecessary blank line above this one. Don't do this.

Do not put multiple blank lines before a heading.#

Yes: Just one blank after section content before the next heading

There is some text here in the section before the next. It's just here to
illustrate the spacing standard. Note that there is just one blank line
after this paragraph.

Just one blank!
There is just one blank line before the heading.

No: Extra blank lines

There is some text here in the section before the next. It's just here to
illustrate the spacing standard. Note that there are too many blank lines
after this paragraph; there should be just one.

Too many blanks
There are too many blanks before the heading for this section.


Indent directives 3 spaces; and put a blank line between the directive and the content. This aligns the directive content with the directive name.

Yes: Three space indent for directives; and nested

Here is a paragraph that has some content. After this content is a

.. my_directive::

   Note that this line's start aligns with the "m" above. The 3-space
   alignment accounts for the ".. " prefix for directives, to vertically
   align the directive name with the content.

   This indentation must continue for nested directives.

   .. nested_directive::

      Here is some nested directive content.

No: One space, two spaces, four spaces, or other indents for directives

Here is a paragraph with some content.

.. my_directive::

  The indentation here is incorrect! It's one space short; doesn't align
  with the directive name above.

  .. nested_directive::

      This isn't indented correctly either; it's too much (4 spaces).

No: Missing blank between directive and content.

Here is a paragraph with some content.

.. my_directive::
   Note the lack of blank line above here.


Consider using .. list-table:: syntax, which is more maintainable and easier to edit for complex tables (details).

Code Snippets#

Use code blocks from actual source code files wherever possible. This helps keep documentation fresh and removes duplicate code examples. There are a few ways to do this with Sphinx.

The literalinclude directive creates a code blocks from source files. Entire files can be included or a just a subsection. The best way to do this is with the :start-after: and :end-before: options.


Documentation Source (.rst file)

.. literalinclude:: run_doxygen.py
   :start-after: [doxygen-environment-variables]
   :end-before: [doxygen-environment-variables]

Source File

# DOCSTAG: [doxygen-environment-variables]
env = os.environ.copy()
env['PW_DOXYGEN_OUTPUT_DIRECTORY'] = str(output_dir.resolve())
env['PW_DOXYGEN_INPUT'] = ' '.join(pw_module_list)
env['PW_DOXYGEN_PROJECT_NAME'] = 'Pigweed'
# DOCSTAG: [doxygen-environment-variables]

Rendered Output

env = os.environ.copy()
env['PW_DOXYGEN_OUTPUT_DIRECTORY'] = str(output_dir.resolve())
env['PW_DOXYGEN_INPUT'] = ' '.join(pw_module_list)
env['PW_DOXYGEN_PROJECT_NAME'] = 'Pigweed'

Generating API documentation from source#

Whenever possible, document APIs in the source code and use Sphinx to generate documentation for them. This keeps the documentation in sync with the code and reduces duplication.


Include Python API documentation from docstrings with autodoc directives. Example:

.. automodule:: pw_cli.log

.. automodule:: pw_console.embed
   :members: PwConsoleEmbed

.. autoclass:: pw_console.log_store.LogStore
   :members: __init__

Include argparse command line help with the argparse directive. Example:

.. argparse::
   :module: pw_watch.watch
   :func: get_parser
   :prog: pw watch

Customize the depth of a page’s table of contents#

Put :tocdepth: X on the first line of the page, where X equals how many levels of section heading you want to show in the page’s table of contents. See //docs/changelog.rst for an example.


This section explains how we update the changelog.

  1. On the Friday before Pigweed Live, use changelog to generate a first draft of the changelog.

  2. Copy-paste the reStructuredText output from the changelog tool to the top of //docs/changelog.rst.

  3. Delete these lines from the previous update in changelog.rst (which is no longer the latest update):

    • .. _docs-changelog-latest:

    • .. changelog_highlights_start

    • .. changelog_highlights_end

  4. Polish up the auto-generated first draft into something more readable:

    • Don’t change the section headings. The text in each section heading should map to one of the categories that we allow in our commit messages, such as bazel, docs, pw_base64, and so on.

    • Add a 1-paragraph summary to each section.

    • Focus on features, important bug fixes, and breaking changes. Delete internal commits that Pigweed customers won’t care about.

  5. Push your change up to Gerrit and kick off a dry run. After a few minutes the docs will get staged.

  6. Copy the rendered content from the staging site into the Pigweed Live Google Doc.

  7. Make sure to land the changelog updates the same week as Pigweed Live.

There is no need to update //docs/index.rst. The What's new in Pigweed content on the homepage is pulled from the changelog (that’s what the docs-changelog-latest, changelog_highlights_start, and changelog_highlights_end labels are for).

Why “changelog” and not “release notes”?#

Because Pigweed doesn’t have releases.

Why organize by module / category?#

Why is the changelog organized by category / module? Why not the usual 3 top-level sections: features, fixes, breaking changes?

  • Because some Pigweed customers only use a few modules. Organizing by module helps them filter out all the changes that aren’t relevant to them faster.

  • If we keep the changelog section heading text fairly structured, we may be able to present the changelog in other interesting ways. For example, it should be possible to collect every pw_base64 section in the changelog and then provide a changelog for only pw_base64 over in the pw_base64 docs.

  • The changelog tool is easily able to organize by module / category due to how we annotate our commits. We will not be able to publish changelog updates every 2 weeks if there is too much manual work involved.

Call-to-action buttons on sales pitch pages (docs.rst)#

Use the following directive to put call-to-action buttons on a docs.rst page:

.. grid:: 2

   .. grid-item-card:: :octicon:`zap` Get started & guides
      :link: <REF>
      :link-type: ref
      :class-item: sales-pitch-cta-primary

      Learn how to integrate <MODULE> into your project and implement
      common use cases.

   .. grid-item-card:: :octicon:`info` API reference
      :link: <REF>
      :link-type: ref
      :class-item: sales-pitch-cta-secondary

      Get detailed reference information about the <MODULE> API.

.. grid:: 2

   .. grid-item-card:: :octicon:`info` CLI reference
      :link: <REF>
      :link-type: ref
      :class-item: sales-pitch-cta-secondary

      Get usage information about <MODULE> command line utilities.

   .. grid-item-card:: :octicon:`table` Design
      :link: <REF>
      :link-type: ref
      :class-item: sales-pitch-cta-secondary

      Read up on how <MODULE> is designed.
  • Remove cards for content that does not exist. For example, if the module doesn’t have a CLI reference, remove the card for that doc.

  • Replace <REF> and <MODULE>. Don’t change anything else. We want a consistent call-to-action experience across all the modules.

Copy-to-clipboard feature on code blocks#

The copy-to-clipboard feature on code blocks is powered by sphinx-copybutton.

sphinx-copybutton recognizes $ as an input prompt and automatically removes it.

There is a workflow for manually removing the copy-to-clipboard button for a particular code block but it has not been implemented yet. See Remove copybuttons using a CSS selector.