Files
doc-forge/ADS.llm.md

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

  1. Single Source of Truth Python source code and docstrings are the only authoritative input.

  2. Renderer Agnosticism MkDocs, Sphinx, MCP, or future renderers must not influence the core model.

  3. Deterministic Output Given the same codebase, outputs must be reproducible.

  4. AI-Native Documentation Documentation must be structured, queryable, and machine-consumable.

  5. 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_intake
  • mail_intake.config
  • mail_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 .md files
  • One file per module
  • Uses mkdocstrings directives 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 .rst files
  • Uses autodoc directives
mail_intake.config
==================

.. automodule:: mail_intake.config
   :members:
   :undoc-members:

Build

  • Uses sphinx.application.Sphinx directly

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://index
  • docs://nav
  • docs://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)

  1. Import paths are canonical identifiers
  2. Core model contains no renderer logic
  3. MCP does not depend on MkDocs or Sphinx
  4. Renderers do not introspect Python directly
  5. 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.