Skip to main content

doxygen-guard

Pre-commit hook that enforces doxygen documentation and reports the change impact of what you commit. Language- and architecture-agnostic.

Scope is deliberately narrow: enforcement and impact. Diagram generation and symbol indexing are out of scope — see Consumer Contract for the machine-readable surface that downstream tools build on.

Quick Start

1. Add the hook to .pre-commit-config.yaml

repos:
  - repo: https://github.com/tvanfossen/doxygen-guard
    rev: main
    hooks:
      - id: doxygen-guard
        types_or: [c, c++, java, python]

2. Create .doxygen-guard.yaml in your repo root

output_dir: docs/generated/

validate:
  exclude:
    - "^tests/"
    - "^\\.venv/"
  tags:
    req:
      pattern: "^REQ-[A-Z]+-[0-9]{3}$"
  version_gate:
    current_version: "auto:git"
    version_field: "min_version"

impact:
  requirements:
    file: docs/requirements.yaml
    format: yaml

3. Add doxygen to your functions

/**
 * @brief Read temperature from sensor hardware.
 * @version 1.0
 * @req REQ-SENSE-001
 * @return Raw ADC value
 */
int Sensor_ReadTemperature(void) {
    return hw_read_adc(TEMP_CHANNEL);
}

Run pre-commit run --all-files — violations print to stderr and the impact report appears in <output_dir>/impact/.

What It Does

Validation (pre-commit gate)

Every function in staged files is checked for:

  • Presence — must have @brief, @version, and @return (non-void functions)
  • Version staleness — if function body changed (git diff), @version must be updated
  • Tag syntax — tag values validated against configured patterns
  • Requirement coverage — functions must have @req or an exemption tag

Exemption Tags

Tag Effect
@internal Exempt from @req; excluded from the coverage report's unmapped list
@utility Exempt from @req
@callback Exempt from @req

Change-Impact Reports

Cross-references git diff with parsed functions to show which requirements are affected by staged changes. Reports in markdown and JSON at <output_dir>/impact/.

Requirement Coverage

doxygen-guard coverage cross-references @req tags against the catalog and reports covered, uncovered and orphan requirements, plus documented functions carrying no @req. Exit code 1 when gaps exist.

Configuration Reference

validate section

Key Type Default Description
languages dict C, C++, Java, Python Per-language function patterns and comment styles
presence.require_doxygen bool true Require doxygen on every function
presence.require_return bool true Require @return on non-void functions
presence.skip_forward_declarations bool true Skip C/C++ forward declarations
version.require_present bool true Require @version tag
version.require_increment_on_change bool true Require version bump when body changes
exclude list [] Regex patterns for files to skip — see doxygen-guard files
duplicate_tags_error bool true Flag repeated @brief/@version/@return/@file in one block
tags.req.cross_reference bool true Validate @req IDs exist in requirements file
version_gate.current_version string auto:git, auto:cmake, or explicit version
version_gate.version_field string Column in requirements file for version gating

impact section

Key Type Default Description
requirements.file string Path to the requirements catalog
requirements.format string yaml Format: yaml, csv, or json
requirements.id_column string Req ID ID column — csv/json only
requirements.name_column string name Requirement name column/field

These defaults are also emitted by doxygen-guard config --schema. Read them from there rather than copying them — see Consumer Contract.

Requirements catalog

The preferred form is a mapping keyed by requirement ID. The ID is the key, so no id_column applies:

requirements:
  REQ-VAL-001:
    name: Doxygen presence check      # required
    subsystem: Validate               # optional
    min_version: v0.1.0               # optional
    description: >-                   # optional
      Every function must have a doxygen comment
    acceptance_criteria: >-           # optional
      Undocumented functions produce presence violations

The catalog is validated on load. A missing file, an unknown format, a wrong document shape, a missing name, or an ID failing validate.tags.req.pattern each raise RequirementsError — the run fails rather than silently proceeding with an empty catalog. Flat csv/json row formats remain supported and use id_column.

Consumer Contract

Tools built on doxygen-guard must read the contract from the tool, not re-derive it. Every declaration the gate honours is observable in this output.

doxygen-guard config --schema       # schema, defaults, catalog constants, contract_version
doxygen-guard config --effective    # the merged config in force and what it resolved to
doxygen-guard files src/            # the exact post-exclude file set the gate walks

All three emit JSON carrying a contract_version. Compare it against the value your tool was written for; when it moves, re-check your assumptions.

doxygen-guard files is the authoritative answer to "which files does the gate consider?" — it applies validate.exclude exactly as validation does. A consumer that walks the tree itself and diffs against this output will detect its own divergence instead of silently reporting on files the gate never sees.

Typed errors are importable from doxygen_guard.errors: GuardError with ConfigError and RequirementsError subclasses. load_config raises rather than exiting, so in-process callers can handle failures; exit codes are produced only at the CLI boundary.

Passthrough config

Consumers may declare their own sections in .doxygen-guard.yaml using an x- prefix, at any nesting level. The guard validates that they parse but never interprets them:

x-my-tool:
  index_path: .cache/index

Any other unknown key is an error.

File-Level Doxygen

Each source file should have a file-level doxygen block:

/**
 * @file
 * @brief Sensor hardware abstraction layer.
 * @version 1.0
 */

Enable validate.presence.require_file_doxygen: true to enforce file-level blocks.

For Python:

## @file
## @brief Configuration loading and validation.
## @version 1.0

Python Function Docstring Style

Python functions accept doxygen tags in two equivalent forms. Use whichever fits your codebase — they are interchangeable on a per-function basis.

