Skip to content

Docs

docs

Audit checks for documentation (7 checks, 18 pts).

check_diataxis_nav(project)

Check 20: nav has Tutorials + How-To + Reference + Explanation.

Source code in packages/axm-init/src/axm_init/checks/docs.py
Python
def check_diataxis_nav(project: Path) -> CheckResult:
    """Check 20: nav has Tutorials + How-To + Reference + Explanation."""
    path = _resolve_mkdocs(project)
    if not path:
        return CheckResult(
            name="docs.diataxis_nav",
            category="docs",
            passed=False,
            weight=3,
            message="mkdocs.yml not found",
            details=[],
            fix="Create mkdocs.yml with Diátaxis nav structure.",
        )
    content = path.read_text().lower()
    sections = {
        "Tutorials": "tutorial" in content,
        "How-To": "how-to" in content or "howto" in content,
        "Reference": "reference" in content,
        "Explanation": "explanation" in content,
    }
    missing = [s for s, present in sections.items() if not present]
    if missing:
        return CheckResult(
            name="docs.diataxis_nav",
            category="docs",
            passed=False,
            weight=3,
            message=f"Diátaxis nav incomplete — missing {len(missing)} section(s)",
            details=[
                f"Missing: {', '.join(missing)}",
                f"Present: {', '.join(s for s, p in sections.items() if p)}",
            ],
            fix=f"Add {', '.join(missing)} section(s) to mkdocs.yml nav.",
        )
    return CheckResult(
        name="docs.diataxis_nav",
        category="docs",
        passed=True,
        weight=3,
        message="Full Diátaxis nav structure",
        details=[],
        fix="",
    )

check_gen_ref_pages(project)

Check 22: docs/gen_ref_pages.py exists.

Source code in packages/axm-init/src/axm_init/checks/docs.py
Python
def check_gen_ref_pages(project: Path) -> CheckResult:
    """Check 22: docs/gen_ref_pages.py exists."""
    found = (project / "docs" / "gen_ref_pages.py").exists()
    if not found and project.parent.name == "packages":
        workspace_root = project.parent.parent
        found = (workspace_root / "docs" / "gen_ref_pages.py").exists()
    if not found:
        return CheckResult(
            name="docs.gen_ref_pages",
            category="docs",
            passed=False,
            weight=2,
            message="docs/gen_ref_pages.py not found",
            details=["Auto-gen script needed for mkdocstrings API reference"],
            fix="Create docs/gen_ref_pages.py for automatic API reference generation.",
        )
    return CheckResult(
        name="docs.gen_ref_pages",
        category="docs",
        passed=True,
        weight=2,
        message="gen_ref_pages.py found",
        details=[],
        fix="",
    )

check_mkdocs_exists(project)

Check 19: mkdocs.yml exists.

Source code in packages/axm-init/src/axm_init/checks/docs.py
Python
def check_mkdocs_exists(project: Path) -> CheckResult:
    """Check 19: mkdocs.yml exists."""
    if not _resolve_mkdocs(project):
        return CheckResult(
            name="docs.mkdocs_exists",
            category="docs",
            passed=False,
            weight=3,
            message="mkdocs.yml not found",
            details=[],
            fix="Create mkdocs.yml with Material theme and Diátaxis navigation.",
        )
    return CheckResult(
        name="docs.mkdocs_exists",
        category="docs",
        passed=True,
        weight=3,
        message="mkdocs.yml found",
        details=[],
        fix="",
    )

check_plugins(project)

Check 21: gen-files + literate-nav + mkdocstrings.

For workspace members (project.parent.name == "packages"), missing plugins are re-checked against the workspace-root mkdocs.yml so that nav-only local configs do not trigger false positives.

Source code in packages/axm-init/src/axm_init/checks/docs.py
Python
def check_plugins(project: Path) -> CheckResult:
    """Check 21: gen-files + literate-nav + mkdocstrings.

    For workspace members (``project.parent.name == "packages"``), missing
    plugins are re-checked against the workspace-root ``mkdocs.yml`` so that
    nav-only local configs do not trigger false positives.
    """
    path = _resolve_mkdocs(project)
    if not path:
        return CheckResult(
            name="docs.plugins",
            category="docs",
            passed=False,
            weight=3,
            message="mkdocs.yml not found",
            details=[],
            fix="Create mkdocs.yml with gen-files, literate-nav, mkdocstrings plugins.",
        )
    content = path.read_text()
    required = {
        "gen-files": "gen-files" in content,
        "literate-nav": "literate-nav" in content,
        "mkdocstrings": "mkdocstrings" in content,
    }
    missing = [p for p, present in required.items() if not present]
    if missing:
        missing = _resolve_missing_from_workspace(missing, project)
    if missing:
        return CheckResult(
            name="docs.plugins",
            category="docs",
            passed=False,
            weight=3,
            message=f"Missing {len(missing)} plugin(s)",
            details=[f"Missing: {', '.join(missing)}"],
            fix=f"Add {', '.join(missing)} to mkdocs.yml plugins.",
        )
    return CheckResult(
        name="docs.plugins",
        category="docs",
        passed=True,
        weight=3,
        message="All plugins configured",
        details=[],
        fix="",
    )

check_readme(project)

Check 23: README.md sections.

