6.1 KiB
doc-forge — Architecture & Design Specification
doc-forge is a renderer-agnostic Python documentation compiler. It converts Python source code and docstrings into a structured, semantic documentation model and then emits multiple downstream representations, including:
- Human-facing documentation sites (MkDocs, Sphinx)
- Machine-facing documentation bundles (MCP JSON)
- Live documentation APIs (MCP servers)
This document is the authoritative design and codebase specification for the library. It is written to be both LLM-friendly and developer-facing, and should be treated as the canonical reference for implementation decisions.
1. Design Goals
-
Single Source of Truth Python source code and docstrings are the only authoritative input.
-
Renderer Agnosticism MkDocs, Sphinx, MCP, or future renderers must not influence the core model.
-
Deterministic Output Given the same codebase, outputs must be reproducible.
-
AI-Native Documentation Documentation must be structured, queryable, and machine-consumable.
-
Library-First, CLI-Second All functionality must be accessible as a Python API. The CLI is a thin wrapper.
2. Core Mental Model
Fundamental Abstraction
The atomic unit of documentation is a Python import path
Examples:
mail_intakemail_intake.configmail_intake.adapters.base
Files, Markdown, HTML, and JSON are representations, not documentation units.
3. High-Level Architecture
Python Source Code
↓
Introspection Layer (Griffe)
↓
Documentation Model (doc-forge core)
↓
Renderer / Exporter Layer
├── MkDocs
├── Sphinx
├── MCP (static JSON)
└── MCP Server (live)
Only the Documentation Model is shared across all outputs.
4. Package Layout (Proposed)
docforge/
├── __init__.py
├── model/
│ ├── project.py
│ ├── module.py
│ ├── object.py
│ └── nav.py
├── loader/
│ └── griffe_loader.py
├── renderers/
│ ├── base.py
│ ├── mkdocs.py
│ └── sphinx.py
├── exporters/
│ └── mcp.py
├── server/
│ └── mcp_server.py
├── cli/
│ └── main.py
└── utils/
5. Documentation Model (Core)
The documentation model is renderer-neutral and must not contain any MkDocs-, Sphinx-, or MCP-specific logic.
5.1 Project
class Project:
name: str
version: str | None
modules: dict[str, Module]
nav: Navigation
5.2 Module
class Module:
path: str # import path
docstring: str | None
members: dict[str, DocObject]
5.3 DocObject
Represents classes, functions, variables, etc.
class DocObject:
name: str
kind: str # class, function, attribute, module
path: str
signature: str | None
docstring: str | None
members: dict[str, DocObject]
Private members (_name) are excluded by default.
5.4 Navigation
class Navigation:
entries: list[NavEntry]
class NavEntry:
title: str
module: str
Navigation is derived, not authored.
6. Introspection Layer
6.1 Griffe Loader
Griffe is the only supported introspection backend.
Responsibilities:
- Load modules by import path
- Resolve docstrings, signatures, and members
- Tolerate alias resolution failures
Output: fully populated Project and Module objects.
7. Renderer Interface
Renderers consume the documentation model and emit renderer-specific source trees.
class DocRenderer(Protocol):
name: str
def generate_sources(self, project: Project, out_dir: Path) -> None:
"""Generate renderer-specific source files."""
def build(self, config: RendererConfig) -> None:
"""Build final artifacts (HTML, site, etc.)."""
def serve(self, config: RendererConfig) -> None:
"""Serve documentation locally (optional)."""
8. MkDocs Renderer
Source Generation
- Emits
.mdfiles - One file per module
- Uses
mkdocstringsdirectives exclusively
# Config
::: mail_intake.config
Build
- Uses
mkdocs.commands.build
Serve
- Uses
mkdocs.commands.serve
MkDocs-specific configuration lives outside the core model.
9. Sphinx Renderer
Source Generation
- Emits
.rstfiles - Uses
autodocdirectives
mail_intake.config
==================
.. automodule:: mail_intake.config
:members:
:undoc-members:
Build
- Uses
sphinx.application.Sphinxdirectly
Serve
- Optional (static build is sufficient)
10. MCP Exporter (Static)
The MCP exporter bypasses renderers entirely.
Output Structure
mcp/
├── index.json
├── nav.json
└── modules/
└── package.module.json
Design Principles
- Alias-safe
- Deterministic
- Fully self-contained
- No Markdown, HTML, or templates
11. MCP Server (Live)
The MCP server exposes documentation as queryable resources.
Resources
docs://indexdocs://navdocs://module/{module}
Characteristics
- Read-only
- Stateless
- Backed by MCP JSON bundle
12. CLI Design
The CLI is a thin orchestration layer.
doc-forge generate --renderer mkdocs
doc-forge generate --renderer sphinx
doc-forge build --renderer mkdocs
doc-forge serve --renderer mkdocs
doc-forge export mcp
Renderer choice never affects the core model.
13. Explicit Non-Goals
- Markdown authoring
- Theme design
- Runtime code execution
- Code formatting or linting
14. Invariants (Must Never Break)
- Import paths are canonical identifiers
- Core model contains no renderer logic
- MCP does not depend on MkDocs or Sphinx
- Renderers do not introspect Python directly
- All outputs trace back to the same model
15. One-Line Definition
doc-forge is a documentation compiler that turns Python code into structured knowledge and emits it through multiple human and machine interfaces.
End of specification.