Skip to content

# docforge

## `` docforge

### Summary

Renderer-agnostic Python documentation compiler that converts Python docstrings into structured documentation for both humans (MkDocs) and machines (MCP / AI agents).

`doc-forge` statically analyzes source code, builds a semantic model of modules, classes, functions, and attributes, and renders that model into documentation outputs without executing user code.

### Installation

Install using pip:

    1

    pip install doc-forge

### CLI usage

#### Generate an MkDocs site from a Python package:

    1

    doc-forge build --mkdocs --module my_package

#### Generate MCP JSON documentation:

    1

    doc-forge build --mcp --module my_package

#### Generate MkDocs site and MCP JSON documentation:

    1

    doc-forge build --mcp --mkdocs --module my_package

#### Serve MkDocs locally:

    1

    doc-forge serve --mkdocs --module my_package

#### Serve MCP locally:

    1

    doc-forge serve --mcp --module my_package

### Core concepts

#### Loader

Extracts symbols, signatures, and docstrings using static analysis.

#### Semantic model

Structured, renderer-agnostic representation of the API.

#### Renderer

Converts the semantic model into output formats such as MkDocs or MCP JSON.

#### Symbol

Any documentable object

- module
- class
- function
- method
- property
- attribute

### Architecture

`doc-forge` follows a compiler architecture:

#### Front-end:

Static analysis of modules, classes, functions, type hints, and docstrings.

#### Middle-end:

Builds a semantic model describing symbols and relationships.

#### Back-end:

Renders documentation using interchangeable renderers.

This architecture ensures deterministic documentation generation.

### Rendering pipeline

Typical flow:

    1
    2
    3
    4
    5
    6
    7
    8
    9

    Python package
        |
    Loader (static analysis)
        |
    Semantic model
        |
    Renderer
        |
    MkDocs site or MCP JSON

### Google-Styled Doc-Forge Convention (GSDFC)

GSDFC defines how docstrings must be written so they render correctly in MkDocs and remain machine-parsable by doc-forge and AI tooling.

- Docstrings are the single source of truth.
- `doc-forge` compiles docstrings but does not generate documentation content.
- Documentation follows the Python import hierarchy.
- Every public symbol should have a complete and accurate docstring.

#### General rules

- Use Markdown headings at package and module level.
- Use Google-style structured sections at class, function, and method level.
- Use type hints in signatures instead of duplicating types in prose.
- Write summaries in imperative form.
- Sections are separated by `---`

### Notes subsection grouping

Group related information using labeled subsections.

Example:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13

    Notes:
        **Guarantees:**

            - deterministic behavior

        **Lifecycle:**

            - created during initialization
            - reused across executions

        **Thread safety:**

            - safe for concurrent reads

### Example formatting

- Use indentation for examples.
- Indent section contents using four spaces.
- Use code blocks for example code.

Example

Single example:

    1
    2
    3
    4
    5
    6

    Example:

        ```python
        foo = Foo("example")
        process(foo, multiplier=2)
        ```

Multiple examples:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13

    Example:
        Create foo:

            ```python
            foo = Foo("example")
            ```

        Run engine:

            ```python
            engine = BarEngine([foo])
            engine.run()
            ```

Avoid fenced code blocks inside structured sections.

### Separator rules

Use horizontal separators only at docstring root level to separate sections:

    1

    ---

Allowed locations:

- package docstrings
- module docstrings
- major documentation sections

Do not use separators inside code sections.

### Package docstrings

Package docstrings act as the documentation home page.

Recommended sections:

    1
    2
    3
    4
    5
    6
    7
    8
    9

    # Summary
    # Installation
    # Quick start
    # CLI usage
    # Core concepts
    # Architecture
    # Rendering pipeline
    # Examples
    # Notes

Example

Package Doc String:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

    '''
    # Summary

    Foo-bar processing framework.

    Provides tools for defining Foo objects and executing Bar pipelines.

    ---

    # Installation

    ```bash
    pip install foo-bar
    ```

    ---

    # Quick start

    ```python
    from foobar import Foo, BarEngine

    foo = Foo("example")
    engine = BarEngine([foo])

    result = engine.run()
    ```

    ---
    '''