Source code in packages/axm-init/src/axm_init/checks/docs.py
Python
def check_readme(project: Path) -> CheckResult:
    """Check 23: README.md sections."""
    path = project / "README.md"
    if not path.exists():
        return CheckResult(
            name="docs.readme",
            category="docs",
            passed=False,
            weight=3,
            message="README.md not found",
            details=[],
            fix="Create README.md following axm-bib standard.",
        )
    content = path.read_text()
    required = {
        "Features": "## Features" in content or "## features" in content.lower(),
        "Installation": "## Installation" in content or "## install" in content.lower(),
        "Development": "## Development" in content or "## develop" in content.lower(),
        "License": "## License" in content or "## license" in content.lower(),
    }
    missing = [s for s, present in required.items() if not present]
    if missing:
        return CheckResult(
            name="docs.readme",
            category="docs",
            passed=False,
            weight=3,
            message=f"README missing {len(missing)} section(s)",
            details=[f"Missing: {', '.join(missing)}"],
            fix=f"Add {', '.join(missing)} section(s) to README.md.",
        )
    return CheckResult(
        name="docs.readme",
        category="docs",
        passed=True,
        weight=3,
        message="README follows standard",
        details=[],
        fix="",
    )

check_readme_badges(project)

Check 24: README has axm-audit + axm-init badges.

Source code in packages/axm-init/src/axm_init/checks/docs.py
Python
def check_readme_badges(project: Path) -> CheckResult:
    """Check 24: README has axm-audit + axm-init badges."""
    path = project / "README.md"
    if not path.exists():
        return CheckResult(
            name="docs.readme_badges",
            category="docs",
            passed=False,
            weight=2,
            message="README.md not found",
            details=[],
            fix="Create README.md with axm-audit and axm-init badges.",
        )
    content = path.read_text()
    required = {
        "axm-audit": "axm-audit" in content,
        "axm-init": "axm-init" in content,
    }
    missing = [b for b, present in required.items() if not present]
    if missing:
        return CheckResult(
            name="docs.readme_badges",
            category="docs",
            passed=False,
            weight=2,
            message=f"README missing {len(missing)} badge(s)",
            details=[f"Missing: {', '.join(missing)}"],
            fix=f"Add {', '.join(missing)} badge(s) to README.md.",
        )
    return CheckResult(
        name="docs.readme_badges",
        category="docs",
        passed=True,
        weight=2,
        message="README has axm-audit + axm-init badges",
        details=[],
        fix="",
    )

check_standalone_api_ref(project)

Check 22b: a member's own reference/api/ nav must build standalone.

Guards mkdocs build --strict standalone integrity. Unlike :func:check_plugins / :func:check_gen_ref_pages, this check does NOT fall back to the workspace-root mkdocs.yml: if a package's local nav declares an auto-generated reference/api/ section, the package MUST carry its own docs/gen_ref_pages.py and the gen-files / literate-nav / mkdocstrings plugins locally — otherwise the promised section resolves to nothing and --strict aborts. The root fallback (correct for monorepo aggregation) previously masked this on scaffolded members, so a green init_check coexisted with a red standalone build.

Passes trivially when the local nav makes no reference/api/ promise or when no local mkdocs.yml exists.

Source code in packages/axm-init/src/axm_init/checks/docs.py
Python
def check_standalone_api_ref(project: Path) -> CheckResult:
    """Check 22b: a member's *own* ``reference/api/`` nav must build standalone.

    Guards ``mkdocs build --strict`` **standalone** integrity. Unlike
    :func:`check_plugins` / :func:`check_gen_ref_pages`, this check does NOT
    fall back to the workspace-root ``mkdocs.yml``: if a package's *local*
    nav declares an auto-generated ``reference/api/`` section, the package
    MUST carry its own ``docs/gen_ref_pages.py`` and the gen-files /
    literate-nav / mkdocstrings plugins locally — otherwise the promised
    section resolves to nothing and ``--strict`` aborts. The root fallback
    (correct for monorepo aggregation) previously masked this on scaffolded
    members, so a green ``init_check`` coexisted with a red standalone build.

    Passes trivially when the local nav makes no ``reference/api/`` promise
    or when no local ``mkdocs.yml`` exists.
    """
    local = project / "mkdocs.yml"
    if not local.exists():
        return _api_ref_pass()
    content = local.read_text()
    if not _local_nav_promises_api_ref(content):
        return _api_ref_pass()
    missing: list[str] = [p for p in _API_REF_PLUGINS if p not in content]
    if not (project / "docs" / "gen_ref_pages.py").exists():
        missing.append("docs/gen_ref_pages.py")
    if missing:
        return CheckResult(
            name="docs.standalone_api_ref",
            category="docs",
            passed=False,
            weight=2,
            message=(
                "nav declares reference/api/ but standalone build cannot "
                f"resolve it — missing {len(missing)} item(s)"
            ),
            details=[f"Missing locally: {', '.join(missing)}"],
            fix=(
                "Add docs/gen_ref_pages.py + gen-files/literate-nav/"
                "mkdocstrings plugins so `mkdocs build --strict` passes "
                "standalone (do not rely on the workspace-root mkdocs.yml)."
            ),
        )
    return _api_ref_pass()