This skill should be used when the user is setting up MkDocs Material, configuring mkdocstrings, writing docstrings, generating API reference pages, structuring documentation with the Diataxis framework, deploying docs to GitHub Pages or ReadTheDocs, or writing a README. Covers mkdocs.yml configuration, Griffe, Google-style docstrings, versioned docs with mike, code example testing, nav structure.
This skill should be used when the user is setting up MkDocs Material, configuring mkdocstrings, writing docstrings, generating API reference pages, structuring documentation with the Diataxis framework, deploying docs to GitHub Pages or ReadTheDocs, or writing a README. Covers mkdocs.yml configuration, Griffe, Google-style docstrings, versioned docs with mike, code example testing, nav structure.
version
1.0.0
Structure Documentation with MkDocs Material and the Diataxis Framework
Documentation fails not from bad writing but from mixing content types. A tutorial that stops to list every parameter loses the learner. A reference page with step-by-step instructions becomes unusable for lookups. The Diataxis framework separates tutorials, how-to guides, reference, and explanation into distinct pages -- and MkDocs Material is the tool to build them. FastAPI, Pydantic, httpx, Rich, and Polars all use MkDocs Material. Sphinx remains appropriate for existing rST codebases and scientific Python, but MkDocs Material is the default for new packages.
MkDocs Material vs Sphinx
Aspect
MkDocs Material
Sphinx
Markup
Markdown (+ PyMdown extensions)
reStructuredText (+ MyST for Markdown)
Learning curve
Low -- Markdown is universal
Medium-High -- rST is niche
API autodoc
mkdocstrings + Griffe (static, no imports)
autodoc (import-based, mature)
Build speed
Fast (seconds)
Slower, especially with autodoc
Theme
Excellent out of box, dark mode
Requires furo or pydata-sphinx-theme
New project adoption
Dominant since 2023
Declining for new projects
Use Sphinx when: existing large rST docs, scientific Python ecosystem (intersphinx), PDF requirements. Use MkDocs Material for everything else.
The Diataxis Framework
Organize all documentation into exactly four types:
Type
Orientation
Rule
Example
Tutorial
Learning
Guide through steps to a working result. No choices, no alternatives.
"Build your first API with MyLibrary"
How-To Guide
Task
Solve a specific problem. Assume basics known.
"How to configure authentication"
Reference
Information
Accurate, complete API docs. Organized by code structure.
"Client class", "Configuration options"
Explanation
Understanding
Discuss trade-offs, design decisions, concepts.
"Why we chose async over sync"
Never mix types on a single page. A tutorial with a 20-row parameter table serves nobody. A reference page with step-by-step prose is unusable for lookups.
Navigation principles: Progressive disclosure -- homepage answers "what is this?", quickstart shows basic usage in 30 seconds. No more than 2 levels of nesting. Separate "getting started" (tutorial for first-time users) from "guide" (how-to for returning users). Put API reference last in nav.
Versioned Documentation
Use mike for versioned docs deployed to GitHub Pages. Each release gets its own version; latest always points to the current stable release. Add mike to your docs dependency group and deploy via CI:
Default to GitHub Pages with mike for new packages. Use ReadTheDocs when you need PR preview builds or existing infrastructure.
Docstring Conventions
Use Google style -- the community standard used by FastAPI, Pydantic, httpx, and Rich. Configure mkdocstrings with docstring_style: google.
Bad Pattern
Good Pattern
url (str): The URL to request.
url: The URL to request. May be absolute or relative to base_url.
Duplicating type annotations in docstring
Types in signature, meaning and constraints in docstring
No docstring on public functions
Every public function, class, and module has a docstring
Docstring says what the code does line-by-line
Docstring says what it means, valid values, and edge cases
deffetch_users(
client: HttpClient,
*,
limit: int = 100,
offset: int = 0,
) -> list[User]:
"""Fetch a paginated list of users from the API.
Retrieves users from the `/users` endpoint with pagination.
Results are ordered by creation date, newest first.
Args:
client: An authenticated HTTP client instance.
limit: Maximum number of users to return. Must be
between 1 and 1000.
offset: Number of users to skip for pagination.
Returns:
A list of User objects. Empty list if no users match.
Raises:
AuthenticationError: If the client credentials are invalid.
"""
API Reference Generation
For packages with 10+ public modules, auto-generate reference pages using mkdocs-gen-files. Create scripts/gen_ref_pages.py that iterates src/**/*.py, skips private modules (_-prefixed), writes a ::: module.path directive per module into reference/, and generates a SUMMARY.md for literate-nav. Enable the gen-files, literate-nav, and section-index plugins in mkdocs.yml.
For small packages (fewer than 10 public objects), write manual reference pages:
Documentation examples that are not tested will drift. Use one of these approaches:
Approach
When to Use
--doctest-modules in pytest
Simple pure functions, data transformations
pytest-examples (Pydantic team)
Testing Markdown code blocks in docs/
Standalone test files (FastAPI approach)
Complex examples with I/O, configuration, setup
Add addopts = ["--doctest-modules"] and doctest_optionflags = ["NORMALIZE_WHITESPACE", "ELLIPSIS"] to [tool.pytest.ini_options] to test docstring examples automatically.
README Best Practices
The README is a landing page, not a manual. Answer three questions in under 60 seconds: (1) What is this? (2) How do I install it? (3) How do I use it?
Badges to include: PyPI version, Python versions, CI status, docs status. Badges to avoid: download counts, "code style: black", coverage percentage.
The README doubles as the PyPI long description via readme = "README.md" in pyproject.toml. Validate rendering with twine check dist/*.