CLI tool
standardese/standardese avatar
standardese/standardese

standardese: documenting C++ headers the way the standard is written

A (work-in-progress) nextgen Doxygen for C++

972 stars42 forksC++NOASSERTION

At a glance

What is it?
standardese is a next generation Doxygen for C++, built on libclang and a pluggable documentation frontend library, whose output imitates the section structure of the C++ standard itself. It still carries a work-in-progress label and its newest tagged release dates from 2021.
Who is it for?
standardese suits C++ library authors who want documentation that reads like the standard, especially those working with modern C++ where the language itself uses the Effects, Requires, and Returns vocabulary.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 157 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why the output should look like the C++ standard

Doxygen produces a documentation format that most C++ developers learn to skim. standardese is an attempt at something different: documentation written the way the C++ standard itself is written. The name comes from that goal. The project describes itself as a nextgen Doxygen for C++, and it aims to provide documentation in a similar way to the C++ standard, which means it provides commands to introduce so called sections in the documentation. The current sections are all the C++ standard lists from the specifications section of the draft, including commands such as \effects, \requires, \returns, and \throws. For anyone who has read the standard, that vocabulary is already loaded with meaning, and the claim is that reusing it makes library documentation more precise rather than more decorative. The audience is C++ library authors and teams whose public API is documented in headers, especially those working with modern C++ where concepts, requirements, and effects are part of the language discussion.

A library for frontends plus a tool that drives it

The project has two parts, and that split is the architectural decision that matters. The library aims at becoming the documentation frontend that can be easily extended and customized, and it parses C++ code with the help of libclang, providing access to it. The tool drives the library to generate documentation for user-specified files. The practical difference between them shows up in what you can build. The tool handles the common case of running a command and getting Markdown files. The library exists so that you can write a different tool, a different output format, or a different documentation model without reimplementing the parsing layer. The libclang dependency is the reason the project tracks C++ so closely, since libclang's C index exposes the syntax tree that a documentation frontend needs. The tool supports a couple of output formats including Markdown and HTML, as well as experimental Latex and man pages.

The swap.hpp example, from header comment to rendered section

The basic example in the project documentation is a header file named swap.hpp with a documented function template:

cpp
#include <type_traits>

namespace std
{

    /// \effects Exchanges values stored in two locations.
    /// \requires Type `T` shall be `MoveConstructible` and `MoveAssignable`.
    template <class T>
    void swap(T &a, T &b) noexcept(is_nothrow_move_constructible<T>::value &&
                                    is_nothrow_move_assignable<T>::value);
}

What comes out is a Markdown document headed by the header file, then the namespace with the template signature, then a section for the function, followed by the prose rendered as Effects and Requires lines. The trailing part of the example shows the rendered function signature in a code block, which is what makes the output usable for a reader who wants to know the exact declaration. Two things are visible here. The comment commands are attached to the declaration as ordinary documentation comments, and the generated section headings come from the command names rather than from a fixed template. The example also demonstrates that the tool rewrites the signature into its own canonical form, so the rendered declaration does not have to match the source formatting character for character.

Install paths: conda, docker, or building with pixi and cmake

The documentation recommends trying your usual software distribution first. If it is not packaged there, three paths are given. conda-forge packages a recent version of standardese for Windows, Linux, and macOS, and the route is to install Miniconda, enable the conda-forge channels, then create and activate an environment:

bash
conda create -n standardese standardese
conda activate standardese

After that the standardese command should be available on the command line. There is also a Docker image at standardese/standardese on Docker Hub, which is the fastest way to try it without touching the host. For a source build the documentation recommends pixi and a single command:

bash
pixi run build

with pixi run test to run the test suite and pixi run standardese to execute the binary. The cmake route is given as an alternative:

bash
mkdir build
cd build
cmake ../
cmake --build . --target standardese_tool

which produces the executable tool/standardese. Two dependencies have to be present: Boost and libclang. Boost.ProgramOptions and Boost.Filesystem are needed as statically linked binaries, and they are found automatically if installed. libclang is also needed, and on Linux the llvm-config binary should be found automatically, while on other systems you are pointed at the cppast build instructions, which apply here too.

The command line, inputs, and the header files only rule

Basic usage is standardese [options] inputs, and standardese --help lists the available options. The inputs can be files or directories, and in the case of a directory each file is documented unless an input option says otherwise. The tool currently generates a corresponding Markdown file with the documentation for each file it receives as input. One rule stands out and is stated as a note in the documentation: you only need and should give header files to standardese, and the source files are unnecessary. That is a design constraint rather than a simplification, and it is explained by how the tool handles compilation options. The compilation options let you pass macro definitions and include directories, as well as a commands_dir which is a directory holding a compile_commands.json file. standardese passes all the flags of all files to libclang, and the documentation gives the reason: you give header files whereas the compile commands use only source files.

