+
+
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:
+
+
+
CLI usage
+
Generate an MkDocs site from a Python package:
+
| doc-forge build --mkdocs --module my_package
+
|
+
Generate MCP JSON documentation:
+
| doc-forge build --mcp --module my_package
+
|
+
Generate MkDocs site and MCP JSON documentation:
+
| doc-forge build --mcp --mkdocs --module my_package
+
|
+
Serve MkDocs locally:
+
| doc-forge serve --mkdocs --module my_package
+
|
+
Serve MCP locally:
+
| 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
+
|
+
+
+
+- Use indentation for examples.
+- Indent section contents using four spaces.
+- Use code blocks for example code.
+
+
+
+
+ Example
+ Single example:
+ | 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:
+
+
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:
+
| # 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:
+
| Attributes:
+Notes:
+Example:
+Raises:
+
|
+
+
+
+ Example
+ Simple Foo:
+ | 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:
+ | 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:
+
| Args:
+Returns:
+Raises:
+Yields:
+Notes:
+Example:
+
|
+
+
+
+ Example
+ Simple process method:
+ | 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:
+ | 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
+
+
+
+
+
+
+
+
+
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
+
+
+
+
| 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
+
+
+
+
| load_project(
+ module_paths: list[str],
+ project_name: str | None = 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
+
+
+
+
| 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
+
+
+
+
| generate_readme(
+ project: Project,
+ docs_dir: Path,
+ module_is_source: bool | None = None,
+ readme_dir: Path | 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 |
+
+ Optional[bool]
+ |
+
+
+ Whether the module is treated as the project source root.
+
+ |
+
+ None
+ |
+
+
+ readme_dir |
+
+ Optional[Path]
+ |
+
+
+ Directory where the generated README.md should be written.
+Defaults to the parent of docs_dir.
+
+ |
+
+ None
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ generate_sources
+
+
+
+
| 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
+
+
+
+
| 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.
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+