### Module docstrings

Module docstrings describe a subsystem.

Recommended sections:

    1
    2
    3

    # Summary
    # Examples
    # Notes

Example

Module Doc String:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    '''
    # Summary

    Foo execution subsystem.

    Provides utilities for executing Foo objects through Bar stages.

    ---

    Example:

        ```python
        from foobar.engine import BarEngine
        from foobar.foo import Foo

        foo = Foo("example")

        engine = BarEngine([foo])
        engine.run()
        ```

    ---
    '''

### Class docstrings

Class docstrings define object responsibility, lifecycle, and attributes.

Recommended sections:

    1
    2
    3
    4

    Attributes:
    Notes:
    Example:
    Raises:

Example

Simple Foo:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

    class Foo:
        '''
        Represents a unit of work.

        Attributes:
            name (str):
                Identifier of the foo instance.

            value (int):
                Numeric value associated with foo.

        Notes:
            Guarantees:

                - instances are immutable after creation

            Lifecycle:

                - create instance
                - pass to processing engine

        Example:
            Create and inspect a Foo:

                ```python
                foo = Foo("example", value=42)
                print(foo.name)
                ```
        '''

Complex Bar:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    class BarEngine:
        '''
        Executes Foo objects through Bar stages.

        Attributes:
            foos (tuple[Foo, ...]):
                Foo instances managed by the engine.

        Notes:
            Guarantees:

                - deterministic execution order

        Example:
            Run engine:

                ```python
                foo1 = Foo("a")
                foo2 = Foo("b")

                engine = BarEngine([foo1, foo2])
                engine.run()
                ```
        '''

### Function and method docstrings

Function docstrings define API contracts.

Recommended sections:

    1
    2
    3
    4
    5
    6

    Args:
    Returns:
    Raises:
    Yields:
    Notes:
    Example:

Example

Simple process method:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    def process(foo: Foo, multiplier: int) -> int:
        '''
        Process a Foo instance.

        Args:
            foo (Foo):
                Foo instance to process.

            multiplier (int):
                Value used to scale foo.

        Returns:
            int:
                Processed result.

        Raises:
            ValueError:
                If multiplier is negative.

        Notes:
            Guarantees:

                - foo is not modified

        Example:
            Process foo:

                ```python
                foo = Foo("example", value=10)

                result = process(foo, multiplier=2)
                print(result)
                ```
        '''

Multiple Examples:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

    def combine(foo_a: Foo, foo_b: Foo) -> Foo:
        '''
        Combine two Foo instances.

        Args:
            foo_a (Foo):
                First foo.

            foo_b (Foo):
                Second foo.

        Returns:
            Foo:
                Combined foo.

        Example:
            Basic usage:

                ```python
                foo1 = Foo("a")
                foo2 = Foo("b")

                combined = combine(foo1, foo2)
                ```

            Pipeline usage:

                ```python
                engine = BarEngine([foo1, foo2])
                engine.run()
                ```
        '''

### Property docstrings

Properties must document return values.

Example

Property Doc String:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    ```python
    @property
    def foos(self) -> tuple[Foo, ...]:
        '''
        Return contained Foo instances.

        Returns:
            tuple[Foo, ...]:
                Stored foo objects.

        Example:
            ```python
            container = FooContainer()

            foos = container.foos
            ```
        '''
    ```

### Attribute documentation

Document attributes in class docstrings using `Attributes:`.

Example

Attribute Doc String:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12

    ```python
    '''
    Represents a processing stage.

    Attributes:
        id (str):
            Unique identifier.

        enabled (bool):
            Whether the stage is active.
    '''
    ```

### Parsing guarantees

GSDFC ensures doc-forge can deterministically extract:

- symbol kind (module, class, function, property, attribute)
- symbol name
- parameters
- return values
- attributes
- examples
- structured Notes subsections

This enables:

- reliable MkDocs rendering
- deterministic MCP export
- accurate AI semantic interpretation

Notes

- doc-forge never executes analyzed modules.
- Documentation is generated entirely through static analysis.

### Classes

#### `` GriffeLoader

    1

    GriffeLoader()