Two-hash block above the def (classic doxygen-for-Python convention):

## @brief Apply a unified-diff patch to a project directory.
#  @version 1.0
#  @req REQ-PATCH-001
#  @return 0 on success, non-zero on failure.
def apply_patch(repo_path: str, patch: str) -> int:
    ...

Inside the PEP 257 docstring (idiomatic Python — Sphinx/IDE-friendly):

def apply_patch(repo_path: str, patch: str) -> int:
    """Apply a unified-diff patch via `git apply`.

    @brief Apply a unified-diff patch to a project directory.
    @version 1.0
    @req REQ-PATCH-001
    @return 0 on success, non-zero on failure.
    """
    ...

When both styles are present on the same function, the ##-block above takes precedence. A docstring without any recognized tag is not treated as a doxygen block (so prose-only docstrings remain free-form).

Config Validation

The config file is validated at load time against a built-in schema. Unknown keys are rejected, with a suggestion when one is close:

doxygen-guard: Invalid config in .doxygen-guard.yaml
Unknown config key: validate.exclud — did you mean 'exclude'?

Keys prefixed x- are exempt (see Passthrough config). The schema itself is available via doxygen-guard config --schema.

Escaping @ in Documentation Text

As in doxygen itself, @word is a command anywhere in a block — including mid-sentence. To mention a tag name in prose, escape it as \@ or @@:

/**
 * @brief Rows carry their declared \@req IDs.
 * @version 1.0
 */

Without the escape, @req IDs parses as a req tag valued IDs, and the gate reports a requirement that does not exist.

Adopting on an Existing Codebase

For repos with existing code that has no doxygen, adopt incrementally:

  1. Start with validation only — add @brief and @version to functions as you touch them. Use version_gate to only enforce @req on functions added after a specific version:
validate:
  version_gate:
    current_version: "auto:git"
    version_field: "min_version"
  1. Add @return to non-void functions — required by default. Disable with presence.require_return: false during migration.

  2. Exclude paths you're not ready to cover:

validate:
  exclude:
    - "^vendor/"
    - "^legacy/"

Supported Languages

Language Extensions Comment Style Body Detection
C .c, .h /** ... */ Brace matching
C++ .cpp, .hpp, .cc, .cxx /** ... */ Brace matching
Java .java /** ... */ Brace matching
Python .py ## ... block above def or @tag lines inside the docstring Indentation

C++ template functions (template<typename T> void func(...)) are fully supported — doxygen comments are associated via tree-sitter AST sibling detection, handling template_declaration wrappers correctly.

CLI Usage

# Pre-commit mode (default — called by pre-commit)
doxygen-guard [--config path] [files...]

# Explicit subcommands
doxygen-guard validate --no-git src/*.c
doxygen-guard impact --staged src/*.c
doxygen-guard coverage src/

# Consumer contract (JSON)
doxygen-guard config --schema
doxygen-guard config --effective
doxygen-guard files src/

# Verbose mode — logs which config sections were declared vs defaulted
doxygen-guard -v coverage src/

Scope and Direction

The tool is feature-complete for what it does: enforcement and change impact. See ROADMAP.md for what is being considered, what is explicitly out of scope, and the three tests any new feature has to pass.

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

doxygen_guard-1.3.1.tar.gz (102.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

doxygen_guard-1.3.1-py3-none-any.whl (44.2 kB view details)

Uploaded Python 3

File details

Details for the file doxygen_guard-1.3.1.tar.gz.

File metadata

  • Download URL: doxygen_guard-1.3.1.tar.gz
  • Upload date:
  • Size: 102.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for doxygen_guard-1.3.1.tar.gz
Algorithm Hash digest
SHA256 86ede66f5755a15eb805e0c07a9f35ae659b86f62c3cdae4a70eb369e7054fab
MD5 2c96336682f4aebc3e036b0789d1a731
BLAKE2b-256 e1d93ef34aca1b10e8924b6e66585c57892d8b0f61d3cce85aa0cce8947ee5e2

See more details on using hashes here.

Provenance

The following attestation bundles were made for doxygen_guard-1.3.1.tar.gz:

Publisher: release.yml on tvanfossen/doxygen-guard

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file doxygen_guard-1.3.1-py3-none-any.whl.

File metadata

  • Download URL: doxygen_guard-1.3.1-py3-none-any.whl
  • Upload date:
  • Size: 44.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for doxygen_guard-1.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5a4f3beb598d92f7ec39a1c3bf6fa5006fc580ec2df7e1d8dbeacddb03091167
MD5 10b1612376f2e9fb645f45c2c0dc5da7
BLAKE2b-256 9449197da6a58ed3fcb4f58528c68d266a659195cdd4141cd7938367944e2105

See more details on using hashes here.

Provenance

The following attestation bundles were made for doxygen_guard-1.3.1-py3-none-any.whl:

Publisher: release.yml on tvanfossen/doxygen-guard

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.4.2

2 files

1.4.1

2 files

1.4.0

2 files

This release

1.3.1 This release

2 files

1.2.9

2 files

1.2.8

2 files

1.2.6

2 files

1.2.5

2 files

1.2.4

2 files

1.2.0

2 files

1.1.16

2 files

1.1.14

2 files

1.1.12

2 files

1.1.11

2 files

1.1.10

2 files

1.1.9

2 files

1.1.8

2 files

1.1.7

2 files

1.1.6

2 files

1.1.5

2 files

1.1.4

2 files

1.1.3

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page