Skip to content

Docs

docs

Documentation tree dump for AI agents.

Discovers README, mkdocs config, and all docs/ markdown files, then formats them as a single concatenated output.

Supports progressive disclosure via detail levels:

  • toc: heading tree + line count per page (~500 tokens)
  • summary: headings + first sentence per section
  • full: complete content (default, backward-compatible)

Example::

>>> result = discover_docs(Path("."))
>>> print(format_docs(result))
📖 README.md
─────────────
# My Project
...

>>> result = discover_docs(Path("."), detail="toc")
>>> result["pages"][0].keys()
dict_keys(['path', 'headings', 'line_count'])

build_docs_tree(docs_path)

Build an ASCII tree of the docs/ directory.

Parameters:

Name Type Description Default
docs_path Path

Path to the docs/ directory.

required

Returns:

Type Description
str | None

ASCII tree string, or None if docs/ doesn't exist.

Source code in packages/axm-ast/src/axm_ast/core/docs.py
def build_docs_tree(docs_path: Path) -> str | None:
    """Build an ASCII tree of the docs/ directory.

    Args:
        docs_path: Path to the docs/ directory.

    Returns:
        ASCII tree string, or None if docs/ doesn't exist.
    """
    if not docs_path.is_dir():
        return None

    lines: list[str] = ["docs/"]
    _walk_tree(docs_path, "", lines)
    return "\n".join(lines)

discover_docs(root, *, detail='full', pages=None)

Walk project root, find README, mkdocs.yml, and docs/*/.md.

Parameters:

Name Type Description Default
root Path

Project root directory.

required
detail str

Detail level — toc, summary, or full.

'full'
pages list[str] | None

Optional list of page name substrings to filter. Case-insensitive. README and mkdocs are always included.

None

Returns:

Type Description
dict[str, Any]

Dict with readme, mkdocs, tree, and pages.

Raises:

Type Description
ValueError

If detail is not a valid level.

Source code in packages/axm-ast/src/axm_ast/core/docs.py
def discover_docs(
    root: Path,
    *,
    detail: str = "full",
    pages: list[str] | None = None,
) -> dict[str, Any]:
    """Walk project root, find README, mkdocs.yml, and docs/**/*.md.

    Args:
        root: Project root directory.
        detail: Detail level — ``toc``, ``summary``, or ``full``.
        pages: Optional list of page name substrings to filter.
            Case-insensitive. README and mkdocs are always included.

    Returns:
        Dict with readme, mkdocs, tree, and pages.

    Raises:
        ValueError: If *detail* is not a valid level.
    """
    if detail not in _VALID_DETAIL_LEVELS:
        msg = (
            f"Invalid detail level: {detail!r}"
            f" (choose from {sorted(_VALID_DETAIL_LEVELS)})"
        )
        raise ValueError(msg)

    return {
        "project": root.name,
        "readme": _find_readme(root),
        "mkdocs": _find_mkdocs(root),
        "tree": build_docs_tree(root / "docs"),
        "pages": _find_docs_pages(root, detail=detail, pages=pages),
    }

extract_headings(content)

Extract H1/H2/H3 headings from markdown content.

Parameters:

Name Type Description Default
content str

Raw markdown text.

required

Returns:

Type Description
list[dict[str, int | str]]

List of dicts with level (1-3) and text keys.

Source code in packages/axm-ast/src/axm_ast/core/docs.py
def extract_headings(content: str) -> list[dict[str, int | str]]:
    """Extract H1/H2/H3 headings from markdown content.

    Args:
        content: Raw markdown text.

    Returns:
        List of dicts with ``level`` (1-3) and ``text`` keys.
    """
    return [
        {"level": len(m.group(1)), "text": m.group(2).strip()}
        for m in _HEADING_RE.finditer(content)
    ]

format_docs(result, *, tree_only=False)

Format documentation dump as human-readable text.

Parameters:

Name Type Description Default
result dict[str, Any]

Dict from discover_docs.

required
tree_only bool

If True, show only the tree structure.

False

Returns:

Type Description
str

Formatted text string.

Source code in packages/axm-ast/src/axm_ast/core/docs.py
def format_docs(result: dict[str, Any], *, tree_only: bool = False) -> str:
    """Format documentation dump as human-readable text.

    Args:
        result: Dict from discover_docs.
        tree_only: If True, show only the tree structure.

    Returns:
        Formatted text string.
    """
    parts: list[str] = []

    if tree_only:
        return _fmt_tree_only(result)

    _fmt_readme(result, parts)
    _fmt_mkdocs(result, parts)
    _fmt_tree_section(result, parts)
    _fmt_pages(result, parts)

    return "\n".join(parts)

format_docs_json(result)

Format documentation dump as JSON-serializable dict.

Parameters:

Name Type Description Default
result dict[str, Any]

Dict from discover_docs.

required

Returns:

Type Description
dict[str, Any]

JSON-serializable dict.

Source code in packages/axm-ast/src/axm_ast/core/docs.py
def format_docs_json(result: dict[str, Any]) -> dict[str, Any]:
    """Format documentation dump as JSON-serializable dict.

    Args:
        result: Dict from discover_docs.

    Returns:
        JSON-serializable dict.
    """
    return {
        "project": result.get("project"),
        "readme": result.get("readme"),
        "mkdocs": result.get("mkdocs"),
        "tree": result.get("tree"),
        "pages": result.get("pages", []),
    }