Load Python modules using Griffe and convert them into doc-forge models.

This loader uses the Griffe introspection engine to analyze Python source code and transform the extracted information into `Project`, `Module`, and `DocObject` instances used by doc-forge.

Initialize the Griffe-backed loader.

Creates an internal Griffe loader instance with dedicated collections for modules and source lines.

##### Functions

###### `` load_module

    1

    load_module(path: str) -> Module

Load and convert a single Python module.

The module is introspected using Griffe and then transformed into a doc-forge `Module` model.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`path` | `str` | Dotted import path of the module. | required

Returns:

Name | Type | Description
--- | --- | ---
`Module` | `Module` | A populated `Module` instance.

###### `` load_project

    1

    load_project(module_paths: List[str], project_name: Optional[str] = None, skip_import_errors: bool = None) -> Project

Load multiple modules and assemble them into a Project model.

Each module path is introspected and converted into a `Module` instance. All modules are then aggregated into a single `Project` object.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`module_paths` | `List[str]` | List of dotted module import paths to load. | required
`project_name` | `str` | Optional override for the project name. Defaults to the top-level name of the first module. | `None`
`skip_import_errors` | `bool` | If True, modules that fail to load will be skipped instead of raising an error. | `None`

Returns:

Name | Type | Description
--- | --- | ---
`Project` | `Project` | A populated `Project` instance containing the loaded modules.

Raises:

Type | Description
--- | ---
`ValueError` | If no module paths are provided.
`ImportError` | If a module fails to load and `skip_import_errors` is False.

#### `` MCPRenderer

Renderer that generates MCP-compatible documentation resources.

This renderer converts doc-forge project models into structured JSON resources suitable for consumption by systems implementing the Model Context Protocol (MCP).

##### Functions

###### `` generate_sources

    1

    generate_sources(project: Project, out_dir: Path) -> None

Generate MCP documentation resources for a project.

The renderer serializes each module into a JSON resource and produces supporting metadata files such as `nav.json` and `index.json`.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`project` | `Project` | Documentation project model to render. | required
`out_dir` | `Path` | Directory where MCP resources will be written. | required

#### `` MkDocsRenderer

Renderer that produces Markdown documentation for MkDocs.

Generated pages use mkdocstrings directives to reference Python modules, allowing MkDocs to render API documentation dynamically.

##### Functions

###### `` generate_readme

    1

    generate_readme(project: Project, docs_dir: Path, module_is_source: bool | None = None) -> None

Generate a `README.md` file from the root module docstring.

Behavior:

- If `module_is_source` is True, `README.md` is written to the project root directory.
- If False, README generation is currently not implemented.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`project` | `Project` | Project model containing documentation metadata. | required
`docs_dir` | `Path` | Directory containing generated documentation sources. | required
`module_is_source` | `bool` | Whether the module is treated as the project source root. | `None`

###### `` generate_sources

    1

    generate_sources(project: Project, out_dir: Path, module_is_source: bool | None = None) -> None

Generate Markdown documentation files for a project.

This method renders a documentation structure from the provided project model and writes the resulting Markdown files to the specified output directory.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`project` | `Project` | Project model containing modules to document. | required
`out_dir` | `Path` | Directory where generated Markdown files will be written. | required
`module_is_source` | `bool` | If True, treat the specified module as the documentation root rather than nesting it inside a folder. | `None`

### Functions

#### `` discover_module_paths

    1

    discover_module_paths(module_name: str, project_root: Path | None = None) -> List[str]

Discover Python modules within a package directory.

The function scans the filesystem for `.py` files inside the specified package and converts them into dotted module import paths.

Discovery rules:

- Directories containing `__init__.py` are treated as packages.
- Each `.py` file is treated as a module.
- Results are returned as dotted import paths.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`module_name` | `str` | Top-level package name to discover modules from. | required
`project_root` | `Path` | Root directory used to resolve module paths. If not provided, the current working directory is used. | `None`

Returns:

Type | Description
--- | ---
`List[str]` | List[str]: A sorted list of unique dotted module import paths.

Raises:

Type | Description
--- | ---
`FileNotFoundError` | If the specified package directory does not exist.