Configuration file syntax and the option groups

Options are split into two groups with different rules. The ones under Generic options must be given on the command line, and they cover things like getting the version, enabling verbose output, or passing an additional configuration file. The options under Configuration can be passed both on the command line and in the config file, and they fall into four families. The input.* options relate to the inputs and can filter both the files inside a directory and the entities in the source code. The compilation.* options relate to the compilation of the source and cover macro definitions, include directories, and the commands_dir described above. The comment.* options relate to the syntax of the documentation markup, where you can set the leading character and the name for each command. The output.* options relate to the output generation and include an option to set the human readable name of a section. The configuration file uses an INI style syntax:

ini
[compilation]
include_dir=foo/
macro_definition=FOO

[input]
blacklist_namespace=detail

That layout is worth understanding properly, because it is where a project decides which entities appear in its public documentation at all.

A work-in-progress tool with a 2021 release tag

The repository description calls standardese a work-in-progress nextgen Doxygen for C++, and that label is accurate in the release history. The recent releases are 0.5.2 dated 2021-04-29, 0.5.1 dated 2021-04-15, and 0.5.0 dated 2021-03-17. So the newest published tag is more than five years old, even though the last push was on 2026-05-20 and the repository is not archived, which means work continues on the master branch without a new tagged release. That is the practical upgrade risk: you can build current master, but there is no versioned artefact to pin, and the CHANGELOG.rst and the news directory at the repository root are where you would look for what changed. The repository layout also shows the pieces of a real tool, with CMakeLists.txt, a pixi.toml and pixi.lock, a Dockerfile, a src and include split, a test directory, a tool directory, and an examples folder that includes a mathjax example.

Licensing, packaging, and how to try it cheaply

The licence needs attention, because the signals disagree. The README carries an MIT licence badge, while the licence information recorded for the repository points to a custom licence that GitHub cannot classify, with the LICENSE file named as the place to look. If you are evaluating this for a commercial codebase, read the LICENSE file yourself rather than trusting the badge, since this is not legal advice and the terms of a custom licence are whatever that file says. The Dockerfile shows how the project is packaged for containers. It uses Ubuntu 24.04, installs the Boost and clang packages, builds with cmake and the standardese_tool target, copies the binary into a run stage, creates a dedicated user, and runs standardese --version at the end of the image as a smoke check. The build stage also takes a NUM_THREADS argument, so a CI machine can parallelise the compilation without editing the Dockerfile.

Editorial conclusion

standardese suits C++ library authors who want documentation that reads like the standard, especially those working with modern C++ where the language itself uses the Effects, Requires, and Returns vocabulary. It is the wrong tool if you need broad C and Objective-C coverage, if your documentation is expected to cover source files rather than headers, or if you need a tool with a recent tagged release, since the newest tag here is 0.5.2 from 2021-04-29 even though the last push was on 2026-05-20. Before adopting it, confirm libclang and the Boost libraries are available on your build machines, read the LICENSE file directly rather than relying on the badge, and try the conda create -n standardese standardese path before committing to a source build.

Frequently asked questions

How do I install standardese without building it from source?

conda-forge packages a recent version for Windows, Linux, and macOS. Create and activate an environment with conda create -n standardese standardese and conda activate standardese, after enabling the conda-forge channels. A Docker image is also published at standardese/standardese.

What are the system dependencies for standardese?

The build system handles the dependencies automatically except for Boost and libclang. Boost.ProgramOptions and Boost.Filesystem are needed as statically linked binaries, and libclang is required, with llvm-config usually found automatically on Linux.

Does standardese document .cpp source files or only headers?

Only headers. The documentation states that you only need and should give header files to standardese, and that the source files are unnecessary. The tool currently generates a corresponding Markdown file for each input file.

What documentation sections does standardese support?

The current sections are the C++ standard lists from the specifications section of the draft, including commands such as \effects, \requires, \returns, and \throws. The comment.* configuration options let you set the leading character and the name used for each command.

What licence does standardese use?

The README shows an MIT licence badge, while the licence recorded for the repository is a custom one that GitHub cannot classify. The LICENSE file in the repository root is the authoritative text, so read it directly before using the tool in a commercial project.

Official sources

  1. Issues
  2. README
  3. Releases
  4. standardese/standardese on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/standardese-standardese.svg)](https://hysenlabs.com/projects/standardese-standardese)

Was this useful?