---------------------------------------------------------------------- This is the API documentation for the great_docs library. ---------------------------------------------------------------------- ## The GreatDocs Class The central class that orchestrates site initialization, building, and deployment for your Python package documentation. GreatDocs(project_path: str | None = None) GreatDocs class for creating beautiful API documentation sites. This class provides methods to install assets and configure Quarto projects with the great-docs styling and functionality. It handles package discovery, API reference generation, Quarto configuration, and site building with a consistent, polished look. Parameters ---------- project_path Path to the project root directory. If `None` (the default), the current working directory is used. Attributes ---------- project_root Absolute path to the project root directory. docs_dir Relative path to the documentation build directory (`great-docs`). project_path Full absolute path to the documentation build directory (`project_root / docs_dir`). Examples -------- Create a documentation site for a Python package: ```python from great_docs import GreatDocs gd = GreatDocs() # One-time setup: generates great-docs.yml and discovers exports gd.install() # Build the documentation site gd.build() # Preview locally in a browser gd.preview() ``` Build from a different directory: ```python gd = GreatDocs(project_path="/path/to/my-package") gd.build() ``` Notes ----- The typical workflow is: `install()` once to scaffold configuration, then `build()` (and optionally `preview()`) as you iterate. The `build()` method re-discovers package exports by default, so new functions and classes are picked up automatically. ## GreatDocs Methods Methods for installing dependencies, building the documentation site, launching a live preview, and validating links across all pages. install(self, force: bool = False) -> None Initialize great-docs in your project. This method creates a great-docs.yml configuration file in the project root with discovered exports and sensible defaults. The docs directory and assets will be created later during the build process. ::: {.callout-note} In practice, you would normally use the `great-docs init` CLI command rather than calling this method directly. See the [CLI reference](cli/init.qmd) for details. ::: Parameters ---------- force If `True`, overwrite existing great-docs.yml without prompting. Default is `False`. Examples -------- Initialize great-docs in the current directory: ```python from great_docs import GreatDocs docs = GreatDocs() docs.install() ``` Initialize in a specific project directory, overwriting existing config: ```python docs = GreatDocs("/path/to/my/project") docs.install(force=True) ``` uninstall(self) -> None Remove Great Docs configuration and generated build directories Delete `great-docs.yml` and the current `great-docs/` build directory. Also delete each historical `great-docs-/` directory that is not a symlink and contains the complete generated-file header. Preserve symlinks and historical directories without this header. ::: {.callout-note} In practice, you would normally use the `great-docs uninstall` CLI command rather than calling this method directly. See the [CLI reference](cli/uninstall.qmd) for details. ::: Examples -------- Uninstall great-docs from the current directory: ```python from great_docs import GreatDocs docs = GreatDocs() docs.uninstall() ``` Uninstall from a specific project directory: ```python docs = GreatDocs("/path/to/my/project") docs.uninstall() ``` build(self, watch: bool = False, refresh: bool = True, version_tags: list[str] | None = None, latest_only: bool = False) -> None Build the documentation site. Generates API reference pages followed by `quarto render`. By default, re-discovers package exports and updates the API reference configuration before building. ::: {.callout-note} In practice, you would normally use the `great-docs build` CLI command rather than calling this method directly. See the [CLI reference](cli/build.qmd) for details. ::: Parameters ---------- watch If `True`, watch for changes and rebuild automatically. refresh If `True` (default), re-discover package exports and update API reference config before building. Set to False for faster rebuilds when your package API hasn't changed. version_tags If provided, only build these specific version tags (for multi-version sites). Ignored when no `versions:` config is present. latest_only If `True`, build only the latest version (skip historical versions). Ignored when no `versions:` config is present. Examples -------- Build the documentation (with API refresh): ```python from great_docs import GreatDocs docs = GreatDocs() docs.build() ``` Build with watch mode: ```python docs.build(watch=True) ``` Quick rebuild without API refresh: ```python docs.build(refresh=False) ``` preview(self, port: int = 3000) -> None Preview the documentation site locally. Starts a local HTTP server and opens the built site in the default browser. If the site hasn't been built yet, it will be built first. Use `great-docs build` to rebuild the site if you've made changes. ::: {.callout-note} In practice, you would normally use the `great-docs preview` CLI command rather than calling this method directly. See the [CLI reference](cli/preview.qmd) for details. ::: Parameters ---------- port The port number for the local HTTP server (default `3000`). Examples -------- Preview the documentation: ```python from great_docs import GreatDocs docs = GreatDocs() docs.preview() ``` check_links(self, include_source: bool = True, include_docs: bool = True, timeout: float = 10.0, ignore_patterns: list[str] | None = None, verbose: bool = False) -> dict Check all links in source code and documentation for broken links. ::: {.callout-note} In practice, you would normally use the `great-docs check-links` CLI command rather than calling this method directly. See the [CLI reference](cli/check_links.qmd) for details. ::: This method scans Python source files and documentation files (`.qmd`, `.md`) for URLs and checks their HTTP status. It reports broken links (404s) and warns about redirects. The following content is automatically excluded from link checking: - **Python comments**: URLs in lines starting with `#` - **Code blocks**: URLs inside fenced code blocks (````` ... `````) - **Inline code**: URLs inside backticks (`` `...` ``) - **Marked URLs**: URLs followed by `{.gd-no-link}` in `.qmd`/`.md` files For documentation, the checker scans the source `user_guide/` directory rather than the generated `docs/` directory to avoid checking transient files. In `.qmd` files, you can exclude specific URLs from checking by adding `{.gd-no-link}` immediately after the URL: Visit http://example.com{.gd-no-link} for an example. Also works with inline code: `http://example.com`{.gd-no-link} Parameters ---------- include_source If `True`, scan Python source files in the package directory for URLs. Default is `True`. include_docs If `True`, scan documentation files (`.qmd`, `.md`) for URLs. Default is `True`. timeout Timeout in seconds for each HTTP request. Default is `10.0`. ignore_patterns List of URL patterns (strings or regex) to ignore. URLs matching any pattern will be skipped. Default is `None`. verbose If `True`, print detailed progress information. Default is `False`. Returns ------- dict A dictionary containing: - `total`: total number of unique links checked - `ok`: list of links that returned 2xx status - `redirects`: list of dicts with `url`, `status`, `location` for 3xx responses - `broken`: list of dicts with `url`, `status`, `error` for 4xx/5xx or errors - `skipped`: list of URLs that were skipped (matched ignore patterns) - `by_file`: dict mapping file paths to lists of links found in each file Examples -------- Check all links in a project: ```python from great_docs import GreatDocs docs = GreatDocs() results = docs.check_links() print(f"Checked {results['total']} links") print(f"Broken: {len(results['broken'])}") print(f"Redirects: {len(results['redirects'])}") ``` Check only documentation files with custom timeout: ```python results = docs.check_links( include_source=False, timeout=5.0, ignore_patterns=["localhost", "127.0.0.1", "example.com"] ) ``` ## Table Preview/Explorer Generate styled HTML table previews from any tabular data source with `tbl_preview()`, and explore tables interactively with `tbl_explorer()`. tbl_preview(data: 'Any', columns: 'list[str] | None' = None, n_head: 'int' = 5, n_tail: 'int' = 5, limit: 'int' = 50, show_all: 'bool' = False, show_row_numbers: 'bool' = True, show_dtypes: 'bool' = True, show_dimensions: 'bool' = True, max_col_width: 'int' = 250, min_tbl_width: 'int' = 500, caption: 'str | None' = None, highlight_missing: 'bool' = True, row_index_offset: 'int' = 0, id: 'str | None' = None) -> 'TblPreview' Generate a self-contained HTML table preview from almost any tabular data source. The `tbl_preview()` function gives you a quick, polished look at a dataset without pulling in heavy rendering dependencies. Pass it a Polars DataFrame, a Pandas DataFrame, a PyArrow Table, a file path to a CSV / TSV / JSONL / Parquet / Feather file, a column-oriented dictionary, or a list of row dictionaries—and get back a styled HTML table that renders identically in notebooks, Quarto documents, and static HTML pages. The preview shows a configurable number of rows from the top and bottom of the table, separated by a blue divider line when the full dataset exceeds the requested row count. Each column header displays the column name and, beneath it, a compact dtype label (e.g., `i64`, `str`, `f64`). A header banner shows a colored badge identifying the data source type (Polars, Pandas, CSV, Parquet, etc.) alongside row and column counts. Missing values (`None`, `NaN`, `NA`) are highlighted in red so they stand out immediately. The output is a :class:`TblPreview` object with `_repr_html_()` support, so it displays automatically in Jupyter notebooks and Quarto code cells. All CSS is scoped to a unique id, and the table includes full dark-mode support. No JavaScript is required. Parameters ---------- data The table to preview. This can be a Polars DataFrame, a Pandas DataFrame, a PyArrow Table, a file path (as a string or `pathlib.Path` object), a column-oriented dictionary, or a list of row dictionaries. When providing a file path, the extension determines the loader: `.csv`, `.tsv`, `.jsonl` (or `.ndjson`), `.parquet`, `.feather`, and `.arrow` (Arrow IPC) are all supported. Read the *Supported Input Data Types* section for details on each accepted format. columns The columns to display in the preview, by default `None` (all columns are shown). This can be a list of column name strings. If any name does not match a column in the table, a `KeyError` is raised. This is useful for focusing on a subset of a wide dataset. n_head The number of rows to show from the start of the table. Set to `5` by default. When the table has fewer rows than `n_head + n_tail`, the full table is displayed without a divider. n_tail The number of rows to show from the end of the table. Set to `5` by default. limit The limit value for the sum of `n_head=` and `n_tail=` (the total number of rows shown). If the sum of `n_head=` and `n_tail=` exceeds the limit, a `ValueError` is raised. The default value is `50`. Increase this when you need to display more rows. show_all Should the entire table be displayed? If `True`, all rows are shown regardless of the `n_head=` and `n_tail=` settings. By default, this is `False`. show_row_numbers Should row numbers be shown? The numbers appear in a narrow gutter column on the left side of the table, separated from the data columns by a subtle blue vertical line. By default, this is set to `True`. show_dtypes Should data type labels be displayed beneath each column name? The labels use short abbreviations (e.g., `i64` for 64-bit integer, `str` for string, `f64` for 64-bit float). By default, this is set to `True`. show_dimensions Should the header banner be shown? The banner displays a colored badge identifying the data source type alongside row and column counts in labeled pill badges. By default, this is set to `True`. max_col_width The maximum width of any single column in pixels. Column widths are computed automatically to fit their content up to this ceiling, beyond which cell text is truncated with an ellipsis. The default value is `250` pixels. min_tbl_width The minimum total width of the table in pixels. If the sum of the computed column widths is less than this value, columns are proportionally widened to fill the available space. The default value is `500` pixels. caption An optional caption string displayed below the header banner and above the column headers. Useful for labeling a preview with a dataset name or description. By default, no caption is shown. highlight_missing Should missing values (`None`, `NaN`, `NA`) be highlighted? When `True` (the default), missing cells are displayed in red text on a light red background so they stand out at a glance. row_index_offset The starting number for row indices. Defaults to `0`, matching the zero-based indexing convention of Python, Polars, and Pandas. Set to `1` for one-based numbering (e.g., for presentation to audiences unfamiliar with zero-based indexing). id An HTML `id` attribute for the outer `
` container. If `None` (the default), a unique ID is auto-generated using `secrets.token_hex(4)`. Providing your own ID is useful when you need to target the table with custom CSS or JavaScript. Returns ------- TblPreview A rendered table preview object. The object has `_repr_html_()` for automatic notebook display. Supported Input Data Types -------------------------- The `data` parameter accepts any of the following: - **Polars DataFrame** — displays a blue *Polars* badge - **Pandas DataFrame** — displays a dark purple *Pandas* badge - **PyArrow Table** — displays an indigo *Arrow* badge - **CSV file** (`.csv`) — loaded automatically; displays a cream *CSV* badge - **TSV file** (`.tsv`) — loaded automatically; displays a green *TSV* badge - **JSONL file** (`.jsonl` or `.ndjson`) — loaded line-by-line; displays a blue *JSONL* badge - **Parquet file** (`.parquet`) — requires `polars`, `pandas`, or `pyarrow`; displays a purple *Parquet* badge - **Feather / Arrow IPC file** (`.feather` or `.arrow`) — requires `polars`, `pandas`, or `pyarrow`; displays an orange *Feather* badge - **Dictionary** (column-oriented, `dict[str, list]`) — displays a gray *Table* badge - **List of dictionaries** (row-oriented, `list[dict]`) — displays a gray *Table* badge For file-based inputs, pass a string or `pathlib.Path` object. The file extension is used to determine the format. Polars is preferred for loading when available; Pandas and PyArrow are used as fallbacks. Examples -------- The simplest way to preview a table is to pass a Python dictionary: ```{python} from great_docs import tbl_preview tbl_preview({"city": ["Tokyo", "Paris", "New York"], "population": [13960000, 2161000, 8336000]}) ``` The result is a styled HTML table with a header banner showing the row and column count, dtype labels beneath each column name, and row numbers on the left. You can also pass a Polars DataFrame: ```{python} import polars as pl df = pl.DataFrame({ "product": ["Widget", "Gadget", "Gizmo", "Doohickey", "Thingamajig"], "category": ["Electronics", "Tools", "Kitchen", "Garden", "Office"], "price": [29.99, 49.50, 12.00, 8.75, 199.99], "in_stock": [True, False, True, True, False], }) tbl_preview(df) ``` For large tables, only the first `n_head=` and last `n_tail=` rows are shown, separated by a blue divider line. Adjust the counts to show more or fewer rows: ```{python} tbl_preview(df, n_head=2, n_tail=1) ``` Use `columns=` to focus on specific columns in a wide dataset: ```{python} tbl_preview(df, columns=["product", "price"]) ``` File paths work directly—no need to load the data yourself: ```{python} #| echo: false #| output: false import pathlib, json _d = pathlib.Path("assets/tbl-preview-data") _d.mkdir(parents=True, exist_ok=True) (_d / "students.csv").write_text( "name,subject,score,grade,passed\n" "Alice,Math,95.5,A,true\n" "Bob,Science,82.0,B,true\n" "Charlie,English,71.3,C,true\n" "Diana,History,60.0,D,true\n" "Eve,Art,55.8,F,false\n" "Frank,Math,88.2,B+,true\n" "Grace,Science,79.9,C+,true\n" "Hank,English,91.0,A-,true\n" "Iris,History,66.4,D+,true\n" "Jack,Art,73.7,C,true\n" ) ``` ```{python} tbl_preview("assets/tbl-preview-data/students.csv") ``` Add a caption to label the preview: ```{python} tbl_preview(df, caption="Product Catalog for Q1 2026") ``` For a minimal look, turn off the header banner, dtype labels, and row numbers: ```{python} tbl_preview(df, show_dimensions=False, show_dtypes=False, show_row_numbers=False) ``` See Also -------- tbl_explorer: Launch an interactive table explorer for deeper data investigation. enable_tbl_preview(**kwargs: 'Any') -> 'None' Register `tbl_preview()` as the default DataFrame display formatter. After calling this, any Polars or Pandas DataFrame that is the last expression in a cell (or passed to `display()`) will be rendered as a `tbl_preview()` table instead of the library's default HTML. Parameters ---------- **kwargs Keyword arguments forwarded to `tbl_preview()` (e.g., `n_head=10`, `show_all=True`, `show_dimensions=False`). Returns ------- None The formatter is registered as a side effect. IPython suppresses `None` output, so nothing is printed in the cell. Examples -------- ```{python} import pandas as pd import great_docs as gd df = pd.DataFrame({"name": ["Alice", "Bob", "Carol"], "score": [92, 87, 95]}) ``` Before enabling, the DataFrame renders with default Pandas HTML: ```{python} df ``` After enabling, the same DataFrame renders as a `tbl_preview()` table: ```{python} gd.enable_tbl_preview(n_head=3) df ``` From this point on, all DataFrames (Pandas, Polars, or otherwise) will render using `tbl_preview()` until `disable_tbl_preview()` is called. See Also -------- disable_tbl_preview : Remove the formatter and restore default display. tbl_preview : Generate a preview table for a single DataFrame. disable_tbl_preview() -> 'None' Remove the `tbl_preview()` display formatter and restore defaults. After calling this, any Polars or Pandas DataFrame will revert to using the library's default HTML representation instead of `tbl_preview()`. This undoes the effect of `enable_tbl_preview()`. Returns ------- None The formatter is removed as a side effect. IPython suppresses `None` output, so nothing is printed in the cell. Examples -------- ```{python} import pandas as pd import great_docs as gd df = pd.DataFrame({"name": ["Alice", "Bob", "Carol"], "score": [92, 87, 95]}) gd.enable_tbl_preview(n_head=3) ``` With the preview formatter active, the DataFrame renders as a `tbl_preview()` table: ```{python} df ``` After disabling, the DataFrame reverts to the default Pandas HTML: ```{python} gd.disable_tbl_preview() df ``` From this point on, all DataFrames (Pandas, Polars, or otherwise) will render using their native styling until `enable_tbl_preview()` is called again. See Also -------- enable_tbl_preview : Register `tbl_preview()` as the default DataFrame display formatter. tbl_preview : Generate a preview table for a single DataFrame. tbl_explorer(data: 'Any', columns: 'list[str] | None' = None, show_row_numbers: 'bool' = True, show_dtypes: 'bool' = True, show_dimensions: 'bool' = True, max_col_width: 'int' = 250, min_tbl_width: 'int' = 500, caption: 'str | None' = None, highlight_missing: 'bool' = True, page_size: 'int' = 10, sortable: 'bool' = True, filterable: 'bool' = True, column_toggle: 'bool' = True, copyable: 'bool' = True, downloadable: 'bool' = True, resizable: 'bool' = False, sticky_header: 'bool' = True, search_highlight: 'bool' = True, id: 'str | None' = None) -> 'TblExplorer' Generate an interactive table explorer from almost any tabular data source. The `tbl_explorer()` function creates a self-contained, interactive HTML table widget from tabular data. Pass it a Polars DataFrame, a Pandas DataFrame, a PyArrow Table, a file path to a CSV / TSV / JSONL / Parquet / Feather file, a column-oriented dictionary, or a list of row dictionaries—and get back an interactive table with sorting, token-based filtering, pagination, column toggling, copy-to-clipboard, and CSV download. The output uses **progressive enhancement**: the initial HTML contains a fully rendered static table (the first page of data) that is readable without JavaScript. When JavaScript is available, the static table is enhanced with interactive controls. All row data is embedded as inline JSON within the HTML, so the widget is completely self-contained with no external dependencies. The interactive toolbar includes a token-based filter bar (with type-aware operators for string, numeric, and boolean columns), a column visibility dropdown, copy and download buttons, and a reset control. Column headers are clickable for single-column sorting, and shift-click enables multi-column sorting. Pagination is enabled by default at 20 rows per page. The output is a :class:`TblExplorer` object with `_repr_html_()` support, so it displays automatically in Jupyter notebooks and Quarto code cells. All CSS is scoped to a unique id, and the table includes full dark-mode support. Parameters ---------- data The table to explore. This can be a Polars DataFrame, a Pandas DataFrame, a PyArrow Table, a file path (as a string or `pathlib.Path` object), a column-oriented dictionary, or a list of row dictionaries. When providing a file path, the extension determines the loader: `.csv`, `.tsv`, `.jsonl` (or `.ndjson`), `.parquet`, `.feather`, and `.arrow` (Arrow IPC) are all supported. Read the *Supported Input Data Types* section for details on each accepted format. columns The columns to display in the explorer, by default `None` (all columns are shown). This can be a list of column name strings. If any name does not match a column in the table, a `KeyError` is raised. This is useful for focusing on a subset of a wide dataset. show_row_numbers Should row numbers be shown? The numbers appear in a narrow gutter column on the left side of the table, separated from the data columns by a subtle blue vertical line. By default, this is set to `True`. show_dtypes Should data type labels be displayed beneath each column name? The labels use short abbreviations (e.g., `i64` for 64-bit integer, `str` for string, `f64` for 64-bit float). By default, this is set to `True`. show_dimensions Should the header banner be shown? The banner displays a colored badge identifying the data source type alongside row and column counts in labeled pill badges. By default, this is set to `True`. max_col_width The maximum width of any single column in pixels. Column widths are computed automatically to fit their content up to this ceiling, beyond which cell text is truncated with an ellipsis. The default value is `250` pixels. min_tbl_width The minimum total width of the table in pixels. If the sum of the computed column widths is less than this value, columns are proportionally widened to fill the available space. The default value is `500` pixels. caption An optional caption string displayed below the header banner and above the column headers. Useful for labeling an explorer with a dataset name or description. By default, no caption is shown. highlight_missing Should missing values (`None`, `NaN`, `NA`) be highlighted? When `True` (the default), missing cells are displayed in red text on a light red background so they stand out at a glance. page_size The number of rows to display per page. The default value is `20`. Set to `0` to disable pagination entirely and display all rows at once. The pagination bar shows the current range (e.g., "Showing 1–20 of 150 rows") and page navigation buttons. sortable Should column sorting be enabled? When `True` (the default), clicking a column header cycles through ascending → descending → unsorted. Hold **Shift** and click to add multi-column sorting. Sort indicators appear as SVG arrows next to column names. filterable Should the token-based filter bar be shown? When `True` (the default), a filter bar appears in the toolbar with a **+** button to add structured filters. Each filter is a token with a column, operator, and optional value. Available operators depend on the column type: string columns offer contains, starts with, ends with, etc.; numeric columns offer comparison operators including between; boolean columns offer is true/is false. Filters support case-sensitive matching via an **Aa** toggle. column_toggle Should the column visibility dropdown be shown? When `True` (the default), a **Columns** button appears in the toolbar. Clicking it opens a dropdown with checkboxes for each column. At least one column must remain visible. copyable Should the copy-to-clipboard button be shown? When `True` (the default), a clipboard icon appears in the toolbar. Clicking it copies the currently visible page of data as tab-separated values. On success, the icon briefly changes to a green checkmark. downloadable Should the CSV download button be shown? When `True` (the default), a download icon appears in the toolbar. Clicking it downloads the full filtered dataset (all pages) as a CSV file. resizable Should column drag-resize be enabled? Reserved for future use. Currently has no effect. The default value is `False`. sticky_header Should column headers remain visible when scrolling vertically? When `True` (the default), the header row sticks to the top of the table container as the user scrolls through rows. search_highlight Should matching cell text be highlighted when a "contains" filter is active? When `True` (the default), text matching the filter value is highlighted with a colored background. Set to `False` to disable highlighting. id An HTML `id` attribute for the outer `
` container. If `None` (the default), a unique ID is auto-generated using `secrets.token_hex(4)`. Providing your own ID is useful when you need to target the table with custom CSS or JavaScript. Returns ------- TblExplorer A rendered interactive table object. The object has `_repr_html_()` for automatic notebook display. Supported Input Data Types -------------------------- The `data` parameter accepts any of the following: - **Polars DataFrame** — displays a blue *Polars* badge - **Pandas DataFrame** — displays a dark purple *Pandas* badge - **PyArrow Table** — displays an indigo *Arrow* badge - **CSV file** (`.csv`) — loaded automatically; displays a cream *CSV* badge - **TSV file** (`.tsv`) — loaded automatically; displays a green *TSV* badge - **JSONL file** (`.jsonl` or `.ndjson`) — loaded line-by-line; displays a blue *JSONL* badge - **Parquet file** (`.parquet`) — requires `polars`, `pandas`, or `pyarrow`; displays a purple *Parquet* badge - **Feather / Arrow IPC file** (`.feather` or `.arrow`) — requires `polars`, `pandas`, or `pyarrow`; displays an orange *Feather* badge - **Dictionary** (column-oriented, `dict[str, list]`) — displays a gray *Table* badge - **List of dictionaries** (row-oriented, `list[dict]`) — displays a gray *Table* badge For file-based inputs, pass a string or `pathlib.Path` object. The file extension is used to determine the format. Polars is preferred for loading when available; Pandas and PyArrow are used as fallbacks. Examples -------- The simplest way to explore a table is to pass a Python dictionary: ```{python} from great_docs import tbl_explorer tbl_explorer({ "city": ["Tokyo", "Paris", "New York", "London", "Sydney"], "population": [13960000, 2161000, 8336000, 8982000, 5312000], "country": ["Japan", "France", "USA", "UK", "Australia"], }) ``` You can also pass a Polars DataFrame: ```{python} import polars as pl df = pl.DataFrame({ "product": ["Widget", "Gadget", "Gizmo", "Doohickey", "Thingamajig"], "category": ["Electronics", "Tools", "Kitchen", "Garden", "Office"], "price": [29.99, 49.50, 12.00, 8.75, 199.99], "in_stock": [True, False, True, True, False], }) tbl_explorer(df) ``` Load a CSV file and show only specific columns: ```python tbl_explorer("data/sales.csv", columns=["product", "revenue", "units"]) ``` Disable pagination to show all rows at once: ```python tbl_explorer(df, page_size=0) ``` Create a minimal, sort-only table with no toolbar controls: ```python tbl_explorer( df, sortable=True, filterable=False, column_toggle=False, copyable=False, downloadable=False, page_size=0, ) ``` See Also -------- tbl_preview: A simpler table preview widget for quick looks at datasets without interactive controls or pagination. ## Skills Install, check, and list Agent Skills from the Python API. install_skill(*, package: 'str | None' = None, url: 'str | None' = None, skill_content: 'str | None' = None, agent: 'AgentFormat | None' = None, global_: 'bool' = False, path: 'str | None' = None, root: 'Path | None' = None, detect: 'bool' = False, skill_name: 'str | None' = None, extra_files: 'dict[str, str] | None' = None, quiet: 'bool' = False) -> 'list[Path]' Install a SKILL.md file for AI coding agents. Resolves skill content from one of three sources (in priority order): 1. `skill_content`: raw SKILL.md text provided directly 2. `url`: fetch from a documentation site's well-known endpoint 3. `package`: find bundled skills inside an installed Python package The skill is installed to the appropriate agent directory based on auto-detection or explicit `agent` parameter. Parameters ---------- package Python package name (e.g., `"great-tables"`). Skills are looked up inside the installed package's `skills/` directory. url Documentation site URL to fetch skills from via the `.well-known` discovery protocol. skill_content Raw SKILL.md content to install directly. agent Target agent format. If not set, auto-detected from the project root or prompted interactively. global_ Install to the global (home directory) location instead of the repo. path Explicit target path. Overrides agent-based path resolution. root Project root directory. Defaults to the current working directory. detect Auto-detect existing installations and update them in place. skill_name Override the skill name (derived from frontmatter by default). extra_files Additional files to install alongside SKILL.md, as `{relative_path: content}` pairs. quiet Suppress output messages. Returns ------- list[Path] Paths to installed SKILL.md files (one per agent if multiple detected). check_skill(*, package: 'str | None' = None, global_: 'bool' = False, local: 'bool' = True, root: 'Path | None' = None, update: 'bool' = False, quiet: 'bool' = False) -> 'list[dict]' Check if installed skills are up to date. Scans for installed SKILL.md files and compares their version with the version bundled in the installed Python package. Parameters ---------- package Python package name to check. If None, checks all detected skills. global_ Only check global (home directory) installations. local Only check local (repository) installations. root Project root directory. Defaults to the current working directory. update Automatically update any outdated skills found. quiet Suppress output messages. Returns ------- list[dict] Status entries: `{"path": Path, "name": str, "installed_version": str, "package_version": str, "status": "current"|"outdated"|"unknown"}`. list_skills(*, package: 'str | None' = None, url: 'str | None' = None, quiet: 'bool' = False) -> 'list[dict]' List available skills from a package or URL. Parameters ---------- package Python package name to list skills from. url Documentation site URL to query for skills. quiet Suppress output messages. Returns ------- list[dict] Skill entries: `{"name": str, "description": str, "path": Path|None, "version": str|None}`. ---------------------------------------------------------------------- This is the CLI documentation for the package. ---------------------------------------------------------------------- ## CLI: great-docs ``` Usage: great-docs [OPTIONS] COMMAND [ARGS]... Great Docs: Beautiful documentation for Python packages. Great Docs generates professional documentation sites with auto-generated API references, CLI documentation, smart navigation, and modern styling. Get started with 'great-docs init' to set up your docs, then use 'great-docs build' to generate your site. Options: --version Show the version and exit. --help Show this message and exit. Commands: init Initialize great-docs in your project (one-time... build Build your documentation site. preview Preview your documentation locally. uninstall Remove great-docs from your project. config Generate a great-docs.yml configuration file. ci Helpers meant to run inside CI (GitHub Actions). scan Discover package exports and preview what can be... freeze Execute specific pages and persist their freeze cache. timings Show page-level build timings from the last build. setup-github-pages Set up automatic deployment to GitHub Pages. check-links Check for broken links in source code and... changelog Generate a Changelog page from GitHub Releases. proofread Check spelling and grammar in documentation files... seo Audit SEO health of your documentation site. lint Lint documentation quality for your package. api-diff Compare the public API between two versions. versions List configured documentation versions. api-snapshot Capture a JSON snapshot of a package's public API. skill Manage AI coding agent skills. termshow Terminal recording and playback for CLI/TUI... ``` ### great-docs init ``` Usage: great-docs init [OPTIONS] Initialize great-docs in your project (one-time bootstrap). Creates a fresh 'great-docs.yml' configuration file with discovered package exports and sensible defaults. Refuses to run if 'great-docs.yml' already exists (use '--force' to reset). • Creates 'great-docs.yml' with discovered API exports • Auto-detects your package name and public API • Updates .gitignore to exclude the build directory • Detects docstring style (numpy, google, sphinx) After init, customize 'great-docs.yml' then use 'great-docs build' for all subsequent builds. You should never need to run 'great-docs init' again unless you want to completely reset your configuration. Examples: great-docs init # Initialize in current directory great-docs init --force # Reset config to defaults great-docs init --project-path ../pkg # Initialize in another project Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --force Delete existing great-docs.yml and generate a fresh default config --help Show this message and exit. ``` ### great-docs build ``` Usage: great-docs build [OPTIONS] Build your documentation site. Requires 'great-docs.yml' to exist (run 'great-docs init' first). This is the only command you need day-to-day and in CI. Creates the 'great-docs/' build directory, copies all assets, and builds the documentation site. The build directory is ephemeral and should not be committed to version control. Use '--project-path' to point to a project in a different directory. Use '-- watch' to automatically rebuild when source files change. Use '--no-refresh' to skip API discovery for faster rebuilds when your package's public API hasn't changed. When multi-version documentation is configured, use '--versions' to build only specific versions, or '--latest-only' to skip historical versions. Use '--from-repo' to build documentation from a remote Git repository. This clones the repo into a temporary directory, creates an isolated virtual environment, installs the package and great-docs, builds the site, and copies the output to '--output-dir' (or './great-docs/_site'). Add '--preview' to automatically start a local server after a '--from-repo' build completes, opening the site in your browser. Examples: great-docs build # Full build with API refresh great-docs build --no-refresh # Fast rebuild (skip API discovery) great-docs build --watch # Rebuild on file changes great-docs build --versions 0.3,dev # Build specific versions only great-docs build --latest-only # Build only the latest version great-docs build --project-path ../pkg great-docs build --from-repo https://github.com/owner/pkg.git great-docs build --from-repo git@github.com:owner/pkg.git --branch v1.0 great-docs build --from-repo https://github.com/owner/pkg.git --output-dir ./site great-docs build --from-repo https://github.com/owner/pkg.git --shallow great-docs build --from-repo https://github.com/owner/pkg.git --preview Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --watch Watch for changes and rebuild automatically --no-refresh Skip re-discovering package exports (faster rebuild when API unchanged) --versions TEXT Build only specific versions (comma-separated tags, e.g. '0.3,dev') --latest-only Build only the latest version (skip historical versions) --from-repo TEXT Clone a remote Git repository and build its docs (HTTPS or SSH URL) --branch TEXT Branch or tag to check out when using --from-repo (default: repo default) --output-dir DIRECTORY Where to copy the built site when using --from- repo (default: ./great-docs/_site) --shallow Force shallow clone with --from-repo (fastest, but no versioned docs or page dates) --preview Start a preview server after building with --from- repo --help Show this message and exit. ``` ### great-docs preview ``` Usage: great-docs preview [OPTIONS] Preview your documentation locally. Starts a local HTTP server and opens the built documentation site in your default browser. If the site hasn't been built yet, it will build it first. The site is served from 'great-docs/_site/'. Use 'great-docs build' to rebuild if you've made changes. Use '--site-dir' to preview a site from any directory (e.g. output from a ' --from-repo' build). Use '--pr', '--run', or '--branch' to fetch and preview a site that CI already built (no hosting setup required). Downloading CI artifacts needs a GitHub token with 'Actions: read' (via GITHUB_TOKEN, a .env, or 'gh auth login' + '--use-gh'). For fork PRs you'll be viewing contributor-authored HTML locally. Examples: great-docs preview # Preview on port 3000 great-docs preview --port 8080 # Preview on port 8080 great-docs preview --site-dir /tmp/weathervault-site great-docs preview --pr 302 # Newest CI build for PR #302 great-docs preview --run 18273645521 # A specific workflow run great-docs preview --pr 302 --path reference/mcp/gd_config.html Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --port INTEGER Port for the local preview server [default: 3000] --site-dir DIRECTORY Path to a pre-built site directory to serve (bypasses project detection) --pr INTEGER Preview the CI docs build for this PR number. --run INTEGER Preview a specific workflow run id. --branch TEXT Preview the newest CI docs build for a branch. --repo TEXT GitHub repo as 'owner/repo' (default: detect from git remote / config). --artifact TEXT Name of the CI artifact to fetch. [default: docs- html] --path TEXT Open the browser at this page within the site (e.g. reference/index.html). --no-open Serve without launching a browser. --refresh Ignore the local cache and re-download. --clear-cache Delete the downloaded PR-preview cache and exit. --use-gh Fetch via the 'gh' CLI (uses your existing gh auth) instead of a token. --env-file FILE Load a .env for GITHUB_TOKEN/GH_TOKEN (default: auto-detect .env). --help Show this message and exit. ``` ### great-docs uninstall ``` Usage: great-docs uninstall [OPTIONS] Remove great-docs from your project. This command removes the great-docs configuration and build directory: • Deletes the 'great-docs.yml' configuration file • Removes the 'great-docs/' build directory Your source files ('user_guide/', 'README.md', etc.) are preserved. Examples: great-docs uninstall # Remove from current project Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --help Show this message and exit. ``` ### great-docs config ``` Usage: great-docs config [OPTIONS] Generate a great-docs.yml configuration file. Creates a 'great-docs.yml' file with all available options documented. The generated file contains commented examples for each setting. Examples: great-docs config # Generate in current directory great-docs config --force # Overwrite existing file great-docs config --project-path ../pkg Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --force Overwrite existing great-docs.yml without prompting --help Show this message and exit. ``` ### great-docs ci ``` Usage: great-docs ci [OPTIONS] COMMAND [ARGS]... Helpers meant to run inside CI (GitHub Actions). These emit the "preview this build locally" hints that let reviewers open a pull request's docs without a preview host: a workflow log notice and a sticky PR comment, both pointing at 'great-docs preview'. Examples: great-docs ci notice --run "$GITHUB_RUN_ID" --pr 302 great-docs ci pr-comment --run "$GITHUB_RUN_ID" --pr 302 Options: --help Show this message and exit. Commands: pr-comment Post or refresh a sticky PR comment with the local-preview... notice Print a workflow log notice with the local-preview command. ``` ### great-docs ci pr-comment ``` Usage: great-docs ci pr-comment [OPTIONS] Post or refresh a sticky PR comment with the local-preview command. Reads the token from GITHUB_TOKEN / GH_TOKEN and needs 'pull-requests: write'. Options: --run INTEGER Workflow run id that built the site. [required] --pr INTEGER Pull request number to comment on. [required] --repo TEXT GitHub repo as 'owner/repo' (default: $GITHUB_REPOSITORY, then git remote). --help Show this message and exit. ``` ### great-docs ci notice ``` Usage: great-docs ci notice [OPTIONS] Print a workflow log notice with the local-preview command. Options: --run INTEGER Workflow run id that built the site. [required] --pr INTEGER Pull request number (adds the --pr hint). --help Show this message and exit. ``` ### great-docs scan ``` Usage: great-docs scan [OPTIONS] Discover package exports and preview what can be documented. This command analyzes your package to find public classes, functions, and other exports. Use this to see what's available before writing your reference config. Examples: great-docs scan # Show discovered exports great-docs scan --verbose # Include method names for classes great-docs scan -v # Short form of --verbose Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --docs-dir TEXT Path to documentation directory relative to project root -v, --verbose Show method names for each class --help Show this message and exit. ``` ### great-docs freeze ``` Usage: great-docs freeze [OPTIONS] [PAGES]... Execute specific pages and persist their freeze cache. Renders one or more QMD pages (always executing their code), then copies the resulting '_freeze/' entries back to a persistent location so they survive future builds. PAGES are paths to .qmd files relative to your project root (e.g., 'user_guide/benchmarks.qmd'). Quarto always executes code when rendering individual files, even with freeze enabled (this is how you update frozen outputs). Use '--clean' to wipe the entire '_freeze/' cache before re-executing. This forces a full refresh of all specified pages from scratch. Use '--info' to see the freeze status of all pages without rendering. After running, the updated '_freeze/' entries are ready to commit to version control. Examples: great-docs freeze user_guide/benchmarks.qmd great-docs freeze user_guide/benchmarks.qmd user_guide/mcmc-demo.qmd great-docs freeze user_guide/benchmarks.qmd --freeze-dir docs/_freeze great-docs freeze user_guide/benchmarks.qmd --clean great-docs freeze --info Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --freeze-dir TEXT Where to persist _freeze/ (default: project root '_freeze/') --clean Delete existing _freeze/ before re-executing (forces full refresh). --info Show freeze status for all pages (which are frozen, cached, stale). --help Show this message and exit. ``` ### great-docs timings ``` Usage: great-docs timings [OPTIONS] Show page-level build timings from the last build. Reads the build-timings.json artifact generated during 'great-docs build' and displays per-page render durations as a sorted table. Pages are listed slowest-first to help identify bottlenecks. Run 'great-docs build' first to generate the timing data. Examples: great-docs timings great-docs timings --top 10 great-docs timings --version 0.10 great-docs timings --output-dir ./public great-docs timings --json Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --top INTEGER Show only the N slowest pages. --version TEXT Show timings for a specific version only (multi- version builds). --json Output raw JSON instead of a table. --output-dir DIRECTORY Path to the build output directory (if different from default _site). --help Show this message and exit. ``` ### great-docs setup-github-pages ``` Usage: great-docs setup-github-pages [OPTIONS] Set up automatic deployment to GitHub Pages. This command creates a GitHub Actions workflow that automatically builds and deploys your documentation when you push to the main branch. The workflow will: • Build docs on every push and pull request • Deploy to GitHub Pages on main branch pushes • Use Quarto's official GitHub Action for reliable builds • Install dev dependencies (auto-detected from your package manager) The Python version is automatically detected from your pyproject.toml's `requires-python` field. Use '--python-version' to override. The package manager is auto-detected by checking for lock files: • uv.lock -> uses uv (installs dev dependencies automatically) • poetry.lock -> uses poetry (installs with dev dependencies) • Otherwise -> uses pip with optional extras like [dev,docs] After running this command, commit the workflow file and enable GitHub Pages in your repository settings (Settings -> Pages -> Source: GitHub Actions). Examples: great-docs setup-github-pages # Auto-detect everything great-docs setup-github-pages --main-branch dev # Deploy from 'dev' branch great-docs setup-github-pages --python-version 3.12 great-docs setup-github-pages --package-manager uv great-docs setup-github-pages --force # Overwrite existing workflow great-docs setup-github-pages --install-from-main # Use GitHub main branch Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --main-branch TEXT Main branch name for deployment (default: main) --python-version TEXT Python version for CI (default: auto-detect from pyproject.toml, or 3.11) --package-manager [auto|pip|uv|poetry] Package manager for installing dependencies (default: auto-detect) --force Overwrite existing workflow file without prompting --install-from-main Install Great Docs from GitHub main branch instead of PyPI release --help Show this message and exit. ``` ### great-docs check-links ``` Usage: great-docs check-links [OPTIONS] Check for broken links in source code and documentation. This command scans Python source files and documentation ('.qmd', '.md') for URLs and checks their HTTP status. It reports broken links (404s) and warns about redirects. Default ignore patterns include: • localhost and 127.0.0.1 URLs • example.com, example.org, yoursite.com URLs • Placeholder URLs with brackets like [username] Examples: great-docs check-links # Check all links great-docs check-links --verbose # Show progress for each URL great-docs check-links --docs-only # Only check documentation great-docs check-links --source-only # Only check source code great-docs check-links -i "github.com/.*#" # Ignore GitHub anchor links great-docs check-links --timeout 5 # Use 5 second timeout great-docs check-links --json-output # Output as JSON Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --source-only Only check links in Python source files --docs-only Only check links in documentation files --timeout FLOAT Timeout in seconds for each HTTP request (default: 10) -i, --ignore TEXT URL pattern to ignore (can be used multiple times) -v, --verbose Show detailed progress for each URL checked --json-output Output results as JSON --help Show this message and exit. ``` ### great-docs changelog ``` Usage: great-docs changelog [OPTIONS] Generate a Changelog page from GitHub Releases. Fetches published releases from the GitHub API and renders them as a 'changelog.qmd' page in the build directory. The page is also linked in the navbar automatically. Requires the project to have a GitHub repository URL in 'pyproject.toml'. Set 'GITHUB_TOKEN' or 'GH_TOKEN' to avoid API rate limits. Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --max-releases INTEGER Maximum number of releases to include (default: from config or 50) --help Show this message and exit. ``` ### great-docs proofread ``` Usage: great-docs proofread [OPTIONS] [FILES]... Check spelling and grammar in documentation files using Harper. Harper is a fast, privacy-first grammar checker that runs locally. It checks spelling, grammar, punctuation, and style in a single pass. By default, checks all documentation files (.qmd, .md) in the project. Uses smart defaults to reduce noise in technical documentation: - Ignores formatting rules that conflict with code/YAML (unless '--strict') - Includes a built-in dictionary of technical terms (unless '--no-builtin-dictionary') Examples: great-docs proofread # Check all docs (smart defaults) great-docs proofread --strict # Check everything (no smart defaults) great-docs proofread --spelling-only # Just spelling great-docs proofread --dialect=uk # UK English great-docs proofread -d griffe -d quartodoc # Add custom words great-docs proofread --json-output # JSON output for CI great-docs proofread --ignore=SpellCheck # Skip specific rules great-docs proofread README.md user_guide/*.qmd # Specific files Requires harper-cli to be installed: brew install harper # macOS cargo install harper-cli # any platform Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --docs-dir TEXT Path to documentation directory relative to project root --include-docstrings Also check Python docstrings --spelling-only Only check spelling (SpellCheck rule) --grammar-only Exclude spelling, check grammar/style only --only TEXT Only run these rules (comma-separated) --ignore TEXT Skip these rules (comma-separated) -d, --dictionary TEXT Additional word(s) to consider correct (can be used multiple times) --dictionary-file PATH Path to file with custom words (one per line) --dialect [us|uk|au|in|ca] English dialect (default: us) -v, --verbose Show detailed progress for each file checked --json-output Output results as JSON for CI --compact One line per issue (GCC-style output) --max-issues INTEGER Exit with error if more than N issues found --strict Disable smart defaults (check everything, no builtin dictionary) --no-builtin-dictionary Don't add built-in technical terms to dictionary --help Show this message and exit. ``` ### great-docs seo ``` Usage: great-docs seo [OPTIONS] Audit SEO health of your documentation site. Checks for common SEO issues and provides recommendations for improvement. Run this after building your site with 'great-docs build'. Checks performed: • sitemap.xml presence and validity • robots.txt presence and configuration • Canonical URLs on all pages • Meta descriptions on pages • JSON-LD structured data • Page titles with site name • Missing alt text on images • Broken internal links (basic check) Examples: great-docs seo # Audit SEO health great-docs seo --fix # Fix issues where possible great-docs seo --json # JSON output for CI Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --fix Attempt to fix some issues automatically (e.g., generate missing files) --json Output results as JSON for CI integration --help Show this message and exit. ``` ### great-docs lint ``` Usage: great-docs lint [OPTIONS] Lint documentation quality for your package. Analyzes your package's public API for documentation issues including missing docstrings, broken cross-references, inconsistent formatting, malformed directives, and stale version annotations. Checks performed: • missing-docstring Public exports or methods without docstrings • broken-xref '%seealso' references to unknown symbols • ambiguous-xref References to a short name two objects claim • unread-source A linked source's inventory could not be read • style-mismatch Docstrings not matching configured style (numpy/google/sphinx) • unknown-directive Unrecognized '%directive' names • stale-badge Version badges far behind latest release • stale-callout Version callouts that are very old • stale-upcoming 'upcoming:' frontmatter for already-released versions Examples: great-docs lint # Run all checks great-docs lint --check stale-versions # Only check for stale annotations great-docs lint --check docstrings # Only check for missing docstrings great-docs lint --check cross-refs --check style great-docs lint --json # JSON output for CI great-docs lint --json | jq '.issues[] | select(.severity == "error")' Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --check [docstrings|cross-refs|style|directives|stale-versions] Run only specific checks (can be repeated). Default: all checks. --json Output results as JSON for CI integration --help Show this message and exit. ``` ### great-docs api-diff ``` Usage: great-docs api-diff [OPTIONS] OLD_VERSION NEW_VERSION Compare the public API between two versions. Analyzes how the API surface changed between 'OLD_VERSION' and 'NEW_VERSION' (git tags). Detects added, removed, and changed symbols, tracks parameter changes, and flags breaking changes with migration hints. Use 'HEAD' as 'NEW_VERSION' to compare against the working tree. Examples: great-docs api-diff v0.1.0 v0.2.0 great-docs api-diff v1.0.0 HEAD great-docs api-diff v0.9.0 v1.0.0 --json great-docs api-diff v0.1.0 v0.2.0 --graph great-docs api-diff v0.1.0 HEAD --timeline great-docs api-diff v0.1.0 v0.5.0 --symbol GreatDocs great-docs api-diff v0.1.0 v0.5.0 --symbol GreatDocs --changes-only great-docs api-diff v0.1.0 v0.5.0 --symbol GreatDocs --table great-docs api-diff v0.1.0 v0.5.0 --symbol GreatDocs --table --html Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --package TEXT Python package name (auto-detected from pyproject.toml if omitted) --json Output results as JSON --graph Show dependency graph as Mermaid diagram for the NEW version --timeline Show API surface growth timeline across all version tags --symbol TEXT Track a single symbol across versions (shows signature history) --changes-only With --symbol, show only versions where the symbol changed --table With --symbol, show parameter evolution as a table --html With --symbol --table, output HTML (with disclosure wrapper) --help Show this message and exit. ``` ### great-docs versions ``` Usage: great-docs versions [OPTIONS] List configured documentation versions. Shows the multi-version documentation configuration from 'great-docs.yml', including version tags, labels, and status indicators. Examples: great-docs versions # List all configured versions great-docs versions --check # Validate configuration Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --check Validate version configuration and exit with non- zero on errors --help Show this message and exit. ``` ### great-docs api-snapshot ``` Usage: great-docs api-snapshot [OPTIONS] [VERSION_TAG] Capture a JSON snapshot of a package's public API. Snapshots record every public symbol, its parameters, type annotations, and other metadata. They are used to build versioned API reference pages and compute diff annotations without needing access to old source code. With no arguments, snapshot the *current* working-tree API: 'great-docs api-snapshot' Snapshot a specific git tag: 'great-docs api-snapshot v1.0.0' Snapshot all version tags at once: 'great-docs api-snapshot --all-tags' Snapshots are saved to '.great-docs/snapshots/.json' by default. Options: --project-path DIRECTORY Path to your project root directory (default: current directory) --package TEXT Python package name (auto-detected from 'pyproject.toml' if omitted) -o, --output FILE Output file path (default: '.great- docs/snapshots/.json') --all-tags Snapshot all version tags in the repository --force Overwrite existing snapshot files --help Show this message and exit. ``` ### great-docs skill ``` Usage: great-docs skill [OPTIONS] COMMAND [ARGS]... Manage AI coding agent skills. Install, check, and list SKILL.md files so AI coding agents can learn to use your Python package. Quick start: great-docs skill install great-docs # install Great Docs' own skill great-docs skill install great-tables # install from PyPI package great-docs skill install pointblank # works with any GD-powered package great-docs skill check # verify freshness great-docs skill check --update # auto-update outdated skills great-docs skill list great-tables # see what's bundled Options: --help Show this message and exit. Commands: install Install skills for AI coding agents. check Check if installed skills are up to date. list List available skills from a package or URL. ``` ### great-docs skill install ``` Usage: great-docs skill install [OPTIONS] [SOURCE] Install skills for AI coding agents. SOURCE can be a Python package name or a documentation site URL. If omitted, looks for skills in the current package. Examples: great-docs skill install # current package (pyproject.toml) great-docs skill install great-tables # any installed package great-docs skill install polars pointblank # multiple packages at once great-docs skill install https://posit-dev.github.io/great-tables/ great-docs skill install great-tables --agent claude # Claude Code great-docs skill install great-tables --agent copilot # GitHub Copilot great-docs skill install great-tables --global # install to ~/ great-docs skill install great-tables --path .claude/skills/gt # custom path great-docs skill install --detect # find and refresh all skills Options: -g, --global Install the skill globally (~/) instead of in the current repository. -p, --path TEXT Custom path where to install the skill. -d, --detect Automatically detect and update existing installations. --agent [claude|copilot|cursor|windsurf|opencode|codex] Target agent format (auto-detected if not specified). --name TEXT Override the skill name. --help Show this message and exit. ``` ### great-docs skill check ``` Usage: great-docs skill check [OPTIONS] [PACKAGE] Check if installed skills are up to date. Scans for installed SKILL.md files and compares their content hash with the currently installed package to detect changes. Examples: great-docs skill check # check all installed skills great-docs skill check great-tables # check a specific package great-docs skill check --global # check global installations only great-docs skill check --update # reinstall any that have changed Options: -g, --global Only check global installations (in home directory). -l, --local Only check local installations (in current repository). -u, --update Automatically update any outdated skills found. --help Show this message and exit. ``` ### great-docs skill list ``` Usage: great-docs skill list [OPTIONS] [SOURCE] List available skills from a package or URL. Shows all SKILL.md files bundled in a package or discoverable at a URL, including their names and file paths. Examples: great-docs skill list # current package (pyproject.toml) great-docs skill list great-tables # any installed package great-docs skill list https://posit-dev.github.io/great-tables/ Options: --url TEXT Documentation site URL to query for available skills. --help Show this message and exit. ``` ### great-docs termshow ``` Usage: great-docs termshow [OPTIONS] COMMAND [ARGS]... Terminal recording and playback for CLI/TUI documentation. Record terminal sessions, edit them with YAML scripts, and render them as SVG frame sequences for the termshow player. Options: --help Show this message and exit. Commands: edit Open the Termshow Editor for a .termshow recording. import-cast Import an asciicast (.cast) file to .termshow format. record Record a terminal session to a .termshow file. render Render a .termshow recording into SVG frames. ``` ### great-docs termshow record ``` Usage: great-docs termshow record [OPTIONS] OUTPUT Record a terminal session to a .termshow file. Spawns an interactive shell and captures all output with timing. Press Ctrl+D or type 'exit' to stop recording. Options: --cols INTEGER Terminal width in columns --rows INTEGER Terminal height in rows --shell TEXT Shell to spawn (default: $SHELL) --capture-input Also capture keyboard input events --help Show this message and exit. ``` ### great-docs termshow render ``` Usage: great-docs termshow render [OPTIONS] SOURCE Render a .termshow recording into SVG frames. Processes the recording through the virtual terminal emulator and produces SVG keyframes + a manifest.json for the player. Options: -o, --output-dir PATH Output directory for frames --interval FLOAT Keyframe interval in seconds --script PATH Path to .termshow.yml script --help Show this message and exit. ``` ### great-docs termshow import-cast ``` Usage: great-docs termshow import-cast [OPTIONS] SOURCE OUTPUT Import an asciicast (.cast) file to .termshow format. Options: --help Show this message and exit. ``` ### great-docs termshow edit ``` Usage: great-docs termshow edit [OPTIONS] SOURCE Open the Termshow Editor for a .termshow recording. Launches a browser-based timeline editor for adding chapters, annotations, and cuts. Changes are saved back to the .termshow.yml script file. Examples: great-docs termshow edit demos/my-demo.termshow great-docs termshow edit demos/install.termshow --port 9000 Options: --port INTEGER Local server port --no-browser Don't auto-open browser --help Show this message and exit. ``` ---------------------------------------------------------------------- This is the User Guide documentation for the package. ---------------------------------------------------------------------- ## Getting Started # Welcome to Great Docs Great Docs is a documentation site generator for Python packages. Run one command, get a complete documentation site. Customize as much or as little as you want. ## Get Up and Running Fast Point Great Docs at your Python package and it does the rest. `great-docs init` scans your codebase, discovers your public API, detects your docstring format, and writes all the configuration for you. Then `great-docs build` produces a full documentation site (landing page, API reference, navigation) ready to preview and deploy. No templates to author. No content pages to write by hand. No build system to learn. ## Your Site Looks Great From the Start The default site isn't a starting point you'll need to overhaul. It's a polished, modern documentation site right away: dark mode, responsive layout, GitHub integration, structured parameter tables, and source links. Whether your package exposes a handful of functions or a deep class hierarchy, Great Docs figures out how to present it well. ## Explore a World of Possibilities When you're ready for more, there's a lot here: - Narrative user guides and tutorials alongside your API reference - Blogs, recipe sections, custom pages, and additional content sections - Diagrams, videos, color swatches, and interactive table previews - Gradient themes, announcement banners, and custom branding - Internationalization across twenty-three languages Every feature is opt-in. Your site stays clean until you decide to expand it. ## Go as Deep as You Need As your project grows, Great Docs keeps up. Publish multiple versions with a version selector. Track API changes across releases. Run the built-in link checker, linter, and proofreader. Generate `llms.txt` for AI tools. Deploy to GitHub Pages in one step. We keep on building the tools you'll need, and they'll be here when the time is right for you. ## What You'll Learn This User Guide covers everything you need to know to build and maintain great documentation sites. Here's what to expect: **Getting started**: Installing Great Docs, creating your first site, authoring `.qmd` files, writing effective docstrings, and understanding the project structure. **Configuration and theming**: Tuning site behavior through `great-docs.yml`, customizing appearance, setting up cross-references, internationalization, and responsive scaling. **Site content**: Auto-generated API and CLI references, narrative user guides, custom sections and static pages, blogs, diagrams, videos, tables, color swatches, and more. **Building and deployment**: Previewing locally, publishing to GitHub Pages, SEO optimization, social cards, and multi-version documentation. **Quality and maintenance**: Link checking, proofreading, linting, changelogs, community files, page status badges, and tracking API evolution. ## Next Steps This User Guide covers everything from first install to production deployment. Start at the beginning or jump to whatever topic you need. - [Installation](installation.qmd) gets Great Docs and Quarto set up on your machine - [Quick Start](quickstart.qmd) walks you through creating your first documentation site - [Authoring QMD Files](authoring-qmd-files.qmd) teaches the Markdown, frontmatter, and Quarto features you'll use everywhere # Installation This guide covers how to install Great Docs and its prerequisites. ## Prerequisites Before installing Great Docs, ensure you have: - **Python 3.11 or later** - **Quarto** – The publishing system that renders your documentation ### Installing Quarto Great Docs uses Quarto to render documentation. Install it from [quarto.org](https://quarto.org/docs/get-started/): ::: {.panel-tabset} ## macOS ```{.bash filename="Terminal"} # Using Homebrew brew install quarto # Or download the installer from quarto.org ``` ::: {.details summary="SVG generation is not working"} Please confirm the successful import via ```{.python filename="Python"} import cairosvg ``` If `cairosvg` is installed but the required libraries still cannot be found, add the brew dynamic library to your terminal environment by running: ```{.bash filename="Terminal"} echo 'export DYLD_FALLBACK_LIBRARY_PATH="/opt/homebrew/lib:$DYLD_FALLBACK_LIBRARY_PATH"' >> ~/.zshrc ``` ::: ## Linux ```{.bash filename="Terminal"} # Download and install the .deb package (Ubuntu/Debian) # Get the latest release URL from https://quarto.org/docs/get-started/ wget .deb sudo dpkg -i .deb # Or use your package manager ``` ## Windows Download and run the installer from [quarto.org](https://quarto.org/docs/get-started/). ::: Verify the installation: ```{.bash filename="Terminal"} quarto --version ``` ## Installing Great Docs ### From PyPI The simplest way to install Great Docs: ```{.bash filename="Terminal"} pip install great-docs ``` ### From GitHub Install the latest development version directly from GitHub: ```{.bash filename="Terminal"} pip install git+https://github.com/posit-dev/great-docs.git ``` Or install a specific version: ```{.bash filename="Terminal"} # Install from a specific branch pip install git+https://github.com/posit-dev/great-docs.git@main # Install from a specific tag pip install git+https://github.com/posit-dev/great-docs.git@v0.1.0 ``` ### Development Installation For contributing to Great Docs or testing the latest features: ```{.bash filename="Terminal"} # Clone the repository git clone https://github.com/posit-dev/great-docs.git cd great-docs # Install in editable mode pip install -e . # Or with development dependencies pip install -e ".[dev]" ``` ## Verify Installation After installation, verify everything is working: ```{.bash filename="Terminal"} # Check Great Docs version great-docs --help # Check Quarto version quarto --version ``` You should see the Great Docs help message and the Quarto version number. ## Upgrading Great Docs When a new version of Great Docs is released, upgrade using the same tool you used to install it: ::: {.panel-tabset} ## pip ```{.bash filename="Terminal"} pip install --upgrade great-docs ``` ## uv ```{.bash filename="Terminal"} uv pip install --upgrade great-docs ``` If Great Docs is declared in your `pyproject.toml` dependencies, update the version constraint there and run `uv sync` instead. ## pipx ```{.bash filename="Terminal"} pipx upgrade great-docs ``` ::: ### After upgrading 1. **Verify the new version** ```{.bash filename="Terminal"} great-docs --version ``` 2. **Review the changelog** — Check the [release notes](https://github.com/posit-dev/great-docs/releases) for breaking changes, new configuration options, or deprecated features that may affect your site. 3. **Rebuild your site** — Run `great-docs build` to pick up any changes in the build pipeline, templates, or default configuration. ::: {.callout-tip} You do **not** need to re-execute user guide notebooks after upgrading. A plain `great-docs build` is sufficient as it regenerates reference pages and templates without re-running notebook code (which can be time-consuming). ::: ## Next Steps With Great Docs and Quarto installed, you're ready to generate your first documentation site. - [Quick Start](quickstart.qmd) walks you through `great-docs init` and `great-docs build` - [Configuration](configuration.qmd) covers customizing behavior through `great-docs.yml` # Quick Start This guide walks you through creating your first documentation site with Great Docs in just a few minutes. ## Initialize Your Documentation Make sure you've [installed Great Docs](installation.qmd) first, then navigate to your Python project's root directory and run: ```{.bash filename="Terminal"} great-docs init ``` You only need to run this **once**. It creates `great-docs.yml` with sensible defaults. After that, `great-docs build` is the only command you need. Great Docs will automatically: 1. **Find your package**: Auto-detects your package name from `pyproject.toml`, `setup.cfg`, `setup.py`, or directory structure 2. **Discover your API**: Finds all public classes, functions, and methods 3. **Create configuration**: Generates `great-docs.yml` with your API structure 4. **Update .gitignore**: Optionally adds `great-docs/` to exclude build artifacts You'll see output like this: ```{.default filename="Terminal output"} Initializing great-docs... Detecting docstring style... Detected numpy docstring style Found package __init__.py at: my_package/__init__.py Using __all__ with 15 exports Auto-excluding 3 item(s): cli, main, version Categorizing API objects... MyClass: class with 8 public methods Testing dynamic introspection mode... Dynamic introspection mode works for this package Generated 2 section(s) from reference config Created /path/to/project/great-docs.yml The great-docs/ directory is ephemeral and should not be committed to git. Add 'great-docs/' to .gitignore? [Y/n]: Y ✅ Updated .gitignore to exclude great-docs/ directory ✅ Great Docs initialization complete! Next steps: 1. Review great-docs.yml to customize your API reference structure (Reorder items, add sections, set 'members: false' to exclude methods) 2. Run `great-docs build` to generate and build your documentation site 3. Run `great-docs preview` to view the site locally Other helpful commands: great-docs scan # Preview API organization great-docs build --watch # Watch for changes and rebuild ``` ::: {.callout-note} ## Configuration File The `great-docs.yml` file contains your API structure and is **committed to git**. The `great-docs/` build directory is **ephemeral** and should be gitignored. ::: ## Customize Your Configuration Open `great-docs.yml` and tailor it to your project. Organize API sections, add authors or funding info, set a `display_name`, add a `user_guide` directory, etc. See [Configuration](configuration.qmd) for all available options. ## Build Your Documentation Build (and rebuild) your docs with: ```{.bash filename="Terminal"} great-docs build ``` This is the only command you need day-to-day and in CI. It prepares the build directory, configures the API reference, generates supporting files (LLM indexes, source links, changelogs), processes your user guide and custom pages, generates API reference pages, and runs Quarto to render the final HTML site. The output shows each step with its status and timing: ```{.default filename="Build output (abbreviated)"} ━━ Step 1/19 ─ Prepare build directory ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [OK] great-docs/ ready <0.1s ━━ Step 2/19 ─ Configure API reference ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [OK] 2 section(s), 15 item(s) 1.2s ... ━━ Step 17/19 ─ Build site with Quarto ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [OK] quarto render 28.4s ━━ Step 18/19 ─ Post-render processing ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [OK] Version assembly complete <0.1s ━━ Step 19/19 ─ Generate SEO files ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Generated sitemap.xml with 120 URLs Generated robots.txt [OK] sitemap.xml + robots.txt <0.1s ============================================================================== | [OK] Build complete — 19/19 steps | | Total time: 35.6s | | | | 🎉 Site ready → | | /path/to/project/great-docs/_site/index.html | ============================================================================== ``` The built site is in `great-docs/_site/`. ::: {.callout-tip} ## Images in README.md If your README contains images with relative paths (like `![](images/screenshot.png)`), they will be copied to the build directory automatically. For the most portable setup (working in both GitHub and your docs site) place images in the `assets/` directory at your project root. ::: ::: {.callout-tip} ## Ephemeral Build Directory The `great-docs/` directory is created fresh on each build. You can safely delete it between builds (it will be recreated from `great-docs.yml` and your source files). ::: ## Preview Locally To preview your documentation with live reload: ```{.bash filename="Terminal"} great-docs preview ``` This starts a local server and opens your browser. Changes to your documentation files trigger automatic rebuilds. ## Project Structure After initialization and your first build, your project will have: ```{.default filename="Project structure"} your-project/ ├── great-docs.yml # Configuration (committed to git) ├── great-docs/ # Build directory (gitignored, ephemeral) │ ├── _quarto.yml # Generated Quarto config │ ├── index.qmd # Landing page (from README.md) │ ├── great-docs.scss # Styling │ ├── github-widget.js # GitHub stars widget │ ├── sidebar-filter.js # API search filter │ ├── llms.txt # LLM-friendly docs index │ ├── llms-full.txt # Full API docs for LLMs │ ├── _source_links.json # Source code links │ ├── reference/ # API reference pages (generated) │ │ ├── index.qmd │ │ ├── MyClass.qmd │ │ └── ... │ ├── user-guide/ # Copied from user_guide/ │ ├── scripts/ │ │ └── post-render.py # HTML post-processing │ └── _site/ # Built HTML site │ ├── index.html │ └── ... ├── user_guide/ # Your narrative docs (optional) │ ├── 01-installation.qmd │ └── ... ├── pyproject.toml ├── README.md └── your_package/ └── ... ``` ::: {.callout-important} ## What to Commit - ✅ `great-docs.yml` – Your configuration - ✅ `user_guide/` – Your narrative documentation - ✅ `README.md` – Your project readme - ❌ `great-docs/` – Ephemeral build directory (gitignored) ::: ## Scan Your API Before (or after) running `init`, you can use `great-docs scan` to preview what Great Docs discovered in your package. It shows every public class, function, constant, and enum, along with whether each item appears in your `great-docs.yml` reference config: ```{.bash filename="Terminal"} great-docs scan # Show discovered exports great-docs scan --verbose # Include method names for each class ``` This is useful for auditing your configuration: items marked `[x]` are included in your docs, while `[ ]` items are not. You can then add or remove entries in `great-docs.yml` accordingly. ## Command Options ### Initialize Options ```{.bash filename="Terminal"} # Initialize a different project great-docs init --project-path /path/to/project # Reset config to fresh defaults (deletes existing great-docs.yml) great-docs init --force ``` ::: {.callout-warning} ## --force Starts From Scratch `great-docs init --force` **deletes** your existing `great-docs.yml` and generates a brand-new default config. Any customizations you made (authors, sections, display_name, etc.) will be lost. Only use this if you genuinely want to reset. ::: ### Build Options ```{.bash filename="Terminal"} # Skip API re-discovery for faster rebuilds great-docs build --no-refresh # Watch for file changes and rebuild automatically great-docs build --watch # Build only specific versions (multi-version sites) great-docs build --versions 0.3,dev # Build only the latest version (skip historical) great-docs build --latest-only ``` ### Preview Options ```{.bash filename="Terminal"} # Preview on the default port (3000) great-docs preview # Use a different port great-docs preview --port 8080 ``` ## Using the Python API You can also use Great Docs programmatically: ```{.python filename="Python"} from great_docs import GreatDocs # Initialize for current directory docs = GreatDocs() docs.install() # Build documentation docs.build() # Preview documentation docs.preview() # Or initialize for a specific project docs = GreatDocs(project_path="/path/to/project") docs.install() docs.build() ``` ## Next Steps Your documentation site is ready! If you're new to writing `.qmd` files, head to the [Authoring QMD Files](authoring-qmd-files.qmd) guide for a thorough introduction to Markdown, frontmatter, callouts, tabsets, and all the other building blocks available to you. - [Authoring QMD Files](authoring-qmd-files.qmd) covers Markdown, frontmatter, callouts, and other building blocks - [Configuration](configuration.qmd) covers customizing Great Docs behavior - [API Documentation](api-documentation.qmd) explains how API discovery works - [CLI Documentation](cli-documentation.qmd) covers Click CLI documentation - [User Guides](user-guides.qmd) explains how to add narrative documentation - [Deployment](deployment.qmd) covers publishing to GitHub Pages # Authoring QMD Files Great Docs sites are built from **`.qmd` files** (Quarto Markdown). If you've written Markdown before, you're already most of the way there. The `.qmd` format extends standard Markdown with YAML frontmatter, executable code blocks, cross-references, callouts, and more. This page teaches you everything you need to write rich documentation pages. ## What Is a `.qmd` File? A `.qmd` file is a plain-text file with three parts: 1. **YAML frontmatter**: metadata at the top of the file, enclosed in `---` fences 2. **Markdown body**: the content of the page, written in Markdown 3. **Optional executable code**: code blocks that Quarto can run and embed output from Here's the simplest possible `.qmd` file: ```{.yaml filename="my-page.qmd"} --- title: "My Page" --- This is a documentation page. ``` When Great Docs builds the site, Quarto converts each `.qmd` file into a styled HTML page with navigation, search, and theming applied automatically. Understanding this three-part structure is all you need to start writing pages. The rest of this guide explores each part in detail so you can take full advantage of `.qmd` capabilities. ## Where You'll Use This As you build out your documentation site, you'll author `.qmd` files in several contexts: - **User Guide pages**: narrative documentation such as tutorials, installation instructions, and conceptual explanations (see [User Guides](user-guides.qmd)) - **Custom sections**: additional page groups like examples, tutorials, FAQs, or cookbooks that you define in `great-docs.yml` (see [Custom Sections](custom-sections.qmd)) - **Blog posts**: time-stamped articles for announcements, release notes, or technical deep dives (see [Blog](blog.qmd)) All of these use the same Markdown syntax, frontmatter, callouts, tabsets, and other features covered on this page. Once you learn the authoring basics here, they transfer directly to every part of your site. ::: {.callout-tip} ## Docstrings Are Markdown Too Much of what you learn here also applies to writing Python docstrings. Great Docs renders docstrings through Quarto, so formatting like **bold**, `inline code`, lists, tables, and even callouts works inside your docstrings as well. You can even embed executable code cells in docstrings, which means your API examples can display rich outputs (tables, plots, and more) right on the reference page. See [Writing Docstrings](writing-docstrings.qmd) for the full guide on structuring docstrings for Great Docs. ::: ## YAML Frontmatter Every `.qmd` file starts with a YAML block delimited by `---` lines. This block sets metadata that controls how the page is rendered and where it appears in navigation. Think of it as the control panel for the page: it never appears in the body text, but it shapes everything about how the page looks and behaves. ### Required Fields At minimum, a page needs a `title`: ```yaml --- title: "Installation Guide" --- ``` For User Guide pages, you'll also want `guide-section` to control sidebar grouping: ```yaml --- title: "Installation Guide" guide-section: "Getting Started" --- ``` The `title` becomes both the page heading and the label readers see in sidebar navigation, so make it concise and descriptive. ### Common Frontmatter Fields | Field | Purpose | Example | |-------|---------|---------| | `title` | Page heading and sidebar label | `"Quick Start"` | | `guide-section` | Sidebar section grouping | `"Getting Started"` | | `tags` | Page tags for filtering and discovery | `[Setup, Configuration]` | | `toc` | Show table of contents | `true` (default) | | `toc-depth` | Max heading depth in the TOC | `3` | The **Table of Contents** (TOC) is the "On this page" sidebar that appears on the right side of every page. It lists the headings on the current page as clickable links, letting readers jump directly to the section they need. By default the TOC is enabled and shows headings down to level 3 (i.e., `##` and `###`). Setting `toc-depth: 2` would limit it to only `##` headings, making the sidebar shorter for pages with many subsections. Setting `toc: false` hides it entirely, which can be useful for very short pages that don't benefit from a navigation outline. These fields give you fine-grained control over each page's behavior without changing its content. ### YAML Syntax Essentials YAML is whitespace-sensitive. Here are the patterns you'll use most: ```yaml --- # Strings (quotes optional unless the value contains special characters) title: "My Title" guide-section: Getting Started # Booleans toc: true # Lists (two equivalent forms) tags: [Setup, Config] tags: - Setup - Config --- ``` ::: {.callout-warning} ## Indentation Matters YAML uses spaces, never tabs. Inconsistent indentation will cause a build error. Use 2 spaces per indent level. ::: You won't need deep YAML knowledge for most pages. The patterns above cover the vast majority of frontmatter you'll write. When in doubt, copy the frontmatter from an existing page and adjust the values. ## Markdown Fundamentals The body of a `.qmd` file is written in Markdown, a lightweight markup language designed to be readable as plain text while converting cleanly to HTML. If you've never used Markdown, this section covers everything you need to start writing documentation. ### Headings Use `#` characters to create headings. The number of `#` symbols determines the level: ```markdown # Heading 1 ## Heading 2 ### Heading 3 #### Heading 4 ``` In a `.qmd` file, the `title` in frontmatter is the page's top-level heading, so your body content typically starts at `##`: ```{.markdown filename="my-page.qmd"} --- title: "Configuration" --- ## Basic Settings Content here... ### Database Options More content... ``` Headings automatically appear in the Table of Contents sidebar and serve as anchor targets for linking. Choose heading levels to reflect the logical structure of your content. Don't skip levels (e.g., jumping from `##` to `####`) as this breaks the outline hierarchy. ### Paragraphs and Line Breaks Paragraphs are separated by blank lines. For example, the following Markdown source: ```markdown This is the first paragraph. It can span multiple lines in the source file and will be rendered as a single flowing paragraph. This is a second paragraph. ``` ...renders as two paragraphs, with the line breaks within the first paragraph collapsed into spaces. ### Emphasis and Formatting Markdown provides several ways to emphasize text. Here's the syntax alongside what it produces: | Syntax | Result | Use For | |--------|--------|---------| | `*italic*` or `_italic_` | *italic* | Introducing terms, emphasis | | `**bold**` or `__bold__` | **bold** | Strong emphasis, important terms | | `***bold italic***` | ***bold italic*** | Rare, combined emphasis | | `` `code` `` | `code` | Function names, variables, file paths | | `~~strikethrough~~` | ~~strikethrough~~ | Deprecated or removed content | Here's a live example: writing `**Great Docs** makes it *easy* to document your ~~old~~ package` produces the following: **Great Docs** makes it *easy* to document your ~~old~~ package. Use emphasis purposefully. Bold works well for key terms on first introduction, italic for slight emphasis, and inline code for anything a programmer would type. Overusing emphasis dilutes its effect and makes prose harder to scan. ### Lists **Unordered lists** use `-`, `*`, or `+`. The syntax: ```markdown - First item - Second item - Nested item (indent 2 spaces) - Another nested item - Third item ``` Renders as: - First item - Second item - Nested item (indent 2 spaces) - Another nested item - Third item **Ordered lists** use numbers followed by a period: ```markdown 1. First step 2. Second step 3. Third step ``` Which produces: 1. First step 2. Second step 3. Third step The actual numbers don't matter because Markdown renumbers them automatically. Writing `1.` for every item is a common shorthand that keeps diffs clean when you reorder items. **Definition lists** pair a term with its definition: ```markdown Term : Definition of the term. Another term : Its definition. ``` This renders as: Term : Definition of the term. Another term : Its definition. Lists are one of the most effective tools for organizing information. Use unordered lists for collections where order doesn't matter, ordered lists for sequences and procedures, and definition lists for glossaries or option descriptions. ### Links Most common are inline links, where you would put the URL right next to the text: ```markdown Visit [Quarto's website](https://quarto.org) for more. ``` This renders as: Visit [Quarto's website](https://quarto.org) for more. For links to other pages in your documentation, use relative paths: ```markdown See the [Configuration](configuration.qmd) page. ``` This renders as: See the [Configuration](configuration.qmd) page. Liberal cross-linking between pages helps readers navigate your documentation. Reference-style links are especially handy when the same URL appears multiple times or when long URLs would clutter your prose. ### Images The basic syntax is: ```markdown ![Alt text describing the image](images/screenshot.png) ``` For more control over sizing and layout, use Quarto's figure syntax: ```markdown ![A descriptive caption](images/diagram.png){width=80% fig-align="center"} ``` The attributes in curly braces let you set width, height, alignment, and more. Always include meaningful alt text for accessibility. Screen readers rely on it, and it also displays as a placeholder if the image fails to load. Images and diagrams break up walls of text and can communicate complex ideas far more efficiently than prose. Store images in a subdirectory (e.g., `images/`) to keep your project organized. ### Blockquotes Prefix lines with `>` to create blockquotes: ```markdown > Documentation is a love letter that you write to your future self. > > — Damian Conway ``` This renders as: > Documentation is a love letter that you write to your future self. > > — Damian Conway Blockquotes work well for attributing quotes, reproducing terminal output in narrative context, or visually setting apart a passage that you're commenting on. ### Horizontal Rules Three or more hyphens, asterisks, or underscores on a line create a visual divider: ```markdown *** ``` Which renders as a horizontal line: *** ::: {.callout-note} Because `---` is also used for YAML frontmatter fences, it's safest to use `***` or `___` for horizontal rules in the body of your document to avoid any ambiguity. ::: Horizontal rules are useful for separating thematically distinct sections within a page when a heading would be too heavy-handed. ### Tables Use pipes and hyphens to create tables: ```markdown | Feature | Status | |------------|-------------| | Dark mode | Supported | | Search | Built-in | | Mobile | Responsive | ``` This renders as: | Feature | Status | |------------|-------------| | Dark mode | Supported | | Search | Built-in | | Mobile | Responsive | Control column alignment with colons in the separator row: ```markdown | Left | Center | Right | |:-----------|:-----------:|------------:| | aligned | aligned | aligned | ``` Which produces: | Left | Center | Right | |:-----------|:-----------:|------------:| | aligned | aligned | aligned | For tables with long content, the pipes don't need to line up perfectly. Markdown is forgiving about column widths in the source. Tables are the best way to present structured comparisons, option listings, and reference data. They're much easier to scan than the equivalent information written as prose. Taken together, the Markdown fundamentals covered in this section are enough to write clear, well-structured documentation pages. The remaining sections introduce Quarto-specific features that take your pages further. ## Code Blocks Code blocks are essential for technical documentation. Quarto offers several forms, each suited to different purposes: from showing syntax-highlighted snippets to running live code and embedding its output. ### Fenced Code Blocks Wrap code in triple backticks. Specify the language after the opening fence for syntax highlighting: ````markdown ```python import great_docs docs = great_docs.GreatDocs() docs.build() ``` ```` This renders with full syntax highlighting: ```python import great_docs docs = great_docs.GreatDocs() docs.build() ``` Quarto supports syntax highlighting for many languages: `python`, `javascript`, `typescript`, `r`, `bash`, `yaml`, `toml`, `json`, `html`, `css`, `sql`, `rust`, `go`, `java`, `cpp`, and more. Syntax highlighting makes code dramatically easier to read by visually distinguishing keywords, strings, comments, and other language elements. Always specify the language tag. There's no reason to show unhighlighted code. ### Code Block Options Add a filename label to give readers context about where the code belongs: ````markdown ```{.python filename="build.py"} from great_docs import GreatDocs docs = GreatDocs() docs.build() ``` ```` This renders as: ```{.python filename="build.py"} from great_docs import GreatDocs docs = GreatDocs() docs.build() ``` The `.python` syntax (with the dot prefix) is Quarto's way of specifying syntax highlighting for non-executable blocks. It's equivalent to plain `python` but allows you to add attributes like `filename`. Filename labels are a small touch that adds important context. They tell readers *where* a piece of code lives, which is especially valuable in tutorials that span multiple files. ### Executable Code Blocks Use curly braces around the language name to make a code block executable. Quarto will run the code and embed the output directly in the page: ````markdown ```{{python}} import pandas as pd df = pd.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]}) df ``` ```` Here's that same block running live: ```{python} import pandas as pd df = pd.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]}) df ``` Control execution with hash-pipe (`#|`) options. For example, the following block hides its source code and produces only the figure output with a caption: ````markdown ```{{python}} #| echo: false #| fig-cap: "A simple plotnine chart" from plotnine import ggplot, aes, geom_col, theme_minimal, labs import pandas as pd df = pd.DataFrame({"category": ["A", "B", "C", "D"], "value": [4, 7, 3, 8]}) ( ggplot(df, aes(x="category", y="value")) + geom_col(fill="#4682B4") + theme_minimal() + labs(x="Category", y="Value") ) ``` ```` And here it is rendered (notice only the plot appears because `echo: false` hides the code): ```{python} #| echo: false #| fig-cap: "A simple plotnine chart" from plotnine import ggplot, aes, geom_col, theme_minimal, labs import pandas as pd df = pd.DataFrame({"category": ["A", "B", "C", "D"], "value": [4, 7, 3, 8]}) ( ggplot(df, aes(x="category", y="value")) + geom_col(fill="#4682B4") + theme_minimal() + labs(x="Category", y="Value") ) ``` Common hash-pipe options: | Option | Effect | |--------|--------| | `#| echo: false` | Hide the source code, show only output | | `#| eval: false` | Show the code but don't run it | | `#| output: false` | Run the code but hide the output | | `#| warning: false` | Suppress warning messages | | `#| fig-cap: "..."` | Add a caption to figure output | | `#| label: fig-name` | Create a referenceable label for the figure | | `#| output-title: "..."` | Wrap the output in a labelled container | | `#| output-frame: true` | Wrap the output in a bordered container (no title) | | `#| source-code: mock` | Display one code block but execute another (see below) | Executable code blocks are what make `.qmd` files more powerful than plain Markdown. They ensure that your documentation's code examples are always tested: if the code breaks, the build fails, so your docs stay in sync with your actual API. ### Output Titles and Frames Cell output can be wrapped in a styled container using `#| output-title` and `#| output-frame`. These options work on any executable code cell and compose with `source-code: mock`. **Adding a title.** Use `#| output-title` to wrap output in a bordered container with a label displayed above it. This is useful for marking chat responses, returned values, or any output that benefits from a heading: ````markdown ```{{python}} #| output-title: "Response" chat.chat("Tell me a joke.") ``` ```` **Adding a frame without a title.** Use `#| output-frame: true` to wrap output in a bordered container *without* a title label. This gives text-based output visual containment that it doesn't normally have: ````markdown ```{{python}} #| output-frame: true from mypackage import greet greet("World") ``` ```` **Rich HTML outputs.** When the output is a rich HTML object (such as a GT table or a styled DataFrame), the frame is automatically removed to avoid a double-border (these objects already carry their own visual structure). With `output-title`, the title appears as a floating label above the output; with `output-frame`, the container is effectively invisible since the object supplies its own styling. **Composing with mock cells.** Both `output-title` and `output-frame` work naturally with `source-code: mock`. The title or frame applies to the eval cell's output: ````markdown ```{{python}} #| source-code: mock #| output-title: "Response" chat.chat("I need your help.") # --- chat.chat("I need your help.", debug=True, header=False) ``` ```` ### Mocked Code Cells Sometimes you need the code the reader *sees* to differ from the code that actually *runs*. Common reasons include: - an output requires a debug parameter that shouldn't be shown - the displayed code uses simplified imports - you want to hide boilerplate setup Normally this requires two separate code cells: one for display (`eval: false`) and one for execution (`echo: false`). The `source-code: mock` option collapses these into a single cell. Place `#| source-code: mock` at the top and separate the display code from the eval code with a `# ---` delimiter: ````markdown ```{{python}} #| source-code: mock import chatlas as ctl chat = ctl.ChatOpenAI() chat.chat("I need your help.") # --- import chatlas as ctl chat = ctl.ChatOpenAI(debug=True) chat.chat("I need your help.", header=False) ``` ```` The reader sees only the clean code above `# ---`, while the code below `# ---` runs and produces the output. Other hash-pipe options (`output-title`, `output-frame`, `warning`, etc.) compose naturally (see [Output Titles and Frames] above for examples). **Edge cases:** - **No delimiter**: the entire cell is display-only (equivalent to `eval: false`) - **Multiple `# ---`**: only the first one splits; subsequent ones are part of the eval code - **Empty eval section**: display-only cell (no output produced) ### Inline Code Use single backticks for inline code. For example, writing `` The `build()` method generates the HTML output `` renders as: The `build()` method generates the HTML output. Inline code is the workhorse of technical writing. Use it every time you mention a function name, variable, command, file path, or any other literal value. It tells readers "this is something you'd type, not just a word in a sentence". Code blocks, whether static or executable, are the backbone of any technical documentation page. They let you show readers exactly what to type and exactly what to expect. ## Callouts Callouts are colored boxes that draw attention to important information. They stand out from the surrounding prose, making them impossible to miss. Quarto provides five built-in types, each with a distinct color and icon: ```markdown ::: {.callout-note} Supplementary information that adds context. ::: ``` Here are all five types rendered live: ::: {.callout-note} Supplementary information that adds context. Use notes for background details, clarifications, or "good to know" asides. ::: ::: {.callout-tip} A helpful suggestion or best practice. Use tips for workflow shortcuts, performance advice, or recommended approaches. ::: ::: {.callout-warning} Something the reader should be careful about. Use warnings for common mistakes, breaking changes, or compatibility issues. ::: ::: {.callout-important} Critical information the reader must not miss. Use important callouts for security considerations, data integrity, or required prerequisites. ::: ::: {.callout-caution} Potential for data loss or irreversible actions. Use caution callouts for destructive operations, production deployments, or anything that can't be undone. ::: ### Callouts with Titles Add a heading inside the callout to give it a custom title: ```markdown ::: {.callout-tip} ## Pro Tip You can chain `great-docs init` and `great-docs build` in CI. ::: ``` This renders as: ::: {.callout-tip} ## Pro Tip You can chain `great-docs init` and `great-docs build` in CI. ::: Custom titles let you summarize the callout's message at a glance, which is especially helpful when a page has several callouts. ### Collapsible Callouts Add `collapse="true"` to make a callout collapsible (readers click to expand): ```markdown ::: {.callout-note collapse="true"} ## Click to expand This content is hidden by default. ::: ``` This renders as: ::: {.callout-note collapse="true"} ## Click to expand This content is hidden by default. Collapsible callouts are perfect for supplementary details that most readers can skip, like lengthy configuration examples or edge-case explanations. ::: Collapsible callouts keep pages scannable by hiding secondary detail behind a click. They're ideal for verbose examples, troubleshooting steps, or background context that would otherwise interrupt the flow. Callouts are one of the most effective tools for guiding readers through your documentation. Use them to flag what matters, but use them sparingly. If everything is highlighted, nothing stands out. ## Tabsets Tabsets present alternative content in switchable tabs. They're perfect for showing platform-specific instructions or code in multiple languages without cluttering the page with content most readers will skip: ````markdown ::: {.panel-tabset} ## pip ```bash pip install great-docs ``` ## conda ```bash conda install great-docs ``` ## pipx ```bash pipx install great-docs ``` ::: ```` This renders as a set of clickable tabs: ::: {.panel-tabset} ## pip ```bash pip install great-docs ``` ## conda ```bash conda install great-docs ``` ## pipx ```bash pipx install great-docs ``` ::: Each `##` heading inside the `::: {.panel-tabset}` block becomes a tab label. Readers click tabs to switch content (no page reload needed). Tabsets solve a common documentation problem: when you need to present the same information in multiple variants (different operating systems, package managers, programming languages, or framework versions), tabs keep all variants accessible without forcing readers to scroll past the ones they don't need. ## Divs and Spans Quarto uses a fenced div syntax (borrowed from Pandoc) to apply classes and attributes to blocks of content. The `:::` fences you've already seen in callouts and tabsets are examples of divs. This section covers the general mechanism so you can use it for layout and styling beyond those built-in features. ### Fenced Divs Wrap content in `:::` with a class name: ```markdown ::: {.border} This content has a border around it. ::: ``` This renders as: ::: {.border} This content has a border around it. ::: Nest divs by using more colons on the outer fence: ```markdown :::: {.columns} ::: {.column width="50%"} Left column content. ::: ::: {.column width="50%"} Right column content. ::: :::: ``` This renders as: :::: {.columns} ::: {.column width="50%"} **Left column**: content placed here appears on the left half of the page. ::: ::: {.column width="50%"} **Right column**: content placed here appears on the right half of the page. ::: :::: Fenced divs give you a structural building block for any layout that Markdown alone can't express. Because they're plain text, they stay readable in source and don't require writing raw HTML. ### Spans Apply classes to inline content with square brackets and curly braces: ```markdown This is [important text]{.text-danger} in a sentence. ``` This renders as: This is [important text]{.text-danger} in a sentence. Spans are the inline counterpart to divs. Use them when you need to style or annotate a word or phrase without affecting the surrounding block. Divs and spans together give you a complete system for applying structure and styling at any granularity, from full-page layouts down to individual words, all without leaving Markdown. ## Cross-References Cross-references let you link to specific figures, tables, sections, and other elements by label. Unlike plain links that break when content moves, cross-references resolve by label during the build, so they stay valid as your documentation evolves. ### Linking to Sections Any heading can be referenced by its auto-generated ID (lowercase, hyphens for spaces): ```markdown See [YAML Frontmatter](#yaml-frontmatter) above. ``` This renders as: See [YAML Frontmatter](#yaml-frontmatter) above. Section links are the simplest form of cross-reference. They help readers jump to related content within the same page without scrolling. ### Linking to Figures Label a figure with `#fig-` prefix and reference it: ````markdown ```{{python}} #| label: fig-revenue #| fig-cap: "Quarterly revenue" import matplotlib.pyplot as plt plt.plot([1, 2, 3, 4], [10, 15, 13, 17]) plt.show() ``` As shown in @fig-revenue, revenue grew steadily. ```` The `@fig-revenue` syntax creates a numbered link like "Figure 1" that stays correct even if you add more figures. This means you never have to manually update figure numbers; Quarto handles the bookkeeping. ### Linking to Other Pages Use relative paths for links within your documentation: ```markdown See the [Configuration](configuration.qmd) guide for all options. For API details, see the [GreatDocs](../reference/GreatDocs.qmd) class. ``` These links are validated during the build, so broken references are caught before your site goes live. Cross-references are essential for any documentation longer than a single page. They weave your pages into a connected whole, letting readers follow their own path through the material. ## Layout and Columns Quarto supports multi-column layouts for side-by-side content. This is useful for comparisons, before/after examples, or pairing explanatory text with a visual: ```markdown :::: {.columns} ::: {.column width="40%"} ### Input Raw Markdown text goes here. ::: ::: {.column width="60%"} ### Output The rendered result appears here. ::: :::: ``` This renders as: :::: {.columns} ::: {.column width="40%"} **Input**: the left column holds source text or code. ::: ::: {.column width="60%"} **Output**: the right column holds the rendered result or a larger visual. ::: :::: You can also use the `layout` attribute on figures for grid arrangements: ````markdown ::: {layout-ncol=2} ![First image](images/one.png) ![Second image](images/two.png) ::: ```` Multi-column layouts let you use horizontal space effectively. They're particularly valuable for tutorials where readers benefit from seeing input and output side by side, or for image galleries that would waste space displayed one-per-row. ## Includes Break large pages into smaller, reusable pieces with the `include` shortcode: ````markdown {{{< include _shared-setup.qmd >}}} ```` This inserts the contents of `_shared-setup.qmd` directly into the page at build time. By convention, included files start with `_` to indicate they aren't standalone pages. Includes are useful for: - Shared preambles or setup instructions across multiple pages - Reusable admonitions or disclaimers - Content that appears in both the User Guide and README Includes promote the "write once, use everywhere" principle. When a paragraph or setup block appears in multiple pages, extracting it into an include file means you only need to update it in one place. ### Code Includes When the `include` shortcode references a code file (anything other than `.qmd` or `.md`), Great Docs automatically wraps the file contents in a syntax-highlighted code block: ```markdown{shortcodes=false} {{{< include src/mypackage/examples/demo.py >}}} ``` The language is auto-detected from the file extension. A `.py` file becomes a `python` code block, a `.js` file becomes `javascript`, and so on. This is the same `include` shortcode used for content includes above. Great Docs handles code files automatically while passing `.qmd` and `.md` includes through to Quarto as usual. Code includes are ideal for keeping documentation in sync with real code. Instead of copying code snippets into your pages (where they can drift out of date), reference the source files directly. ::: {.callout-note} Generally, include shortcodes should not be enclosed in code blocks, as the formatting is applied automatically. ::: #### Including existing source files If your library already has runnable examples, tests, or configuration files that you want to showcase in the documentation, point `include` at them directly: ```markdown{shortcodes=false} {{{< include src/mypackage/examples/usage.py >}}} {{{< include tests/test_core.py lines="12-30" >}}} {{{< include pyproject.toml >}}} ``` Because paths are resolved relative to the project root, any file in your repository is reachable. This is the primary use case: your code examples are real, tested code that stays in sync automatically. When the source file changes, the documentation updates on the next build with no manual copying required. #### Writing new snippets for the docs When you need purpose-written examples that don't belong in your library's source tree, place them in an underscore-prefixed subdirectory of your user guide directory (for example, `user_guide/_includes/` or `user_guide/_snippets/`): ```text user_guide/ ├── _includes/ │ ├── quickstart.py │ ├── config-example.yaml │ └── shortcode-demo.qmd ├── 01-introduction.qmd └── 02-tutorial.qmd ``` Then reference them with a path relative to the user guide directory: ```markdown {{{< include _includes/quickstart.py >}}} {{{< include _includes/shortcode-demo.qmd lang="markdown" >}}} ``` This keeps documentation-only snippets close to the pages that use them, separate from the real source code. You can include `.qmd` files as code too, just add the `lang` or `lines` keyword to tell Great Docs to wrap the contents in a fenced code block instead of passing it through to Quarto for rendering. ::: {.callout-important} ## Use underscore-prefixed directories for snippet files Directories inside `user_guide/` that contain `.qmd` files are normally treated as content subdirectories. Their `.qmd` files are discovered as user guide pages. A leading underscore (e.g., `_includes/`, `_snippets/`) tells Great Docs to treat the directory as an **asset directory** instead: the files are copied to the build output but are not discovered as standalone pages. This means you can safely store `.qmd` snippets in `_includes/` without them appearing as pages in your site navigation. Without the underscore prefix, any `.qmd` files in the directory would either be picked up as user guide pages or prevent the directory from being copied as an asset directory. For non-`.qmd` snippet files (`.py`, `.js`, `.yaml`, etc.), the underscore prefix is not strictly required but using it consistently keeps all your snippet files in one predictable place. ::: #### Options **Line ranges**: include only specific lines with the `lines` keyword: ```markdown {{{< include src/mypackage/core.py lines="10-25" >}}} ``` Line numbers are 1-based and inclusive. This is useful for highlighting a specific function or block without showing the entire file. **Language override**: override the auto-detected language with the `lang` keyword: ```markdown {{{< include config/settings.conf lang="toml" >}}} ``` **Combining options**: both keywords can be used together: ```markdown {{{< include src/mypackage/core.py lines="5-15" lang="python" >}}} ``` #### Path resolution File paths are resolved relative to the directory containing the `.qmd` file first, then relative to the project root. This two-step lookup means you can use whichever style is most natural: - `_includes/example.py`: relative to the user guide directory (documentation-only snippets) - `src/mypackage/utils.py`: relative to the project root (existing source files) - `tests/test_core.py`: any file in the project tree If the referenced file is not found, a warning comment is inserted in the output so you can catch broken references during review. ## Math Equations For technical documentation that involves math, Quarto renders LaTeX equations natively. **Inline math** uses single dollar signs. For example, `$E = mc^2$` renders as $E = mc^2$. **Display math** uses double dollar signs for centered, standalone equations: ```markdown $$ L = \frac{1}{n}\sum_{i=1}^{n}(y_i - \hat{y}_i)^2 $$ ``` This renders as: $$ L = \frac{1}{n}\sum_{i=1}^{n}(y_i - \hat{y}_i)^2 $$ Math rendering uses KaTeX, so most LaTeX math commands are supported, from simple expressions like $\alpha + \beta$ to complex formulas with fractions, summations, and matrices. Math support is indispensable for packages that deal with statistics, machine learning, physics, or any domain where precise notation matters. Equations embedded directly in your docs are more readable and maintainable than screenshot images of formulas. ## Raw HTML When Markdown doesn't offer enough control, you can embed raw HTML directly: ```markdown
Click to expand This content is hidden by default but still written in Markdown. - List item one - List item two
``` This renders as:
Click to expand This content is hidden by default but still written in Markdown. - List item one - List item two
::: {.callout-note} Use raw HTML sparingly. Markdown content is portable and easier to maintain. Reserve HTML for cases where Markdown and Quarto's built-in features can't achieve the layout you need. ::: Raw HTML is an escape hatch for the rare cases where Markdown's abstractions aren't sufficient. The `
` element shown above is a good example: it creates a native browser disclosure widget that's simpler than a collapsible callout for short asides. ## Comments Add comments that don't appear in the rendered output: ```markdown Content visible to readers. ``` Comments are invisible to readers but visible to anyone editing the source file. Use them to leave notes for yourself or other authors: TODO reminders, explanations of why content is structured a certain way, or placeholders for sections you plan to fill in later. They're a lightweight coordination tool that costs nothing in the rendered output. ## Putting It All Together Here's a realistic User Guide page that combines many of these features: ````{.yaml filename="user_guide/04-getting-started.qmd"} --- title: "Getting Started" guide-section: "Tutorials" tags: [Setup, Tutorial] --- ## Prerequisites Before you begin, make sure you have: - Python 3.9 or later - A Python package with a `pyproject.toml` ::: {.callout-tip} ## Virtual Environments We recommend using a virtual environment to keep your dependencies isolated. ::: ## Installation ::: {.panel-tabset} ## pip ```bash pip install great-docs ``` ## pipx ```bash pipx install great-docs ``` ::: ## Your First Build Run these two commands from your project root: ```{.bash filename="Terminal"} great-docs init great-docs build ``` The generated site is in `great-docs/_site/`. Open `index.html` to preview it. ## What's Next? | Topic | Page | |-------|------| | Customize settings | [Configuration](configuration.qmd) | | Add narrative docs | [User Guides](user-guides.qmd) | | Deploy your site | [Deployment](deployment.qmd) | ```` This example uses frontmatter, a list, a callout, a tabset, a code block with a filename label, and a table (all features covered on this page). As you write your own pages, mix and match these building blocks to create documentation that's clear, scannable, and engaging. ## Quick Reference A compact cheat sheet for the most common `.qmd` authoring patterns: | Element | Syntax | |---------|--------| | Heading | `## My Heading` | | Bold | `**bold text**` | | Italic | `*italic text*` | | Inline code | `` `my_function()` `` | | Link | `[text](url)` | | Image | `![alt](path.png)` | | Unordered list | `- item` | | Ordered list | `1. item` | | Code block | ```` ```python ... ``` ```` | | Executable block | ```` ```{python} ... ``` ```` | | Callout | `::: {.callout-note} ... :::` | | Tabset | `::: {.panel-tabset} ... :::` | | Cross-ref to section | `[Section Name](#section-name)` | | Cross-ref to figure | `@fig-label` | | Inline math | `$E = mc^2$` | | Display math | `$$ ... $$` | | Include | `{{{< include file.qmd >}}}` | Keep this table close at hand as you write your first few pages. After a short while, the syntax becomes second nature. ## Next Steps The syntax covered here (frontmatter, Markdown, callouts, tabsets, executable code, cross-references) applies everywhere in Great Docs: user guide pages, docstrings, recipes, and custom sections. Once it's second nature, you're well-prepared to dive into any of these topics: - [Writing Docstrings](writing-docstrings.qmd): structure docstrings with sections, executable examples, and Great Docs directives - [Configuration](configuration.qmd): customize your site's structure and behavior - [API Documentation](api-documentation.qmd): how Great Docs discovers and renders your package's API - [User Guides](user-guides.qmd): organize pages into a multi-page guide with sidebar navigation - [Cross-Referencing](cross-referencing.qmd): Great Docs' advanced linking system for API symbols # Writing Docstrings Your docstrings are the single biggest input to your API reference. Great Docs renders them through Quarto, which means everything you can do in a `.qmd` file (Markdown formatting, callouts, tables, executable code cells) also works inside a docstring. A well-written docstring becomes a polished reference page with almost no extra effort; a thin or poorly structured one leaves your users guessing. This page covers how to structure docstrings so that Great Docs can extract the most value from them: which format to choose, what sections are available, how to embed live examples, and how to use Great Docs directives to control what gets documented. ## Choosing a Docstring Format Great Docs supports two widely used docstring conventions: **NumPy style** and **Google style**. Both produce the same rendered output. The difference is purely syntactic, so pick whichever your team already uses. If you're starting from scratch, either works well. When you run `great-docs init`, Great Docs analyzes your existing docstrings and auto-detects the style. You can override this in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} parser: numpy # or "google" ``` ### NumPy Style NumPy-style docstrings use underlined section headers. Parameters are listed one per line with the type on the same line as the name, separated by a colon: ```python def connect(host: str, port: int = 5432) -> Connection: """Open a connection to the database server. Establishes a TCP connection to the specified host and port. The connection is returned in an idle state, ready for queries. Call `close()` when you're finished to release the underlying socket. Parameters ---------- host The server hostname or IP address. port The TCP port number. Defaults to the standard PostgreSQL port. Returns ------- Connection An open connection object. Raises ------ ConnectionError If the server is unreachable or refuses the connection. Examples -------- ```{{python}} conn = connect("localhost", port=5432) ``` """ ... ``` ### Google Style Google-style docstrings use indented section headers followed by a colon. Parameters are indented under the section header: ```python def connect(host: str, port: int = 5432) -> Connection: """Open a connection to the database server. Establishes a TCP connection to the specified host and port. The connection is returned in an idle state, ready for queries. Call `close()` when you're finished to release the underlying socket. Args: host: The server hostname or IP address. port: The TCP port number. Defaults to the standard PostgreSQL port. Returns: An open connection object. Raises: ConnectionError: If the server is unreachable or refuses the connection. Examples: ```{{python}} conn = connect("localhost", port=5432) ``` """ ... ``` Leave a blank line before each Google-style section header, as shown above. Without the blank line, the header and its contents are treated as one. Both formats render identically in the final documentation. Great Docs parses them using [griffe](https://mkdocstrings.github.io/griffe/) and produces structured HTML with proper headings, parameter tables, and type annotations. ## Docstring Sections A docstring can contain several recognized sections. You don't need all of them for every function or class. Use only what's relevant. The standard sections are: | Section | Purpose | |---------|---------| | **Summary line** | A one-line description. Always present. Shows up in API index tables. | | **Extended description** | Extra paragraphs after the summary. Markdown formatting applies. | | **Parameters** | Describes each parameter (name, type, meaning, default). | | **Returns** | What the function returns, including the type. | | **Raises** | Exceptions the function may raise and when. | | **Notes** | Implementation details, algorithms, or caveats. | | **Examples** | Code demonstrating usage. Can be executable (see below). | | **See Also** | Related functions or classes. See [Cross-Referencing](cross-referencing.qmd). | | **Warnings** | Important cautions about usage. | | **References** | Citations or links to external resources. | Not every section needs to appear, and sections with no content are simply omitted from the rendered page. At minimum, include a summary line and a Parameters section for any function that accepts arguments. Returns and Raises sections are also high value: they tell users what to expect without reading source code. ### Custom Sections Both NumPy and Google docstring formats allow you to define your own named sections beyond the standard ones. This is useful when a function has domain-specific concepts that deserve their own heading. For example, the Pointblank library uses custom sections like "Supported DataFrame Types", "Preprocessing", "Segmentation", and "Thresholds" to document recurring concepts that cut across many validation methods: ```python def col_vals_gt( self, columns: str | list[str], value: float | int, na_pass: bool = False, pre: Callable | None = None, thresholds: Thresholds | None = None, ) -> Validate: """Are column data greater than a fixed value or data in another column? The `col_vals_gt()` validation method checks whether column values in a table are *greater than* a specified `value=`. Parameters ---------- columns A single column or a list of columns to validate. value The value to compare against. This can be a single value or a column name given in `col()`. na_pass Should any encountered None, NA, or Null values be considered as passing test units? By default, this is `False`. pre An optional preprocessing function or lambda to apply to the data table during interrogation. thresholds Failure-condition levels for reporting and reacting to exceedences. Returns ------- Validate The `Validate` object with the added validation step. What Can Be Used in `value=`? ----------------------------- The `value=` argument allows for a variety of input types: - a single numeric value - a single date or datetime value - a `col()` object that represents a column name Preprocessing ------------- The `pre=` argument allows for a preprocessing function or lambda to be applied to the data table during interrogation. The transformed table only exists during the validation step and is not stored. Thresholds ---------- The `thresholds=` parameter sets the failure-condition levels. There are three levels: 'warning', 'error', and 'critical'. Examples -------- ... """ ... ``` Each custom section becomes its own heading on the rendered reference page, giving readers a structured way to learn about concepts without cramming everything into the extended description. ## Executable Examples in Docstrings One of the most powerful features of Great Docs is that executable code cells work inside docstrings. Instead of showing static code snippets, you can write live examples that Quarto runs during the build. The output (tables, plots, printed values) appears directly on the reference page. Use the same ```` ```{python} ```` syntax you'd use in a `.qmd` file: ```python def preview(data, limit: int = 5): """Display a preview of the first rows of a table. Parameters ---------- data The table to preview. limit Maximum number of rows to show. Examples -------- Load a dataset and preview it: ```{{python}} import pointblank as pb tbl = pb.load_dataset(dataset="small_table", tbl_type="polars") pb.preview(tbl) ``` The preview shows column names, types, and the first few rows. This is useful for quickly inspecting data before writing validation steps. """ ... ``` When Great Docs builds the site, Quarto executes the code block and embeds the resulting HTML table directly on the reference page. Readers see both the code and its output, so they know exactly what to expect when they call the function. ### Tips for Executable Examples Executable examples are powerful, but they add build time and can break if APIs change. These guidelines help you get the most from them while keeping your builds fast and reliable: - **Set up shared state with hidden cells.** If every example needs the same imports or configuration, use a hidden code cell at the top of the Examples section. Mark it with `#| echo: false` and `#| output: false` so readers see only the meaningful examples: ````python """ Examples -------- ```{{python}} #| echo: false #| output: false import mypackage as mp mp.config(report_header=False) ``` Now the visible example is clean: ```{{python}} result = mp.transform(data) result ``` """ ```` - **Add prose between code cells.** Docstring examples don't have to be just code. Intersperse explanatory paragraphs that guide readers through what each example demonstrates and what the output means. - **Keep examples self-contained.** Each example should run on its own. Don't rely on variables defined in earlier examples unless you've set them up in a hidden cell. Following these patterns keeps your reference pages informative without turning the build into a fragile integration test. ## Great Docs Directives Great Docs recognizes special `%`-prefixed directives that you can place anywhere in a docstring. These directives are stripped from the rendered output and used to control documentation behavior. ### `%seealso`: Cross-Reference Related Items The `%seealso` directive adds a "See Also" section to the rendered reference page with clickable links to related symbols. Place it on its own line anywhere in the docstring: ```python def encode(data: bytes, encoding: str = "utf-8") -> str: """Encode bytes to a string. %seealso decode, transcode """ ... ``` You can add descriptions after each name, separated by a colon: ```python def load(path: str) -> dict: """Load data from a file. %seealso save : Write data back to a file, validate : Check integrity """ ... ``` You can also use multiple `%seealso` lines. Great Docs merges them into a single "See Also" section: ```python def transform(data: dict) -> dict: """Transform data before processing. %seealso load : Read raw data from a file %seealso save : Write transformed data back %seealso validate : Check data integrity after transform """ ... ``` For full details on cross-referencing (including inline interlinks and code autolinks), see [Cross-Referencing](cross-referencing.qmd). ### `%nodoc`: Exclude an Item from Documentation Sometimes a function or class is public (no leading underscore) but you don't want it in the API reference. Perhaps it's a legacy function kept for backward compatibility, or an implementation detail that happens to be exported. The `%nodoc` directive tells Great Docs to skip it entirely: ```python def _real_implementation(): ... def legacy_wrapper(): """Old entry point, kept for backward compatibility. %nodoc """ return _real_implementation() ``` When Great Docs discovers `legacy_wrapper` during static analysis, it reads the docstring, finds the `%nodoc` directive, and excludes the item from the generated reference. The function still exists in your package and still works; it simply won't appear in the documentation. This is different from the `exclude` list in `great-docs.yml`. The `exclude` config is for items you always want hidden (CLI entry points, internal modules). The `%nodoc` directive is for per-item decisions that live alongside the code, where the author of the function is best positioned to decide whether it belongs in the docs. You can verify which items are excluded by running `great-docs scan`. Items marked with `%nodoc` won't appear in the output. ## Markdown in Docstrings Since Great Docs renders docstrings through Quarto, all standard Markdown formatting works: - **Bold** and *italic* text - `Inline code` with backticks - [Links](https://example.com) to external resources - Bulleted and numbered lists - Tables - Callout blocks (tip, note, warning, caution) - Block quotes - Images Here's an example showing callouts and tables inside a docstring: ```python class DataStore: """A persistent key-value store backed by SQLite. ::: {.callout-warning} The store is not thread-safe. If you need concurrent access, use `ThreadSafeStore` instead. ::: The following storage backends are supported: | Backend | Persistence | Speed | |----------|-------------|--------| | memory | None | Fast | | sqlite | Disk | Medium | | redis | Network | Varies | %seealso ThreadSafeStore, connect """ ... ``` All of this renders exactly as it would in a `.qmd` page: the callout becomes a styled warning box, the table gets proper formatting, and the `%seealso` directive produces a "See Also" section with links. ## Linking to Other API Items Inside docstrings, you can create clickable links to other documented symbols using interlinks syntax. This is useful for guiding readers to related classes or functions: ```python class Validator: """Run validation checks on a data table. After creating a `Validator`, add steps with methods like [](`~mypackage.col_vals_gt`) and [](`~mypackage.col_vals_lt`), then call [](`~mypackage.Validator.interrogate`) to run them. """ ... ``` The `~` prefix strips the package path so readers see just `col_vals_gt` instead of the full qualified name. Great Docs also auto-links inline code: if you write `` `col_vals_gt` `` in a docstring and that name is a documented symbol, it automatically becomes a clickable link. See [Cross-Referencing](cross-referencing.qmd) for the full details. ## Beyond Functions and Classes Most docstring guidance focuses on functions, methods, and classes. But Python has other objects that appear in your public API and benefit just as much from documentation: constants, module-level variables, type aliases, `TypeVar` declarations, properties, and modules themselves. These objects often go undocumented simply because developers don't think of them as "documentable", yet they show up in your API reference and can leave readers guessing if they lack context. Great Docs can render docstrings for all of these. The pattern is the same everywhere: a summary line, an optional extended description, and whichever sections make sense. Here's some guidance on what to write for each. ### Constants A constant (typically uppercase, optionally annotated with `Final`) should explain what the value controls and why it has the value it does. If the constant is part of a set of related constants, mention the others: ```python from typing import Final MAX_CONNECTIONS: Final[int] = 128 """Upper bound on simultaneous database connections. Exceeding this limit raises `ConnectionPoolExhausted`. The default of 128 matches the PostgreSQL `max_connections` default so that a single application instance can saturate one server without over-provisioning. Notes ----- Deployments behind a connection pooler (PgBouncer, Odyssey) can safely raise this to 500 or more, since the pooler manages the actual backend connection count. %seealso MIN_CONNECTIONS, ConnectionPoolExhausted """ ``` ### Module-Level Variables A mutable module-level variable is documented the same way as a constant, but its docstring should emphasize valid values, defaults, and what happens when a user changes it: ```python timeout: int = 30 """Seconds to wait before abandoning a request. Set this before calling any request functions. Values below 1 are treated as "no timeout" (the request blocks indefinitely). The default of 30 seconds suits most interactive use. Batch pipelines may want 120 or more. Examples -------- ```{python} #| eval: false import mypackage mypackage.timeout = 60 # generous timeout for batch jobs """ ``` ### Type Aliases Type aliases name complex types so that signatures stay readable. The docstring should explain the *intent* behind the alias (i.e., what it represents in the domain) not just restate the underlying type: ```python type Key[K: (str, bytes)] = dict[K, ContractId] """A lookup keyed by either `str` or `bytes`, but not a mix of the two. `Key` appears in every registry function that needs to look up a contract. The constraint to `str | bytes` reflects the fact that contract identifiers arrive as strings from the API and as raw bytes from the binary ledger format. Callers pick one and stick with it. %seealso ContractId, Ledger """ ``` For the pre-PEP 695 `TypeAlias` spelling, the same guidance applies: ```python from typing import TypeAlias Signature: TypeAlias = Literal["ed25519", "rsa"] """Which signing scheme produced a signature. Only `ed25519` and `rsa` are currently supported. The literal type ensures invalid schemes are caught by type checkers before runtime. """ ``` ### TypeVar, ParamSpec, and TypeVarTuple These declarations constrain generic signatures. Their docstrings should explain *why* the constraint exists and what it means for callers: ```python from typing import TypeVar Sortable = TypeVar("Sortable", bound="SupportsLessThan") """A type that can be compared with `<`. Any type passed where `Sortable` is expected must implement `__lt__`. This is the minimum needed for `sorted()` and `heapq` to work, and it's deliberately narrower than `SupportsRichComparison` to avoid requiring `__eq__`. """ ``` ### Properties A property looks like an attribute to the caller but may involve computation, caching, or validation. The docstring should make this behavior visible: ```python class Connection: @property def is_idle(self) -> bool: """Whether the connection has no in-flight queries. Computed from the internal transaction counter, so this is always consistent even if queries are being submitted from another thread. An idle connection can be safely returned to the pool or closed. %seealso close, release """ return self._in_flight == 0 ``` ### Modules The module docstring (the first string literal in a `.py` file) sets context for everything the module contains. It should orient readers who land on the module's page in the API reference: ```python """Connection pooling and lifecycle management. This module owns the connection pool, the health-check loop, and the retry logic that wraps individual queries. Most users interact with it through `get_connection()` and the `Connection` context manager; the pool configuration constants are exposed for tuning. %seealso config, query """ ``` ### General Tips A few guidelines apply across all of these: - **Lead with intent, not structure.** "A lookup keyed by either `str` or `bytes`" tells the reader more than "`dict[K, ContractId]` where `K` is constrained to `str` or `bytes`." - **Use `%seealso` liberally.** Constants, type aliases, and TypeVars rarely stand alone. Link to the functions and classes that use them. - **Keep the summary line short.** Even for a complex type alias, the first line should fit comfortably in an API index table. - **Don't repeat the type annotation.** The rendered page already shows the type, so the docstring should add what the type alone can't express. ## Docstrings and Sphinx Compatibility Great Docs supports `%` directives for callouts and API-reference behaviour under every docstring parser. For example, `%versionadded 2.0` adds a version annotation, and `%warning` adds a warning callout. Numbered citations also work with every parser. Define one in a References section with `.. [1]`; Great Docs renders it as an ordered-list item. Refer to it from prose in the same docstring with `[1]_`. The reference links to the citation, and the citation links back to every reference. Nonnumeric labels such as `.. [CIT2002]` render as literal text. Set `parser: sphinx` to use other RST forms: cross-reference roles such as `` :py:exc:`ValueError` ``, `math`, `seealso`, and `todo` directives, the inline `:math:` role, literal blocks, and simple or grid tables. Under `parser: numpy` or `parser: google`, these forms render as literal text. To cite from a project bibliography with any parser, use `[@citekey]` and set the project-level `bibliography:` key. A bold pseudo-heading such as `**Examples**::` renders as plain text under every parser, including Sphinx. Use a valid section heading instead. See [API Documentation: Docstring Directives](api-documentation.qmd#docstring-directives) for the supported directives and syntax. ## Next Steps Well-structured docstrings are the foundation of a useful API reference. By choosing a consistent format, using the right sections, and embedding executable examples, you give Great Docs the raw material it needs to produce polished reference pages with minimal extra effort. - [API Documentation](api-documentation.qmd) explains how Great Docs discovers exports, classifies them, and organizes the reference - [Cross-Referencing](cross-referencing.qmd) covers `%seealso`, inline interlinks, and code autolinks in depth - [Linting](linting.qmd) checks for missing docstrings, malformed directives, and other issues - [Configuration](configuration.qmd) covers the `parser` setting and other `great-docs.yml` options ## Config & Theming # Configuration Great Docs is designed to work with zero configuration, but you can customize its behavior through a `great-docs.yml` file. This page covers the functional settings: API discovery, docstring parsing, GitHub integration, sidebar behavior, content features, and more. For visual customization (logos, gradients, banners, hero sections, dark mode), see [Theming & Appearance](theming.qmd). ::: {.version-only versions=">=0.6"} For HTML-based landing pages and demo surfaces, see [Custom Static Pages](custom-pages.qmd). That feature is configured with `custom_pages` and still falls back to `custom/` when omitted. ::: ## Configuration Location All Great Docs settings go in a `great-docs.yml` file in your project root directory. This dedicated configuration file keeps your documentation settings separate and easy to manage: ```{.yaml filename="great-docs.yml"} # Your settings here ``` To generate a starter configuration file with all options documented: ```bash great-docs config ``` ## Display Name By default, Great Docs uses your package name exactly as-is for the site title and navbar. For packages with technical names like `my_package` or `my-package`, you might want a more polished presentation name. ### Setting a Display Name Use the `display_name` field to specify how your package name appears in the site: ```{.yaml filename="great-docs.yml"} display_name: My Package ``` This will display `My Package` in the navbar instead of the actual package name. ### When to Use It Common use cases for `display_name`: - **Branding**: Convert technical names to marketing names - `weathervault` -> `WeatherVault` - `great_docs` -> `Great Docs` - **Readability**: Add spaces and capitalization - `my_awesome_lib` -> `My Awesome Lib` - `data-processor` -> `Data Processor` - **Product names**: Use your product's official name - `ml_toolkit` -> `ML Toolkit Pro` ### Default Behavior If you don't specify `display_name`: - the site title will be your actual package name - no automatic title-casing or transformation is applied - `great_docs` stays as `great_docs`, not `Great Docs` - `my-package` stays as `my-package`, not `My Package` This ensures predictable behavior and respects your package's actual naming. ## Project Type By default, Great Docs assumes a Python project. Set `project_type` to tell Great Docs about the primary language of your project: ```{.yaml filename="great-docs.yml"} project_type: rust ``` Valid values: | Value | Effect | |-------|--------| | `python` | (default) Enables Python API reference, PyPI link, and Click CLI support | | `go` | Enables Go CLI support; disables Python-specific features (PyPI link, package info page) | | `rust` | Enables Rust CLI support; disables Python-specific features (PyPI link, package info page) | For projects that combine languages (e.g., a Rust binary with Python bindings), use a list: ```{.yaml filename="great-docs.yml"} project_type: [python, rust] ``` When `python` is included in the list, Python-specific features remain active alongside the other language's CLI documentation. ## API Discovery Settings ### Excluding Items To exclude specific items from documentation during `init` and `scan`: ```{.yaml filename="great-docs.yml"} exclude: - InternalClass - helper_function ``` Note: The `exclude` setting affects what appears when running `great-docs init` (which auto-generates your `reference` config) and `great-docs scan` (which shows discovered exports). Once you have a `reference` config, you control exactly what's documented by listing items there. ### Auto-Excluded Names Great Docs automatically excludes these common internal names during discovery: | Category | Names | |----------|-------| | CLI/Entry points | `main`, `cli` | | Version/Metadata | `version`, `VERSION`, `VERSION_INFO` | | Module re-exports | `core`, `utils`, `helpers`, `constants`, `config`, `settings` | | Standard library | `PackageNotFoundError`, `typing`, `annotations`, `TYPE_CHECKING` | | Logging | `logger`, `log`, `logging` | ### Force-Including Auto-Excluded Names Some packages intentionally export names that match the auto-exclude list (e.g., a `config` or `logging` module that is part of the public API). Use `auto_include` to force specific names back into discovery: ```{.yaml filename="great-docs.yml"} auto_include: - config - logging ``` Names listed in `auto_include` are removed from the auto-exclude filter while all other auto-excluded names remain filtered as usual. ### Disabling Auto-Exclude Entirely If the auto-exclude list doesn't suit your package at all, you can bypass it completely: ```{.yaml filename="great-docs.yml"} no_auto_exclude: true ``` With this setting, no names are automatically excluded. You can still use `exclude` to manually remove specific items. ## Docstring Parser Different projects use different docstring conventions, so Great Docs automatically detects your docstring style during initialization. For a full guide on structuring docstrings (sections, executable examples, directives), see [Writing Docstrings](writing-docstrings.qmd). ### Supported Styles | Style | Description | Example | |-------|-------------|--------| | `numpy` | NumPy-style with section underlines | `Parameters\n----------` | | `google` | Google-style with indented sections | `Args:\n x: The value` | | `sphinx` | Sphinx-style with field markers | `:param x: The value` | ### Automatic Detection When you run `great-docs init`, Great Docs analyzes your package's docstrings to detect the style: - **NumPy style** is identifiable by section headers with `---` underlines (e.g., `Parameters\n----------`) - **Google style** is identifiable by section headers with colons (e.g., `Args:`, `Returns:`) - **Sphinx style** is identifiable by field markers (e.g., `:param:`, `:returns:`, `:rtype:`) The detected style is saved to `great-docs.yml` and forwarded to the API reference renderer during builds. ### Manual Configuration If auto-detection doesn't work for your project, or you want to override it: ```{.yaml filename="great-docs.yml"} parser: google # Options: numpy (default), google, sphinx ``` ### When to Change the Parser You might need to manually set the parser if: - your package has few or no docstrings (detection defaults to `numpy`) - you use a mix of styles and want to standardize on one - auto-detection chose the wrong style ### Example Docstrings ::: {.panel-tabset} #### NumPy Style ```python def my_function(x, y): """ Add two numbers together. Parameters ---------- x The first number. y The second number. Returns ------- int The sum of x and y. """ return x + y ``` #### Google Style ```python def my_function(x, y): """Add two numbers together. Args: x: The first number. y: The second number. Returns: The sum of x and y. """ return x + y ``` #### Sphinx Style ```python def my_function(x, y): """Add two numbers together. :param x: The first number. :type x: int :param y: The second number. :type y: int :returns: The sum of x and y. :rtype: int """ return x + y ``` ::: ## Interlinks Your prose can link to another project's documentation the same way it links to your own. Name each project you want to reach, and the URL its documentation is served from: ```yaml interlinks: sources: numpy: url: https://numpy.org/doc/stable/ aliases: [np] pandas: url: https://pandas.pydata.org/pandas-docs/stable/ ``` With that in place, `` [](`numpy.ndarray`) `` resolves to numpy's page for `ndarray`, exactly as a reference to one of your own objects resolves to yours. Each source takes two fields: - `url` is where the project's documentation lives. Its inventory is read from `/objects.inv`, where every project publishes one, and every link into the project is written against ``. - `aliases` lists the module names your prose uses for the project. With `aliases: [np]`, a reference to `` [](`np.ndarray`) `` resolves as `numpy.ndarray`. A `url` may name a directory on disk rather than a served site. Great Docs reads the inventory from that directory and writes links against the same path, so this reaches a project you build alongside this one only when its path on disk is also its path on the site. Where the two differ, point `url` at the published site and let the build fetch the inventory over the network. Give a `url` that means the same thing from every page. One prefix is written into the index and used from pages at every depth, so a relative `url` such as `../sibling` resolves from wherever the reading page sits and cannot suit them all. Great Docs reports a relative `url` in the build log and writes the links as configured. A source with no `url` at all is skipped, and the build log says that too. Add Python's standard library as a source in the same way: ```yaml interlinks: sources: python: url: https://docs.python.org/3/ ``` Do not add `aliases` here. The standard library has no single root. An alias rewrites a prefix to a project's root module, which works when a project puts every name under one package, as numpy and pandas do. Inventories are downloaded during the build and cached, so repeated builds do no network work, and a build that cannot reach a project falls back to the copy it already has. A project it has never reached is reported and skipped, leaving those references unlinked rather than failing the build. Your own site publishes `objects.inv` at its root, so other projects can point a source at your documentation in the same way. ### Parentheses on Function Links A function or method link displays a trailing `()`, so `[](`decode`)` renders as `decode()`. Class links never display parentheses. Set `add_function_parentheses: false` to display the bare name: ```yaml interlinks: add_function_parentheses: false ``` This setting applies to links whose targets you write, including links generated by `%seealso`. It does not affect inline-code autolinks. Their display text remains exactly as written: `decode()` keeps its parentheses, while `decode` never gains them. ## Dynamic Introspection Great Docs uses its built-in renderer to generate API reference pages. By default, it uses **dynamic introspection** (importing your package at runtime), which produces the most accurate documentation for complex packages with re-exports and aliases. ```{.yaml filename="great-docs.yml"} dynamic: true # Default: true ``` Some packages have internal attributes that cause errors during dynamic introspection. If this happens, Great Docs will **automatically retry the build with static analysis** (`dynamic: false`). You'll see a message like: ``` ⚠️ API reference build failed with dynamic introspection. Retrying with static analysis (dynamic: false)... ``` To skip the retry and always use static analysis, set it explicitly: ```{.yaml filename="great-docs.yml"} dynamic: false ``` ### When to Set `dynamic: false` - your package has cyclic aliases or complex re-export patterns - the build fails with `AttributeError` during introspection - you're documenting a compiled extension (PyO3/Rust/Cython) ## GitHub Integration Several Great Docs features require knowing your GitHub repository URL: - **GitHub widget/icon** in the navbar (with star count) - **Source links** on API reference pages - **Version badge** next to the package name (from GitHub Releases) - **Changelog** page (from GitHub Releases) ### Repository URL Detection Great Docs looks for your GitHub repository in this order: 1. **`repo:` in great-docs.yml**: explicit override, takes precedence 2. **`[project.urls]` in pyproject.toml**: looks for `Repository`, `Source`, `GitHub`, or `Homepage` keys containing a GitHub URL ```{.yaml filename="great-docs.yml"} repo: https://github.com/your-org/your-package ``` Or via pyproject.toml: ```{.toml filename="pyproject.toml"} [project.urls] Repository = "https://github.com/your-org/your-package" ``` ::: {.callout-note} ## Build Messages During `great-docs build`, you may see messages about GitHub integration: - **"No GitHub repository info available"**: no repository URL was found. Check that `repo:` is set in great-docs.yml or `[project.urls]` is configured in pyproject.toml. - **"No GitHub releases found"**: the repository was detected, but has no published GitHub Releases. The version badge feature requires at least one published release. ::: ### GitHub Link Style Choose how the GitHub link appears in the navbar: ```{.yaml filename="great-docs.yml"} # Shows stars count (default) github_style: widget # Or use a simple GitHub icon github_style: icon ``` ### Version Badge When your repository has published GitHub Releases, Great Docs automatically displays a version badge next to your package name in the navbar. The badge shows the latest release version and updates automatically on each build. This feature requires: 1. a detected GitHub repository URL (see above) 2. at least one published [GitHub Release](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases) No configuration is needed (the badge appears automatically when these conditions are met). ### Source Links Great Docs automatically creates "source" links to GitHub. Configure the branch: ```{.yaml filename="great-docs.yml"} source: branch: main # Default: auto-detected from git ``` To disable source links entirely: ```{.yaml filename="great-docs.yml"} source: enabled: false ``` Full source link configuration: ```{.yaml filename="great-docs.yml"} source: enabled: true # Enable/disable source links (default: true) branch: main # Git branch/tag to link to (default: auto-detect) path: src/package # Custom source path for monorepos (default: auto-detect) placement: usage # Where to place the link: "usage" (default) or "title" ``` ## PyPI Link The homepage metadata sidebar includes a "View on PyPI" link, auto-detected from your package name in `pyproject.toml`. You can disable it or point it to a custom package index: ```{.yaml filename="great-docs.yml"} # Disable the PyPI link entirely pypi: false ``` ```{.yaml filename="great-docs.yml"} # Use a custom package index URL (e.g., a private registry) pypi: "https://packages.example.com/simple/my-package" ``` By default (`pypi: null`) the link is generated for Python projects and omitted for everything else, so a Go-only project gets no PyPI link without your having to say so. Setting `pypi: true` forces the link on regardless of `project_type`; it is auto-generated as `https://pypi.org/project/{package_name}/`. ## Site URL Set `site_url` to the canonical URL where your documentation site is (or will be) hosted. This value is used in several places: - **Skills page** install instructions (e.g., `npx skills add `) - **`.well-known/` discovery** endpoints for agent skills - **Quarto's `website.site-url`** (canonical links, sitemaps) - **Subdirectory deployments** where the site lives at a path other than `/` (e.g., `https://internal.example.com/docs/mypackage/`) Without it, the Skills page renders literal `` placeholders instead of working install commands, and subdirectory-hosted sites will have broken asset paths. ```{.yaml filename="great-docs.yml"} # Site URL: the canonical address of the deployed documentation site. # Used for skills page install commands, .well-known/ discovery, and sitemaps. site_url: "https://your-org.github.io/your-package/" ``` Alternatively, you can set a `Documentation` entry in `pyproject.toml`: ```{.toml filename="pyproject.toml"} [project.urls] Documentation = "https://your-org.github.io/your-package/" ``` Great Docs checks these sources in order: 1. `site_url` in `great-docs.yml` 2. `Documentation` URL in `[project.urls]` (pyproject.toml) 3. `website.site-url` already present in `_quarto.yml` If none are found, the build emits a warning: ``` ⚠ No site URL found — skills page will show placeholders. Set site_url in great-docs.yml or add a Documentation URL to [project.urls] in pyproject.toml. ``` ::: {.callout-tip} Set `site_url` even before your site is deployed. Once the site goes live at that address, all generated install commands will already be correct. ::: ## Sidebar Filter The API reference sidebar includes a search filter for large APIs. Configure it: ```{.yaml filename="great-docs.yml"} sidebar_filter: enabled: true # Enable/disable filter (default: true) min_items: 20 # Minimum items before showing filter (default: 20) ``` ## Method Page Splitting Control whether class methods get their own pages or stay inline on the class page: ```{.yaml filename="great-docs.yml"} inline_methods: 5 # Split above 5 methods (default) inline_methods: 10 # Split above 10 methods inline_methods: true # Always inline (never split) inline_methods: false # Always split to separate pages ``` See [API Documentation: Smart Method Handling](06-api-documentation.qmd#smart-method-handling) for detailed examples. ## Markdown Pages Every HTML page gets a companion `.md` file generated automatically. A small widget appears in the top-right corner of each page allowing visitors to **copy** the page content as Markdown or **view** the raw `.md` file. This is enabled by default: ```{.yaml filename="great-docs.yml"} markdown_pages: true # Enable/disable (default: true) ``` To disable both the `.md` generation and the copy/view widget: ```{.yaml filename="great-docs.yml"} markdown_pages: false ``` To generate `.md` pages but hide the widget: ```{.yaml filename="great-docs.yml"} markdown_pages: widget: false ``` ## Theming & Visual Options Great Docs offers extensive visual customization: announcement banners, animated gradient presets for the navbar and content area, solid navbar colors, custom head injections, logos with light/dark variants, automatic favicon generation, and hero sections on the landing page. These options are covered in their own dedicated page. See [Theming & Appearance](theming.qmd) for full details on all visual customization options. ## HTML Math Renderer Great Docs forwards `site.html-math-method` to Quarto's HTML configuration. It defaults to KaTeX, which renders mathematical notation without a browser-side MathJax dependency: ```{.yaml filename="great-docs.yml"} site: html-math-method: katex ``` To use MathJax instead, set the method explicitly: ```{.yaml filename="great-docs.yml"} site: html-math-method: mathjax ``` Other Quarto-supported HTML math methods can also be selected with this setting. Configure it in `great-docs.yml`; Great Docs writes the corresponding value into its generated `_quarto.yml`. ## User Guide Directory By default, Great Docs looks for a `user_guide/` directory in your project root. To use a different location: ```{.yaml filename="great-docs.yml"} user_guide: docs/guides ``` The path is relative to the project root. If both the config option and a `user_guide/` directory exist, the config option takes precedence. See [User Guides](user-guides.qmd) for details on writing and organizing User Guide content. ## Homepage Mode By default, Great Docs generates a separate homepage from your project's README (or `index.qmd`/`index.md`), with a "User Guide" link in the top navbar. Many Python documentation sites use a different layout where the first User Guide page _is_ the landing page. The `homepage` setting controls which layout to use: ```{.yaml filename="great-docs.yml"} homepage: user_guide ``` ### Available Modes | Value | Behaviour | |-------|-----------| | `index` (default) | Separate homepage from README / `index.qmd`. "User Guide" appears as a navbar link. | | `user_guide` | First User Guide page becomes the landing page. Left sidebar shows the UG table of contents. Right sidebar shows project metadata. No separate "User Guide" navbar link. | ### How `user_guide` Mode Works When `homepage: user_guide` is set: 1. **Landing page**: the first User Guide page (determined by filename sort order or explicit config) becomes `index.qmd` at the site root. Its content is preserved verbatim, with the project metadata sidebar (links, license, authors, etc.) appended in the right margin. 2. **Left sidebar**: the User Guide table of contents appears in the left sidebar on every UG page, including the homepage. The first entry links to the site root. 3. **Navbar**: the "User Guide" link is omitted from the top navbar since clicking the site title already takes you to the User Guide landing page. All other navbar items (Reference, custom sections, etc.) are unchanged. 4. **README**: your `README.md` is not used for the homepage. It still serves its purpose on PyPI and GitHub. ### Example A project with this structure: ``` my_package/ ├── user_guide/ │ ├── 00-getting-started.qmd # ← becomes the homepage │ ├── 01-installation.qmd │ └── 02-configuration.qmd ├── great-docs.yml └── pyproject.toml ``` And this config: ```{.yaml filename="great-docs.yml"} homepage: user_guide ``` Will produce a site where: - the homepage shows the "Getting Started" content with a project metadata sidebar - the left sidebar lists all three User Guide pages - the navbar has no "User Guide" link (the site title links home) ### Fallback Behavior If `homepage: user_guide` is set but no User Guide pages exist, Great Docs will warn and fall back to the default `index` mode (generating a homepage from your README). ## CLI Documentation Great Docs can generate CLI reference pages for Python, Go, and Rust projects. Each ecosystem has its own configuration key. ### Python CLI (Click) Enable automatic CLI documentation for Click-based CLIs: ```{.yaml filename="great-docs.yml"} cli: enabled: true ``` With optional explicit configuration: ```{.yaml filename="great-docs.yml"} cli: enabled: true module: my_package.cli # Module containing Click commands name: cli # Name of the Click command object ``` ### Go CLI (Cobra) For Go projects using Cobra, urfave/cli, or similar frameworks. Requires `go` on your `PATH`: ```{.yaml filename="great-docs.yml"} project_type: go go_cli: enabled: true ``` ### Rust CLI (clap) For Rust projects using clap, structopt, argh, or similar frameworks. Requires `cargo` on your `PATH`: ```{.yaml filename="great-docs.yml"} project_type: rust rust_cli: enabled: true ``` See [CLI Documentation](cli-documentation.qmd) for full details on each ecosystem, including project detection, help-text formatting tips, and troubleshooting. ## Changelog Great Docs auto-generates a Changelog page from your GitHub Releases. It's enabled by default so if your `pyproject.toml` has a GitHub repository URL, a changelog page will appear automatically. To customize: ```{.yaml filename="great-docs.yml"} changelog: enabled: true # Enable/disable changelog (default: true) max_releases: 50 # Max releases to include (default: 50) ``` To disable it entirely: ```{.yaml filename="great-docs.yml"} changelog: enabled: false ``` See [Changelog](changelog.qmd) for full details on authentication, CLI usage, and edge cases. ## Custom Sections Add custom page groups (examples, tutorials, blog, etc.) to your site. Each section gets a navbar link and an auto-generated index page: ```{.yaml filename="great-docs.yml"} sections: - title: Examples # Navbar link text dir: examples # Source directory navbar_after: User Guide # Position in navbar (optional) - title: Tutorials dir: tutorials - title: Blog # Blog with Quarto's listing directive dir: blog type: blog # "blog" for listing page; omit for card grid ``` Default sections get a card-grid index and sidebar navigation. Blog-type sections use Quarto's native `listing:` directive. Posts are sorted by date and displayed with author, categories, and descriptions. See [Custom Sections](custom-sections.qmd) and [Blog](blog.qmd) for full details. ## Navbar Order By default, navbar items appear in the order they are added during the build (Reference, Changelog, User Guide, custom sections). Use `navbar_order` to set an explicit ordering: ```{.yaml filename="great-docs.yml"} navbar_order: - User Guide - Reference - Demos - Changelog ``` Items are matched by their display text. Any navbar items not listed are appended at the end in their original order. This is useful when you want a specific item (like the User Guide) to appear first. ## Reference Section Order When your site includes multiple reference sections (Python API, CLI, MCP Server), the default ordering of sections is: Python API, CLI, MCP Server. You may prefer a different order and we can use `ref_section_order` to change this. For example, a CLI-first tool might want this particular ordering of reference pages: ```{.yaml filename="great-docs.yml"} ref_section_order: - cli - api - mcp ``` Valid values are `api`, `cli`, and `mcp`. Sections listed here that don't exist in your project are silently ignored, so it's safe to include `mcp` even if your package has no MCP server. Sections not listed are appended at the end in the default order. The navbar "Reference" link will point to whichever section is first. ## Author Information Customize author display in the landing page sidebar: ```{.yaml filename="great-docs.yml"} authors: - name: Your Name email: you@example.com role: Lead Developer affiliation: Organization github: yourusername homepage: https://yoursite.com orcid: 0000-0002-1234-5678 ``` Multiple authors are supported: ```{.yaml filename="great-docs.yml"} authors: - name: First Author role: Lead Developer github: firstauthor - name: Second Author role: Contributor github: secondauthor ``` ### Supported Author Fields | Field | Description | |-------|-------------| | `name` | **Required.** Author's full name | | `email` | Email address (clickable icon) | | `role` | Role in the project (e.g., "Lead Developer") | | `affiliation` | Organization or institution | | `github` | GitHub username (clickable icon) | | `homepage` | Personal website URL (clickable icon) | | `orcid` | ORCID identifier (clickable icon) | ## API Reference Structure Control how your API documentation is organized with the `reference` config: ```{.yaml filename="great-docs.yml"} reference: - title: Core Classes desc: Main classes for working with the package contents: - name: MyClass members: false # Don't document methods here - SimpleClass # Methods documented inline (default) - title: Utility Functions desc: Helper functions for common tasks contents: - helper_func - another_func ``` If no `reference` config is provided, Great Docs auto-generates sections from discovered exports. ### Page Title and Description You can set a custom heading and introductory paragraph for the API reference index page: ```{.yaml filename="great-docs.yml"} reference: title: "API Docs" desc: >- Complete reference for all public classes and functions available in this package. ``` The `title` replaces the default "Reference" text in both the page heading and the navbar. The `desc` appears as a paragraph below the heading, before the section listings. If omitted, the heading defaults to "Reference" with no introductory text. These keys can be combined with explicit `sections` for full control over both the page heading and the section structure: ```{.yaml filename="great-docs.yml"} reference: title: "API Docs" desc: "All public symbols documented below." sections: - title: Core contents: - MyClass ``` ## Agent Skills (skill.md) Great Docs supports the [Agent Skills](https://agentskills.io/) open standard, which gives AI coding agents structured context about your package so they can write better code when using it. During the build, a `SKILL.md` is generated (or copied from your hand-written version) and served at `.well-known/agent-skills//SKILL.md` for discovery. Users can then install it with `npx skills add` or `great-docs skill install`. ```{.yaml filename="great-docs.yml"} skill: enabled: true # Set to false to disable skill.md entirely file: null # Path to a SKILL.md (overrides curated and generated) well_known: true # Serve at /.well-known/ discovery endpoints gotchas: [] # Gotcha strings (for auto-generated skill only) best_practices: [] # Best-practice strings (for auto-generated skill only) decision_table: [] # Rows: [{need: "...", use: "..."}] extra_body: null # Path to extra Markdown to append (auto-generated only) skills: [] # Multi-skill mode: [{name: "...", file: "..."}] ``` For the full guide — including how to write a skill, the resolution order, multi-skill mode, the `great-docs skill` CLI, freshness checking, and the Python API — see [Agent Skills](38-agent-skills.qmd). ## Page Metadata [version-badge new 0.2] Display page creation and modification dates at the bottom of documentation pages, giving readers a sense of content freshness. ### Enabling Page Metadata ```{.yaml filename="great-docs.yml"} site: show_dates: true ``` When enabled, pages display timestamps in a compact horizontal format: ``` ✏️ 4 months ago 📄 2 years ago ``` - **✏️ (pencil icon)**: Last modification date - **📄 (file icon)**: Creation date Hovering over a timestamp shows the full date (e.g., "March 24, 2026"). ### How Dates Are Determined Great Docs determines dates from Git history when available: | Date Type | Source | |-----------|--------| | **Created** | Date of the first Git commit that added the file | | **Modified** | Date of the most recent Git commit that changed the file | If Git history is unavailable (e.g., shallow clones in CI), the file system timestamps are used as a fallback. ### Overriding Dates in Frontmatter You can override Git-derived dates using frontmatter, which is useful when: - you want to set a specific "last updated" date - git history is unavailable or incorrect (shallow clones, file renames) - you're migrating content from another system ```{.yaml filename="guide.qmd"} --- title: "Getting Started" last_update: date: "2026-01-15" author: "Jane Developer" date_created: "2024-06-01" --- ``` The `last_update` field follows this format: - `date`: ISO date string (with or without time/timezone) - `author`: optional author name override Frontmatter values take precedence over Git history. If only `last_update.date` is provided, the creation date still comes from Git. ### CI/CD Considerations In CI environments like GitHub Actions, the default checkout only fetches the latest commit (shallow clone). This means all pages would show identical timestamps. The `great-docs setup-github-pages` command generates a workflow with full Git history enabled: ```yaml - uses: actions/checkout@v6 with: fetch-depth: 0 # Full history for accurate timestamps ``` For large repositories, you can use sparse checkout to speed up builds while still getting full history for documentation files: ```yaml - uses: actions/checkout@v6 with: fetch-depth: 0 sparse-checkout: | user_guide recipes ``` ### Auto-Generated Pages Pages that Great Docs generates automatically (API reference, changelog, CLI reference) show a "Refreshed" timestamp instead: ``` 🔄 Refreshed 2 hours ago ``` This indicates when the page content was last regenerated during a build, not when source code was edited. ### Which Pages Show Metadata | Page Type | Shows Metadata | |-----------|----------------| | User Guide pages | ✓ Yes | | Recipes | ✓ Yes | | Roadmap, Contributing, etc. | ✓ Yes | | API Reference pages | ✓ Yes (as "Refreshed") | | Changelog | ✓ Yes (as "Refreshed") | | Homepage | ✗ No | ### Configuration Options ```{.yaml filename="great-docs.yml"} site: show_dates: true # Enable/disable page metadata (default: false) show_author: true # Show author attribution when enabled (default: true) show_security: true # Show security policy page from SECURITY.md (default: true) ``` ### Author Attribution When `show_author` is enabled and a page has author information in its frontmatter, author avatars appear alongside the timestamps: ``` ✏️ 4 months ago 📄 2 years ago — ○ ○ ``` To add author information to a page, include it in the YAML frontmatter: ```{.yaml filename="guide.qmd"} --- title: "Getting Started" author: name: "Jane Developer" image: "https://github.com/janedev.png" url: "https://github.com/janedev" --- ``` Great Docs automatically looks up author details from the `authors` list in `great-docs.yml`, so you can often just specify the name: ```{.yaml filename="guide.qmd"} --- title: "Getting Started" author: "Jane Developer" --- ``` If the author is listed in `great-docs.yml` with a `github` field, their GitHub avatar is used automatically. ## Complete Example Here's a comprehensive configuration demonstrating all available options: ```{.yaml filename="great-docs.yml"} # Display Name display_name: My Package # Custom display name for navbar/title # Docstring Parser parser: numpy # Auto-detected: numpy, google, or sphinx # API Discovery exclude: - _InternalClass # GitHub Integration repo: https://github.com/your-org/your-package # Override auto-detect github_style: widget # Site URL — canonical address of the deployed documentation site. # Used for skills page install commands, .well-known/ discovery, and sitemaps. # site_url: "https://your-org.github.io/your-package/" # Source Links source: enabled: true branch: main placement: usage # PyPI Link pypi: null # null (default) links for Python projects; true forces, false disables, or a URL string # Sidebar sidebar_filter: enabled: true min_items: 15 # Site Settings site: show_dates: true # Show page timestamps show_author: true # Show author avatars # Markdown Pages markdown_pages: true # User Guide Directory # user_guide: docs/guides # Homepage Mode # homepage: user_guide # First UG page becomes the landing page # CLI Documentation cli: enabled: true # Changelog (GitHub Releases) changelog: enabled: true max_releases: 50 # Custom Sections sections: - title: Examples dir: examples - title: Tutorials dir: tutorials navbar_after: Examples - title: Blog dir: blog type: blog # Navbar Order navbar_order: - User Guide - Reference - Examples - Tutorials - Changelog # Reference Section Order (within the Reference area) ref_section_order: - cli - api - mcp # API Reference Structure reference: title: "API Reference" desc: "Complete reference for the library's public API." sections: - title: Core Classes desc: Main classes for the library contents: - name: MainClass members: false - HelperClass - title: MainClass Methods desc: Methods for the MainClass contents: - MainClass.process - MainClass.validate - title: Utility Functions desc: Helper functions contents: - utility_func - helper_func # Authors authors: - name: Jane Developer email: jane@example.com role: Lead Developer github: janedev orcid: 0000-0001-2345-6789 - name: John Contributor role: Contributor github: johncontrib # Agent Skills (skill.md) skill: gotchas: - "Always call init() before using other functions" best_practices: - "Use context managers for resource cleanup" decision_table: - need: "Create a widget" use: "Widget()" - need: "Process data" use: "MainClass.process()" ``` You don't need all of these settings. Start with just the options you need and add more as your project grows. The defaults work well for most packages, so you may find that a minimal configuration (or none at all) is sufficient. ## Generating a Configuration File To create a starter `great-docs.yml` with all options documented: ```bash great-docs config ``` This creates a file with all available options as comments, making it easy to enable the features you need. ## Quarto Configuration Great Docs generates and maintains a `_quarto.yml` file in the `great-docs/` output directory. This is an internal file that controls how Quarto renders your site, including navigation, theming, and the API reference configuration. It is regenerated on every `great-docs build`. **Should you edit it?** No. Any manual edits will be overwritten on the next build. All customization should go through `great-docs.yml`, which is the single source of truth for your documentation configuration. **Should you commit it?** No. The entire `great-docs/` output directory is ephemeral and should be gitignored (which `great-docs init` offers to set up for you). ## Next Steps With `great-docs.yml` you control everything from API discovery and docstring parsing to sidebar layout and GitHub integration. Most projects only need a handful of settings, but the full range is here when you need it. - [Theming & Appearance](theming.qmd) covers logos, gradients, banners, dark mode, hero sections, and other visual options - [API Documentation](api-documentation.qmd) explains how API discovery and organization works - [CLI Documentation](cli-documentation.qmd) covers Click CLI documentation - [Cross-Referencing](cross-referencing.qmd) covers the Great Docs Linking System (GDLS) ## Site Content # API Documentation Most Python packages need an API reference, but writing one by hand is tedious and keeping it in sync with code changes is even harder. Great Docs takes care of both: it automatically discovers your package's public API through static analysis, classifies every export by type, and generates a complete, styled reference section. You can ship a polished API reference without writing a single docstring page yourself, and as your code evolves the documentation stays up to date. This page explains how discovery works, what gets documented, and how to customize the result. ## How Discovery Works When you run `great-docs init` or `great-docs build`, Great Docs: 1. **Finds your package**: looks in standard locations (`src/`, `python/`, project root) 2. **Uses static analysis**: analyzes your code with `griffe` without importing it 3. **Discovers public names**: finds all non-private names (not starting with `_`) 4. **Introspects submodules**: drills into exported modules to discover their classes, functions, and constants 5. **Categorizes items**: classifies every export into one of 13 object types 6. **Generates configuration**: creates API reference sections in `_quarto.yml` The entire pipeline runs in seconds and produces a fully structured reference. You don't need to maintain a manifest of your public symbols; Great Docs figures it out from your code. To preview what Great Docs will find without generating any files, run `great-docs scan` in your project directory. This lists every discovered export grouped by type, and marks which items are already included in your `reference` config. Add `--verbose` to see individual methods on each class. ### Static Analysis Benefits Great Docs uses static analysis rather than importing your package. This means: - **No side effects**: your code isn't executed during discovery - **No import errors**: missing dependencies won't break documentation - **Faster discovery**: no need to set up a complete environment - **Safer**: works even if your package has complex initialization Because discovery never executes your code, you can generate documentation in CI environments, containers, or any machine where your package's runtime dependencies aren't installed. ## What Gets Documented By default, Great Docs documents everything it discovers in your package's public API. These discovered items are the package's *documentable objects*: any public class, function, constant, or type alias that Great Docs can identify through static analysis. Each documentable object is classified into one of the following 13 object types: **Class-like types** - **Classes**: regular public classes with their methods - **Dataclasses**: classes decorated with `@dataclass` - **Abstract Classes**: classes inheriting from `ABC` or using `ABCMeta` - **Protocols**: structural typing protocols (`typing.Protocol` subclasses) - **Enumerations**: `Enum` subclasses - **Exceptions**: `Exception` and `BaseException` subclasses - **Named Tuples**: `NamedTuple` definitions - **Typed Dicts**: `TypedDict` definitions **Function-like types** - **Functions**: synchronous public functions - **Async Functions**: functions defined with `async def` **Data types** - **Constants**: module-level constants and data - **Type Aliases**: type alias definitions (including `TypeVar`) **Other** - **Other**: anything that doesn't fit the above categories Each type is placed into its own section in the generated reference and receives a distinct visual badge (see [Type Labels](#type-labels) below). ### Exclusion Rules Not everything in your package's namespace belongs in the API reference. Internal wiring like CLI entry points, logging setup, and utility modules are implementation details that would clutter the documentation without helping users. Great Docs automatically excludes a set of common names that almost never represent public API: ```python # These are auto-excluded: main # CLI entry points cli version # Version metadata VERSION core # Internal modules utils helpers logger # Logging log ``` To exclude additional names from `init` and `scan`, add them to the `exclude` list in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} exclude: - InternalHelper - deprecated_function ``` Once you have a `reference` config in `great-docs.yml`, you control exactly what gets documented by listing items there. The `exclude` setting only affects what `great-docs init` discovers when generating your initial config. Between the built-in exclusions and the explicit list, you can keep the reference focused on the symbols your users actually need. ## Smart Method Handling Large classes with many methods can create overwhelming documentation. Great Docs handles this intelligently by separating methods into their own pages when a class exceeds a threshold. ### Default Behavior By default, classes with **more than 5 methods** are split: the class itself gets one page, and each method gets its own page in a companion "Methods" section. Classes with 5 or fewer methods keep their methods inline on the class page. ### Configuring the Threshold You can control this behavior with the `inline_methods` setting in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} # Keep the default (split above 5 methods) inline_methods: 5 # Custom threshold: split above 10 methods inline_methods: 10 # Always inline: never split methods to separate pages inline_methods: true # Always split: every class gets separate method pages inline_methods: false ``` | Value | Behavior | | --- | --- | | `true` | Methods always stay inline on the class page, regardless of count | | `false` | Methods always get their own pages (even for classes with 1–2 methods) | | Integer `N` | Methods stay inline for classes with ≤N methods; classes with >N get split (default: `5`) | The examples below show what Great Docs generates in `_quarto.yml`. This file is regenerated on every build, so don't edit it by hand. Use `inline_methods` in `great-docs.yml` to control the behavior and let the build produce the right output. ### Small Classes (≤ threshold) When a class has fewer methods than the threshold, all of its methods appear directly on the class page. Readers see everything in one place without navigating between pages. In the generated `_quarto.yml`, the class is listed as a simple entry: ```{.yaml filename="_quarto.yml"} sections: - title: Classes contents: - MySmallClass # Methods shown inline ``` This keeps the sidebar compact and works well for classes where the full method list fits comfortably on a single page. ### Large Classes (> threshold) When a class exceeds the threshold, Great Docs automatically splits it in the generated `_quarto.yml`. The methods are pulled out into a dedicated "Methods" section with individual pages, and the class entry suppresses inline method documentation so readers aren't overwhelmed: ```{.yaml filename="_quarto.yml"} sections: - title: Classes contents: - name: MyLargeClass members: [] # Suppresses inline methods - title: MyLargeClass Methods desc: Methods for the MyLargeClass class contents: - MyLargeClass.method_one - MyLargeClass.method_two # ... all methods listed individually ``` Each method gets its own sidebar entry and its own page, making it easier to link to specific methods and to find them through search. ### When to Adjust The right setting depends on how users interact with your API documentation: - set `inline_methods: true` if your classes have many methods but users typically need to see them all at once (e.g., configuration objects, builder patterns). - set `inline_methods: false` if every method deserves its own discoverable page (e.g., a large framework API where methods are searched individually). - set a higher number (e.g., `10` or `15`) if your classes tend to have moderate method counts and the default of `5` splits too aggressively. When in doubt, start with the default and adjust once you see how your rendered documentation feels to navigate. ## Callable Signatures The `callable_signatures` block in `great-docs.yml` controls how a callable's signature is written to the page. It applies to functions, methods, and classes; attributes and type aliases render the same way whatever it says. ```{.yaml filename="great-docs.yml"} callable_signatures: style: highlighted # a highlighted code block (default) wrap: per_parameter # one parameter per line (default) ``` | Setting | Value | Behaviour | | --- | --- | --- | | `style` | `highlighted` | The signature is a fenced Python code block, highlighted by Quarto (default) | | `style` | `plain` | The signature is inline markup carrying the callable's name and its parameters | | `wrap` | `per_parameter` | Every parameter takes its own line whenever there is more than one (default) | | `wrap` | `width` | The signature stays on one line until it exceeds 78 characters | ## API Organization The auto-generated reference is organized into sections by object type. This works well out of the box, but as your package grows you may want to group exports by domain rather than by type. Great Docs gives you full control over the section structure through the `reference` config in `great-docs.yml`, from simple title changes to completely custom groupings. ### Default Sections Great Docs creates sections automatically based on what it discovers. Only non-empty sections appear, so if your package has no enumerations or protocols, those sections are simply omitted. Here is the full set of possible sections: | Section | Description | | --- | --- | | **Classes** | Regular public classes | | **Dataclasses** | Data-holding classes | | **Abstract Classes** | Abstract base classes | | **Protocols** | Structural typing protocols | | **Enumerations** | Enum types | | **Exceptions** | Exception classes | | **Named Tuples** | NamedTuple types | | **Typed Dicts** | TypedDict types | | **Functions** | Synchronous functions | | **Async Functions** | Asynchronous functions (`async def`) | | **Constants** | Module-level constants and data | | **Type Aliases** | Type alias definitions | | **Other** | Additional exports | | **[ClassName] Methods** | Created for classes exceeding the `inline_methods` threshold | A typical package might only produce a few of these (e.g., Classes, Functions, and Constants). The section structure is automatically tailored to your package's contents. You're encouraged to customize the organization using the `reference` config in `great-docs.yml` to create sections that better reflect your package's domain. ### Custom Organization with `reference` Config The default sections group exports by type, but your users probably think about your API in terms of what it does, not what kind of Python object each export is. A data validation library might group things into "Schema Definition", "Validators", and "Error Handling" rather than "Classes", "Functions", and "Exceptions". Custom organization lets you tell a story with your API reference, guiding readers to the right part of the documentation based on what they are trying to accomplish. You can explicitly control the structure in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} reference: - title: User Management desc: Functions for managing users contents: - create_user - delete_user - update_user - title: Authentication desc: Functions for authentication contents: - login - logout ``` Items appear in the order listed within each section. This explicit configuration gives you complete control over how your API documentation is organized. One thing to watch out for: the names in `contents` must match your package's actual public API exactly. A misspelled name, a name that was renamed or removed, or a name that appears in the `exclude` list will silently produce a missing or empty reference page. If a page doesn't render as expected after a build, check that the name in your `reference` config matches what your package exports. ### Custom Title and Description You can customize the heading and introductory text of the API reference page using the `title` and `desc` keys: ```{.yaml filename="great-docs.yml"} reference: title: "API Docs" desc: > Welcome to the API documentation. This reference covers all public classes and functions available in the package. ``` When set, the `title` replaces the default "Reference" heading on the API index page and in the navigation bar. The `desc` text appears as a paragraph immediately below the heading, providing context before the section listings. Without explicit `sections`, sections are auto-generated from your package's public API. You can also combine `title`/`desc` with explicit section ordering using a `sections` key: ```{.yaml filename="great-docs.yml"} reference: title: "API Reference" desc: "Complete reference for all public symbols." sections: - title: Core desc: Primary classes contents: - MyClass - Config - title: Utilities desc: Helper functions contents: - format_output - parse_input ``` If neither `title` nor `desc` is set, the page heading defaults to "Reference" with no introductory text. ### Controlling Method Documentation By default, class methods are documented inline on the class page. To exclude methods from documentation (for example, if you want to document them separately elsewhere), use `members: false`: ```{.yaml filename="great-docs.yml"} reference: - title: Core Classes desc: Main classes for the package contents: - name: MyClass members: false # Don't document methods here - SimpleClass # Methods documented inline (default) - title: MyClass Methods desc: Methods for the MyClass class contents: - MyClass.method1 - MyClass.method2 ``` When `members: false` is set, only the class itself is documented. You can then place individual methods wherever you want in your reference structure. ### Documenting Inherited Methods By default, only methods defined directly on a class are documented. Inherited methods are excluded unless you opt in. This keeps reference pages focused and avoids duplicating parent class methods on every child page (especially important in deep class hierarchies where it would add significant clutter). If your class hierarchy uses inheritance and you want child classes to show inherited methods, there are two approaches. **Explicit member list.** List the methods you want documented (including inherited ones) in the `members` key: ```{.yaml filename="great-docs.yml"} reference: - title: API contents: - BaseProcessor - name: AdvancedProcessor members: - process # own method - validate # inherited from BaseProcessor - reset # inherited from BaseProcessor ``` This gives you full control over which inherited methods appear and in what order. **Auto-include inherited methods.** Use `include_inherited: true` to automatically document all inherited methods without listing them explicitly: ```{.yaml filename="great-docs.yml"} reference: - title: Shapes contents: - Shape - name: Circle include_inherited: true # includes area(), perimeter(), describe() from Shape ``` With this flag, the child class page will show its own methods plus all public methods inherited from parent classes. ::: {.callout-tip} You can combine both approaches. Use `include_inherited: true` for convenience, or provide an explicit `members` list when you want to cherry-pick specific inherited methods or control ordering. ::: ### Excluding Items with `exclude` To exclude items from documentation, add them to the `exclude` list in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} exclude: - internal_helper - deprecated_function ``` Items in the exclude list won't appear when running `great-docs init` or `great-docs scan`, and won't be documented even if discovered. ## Source Code Links Great Docs automatically adds "source" links to each documented item, pointing to the exact line numbers on GitHub. ### How It Works 1. Great Docs detects your GitHub repository from `pyproject.toml` or `.git` 2. For each documented item, it finds the source file and line numbers 3. Links are generated pointing to `github.com/owner/repo/blob/branch/file#L1-L10` Source links let readers jump straight from the documentation to the implementation, which is especially valuable during code reviews and debugging. ### Configuration ```{.yaml filename="great-docs.yml"} source: # Use a specific branch (default: auto-detected) branch: main # Disable source links enabled: false ``` ## Submodule Introspection When your package exports submodules (e.g., `dateutil.parser`, `dateutil.tz`), Great Docs automatically drills into each module to discover its public classes, functions, and constants. This means you can list a module name in your `reference` config and Great Docs will expand it into all of its individual members. For example, if your package exports a `parser` submodule containing a `parse()` function, a `parser` class, and a `ParserError` exception, writing: ```{.yaml filename="great-docs.yml"} reference: - title: Parser desc: Date string parsing contents: - parser ``` will automatically expand to document `parser.parse`, `parser.parser`, `parser.ParserError`, and all other public members of the `parser` module. Each member is classified into the correct object type and receives appropriate visual treatment. This is particularly useful for packages like `dateutil` that organize their API into topical submodules rather than exporting everything from the top-level `__init__.py`. ## Cross-Referencing Great Docs includes a linking system (GDLS) that automatically creates clickable navigation between your API reference pages. It supports `%seealso` directives in docstrings, inline interlinks using Markdown syntax, and automatic code-to-link conversion for inline code that matches documented symbols. See [Cross-Referencing](cross-referencing.qmd) for the full guide to all linking features. ## Docstring Directives Great Docs directives add document structure and control API-reference behavior. Write directives as `%` in NumPy-, Google-, or Sphinx-style docstrings. Great Docs supports two kinds of directives: - `%nodoc` excludes an object, and `%seealso` adds cross-references. - Callout directives add version annotations and admonitions. ### Callout Directives Short callouts can put their content on the directive line: ```python %warning This operation modifies the input. %versionadded 2.0 %deprecated 3.0 Use `new_function` instead. ``` For longer content, indent the body below the directive: ```python %versionchanged 2.1 Now returns a copy. %warning This operation modifies the input. Make a copy first if mutation is undesirable. ``` An inline body may also continue on indented lines. Great Docs preserves Markdown and paragraph breaks within the body. Version directives use the first argument as the version and the remaining content as the optional description. | Directive | Appearance | | --- | --- | | `%versionadded 2.0` | Quarto `note` callout titled "Added in version 2.0" | | `%versionchanged 3.1` | Quarto `note` callout titled "Changed in version 3.1" | | `%deprecated 2.6` | Quarto `warning` callout titled "Deprecated since version 2.6" | | `%note ...` | Quarto `note` callout | | `%warning ...` | Quarto `warning` callout | | `%caution ...` | Quarto `caution` callout | | `%danger ...` | Quarto `important` callout | | `%important ...` | Quarto `important` callout | | `%tip ...` | Quarto `tip` callout | | `%hint ...` | Quarto `tip` callout | ### Sphinx Compatibility With `parser: sphinx`, Great Docs also recognises these equivalent reStructuredText directives: ```rst .. versionadded:: 2.0 .. versionchanged:: 2.1 Now returns a copy. .. warning:: This operation modifies the input. ``` Both forms produce the same callouts. Use `parser: sphinx` when docstrings must build with both Great Docs and Sphinx. Otherwise, use Great Docs `%` directives. ### Sphinx Cross-Reference Roles With `parser: sphinx`, Great Docs renders Sphinx roles such as `:py:class:`, `:func:`, and `:exc:` as inline code. For example, `` :py:exc:`ValueError` `` renders as `ValueError`, and `` :py:class:`datetime.datetime` `` renders as `datetime.datetime`. Function and method roles gain trailing parentheses: `` :func:`my_function` `` renders as `my_function()`, and `` :meth:`MyClass.run` `` renders as `MyClass.run()`. With `parser: numpy` or `parser: google`, these roles render as literal text. To link to another symbol with any parser, use `%seealso` or an inline interlink. See [Cross-Referencing](cross-referencing.qmd). ## Visual Enhancements Great Docs applies consistent styling to your API documentation, making it easier to scan and understand at a glance. ### Type Labels {#type-labels} Each documented item displays a colored badge indicating its object type: | Type | Color | Used For | | --- | --- | --- | | **class** | Indigo | Classes, dataclasses, protocols, ABCs, named tuples, typed dicts | | **exception** | Red | Exception classes | | **enum** | Indigo | Enum types | | **function** | Violet | Functions (shown with trailing `()`) | | **method** | Cyan | Class methods (shown as `Class.method()`) | | **constant** | Amber | Module-level constants | | **type alias** | Green | Type alias definitions | | **other** | Gray | Uncategorized exports | Great Docs uses a metadata file (`_object_types.json`) generated during the build to determine the correct badge for each item. This ensures accurate classification even for edge cases like constants that start with an uppercase letter or functions named after classes. ### Code Styling The documentation applies careful typography to code elements throughout. Function signatures use monospace fonts for clarity, and type annotations are formatted to be easily readable. Parameter lists have improved spacing that makes long signatures scannable. Code blocks benefit from enhanced syntax highlighting that matches the overall site theme. Together, these refinements make technical content more approachable. ### Responsive Design API documentation needs to work on devices of all sizes, from large desktop monitors to phones. Great Docs optimizes the layout for each screen size with mobile-friendly navigation that adapts to touch interactions. The sidebar becomes collapsible on smaller screens, and typography scales appropriately to remain readable. Whether you're at your desk or reviewing docs on your phone during a commute, the experience remains consistent. ## Sidebar Filter For packages with many exports, navigating the sidebar can become cumbersome. Great Docs addresses this with a built-in search filter that appears automatically when your API has 20 or more items. The filter provides instant results as you type, narrowing down the sidebar to show only matching items. A count indicator shows how many items match your search out of the total. The section structure is preserved during filtering, so you maintain context about where items live in your API hierarchy. You can customize when the filter appears in your `great-docs.yml`: ```{.yaml filename="great-docs.yml"} sidebar_filter: enabled: true min_items: 15 # Show filter with 15+ items ``` Set `enabled: false` to disable it entirely, or adjust `min_items` to change the threshold. ## Refreshing API Documentation When your package's API changes, rebuild with: ```{.bash filename="Terminal"} great-docs build ``` This automatically re-discovers exports and updates the configuration. For faster builds when only documentation content changed (not API): ```{.bash filename="Terminal"} great-docs build --no-refresh ``` Either way, the rendered output reflects the current state of your package. You never need to manually edit generated reference pages. ## Migrating from quartodoc If you have an existing site built with [quartodoc](https://machow.github.io/quartodoc/), switching to Great Docs is straightforward. The two tools share similar ideas (sections, contents lists, Quarto rendering) but differ in where configuration lives and how much you need to specify by hand. ### Key Differences | | **quartodoc** | **Great Docs** | | --- | --- | --- | | Config file | `_quarto.yml` (under a `quartodoc:` key) | `great-docs.yml` | | API discovery | Manual: you list every object | Automatic: discovers your public API from source | | Build command | `quartodoc build` then `quarto render` | `great-docs build` (handles both steps) | | Preview command | `quarto preview` | `great-docs preview` | | Generated output | `reference/` directory with `.qmd` files and `_sidebar.yml` | `great-docs/` directory (ephemeral, gitignored) | | Sidebar | You include a generated `_sidebar.yml` via `metadata-files` | Managed automatically | ### Step-by-Step Migration 1. **Install Great Docs** and run `great-docs init` in your project root. This auto-discovers your package and creates `great-docs.yml`. 2. **Translate your reference layout.** The `sections` structure maps almost directly. A quartodoc config like this: ```{.yaml filename="_quarto.yml (quartodoc)"} quartodoc: package: my_package sections: - title: Core desc: Primary interface contents: - MyClass - helper_function - title: Utilities desc: Utility helpers contents: - format_output ``` becomes this in Great Docs: ```{.yaml filename="great-docs.yml"} reference: sections: - title: Core desc: Primary interface contents: - MyClass - helper_function - title: Utilities desc: Utility helpers contents: - format_output ``` The section structure (`title`, `desc`, `contents`) is the same and you just move it from `quartodoc.sections` in `_quarto.yml` to `reference.sections` in `great-docs.yml`. One syntax difference: quartodoc uses `members: []` (an empty list) to suppress inline method documentation on a class, while Great Docs uses `members: false`. So a quartodoc entry like: ```yaml - name: MyClass members: [] ``` becomes: ```yaml - name: MyClass members: false ``` 3. **Move your user guide pages.** If you have narrative `.qmd` files (tutorials, guides, etc.), move them into a top-level `user_guide/` directory. Great Docs expects user guide content there rather than scattered alongside `_quarto.yml`. See [User Guides](user-guides.qmd) for naming conventions and sidebar ordering. 4. **Clean up quartodoc artifacts.** Great Docs generates its own `_quarto.yml` inside the ephemeral `great-docs/` build directory on every build, so you don't need to edit or keep your old `_quarto.yml`. The main thing to do is delete the `reference/` directory that quartodoc generated (but check it first for any hand-written `.qmd` content you want to migrate into your `user_guide/` directory or `great-docs.yml` reference config). 5. **Build and preview.** Run `great-docs build` followed by `great-docs preview`. Your reference pages should render with the same content, now with Great Docs' enhanced styling and features. ## Next Steps Great Docs handles the tedious parts of API documentation (discovery, classification, layout, linking) so you can focus on writing clear docstrings. Whether your package exports a handful of functions or hundreds of classes, the reference section stays organized and up to date. - [Writing Docstrings](writing-docstrings.qmd) covers docstring format, sections, executable examples, and `%nodoc` - [Cross-Referencing](cross-referencing.qmd) covers the full linking system (GDLS) for connecting API pages - [CLI Documentation](cli-documentation.qmd) covers Click CLI documentation - [User Guides](user-guides.qmd) explains how to add narrative documentation - [Configuration](configuration.qmd) covers all `great-docs.yml` options # CLI Documentation Great Docs can generate reference pages for command-line interfaces automatically. Each command and subcommand gets its own structured page showing the usage signature, description, typed options, and examples, all using the same layout as API reference pages. Three CLI ecosystems are supported: - **Python** (Click): introspects Click commands at import time - **Go** (Cobra, urfave/cli): compiles the Go binary and extracts `--help` output - **Rust** (clap, structopt, argh): compiles via `cargo build` and extracts `--help` output The Go and Rust pipelines work the same way: build the binary, run it with `--help` recursively on every subcommand, parse the output, and generate the same structured pages as the Python pipeline. This means your CLI documentation stays perfectly in sync with your code regardless of language. This page covers each ecosystem in turn: how to enable it, how discovery works, and how to write help text that produces clear reference pages. ## Python CLI (Click) {#python-cli} ### Enabling Python CLI Documentation Add the following to your `great-docs.yml`: ```{.yaml filename="great-docs.yml"} cli: enabled: true ``` With this single setting, Great Docs handles the rest: it finds your Click commands, captures their help output, and generates reference pages during every build. No additional configuration is needed for standard project layouts. ### How It Works When CLI documentation is enabled, Great Docs runs a pipeline that mirrors how it handles API documentation: discover, extract, generate, and integrate. Here's what happens during each build: 1. **Finds your CLI**: looks for Click commands in common locations 2. **Discovers entry point**: reads `[project.scripts]` from `pyproject.toml` 3. **Extracts metadata**: introspects each command for its description, options, arguments, subcommands, and examples 4. **Generates structured pages**: creates `.qmd` files in `reference/cli/` with the same layout as API reference pages 5. **Updates navigation**: adds a CLI section to the sidebar The pipeline runs as part of `great-docs build`, so CLI pages are always regenerated from the current state of your code. You never need to update them manually. ### Auto-Discovery Most Click-based packages follow a handful of common patterns for where the CLI entry point lives. Great Docs checks these locations automatically, so you rarely need to tell it where to look: 1. `your_package.cli`: the most common location 2. `your_package.__main__`: for `python -m your_package` support 3. `your_package.main`: alternative location 4. entry point module from `[project.scripts]` Great Docs tries each location in order and uses the first one that contains a Click command. If you have a `[project.scripts]` section: ```{.toml filename="pyproject.toml"} [project.scripts] my-cli = "my_package.cli:main" ``` Great Docs uses `my-cli` as the command name in documentation. ### Explicit Configuration If your CLI lives in a non-standard location, or if auto-discovery picks up the wrong command object, you can specify the module and command name explicitly in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} cli: enabled: true module: my_package.commands # Module containing Click commands name: app # Name of the Click command object ``` The `module` value should be the dotted import path to the Python module containing your Click group or command. The `name` value is the variable name of the Click command object within that module. With explicit configuration, Great Docs skips auto-discovery entirely and goes straight to the specified location. ### Writing Good Click Help The quality of your CLI documentation depends on the help text you write in your Click decorators and docstrings. Great Docs parses your docstrings into structured sections, so following a few conventions produces the best results. Every Click command should have a docstring that explains what it does. The first paragraph becomes the **subject** (displayed prominently at the top of the page), and remaining paragraphs form the **extended description**: ```{.python filename="cli.py"} @click.command() @click.argument("path") @click.option("--output", "-o", help="Output directory for generated files") @click.option("--verbose", "-v", is_flag=True, help="Enable verbose logging") def build(path, output, verbose): """Build the project at PATH. This command compiles all source files and generates output in the specified directory. Use --verbose to see detailed progress information. """ ... ``` The first paragraph is especially important because it also appears as the short description in the parent group's **Commands** list and in search results. **Document all options.** Every `@click.option()` should include a `help=` string. Options without help text appear in the reference page but give readers no indication of what they do. Use single quotes around file names or values to have them rendered as inline code: ```{.python filename="cli.py"} @click.option( "--format", type=click.Choice(["json", "yaml", "toml"]), default="json", help="Output format (default: json)" ) @click.option( "--config", help="Path to config file (default: 'pyproject.toml')" ) ``` In the generated page, `'pyproject.toml'` in the second option's help text becomes inline code automatically, so the rendered description reads "Path to config file (default: `pyproject.toml`)". **Use Click groups for subcommands.** If your CLI has multiple commands, use a `@click.group()` to organize them. Great Docs generates a separate page for each subcommand and links them together in the sidebar: ```{.python filename="cli.py"} @click.group() def cli(): """My CLI application for managing projects.""" pass @cli.command() def init(): """Initialize a new project.""" ... @cli.command() def build(): """Build the project.""" ... ``` Well-structured Click groups produce the clearest documentation. Each subcommand becomes its own page, and the group's docstring serves as the overview for the CLI section. **Include examples.** If your docstring contains a paragraph starting with `Examples:`, Great Docs extracts it into a dedicated **Examples** section rendered as a `bash` code block. Use Click's `\b` marker to prevent paragraph rewrapping: ```{.python filename="cli.py"} @click.command() def deploy(): """Deploy the built site. Uploads the contents of _site/ to your configured host. \b Examples: my-cli deploy # Deploy to production my-cli deploy --dry-run # Preview what would happen my-cli deploy --target staging # Deploy to staging """ ... ``` Without the `\b` marker, Click joins continuation lines into a single paragraph, which would collapse the example lines together. Always place `\b` on its own line before `Examples:` to preserve the formatting. ### Example: Great Docs CLI Great Docs uses this feature to document its own CLI. Here's what the generated page for `great-docs build` looks like (simplified): **Subject and usage:** > Build your documentation site. ```bash great-docs build [OPTIONS] ``` **Extended description (formatted as prose):** > Requires `great-docs.yml` to exist (run `great-docs init` first). This is the only command you > need day-to-day and in CI. **Collapsible `--help` output:** The full raw terminal output is available inside a disclosure widget labeled "Full --help output". Readers can expand it when they want the complete reference, but it doesn't dominate the page. **Options (structured definition list):** | Option | Type | Description | |--------|------|-------------| | `--watch` | flag | Watch for changes and rebuild automatically | | `--no-refresh` | flag | Skip re-discovering package exports | | `--versions` | TEXT | Build only specific versions (comma-separated) | | `--from-repo` | TEXT | Clone a remote Git repository and build its docs | **Examples (bash code block):** ```bash great-docs build # Full build with API refresh great-docs build --no-refresh # Fast rebuild (skip API discovery) great-docs build --watch # Rebuild on file changes ``` The main group page (`great-docs`) additionally includes a **Commands** section that links to each subcommand's dedicated page. You can see these pages live in the Great Docs reference section. All of these sections are generated from the same Click decorators and docstrings shown earlier in this guide. ## Go CLI (Cobra) {#go-cli} Great Docs can document Go CLI projects that use [Cobra](https://github.com/spf13/cobra), [urfave/cli](https://github.com/urfave/cli), or any framework whose `--help` output follows the standard Cobra convention. The process is fully automatic: Great Docs compiles the Go binary, runs it with `--help`, and parses the output into structured reference pages. ### Enabling Go CLI Documentation Set `project_type` to `go` (or include `go` in a list for mixed projects) and enable `go_cli`: ```{.yaml filename="great-docs.yml"} project_type: go go_cli: enabled: true ``` This requires `go` to be on your `PATH`. Great Docs compiles the binary to a temporary directory during each build, so the project tree is never modified. ### Project Detection Great Docs recognizes a Go CLI project when it finds: 1. A `go.mod` file at the project root 2. At least one main package in a standard layout: - `cmd//main.go` (multi-binary layout, most common) - `cmd/main.go` (single binary under `cmd/`) - `main.go` (flat layout) The binary name is inferred from the directory name (for `cmd//`) or from the module path (for flat layouts). ### How It Works During each build: 1. **Detects the project**: reads `go.mod` for the module path, locates the main package 2. **Compiles the binary**: runs `go build` to a temporary directory 3. **Extracts the command tree**: runs ` --help` and parses subcommands recursively 4. **Generates pages**: creates the same structured `.qmd` pages as the Python CLI pipeline 5. **Updates navigation**: adds a CLI section to the sidebar Cobra's help format uses `Available Commands:` and `Flags:` sections. Great Docs parses these automatically, including custom command groups defined with `AddGroup()`. ## Rust CLI (clap) {#rust-cli} Great Docs can document Rust CLI projects that use [clap](https://docs.rs/clap/), [structopt](https://docs.rs/structopt/), [argh](https://docs.rs/argh/), or any framework whose `--help` output follows standard conventions. Like the Go pipeline, the process is fully automatic: Great Docs compiles the Rust binary via `cargo build`, runs it with `--help`, and parses the output into structured reference pages. ### Enabling Rust CLI Documentation Set `project_type` to `rust` and enable `rust_cli`: ```{.yaml filename="great-docs.yml"} project_type: rust rust_cli: enabled: true ``` This requires `cargo` to be on your `PATH`. Great Docs compiles a release binary to a temporary directory during each build, so the project tree is never modified. ### Project Detection Great Docs recognizes a Rust CLI project when it finds: 1. A `Cargo.toml` at the project root with a `[package]` section 2. At least one binary target: - Explicit `[[bin]]` sections in `Cargo.toml` - `src/main.rs` (Cargo's default binary target, named after the package) For projects that produce multiple binaries (like separate `ir` and `rx` binaries), Great Docs documents the first binary listed. ### How It Works During each build: 1. **Detects the project**: reads `Cargo.toml` for the package name and binary targets 2. **Compiles the binary**: runs `cargo build --release` with a temporary `--target-dir` 3. **Extracts the command tree**: runs ` --help` and parses subcommands recursively 4. **Generates pages**: creates the same structured `.qmd` pages as the Python and Go pipelines 5. **Updates navigation**: adds a CLI section to the sidebar clap's help format uses `Commands:` and `Options:` sections. Great Docs parses these automatically, including nested subcommand groups (e.g., `yamark git-filter clean`), positional arguments, default values in `[default: ...]` brackets, and flags with no description text. ### Writing Good `--help` Text The quality of generated documentation depends directly on your `--help` output. For clap-based projects using the derive API: - **Add `about` or `long_about`** to every command and subcommand via the `#[command(...)]` attribute or doc comments. The description text becomes the page's subject and extended description. - **Add `help` to every argument and option** via `#[arg(help = "...")]` or doc comments. Options without help text still appear on the page but give readers no context. - **Use `after_help`** for examples. clap renders this after the options list, and Great Docs captures it in the full `--help` output shown in the collapsible disclosure widget. ```{.rust filename="src/cli.rs"} /// Format YAML and Markdown files. /// /// Reads files from the given paths and writes formatted output. /// When no paths are given, reads from standard input. #[derive(Parser)] struct Cli { /// Enable check mode (exit 1 if files would change) #[arg(long)] check: bool, /// Output width for prose wrapping #[arg(long, default_value_t = 72)] wrap: usize, /// Files to format paths: Vec, } ``` ### Mixed Projects For projects that include both a Rust CLI and a Python package (e.g., a Rust binary with Python bindings), use a list for `project_type`: ```{.yaml filename="great-docs.yml"} project_type: [python, rust] rust_cli: enabled: true ``` This enables both the Python API reference and the Rust CLI reference. The generated site shows both sections in the Reference sidebar. ## Generated Output Regardless of which ecosystem your CLI uses, Great Docs generates the same structured pages. ### Sidebar Structure CLI commands appear in the Reference sidebar: ``` Reference ├── API │ └── (your classes and functions) └── CLI ├── my-cli (main command) ├── my-cli build ├── my-cli deploy └── my-cli config ``` ### Page Format Each CLI page uses the same structured layout as API reference pages, making the site feel cohesive. A generated page contains these sections in order: 1. **Title** with a colored label badge (`cli` or `cli-group`) 2. **Subject**: the first paragraph of the description (the short description) 3. **Usage signature**: a `bash` code block showing the invocation pattern 4. **Extended description**: remaining paragraphs, formatted as prose 5. **Collapsible `--help` output**: the full raw `--help` text, tucked inside a disclosure widget 6. **Arguments**: if the command takes positional arguments 7. **Options**: a definition list with name, type, default, and help text 8. **Subcommands**: for groups, each subcommand links to its own page 9. **Examples**: if the help text includes an `Examples:` section This structured layout gives readers quick access to what they need (usage, options, examples) while preserving the full `--help` output for those who want the raw reference. ### Text Enhancements Within the description and option help text, Great Docs automatically applies two enhancements: - **Single-quoted text -> code**: `'great-docs build'` in your help text renders as `great-docs build` in inline code - **Option names -> code**: references to options like `--watch` or `--from-repo` are rendered as inline code automatically These enhancements are applied automatically during page generation. You don't need to use backticks or any special markup in your help strings. ## Styling CLI reference pages share the same visual system as API reference pages: - **Colored label badges**: `cli` (blue) and `cli-group` (teal) distinguish commands from groups - **Structured definition lists**: options are displayed with the same parameter styling used for function signatures in API docs - **Consistent layout**: subject, signature, description, and parameters mirror the API page structure - **Responsive design**: pages adapt to mobile and desktop viewports - **Collapsible details**: the raw `--help` output is available but doesn't clutter the page This shared design language means readers moving between API docs and CLI docs see the same patterns: a short subject at the top, a signature block, extended prose, and a structured parameter list. ## Troubleshooting ### Python CLI Not Detected If your Click CLI isn't found: 1. verify Click is installed 2. check the module path is correct 3. ensure the Click command is importable 4. use explicit configuration: ```{.yaml filename="great-docs.yml"} cli: enabled: true module: your_package.cli name: cli # The Click command object name ``` ### Go or Rust CLI Not Detected If your Go or Rust CLI isn't found: 1. verify the compiler is on `PATH` (`go` or `cargo`) 2. check that `go.mod` or `Cargo.toml` exists at the project root 3. ensure there is a binary entry point (`main.go` or `src/main.rs`) 4. check the build log for compilation errors ### Help Text Missing If commands show minimal help: - **Python**: add docstrings to Click functions and `help=` to all options - **Go**: add descriptions to Cobra commands via `Short` and `Long` fields - **Rust**: add doc comments or `#[arg(help = "...")]` to clap structs The generated page will still show the command's usage signature and options, but the description sections will be empty without help text. ## Next Steps CLI documentation works best when your commands have good help text. Great Docs takes what you've written and turns it into browsable, searchable reference pages that stay in sync with your code. - [User Guides](08-user-guides.qmd) explains how to add narrative documentation - [Deployment](14-deployment.qmd) covers publishing to GitHub Pages # User Guides API reference pages are valuable, but they only describe individual functions and classes in isolation. For users to truly understand your project, they need narrative documentation: tutorials that walk them through real tasks, guides that explain concepts in context, and explanations that connect the pieces together. Without this kind of content, users are left to figure out the bigger picture on their own. Great Docs treats user guides as first-class content. When you add a `user_guide/` directory to your project, Great Docs automatically generates sidebar navigation, adds a navbar link, applies narrative-optimized styling, and keeps everything in sync across builds. You write Quarto Markdown files and Great Docs handles the rest. ## Creating a User Guide Getting started takes just three steps: 1. create a `user_guide/` directory in your project root 2. add `.qmd` files for each page 3. run `great-docs build` Great Docs automatically: - copies files to `great-docs/user-guide/` - generates sidebar navigation - adds a "User Guide" link to the navbar - organizes pages into sections No additional configuration is required. As soon as Great Docs finds `.qmd` files in the `user_guide/` directory, the User Guide section appears in your site. ## Directory Structure A typical project with a User Guide looks like this: ```{.default filename="Project structure"} your-project/ ├── great-docs/ # Build directory (ephemeral, gitignored) │ ├── user-guide/ # Copied from user_guide/ │ └── ... ├── user_guide/ # Your source files (committed to git) │ ├── 00-introduction.qmd │ ├── 01-installation.qmd │ ├── 02-quickstart.qmd │ ├── 03-configuration.qmd │ └── images/ # Asset directories are copied too │ └── screenshot.png ├── great-docs.yml ├── pyproject.toml └── your_package/ ``` The `user_guide/` directory is the default location. You can use a [custom directory](#custom-user-guide-directory) by setting `user_guide` in `great-docs.yml`. ## Page Ordering The order of pages in the sidebar matters for guiding readers through your content in a logical sequence. Files are sorted alphabetically by filename, so numeric prefixes give you full control over the ordering: ```{.default filename="user_guide/"} user_guide/ ├── 00-introduction.qmd # First ├── 01-installation.qmd # Second ├── 02-getting-started.qmd # Third └── 03-advanced.qmd # Fourth ``` The prefix is stripped from the title, so `01-installation.qmd` becomes "Installation" in the navigation. This means you can reorder pages at any time by renaming files without affecting how titles appear in the sidebar. ## Organizing into Sections As your user guide grows, flat lists of pages become hard to navigate. Sections let you group related pages together so readers can find what they need and understand how topics relate to each other. The simplest approach is the `guide-section` frontmatter key: ```{.yaml filename="01-installation.qmd"} --- title: "Installation" guide-section: "Getting Started" --- ``` Pages with the same `guide-section` value are grouped together in the sidebar: ```{.default filename="Sidebar navigation"} User Guide ├── Getting Started │ ├── Introduction │ └── Installation ├── Core Concepts │ ├── Configuration │ └── API Documentation └── Advanced └── Customization ``` This grouping is purely visual in the sidebar. The pages themselves remain as flat files in the `user_guide/` directory. ### Section Order Sections appear in the order they're first encountered (based on file sort order). To control section order, ensure the first file in each section has the appropriate prefix: ```{.default filename="user_guide/"} user_guide/ ├── 00-introduction.qmd # guide-section: "Getting Started" ├── 01-installation.qmd # guide-section: "Getting Started" ├── 10-configuration.qmd # guide-section: "Core Concepts" ├── 11-api-docs.qmd # guide-section: "Core Concepts" ├── 20-customization.qmd # guide-section: "Advanced" ``` ### Subdirectory-Based Sections For larger user guides, you may prefer organizing pages into actual subdirectories rather than using frontmatter. Each subdirectory becomes a section in the sidebar, with the section title derived from the subdirectory's `index.qmd` title (or the directory name if there is no `index.qmd`): ```{.default filename="user_guide/"} user_guide/ ├── index.qmd # Root page (appears first in sidebar) ├── getting-started/ │ ├── index.qmd # Section title: "Getting Started" │ ├── installation.qmd │ └── quickstart.qmd └── advanced/ ├── index.qmd # Section title: "Advanced Usage" ├── configuration.qmd └── deployment.qmd ``` This produces a sidebar like: ```{.default filename="Sidebar navigation"} User Guide ├── User Guide # Root index.qmd ├── Getting Started │ ├── Installation │ └── Quickstart └── Advanced Usage ├── Configuration └── Deployment ``` A root-level `index.qmd` is recommended so the "User Guide" navbar link has a landing page. Subdirectory `index.qmd` files provide section titles but don't appear as separate pages in the sidebar. Rather, their title is used as the collapsible section heading. Subdirectories are sorted alphabetically by directory name. To control the order of sections and pages within them, use numeric prefixes. They are stripped from both directory names and filenames in URLs and navigation: ```{.default filename="user_guide/"} user_guide/ ├── index.qmd ├── 01-getting-started/ │ ├── index.qmd # Section title: "Getting Started" │ ├── 01-installation.qmd │ └── 02-quickstart.qmd ├── 02-guides/ │ ├── index.qmd # Section title: "Guides" │ ├── 01-configuration.qmd │ └── 02-troubleshooting.qmd └── 03-advanced/ ├── index.qmd # Section title: "Advanced" └── 01-deployment.qmd ``` The prefixes control ordering but don't appear in the output: - `01-getting-started/` → `getting-started/` in URLs - `01-installation.qmd` → `installation.html` in rendered pages - Numbering restarts at `01-` in each subdirectory This pattern gives you full control over section and page order while keeping URLs clean. The subdirectory approach works well for larger user guides where the directory structure itself communicates the organization, while `guide-section` frontmatter is better suited for flat file layouts. ### Mixing Root Files and Subdirectories You can mix root-level files with subdirectory sections in the same user guide. Numeric prefixes sort them together so the nav order follows the prefix regardless of whether an item is a file or a directory: ```{.default filename="user_guide/"} user_guide/ ├── 01-overview.qmd # Page: Overview ├── 02-concepts/ │ ├── index.qmd # Section title: "Concepts" │ └── details.qmd └── 03-quickstart.qmd # Page: Quickstart ``` This produces a sidebar that interleaves files and sections in prefix order: ```{.default filename="Sidebar navigation"} User Guide ├── Overview ├── Concepts │ └── Details └── Quickstart ``` A root-level `index.qmd` always appears first regardless of its prefix. ::: {.callout-warning} Avoid giving a root file and a subdirectory the same base name (e.g., `02-concepts.qmd` alongside `02-concepts/`). After numeric prefixes are stripped from URLs, both would map to the same `concepts` path, which causes duplicate entries in the sidebar. ::: ## Writing Pages User Guide pages are standard Quarto Markdown files, which means you have access to all of Quarto's powerful features for creating rich, interactive documentation. Here are some of the most useful features for writing guides. ### Basic Frontmatter Every User Guide page needs frontmatter at the top to define its title and section. The `title` appears in the sidebar navigation and as the page heading, while `guide-section` determines which group the page belongs to: ```{.yaml filename="your-page.qmd"} --- title: "Your Page Title" guide-section: "Section Name" --- ``` ### Code Blocks Code blocks with syntax highlighting are essential for technical documentation. Specify the language after the opening backticks to enable highlighting: ````markdown ```python from great_docs import GreatDocs docs = GreatDocs() docs.build() ``` ```` Quarto supports syntax highlighting for dozens of languages including Python, JavaScript, TypeScript, R, Bash, YAML, TOML, and many more. For Python code that you want to actually execute and show the output, use `{python}` instead of just `python`. You can control execution behavior with hash-pipe options at the top of the code block. Some useful hash-pipe options include: - `#| echo: false`: hide the code, show only output - `#| eval: false`: show the code but don't run it - `#| output: false`: run the code but hide output - `#| warning: false`: suppress warning messages - `#| fig-cap: "Caption"`: add a caption to figure output ### Tabsets Tabsets let you present alternative content (like code in multiple languages or instructions for different platforms) without cluttering the page. Readers can click to switch between tabs: ````markdown ::: {.panel-tabset} ## Python ```python print("Hello") ``` ## JavaScript ```javascript console.log("Hello"); ``` ::: ```` This is particularly useful for showing installation commands for different operating systems or demonstrating concepts in multiple programming languages. ### Callouts Callouts draw attention to important information. Use them sparingly to highlight notes, warnings, or tips that readers shouldn't miss: ```markdown ::: {.callout-note} This is a note. ::: ::: {.callout-warning} This is a warning. ::: ::: {.callout-tip} This is a tip. ::: ``` Each callout type has distinct styling. Notes are informational, warnings alert readers to potential issues, and tips offer helpful suggestions. ### Images Visual content like screenshots, diagrams, and architecture charts can greatly improve documentation. Store images in a subdirectory to keep your User Guide organized: ```{.default filename="user_guide/"} user_guide/ ├── 01-getting-started.qmd └── images/ └── screenshot.png ``` Reference them in your content using standard Markdown image syntax. The alt text in brackets improves accessibility: ```markdown ![Screenshot](images/screenshot.png) ``` ### Cross-References Link freely between pages to help readers navigate related content. For other User Guide pages, use relative paths: ```markdown See the [Installation](installation.qmd) guide for details. ``` To link to API reference pages, use a relative path that goes up one directory level first: ```markdown See the [GreatDocs](../reference/GreatDocs.qmd) class for the full API. ``` These links are validated during the build, so you'll catch broken references early. ## Asset Directories User guide pages often need supporting files like images, diagrams, or sample data. Any subdirectory that doesn't contain `.qmd` files is treated as an asset directory and copied as-is: ```{.default filename="user_guide/"} user_guide/ ├── 01-guide.qmd ├── images/ # Copied to great-docs/user-guide/images/ │ ├── logo.png │ └── diagram.svg └── data/ # Copied to great-docs/user-guide/data/ └── example.json ``` This means you can reference images and other files using simple relative paths (e.g., `images/screenshot.png`) in your `.qmd` files, and Great Docs will make sure those files are available in the built site. ## User Guide Styling Because user guides serve a different purpose than API references, Great Docs applies different styling to match. The sidebar filter that helps navigate large API listings is hidden since user guides are typically smaller and have a clear hierarchical structure. Breadcrumb navigation is also removed to provide a cleaner reading experience. The sidebar itself uses section-based navigation that mirrors your `guide-section` organization, making it easy for readers to see where they are in the guide. These styling differences are applied automatically. You don't need to configure anything to get the narrative-optimized layout. ## Example: This User Guide The User Guide you're reading right now is built with Great Docs, using the same features described on this page. Here's a representative sample of its structure: ```{.default filename="user_guide/"} user_guide/ ├── 00-introduction.qmd # Getting Started ├── 01-installation.qmd # Getting Started ├── 02-quickstart.qmd # Getting Started ├── 03-authoring-qmd-files.qmd # Getting Started ├── 04-writing-docstrings.qmd # Getting Started ├── 05-configuration.qmd # Config & Theming ├── 06-api-documentation.qmd # Site Content ├── 07-cli-documentation.qmd # Site Content ├── 08-user-guides.qmd # Site Content (this page) ├── ... # 26 more pages └── 35-keyboard-keys.qmd # Site Content ``` The guide spans 36 pages organized across five sections: Getting Started, Config & Theming, Site Content, Build & Deploy, and Quality & Maintenance. Numeric prefixes control page order, and `guide-section` frontmatter handles the grouping. ## Custom User Guide Directory By default, Great Docs looks for a `user_guide/` directory in your project root. If you need your User Guide source files in a different location (e.g., inside a `docs/` folder or a monorepo subdirectory), you can specify a custom path in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} user_guide: docs/guides ``` The path is relative to the project root. Any directory structure works, including nested paths: ```{.yaml filename="great-docs.yml"} user_guide: content/user-docs ``` ### Precedence Rules If both a `user_guide` config option **and** a conventional `user_guide/` directory exist, the config option takes precedence and the `user_guide/` directory is ignored. Great Docs will print a warning to let you know: ``` ⚠️ Both 'user_guide' config option ('docs/guides') and 'user_guide/' directory exist; using configured path ``` ### Warnings Great Docs warns you if the resolved directory: - **Doesn't exist**: the path specified in `user_guide` couldn't be found - **Is empty**: the directory exists but contains no files at all - **Has no `.qmd` files**: the directory exists but doesn't contain any Quarto Markdown files In all three cases, the User Guide is skipped and processing continues normally. ## Tips These tips cover common patterns and best practices for maintaining user guides as they grow. ### Keep Source Separate from Output Whether you use the default `user_guide/` directory or a custom path, Great Docs copies files to `great-docs/user-guide/` during each build, keeping your source separate from generated output. ### Use Descriptive Titles The `title` in frontmatter appears in navigation. Make it clear and concise: ```yaml --- title: "Configuration Options" # Good guide-section: "Reference" --- ``` ### Organize Logically Group related content into sections that make sense for your users. A common pattern starts with "Getting Started" content that covers installation and quick start guides. This is everything new users need to get up and running. "Core Concepts" sections explain the main features and typical usage patterns. "Advanced" sections dive into complex topics and customization options for power users. Finally, a "Reference" section can house configuration options and troubleshooting guides. Adapt this structure to fit your project's needs. ## Next Steps User guides bring the narrative depth that API references alone can't provide. With numbered files, frontmatter sections, and automatic sidebar generation, you can build a structured guide that grows alongside your project. - [Custom Sections](custom-sections.qmd) explains how to add entirely new sidebar sections beyond the User Guide and API reference - [Cross-Referencing](cross-referencing.qmd) covers linking between User Guide pages and API reference pages - [Theming](theming.qmd) lets you customize the look and feel of your entire site, including User Guide pages - [Deployment](deployment.qmd) covers publishing your finished documentation to GitHub Pages # Custom Sections Great Docs lets you add any number of custom page groups to your documentation site (examples, tutorials, demos, or anything else). Each section gets its own navbar link and sidebar navigation. By default, the navbar links directly to the first page in the section. Set `index: true` to generate a card-based index page instead. For blog-style content, there's a dedicated `type: blog` mode that uses Quarto's native listing directive. ::: {.version-only versions=">=0.6"} If you need a single hand-written HTML page rather than a section of `.qmd` files, see [Custom Static Pages](custom-pages.qmd). Custom sections and custom static pages are complementary features. ::: ## Quick Start 1. Create a directory in your project root with `.qmd` files: ``` my-package/ ├── examples/ │ ├── 01-basic-usage.qmd │ ├── 02-advanced.qmd │ └── 03-real-world.qmd ├── great-docs.yml └── ... ``` 2. Add the section to `great-docs.yml`: ```{.yaml filename="great-docs.yml"} sections: - title: Examples dir: examples ``` 3. Run `great-docs build`: the Examples link appears in the navbar and the pages are rendered with a sidebar. ## Configuration Each section is defined as an entry in the `sections` array: ```{.yaml filename="great-docs.yml"} sections: - title: Examples # Navbar link text (required) dir: examples # Source directory (required) index: true # Generate card-based index page (optional) navbar_after: User Guide # Insert after this navbar item (optional) type: default # Section type: "default" or "blog" (optional) ``` ### Required Fields | Field | Description | |---------|-------------| | `title` | The text shown in the navbar link and sidebar heading | | `dir` | Path to the source directory (relative to project root) | ### Optional Fields | Field | Default | Description | |------------------|--------------------|-------------| | `index` | `false` | When `true`, auto-generates a card-based index page; when `false`, navbar links to the first page | | `navbar_after` | Before "Reference" | Name of an existing navbar item to place this section after | | `type` | `default` | `"default"` for card-grid index with sidebar; `"blog"` for Quarto listing page | ::: {.version-only versions=">=0.7"} | `index_columns` | `2` | Number of columns for image cards on the index page (1 or 2). Only applies when `index: true` [version-badge new 0.7] | ::: ::: {.version-only versions="dev"} | `dir_titles` | `{}` | Mapping of subdirectory names to custom sidebar section titles (see [Subdirectories](#subdirectories)) [version-badge new dev] | ::: ## Multiple Sections Add as many sections as you need: ```{.yaml filename="great-docs.yml"} sections: - title: Examples dir: examples - title: Tutorials dir: tutorials navbar_after: Examples - title: Blog dir: blog type: blog navbar_after: Reference ``` This produces a navbar like: ``` Home | User Guide | Examples | Tutorials | Reference | Blog ``` ::: {.callout-tip} ## Blog sections The `type: blog` option uses Quarto's native listing directive for date-sorted, searchable blog posts. See [Blog](blog.qmd) for the full guide. ::: ## Navbar Positioning By default, custom sections are inserted **before "Reference"** in the navbar. Use `navbar_after` to control placement: | `navbar_after` value | Result | |---------------------|--------| | *(not set)* | Before "Reference" | | `Home` | After "Home" | | `User Guide` | After "User Guide" | | `Reference` | After "Reference" | | `Changelog` | After "Changelog" | Sections appear in the order they're listed in the config. ## Page Files Place `.qmd` or `.md` files in the section directory. Great Docs will: - **Strip numeric prefixes** from filenames for clean URLs (`01-basic.qmd` → `basic.qmd`) - **Add `bread-crumbs: false`** to frontmatter automatically - **Copy all files** to the build directory ### Frontmatter Each page's YAML frontmatter is used to populate the auto-generated index and the sidebar: ```{.yaml filename="examples/01-basic-usage.qmd"} --- title: "Basic Usage" description: "A simple example showing core functionality" image: "img/basic.png" --- ``` | Field | Used for | |---------------|----------| | `title` | Sidebar link text, index page heading | | `description` | Index page summary text | | `image` | Index page thumbnail (optional) | ## Index Page ### No Index (Default) By default, sections do **not** get an index page. The navbar links directly to the first page in the section, and all pages are accessible via the sidebar. This is the simplest setup and works well when pages are self-explanatory. ### Auto-Generated Index Set `index: true` to generate a gallery-style index page with cards for each page, using each file's `title`, `description`, and `image` from frontmatter: ```{.yaml filename="great-docs.yml"} sections: - title: Examples dir: examples index: true ``` The generated index page renders entries in two zones: 1. **Image cards** — pages with an `image` field in frontmatter appear first as clickable cards in a responsive grid. Each card shows the hero image, title, and description. 2. **Plain links** — pages without an `image` field appear below as a single-column list of title + description links. When both zones are present, a horizontal rule separates them. This design mirrors the pattern used by the [pointblank demos page](https://posit-dev.github.io/pointblank/demos/), where featured items with screenshots sit above a simpler list of additional entries. ::: {.version-only versions=">=0.7"} #### Controlling Columns By default, image cards use a **2-column** responsive grid. Set `index_columns: 1` for a single-column layout (useful for wide screenshots or fewer items): ```{.yaml filename="great-docs.yml"} sections: - title: Gallery dir: gallery index: true index_columns: 1 ``` ::: {.callout-tip} ## Mixed layouts You can combine both approaches in the same site: a 2-column demos section with featured screenshots alongside a 1-column gallery with full-width images, plus plain text links for supplementary pages that don't need a visual. ::: ::: #### Example: Featured Demos with Plain Links Given this directory: ``` demos/ ├── 01-starter.qmd ← Has image: "img/starter.png" ├── 02-advanced.qmd ← Has image: "img/advanced.png" ├── 03-tips.qmd ← No image ├── 04-faq.qmd ← No image └── img/ ├── starter.png └── advanced.png ``` With this config: ```{.yaml filename="great-docs.yml"} sections: - title: Demos dir: demos index: true ``` The generated index page shows: - Two image cards side by side (Starter and Advanced) at the top - A horizontal rule - Two plain link entries (Tips and FAQ) in a single-column list below ### Custom Index If you provide your own `index.qmd` in the directory, Great Docs uses it as-is (regardless of the `index` setting). This gives you full control over the landing page layout as you can write custom HTML, use Quarto grid layouts, or embed interactive content. ``` examples/ ├── index.qmd ← Your custom gallery page ├── 01-basic.qmd ├── 02-advanced.qmd └── img/ ├── basic.png └── advanced.png ``` ## Subdirectories Sections support nested subdirectories. Files in subdirectories are copied with their relative paths preserved, and each subdirectory becomes a **sidebar section** with its own heading. ``` tutorials/ ├── getting-started/ │ ├── installation.qmd │ └── first-steps.qmd └── advanced/ └── custom-config.qmd ``` ### Numeric Prefix Stripping Just like individual files, subdirectory names have numeric prefixes stripped automatically. This lets you control the sort order of sidebar sections while keeping clean display titles: ``` examples/ ├── 01-getting-started/ │ ├── installation.qmd │ └── first-steps.qmd ├── 02-results-and-reporting/ │ ├── basic-report.qmd │ └── custom-output.qmd └── 03-advanced-topics/ └── custom-config.qmd ``` The sidebar displays these as **"Getting Started"**, **"Results And Reporting"**, and **"Advanced Topics"** (not "01 Getting Started", etc.). ::: {.version-only versions="dev"} ### Custom Subdirectory Titles {#custom-subdirectory-titles} The auto-generated title converts hyphens and underscores to spaces and applies title case. If you need different capitalization or phrasing, use `dir_titles` to override specific subdirectory headings: ```{.yaml filename="great-docs.yml"} sections: - title: Demos dir: examples index: true dir_titles: getting-started: "Getting Started" results-and-reporting: "Results/Reporting" advanced-topics: "Advanced Topics" ``` The keys in `dir_titles` are the subdirectory names **after** numeric prefix stripping (e.g., use `getting-started`, not `01-getting-started`). Any subdirectory not listed in the mapping falls back to the auto-generated title. ::: {.callout-tip} ## When to use `dir_titles` This is useful when the auto-generated title doesn't match your preferred style — for example, turning "Results And Reporting" into "Results/Reporting", or "Actions And Thresholds" into "Actions & Thresholds". ::: ::: ## Example: Visual Gallery To create a visual gallery with a hand-crafted index page: 1. Create the directory structure: ``` demos/ ├── index.qmd ├── 01-starter/ │ └── index.qmd ├── 02-advanced/ │ └── index.qmd └── img/ ├── starter.png └── advanced.png ``` 2. Write your custom `index.qmd` with a visual grid: ```{.markdown filename="demos/index.qmd"} --- title: "Examples" toc: false --- :::::: {.column-page} ::::: {.grid} :::{.g-col-lg-6 .g-col-12} ### [Starter](01-starter/index.qmd) ![](img/starter.png){width="100%"} A validation with the basics. ::: :::{.g-col-lg-6 .g-col-12} ### [Advanced](02-advanced/index.qmd) ![](img/advanced.png){width="100%"} A comprehensive example. ::: ::::: :::::: ``` 3. Add to config: ```{.yaml filename="great-docs.yml"} sections: - title: Examples dir: demos ``` ## Next Steps Custom sections let you go beyond the standard User Guide and API Reference to organize content in whatever way makes sense for your project. Whether it's a tutorials section, a cookbook, or a gallery of examples, each section gets its own navbar link, sidebar navigation, and optional index page. - [Blog](blog.qmd) covers setting up a blog with Quarto's listing directive - [Configuration](configuration.qmd) covers all available `great-docs.yml` options - [User Guides](user-guides.qmd) covers the User Guide section setup # Blog Great Docs supports adding a blog to your documentation site using Quarto's native [listing](https://quarto.org/docs/websites/website-listings.html) feature. Blog posts are automatically sorted by date, display author and category metadata, and include built-in search. ## Quick Start 1. Create a `blog/` directory with each post in its own subdirectory: ``` my-package/ ├── blog/ │ ├── welcome-post/ │ │ └── index.qmd │ └── v0.2-release/ │ └── index.qmd ├── great-docs.yml └── ... ``` 2. Add the blog section to `great-docs.yml` with `type: blog`: ```{.yaml filename="great-docs.yml"} sections: - title: Blog dir: blog type: blog ``` 3. Run `great-docs build`: a **Blog** link appears in the navbar, and the listing page is generated automatically. ## Post Structure Each blog post lives in its own subdirectory under `blog/`, with an `index.qmd` file containing the post content. This is the same convention used by Quarto's blog projects. ``` blog/ ├── welcome-post/ │ ├── index.qmd │ └── images/ │ └── hero.png # Post-specific images ├── v0.2-release/ │ └── index.qmd └── tips-and-tricks/ └── index.qmd ``` ### Post Frontmatter Each post's `index.qmd` should include frontmatter with metadata that Quarto uses for the listing page: ```{.yaml filename="blog/welcome-post/index.qmd"} --- title: "Welcome to Our Blog" author: Vivian Smith date: 2024-01-15 categories: [announcements, getting-started] description: "An introduction to us and what we're building." --- ``` | Field | Required | Description | |----------------|----------|-------------| | `title` | Yes | Post title, shown in listing and as the page heading | | `date` | Yes | Publication date (`YYYY-MM-DD`); controls sort order | | `author` | No | Author name, displayed in the listing | | `categories` | No | List of tags for filtering posts | | `description` | No | Summary text shown in the listing | | `image` | No | Thumbnail image for the listing card | ## Listing Page When no `index.qmd` exists at the root of the blog directory, Great Docs auto-generates one using Quarto's `listing:` directive: ```{.yaml} --- title: "Blog" listing: type: default sort: "date desc" contents: - "**.qmd" --- ``` This produces a listing page that: - sorts posts by date (newest first) - shows title, author, date, description, and categories - includes client-side search across all posts - links each entry to the full post ### Custom Listing Page To customize the listing layout, provide your own `blog/index.qmd`. For example, to use a table layout: ```{.yaml filename="blog/index.qmd"} --- title: "Blog" listing: type: table sort: "date desc" feed: true contents: - "**.qmd" --- ``` Quarto supports three listing types: | Type | Description | |-----------|-------------| | `default` | Card-style listing with thumbnails | | `grid` | Grid of equal-sized cards | | `table` | Compact table with sortable columns | See [Quarto Listings](https://quarto.org/docs/websites/website-listings.html) for all options, including custom templates and feeds. ## How It Differs from Default Sections Blog sections (`type: blog`) differ from default sections in several ways: | Feature | Default Sections | Blog Sections | |---------|-----------------|---------------| | Index page | Card grid (auto-generated) | Quarto listing (auto-generated) | | Sidebar | Yes (with page links) | No | | Sort order | Alphabetical | By date (newest first) | | Post metadata | `title`, `description` | `title`, `date`, `author`, `categories`, `description` | | Frontmatter modification | Adds `bread-crumbs: false` | No modification | | File structure | Flat `.qmd` files | Subdirectories with `index.qmd` | ## Configuration The blog section is configured as part of the `sections` array in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} sections: - title: Blog # Navbar link text dir: blog # Source directory type: blog # Use Quarto's listing directive navbar_after: Reference # Position in navbar (optional) ``` ## Example: Full Blog Setup Here's a complete example with three posts: ### Directory Structure ``` my-package/ ├── blog/ │ ├── introducing-the-project/ │ │ └── index.qmd │ ├── february-update/ │ │ └── index.qmd │ └── v0.2-release/ │ └── index.qmd ├── my_package/ │ └── __init__.py ├── great-docs.yml └── pyproject.toml ``` ### Configuration ```{.yaml filename="great-docs.yml"} sections: - title: Blog dir: blog type: blog ``` ### Blog Post ```{.markdown filename="blog/v0.2-release/index.qmd"} --- title: "Version 0.2 Release Notes" author: Vivian Smith date: 2024-03-10 categories: [releases] description: "New features and improvements in v0.2." --- We're happy to announce the v0.2 release! ## New Features - blog support via Quarto's listing directive - improved dark mode styling - better section card colors ## Breaking Changes None in this release. ``` ## Next Steps A blog gives your project a voice beyond reference documentation. Use it for release announcements, tutorials, design rationale, or anything else that benefits from a chronological format. Great Docs handles the listing page, categories, and date sorting so you can focus on writing. - [Custom Sections](custom-sections.qmd) covers adding non-blog sections (examples, tutorials, etc.) - [Configuration](configuration.qmd) covers all available `great-docs.yml` options ## Config & Theming # Theming & Appearance The default Great Docs site looks polished out of the box, but most projects want their documentation to reflect their own identity. Great Docs gives you control over every visual layer of the site: the color scheme, navbar styling, dark mode, logos, hero section, icons, and more. All of these options live in `great-docs.yml`, so you can adjust the look without writing any CSS or JavaScript. This page covers the visual customization options. For functional settings (API discovery, parsers, GitHub integration, etc.), see [Configuration](configuration.qmd). ## Dark Mode Toggle Great Docs includes a light/dark mode toggle in the navbar. It respects the visitor's system preference on first visit and remembers their choice in local storage for subsequent visits. The toggle is enabled by default. To disable the toggle, set `dark_mode_toggle` to `false` in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} dark_mode_toggle: true # Enabled by default ``` ```{.yaml filename="great-docs.yml"} dark_mode_toggle: false # Disable the toggle ``` When enabled, the toggle provides instant switching without a page reload. Visitors who prefer reduced motion in their operating system settings will still see the theme change, but without the transition animation. ## GitHub Link Style Great Docs automatically adds a GitHub link to the navbar when it detects your repository URL. The `github_style` option controls how that link is displayed: ```{.yaml filename="great-docs.yml"} github_style: widget # Default: interactive widget with stats dropdown ``` ```{.yaml filename="great-docs.yml"} github_style: icon # Simple GitHub icon linking to the repo ``` The `widget` style shows a GitHub icon that, on hover, reveals a dropdown with live star, fork, issue, and pull request counts. The `icon` style renders a plain GitHub icon that links directly to the repository. ## Sidebar Filter API reference sidebars can grow large as your package adds more exports. The sidebar filter adds a search input at the top of the sidebar so visitors can quickly find the function or class they're looking for. It is enabled by default and appears automatically when the sidebar has enough items. To configure the filter in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} sidebar_filter: enabled: true # Default: true min_items: 20 # Default: show filter when sidebar has 20+ items ``` The `min_items` threshold prevents the filter from appearing on small APIs where it would not be useful. Set `enabled: false` to hide the filter entirely. ## Display Name By default, Great Docs uses your package name (from `pyproject.toml`) in the navbar and page titles. If your package name uses underscores or hyphens (e.g., `great_docs` or `great-docs`), you can set a friendlier display name: ```{.yaml filename="great-docs.yml"} display_name: "Great Docs" ``` This name appears in the navbar title, the hero section (if enabled), the page `` tag, and anywhere else the package name is shown to visitors. ## GitHub Link Style A floating button appears in the bottom-right corner of the page after the visitor scrolls down, providing a one-click way to return to the top. The button uses smooth scrolling and automatically shifts upward when it would overlap with the prev/next page navigation links. It is enabled by default. ```{.yaml filename="great-docs.yml"} back_to_top: true # Enabled by default ``` ```{.yaml filename="great-docs.yml"} back_to_top: false # Disable the button ``` The button respects the visitor's `prefers-reduced-motion` setting: when reduced motion is preferred, scrolling is instant rather than animated. When `back_to_top` is enabled, a companion **On this page** button also appears on mobile viewports (below 768 px). This round floating button sits directly above the back-to-top button and opens a compact table-of-contents panel. Tapping a heading scrolls to that section and dismisses the panel whereas tapping outside the panel dismisses it without navigating. The button is hidden on tablet and desktop widths where the sidebar TOC is already visible. ## Keyboard Navigation [version-badge new 0.5] Great Docs includes built-in keyboard shortcuts that let visitors navigate the site and access common actions without reaching for the mouse. A small keyboard icon appears in the navbar; clicking it (or pressing `h` / `?`) opens an overlay listing every shortcut. ### Available Shortcuts The shortcuts are organized into three groups: #### Navigation Move between pages and jump to common destinations without leaving the keyboard. | Key | Action | |-----|--------| | `s` or `/` | Focus the search input | | `[` | Go to the previous page | | `]` | Go to the next page | | `q` | Go to the homepage | | `u` | Go to the User Guide | | `r` | Go to the API Reference | | `m` or `n` | Show/hide the floating menu overlay | The floating menu shows the sidebar navigation on documentation pages and the navbar links on the homepage, giving quick access to any section without scrolling. #### Display Control how the page looks and capture its content. | Key | Action | |-----|--------| | `d` | Toggle dark mode | | `c` | Copy the current page as Markdown (when available) | #### General Access help and dismiss any open overlay. | Key | Action | |-----|--------| | `h` or `?` | Show/hide the keyboard shortcuts help overlay | | `Escape` | Close the active overlay or unfocus the current element | ### Configuration Keyboard navigation is enabled by default. To disable it: ```{.yaml filename="great-docs.yml"} keyboard_nav: false ``` ### Accessibility Keyboard shortcuts are automatically skipped when the visitor is typing in an input field, textarea, or content-editable element, so they never interfere with form entry or search. The help overlay uses ARIA attributes for screen reader compatibility, and animations respect the visitor's `prefers-reduced-motion` system setting. ## Announcement Banner A site-wide banner can be displayed above the navbar to highlight important news, releases, or alerts. The banner appears on every page and can optionally be dismissed by the visitor. ### Simple Form The simplest way to add a banner is with a string value. This creates a blue, info-styled banner that visitors can dismiss: ```{.yaml filename="great-docs.yml"} announcement: "Version 2.0 is now available!" ``` ### Full Configuration For more control over the banner's appearance and behavior, use a dictionary with `content`, `type`, `dismissable`, and `url` keys: ```{.yaml filename="great-docs.yml"} announcement: content: "We've moved to a new domain. Please update your bookmarks!" type: warning # info (default), warning, success, or danger dismissable: true # Allow visitors to close the banner (default: true) url: https://example.com/blog/migration # Optional: makes the text a link ``` The available banner types and their colors: | Type | Light Mode | Dark Mode | |------|-----------|-----------| | `info` | Blue | Dark blue | | `warning` | Yellow (dark text) | Dark yellow | | `success` | Green | Dark green | | `danger` | Red | Dark red | ### Dismiss Behavior When `dismissable: true` (the default), visitors can click the close button to hide the banner. The dismissal is stored in `sessionStorage`, so the banner stays hidden for the rest of the browsing session but reappears after the browser is closed. If you change the announcement text, the new message will appear even for visitors who dismissed the previous one. ### Disabling the Banner To remove a previously configured banner, either set the key to `false` or remove it from the file entirely: ```{.yaml filename="great-docs.yml"} announcement: false ``` ## Animated Gradient Presets The announcement banner, navbar, and content area all support gradient backgrounds. The banner and navbar use animated gradients that shift slowly across the element, creating a subtle, eye-catching effect. The content area uses a soft radial glow at the top of each page. Each preset includes paired light-mode and dark-mode color palettes. ### Available Presets Great Docs ships with eight gradient presets. Each bar below shows the light-mode gradient on the left and the dark-mode gradient on the right: ```{=html} <style> @media (max-width: 576px) { .gd-preset-desc { font-size: 0.6em; } .gd-preset-bar { height: 34px; font-size: 0.6em; } } </style> <div style="display: flex; flex-direction: column; gap: 6px; margin: 1em 0;"> <div class="gd-preset-bar" style="display: flex; border-radius: 6px; overflow: hidden; height: 38px; font-size: 0.88em; font-weight: 500;"> <div style="flex: 1; background: linear-gradient(-45deg, #d0ecf9, #e0f4ff, #c5e8f7, #b8e0f5); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #1a1a1a;"><code style="background: none; font-weight: 700; color: inherit;">sky</code><span class="gd-preset-desc"> Soft sky blues</span></div> <div style="flex: 1; background: linear-gradient(-45deg, #023e8a, #0077b6, #005f73, #0096c7); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #ffffff;"><code style="background: none; font-weight: 700; color: inherit;">sky</code><span class="gd-preset-desc"> Soft sky blues</span></div> </div> <div class="gd-preset-bar" style="display: flex; border-radius: 6px; overflow: hidden; height: 38px; font-size: 0.88em; font-weight: 500;"> <div style="flex: 1; background: linear-gradient(-45deg, #ffddc1, #ffe4cc, #fdd0d8, #fbc4d4); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #1a1a1a;"><code style="background: none; font-weight: 700; color: inherit;">peach</code><span class="gd-preset-desc"> Peach and blush</span></div> <div style="flex: 1; background: linear-gradient(-45deg, #cc4a1a, #c7760f, #b84a5f, #a33560); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #ffffff;"><code style="background: none; font-weight: 700; color: inherit;">peach</code><span class="gd-preset-desc"> Peach and blush</span></div> </div> <div class="gd-preset-bar" style="display: flex; border-radius: 6px; overflow: hidden; height: 38px; font-size: 0.88em; font-weight: 500;"> <div style="flex: 1; background: linear-gradient(-45deg, #c4f0e0, #d0e8f5, #e4d4f4, #d8cef0); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #1a1a1a;"><code style="background: none; font-weight: 700; color: inherit;">prism</code><span class="gd-preset-desc"> Mint, sky, and lavender</span></div> <div style="flex: 1; background: linear-gradient(-45deg, #048a65, #0c6a8a, #52077d, #2a0978); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #ffffff;"><code style="background: none; font-weight: 700; color: inherit;">prism</code><span class="gd-preset-desc"> Mint, sky, and lavender</span></div> </div> <div class="gd-preset-bar" style="display: flex; border-radius: 6px; overflow: hidden; height: 38px; font-size: 0.88em; font-weight: 500;"> <div style="flex: 1; background: linear-gradient(-45deg, #e8d0f0, #f5d0e0, #f0d4f8, #eac8ee); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #1a1a1a;"><code style="background: none; font-weight: 700; color: inherit;">lilac</code><span class="gd-preset-desc"> Lilac and pink</span></div> <div style="flex: 1; background: linear-gradient(-45deg, #561e64, #8b1140, #a02db3, #6e1a7d); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #ffffff;"><code style="background: none; font-weight: 700; color: inherit;">lilac</code><span class="gd-preset-desc"> Lilac and pink</span></div> </div> <div class="gd-preset-bar" style="display: flex; border-radius: 6px; overflow: hidden; height: 38px; font-size: 0.88em; font-weight: 500;"> <div style="flex: 1; background: linear-gradient(-45deg, #e0e4e8, #eceff1, #dde2e6, #d5dadf); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #1a1a1a;"><code style="background: none; font-weight: 700; color: inherit;">slate</code><span class="gd-preset-desc"> Cool grays</span></div> <div style="flex: 1; background: linear-gradient(-45deg, #37474f, #455a64, #3e525e, #263238); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #ffffff;"><code style="background: none; font-weight: 700; color: inherit;">slate</code><span class="gd-preset-desc"> Cool grays</span></div> </div> <div class="gd-preset-bar" style="display: flex; border-radius: 6px; overflow: hidden; height: 38px; font-size: 0.88em; font-weight: 500;"> <div style="flex: 1; background: linear-gradient(-45deg, #ffe0c2, #ffedcc, #ffe5b4, #ffd6a8); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #1a1a1a;"><code style="background: none; font-weight: 700; color: inherit;">honey</code><span class="gd-preset-desc"> Warm cream and apricot</span></div> <div style="flex: 1; background: linear-gradient(-45deg, #bf360c, #e65100, #ef6c00, #b71c1c); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #ffffff;"><code style="background: none; font-weight: 700; color: inherit;">honey</code><span class="gd-preset-desc"> Warm cream and apricot</span></div> </div> <div class="gd-preset-bar" style="display: flex; border-radius: 6px; overflow: hidden; height: 38px; font-size: 0.88em; font-weight: 500;"> <div style="flex: 1; background: linear-gradient(-45deg, #d8daf0, #dddff5, #d4d0ee, #dad4f2); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #1a1a1a;"><code style="background: none; font-weight: 700; color: inherit;">dusk</code><span class="gd-preset-desc"> Soft lavender-blue</span></div> <div style="flex: 1; background: linear-gradient(-45deg, #0d1244, #141b55, #1a0f52, #261560); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #ffffff;"><code style="background: none; font-weight: 700; color: inherit;">dusk</code><span class="gd-preset-desc"> Soft lavender-blue</span></div> </div> <div class="gd-preset-bar" style="display: flex; border-radius: 6px; overflow: hidden; height: 38px; font-size: 0.88em; font-weight: 500;"> <div style="flex: 1; background: linear-gradient(-45deg, #ccece8, #d5f0ec, #c4e8e4, #d0f2ee); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #1a1a1a;"><code style="background: none; font-weight: 700; color: inherit;">mint</code><span class="gd-preset-desc"> Pale aqua</span></div> <div style="flex: 1; background: linear-gradient(-45deg, #00695c, #00796b, #004d40, #00897b); background-size: 400% 400%; display: flex; align-items: center; padding: 0 14px; color: #ffffff;"><code style="background: none; font-weight: 700; color: inherit;">mint</code><span class="gd-preset-desc"> Pale aqua</span></div> </div> <div style="display: flex; gap: 0; font-size: 0.75em; color: #888; margin-top: 2px;"> <div style="flex: 1; text-align: center;">Light mode</div> <div style="flex: 1; text-align: center;">Dark mode</div> </div> </div> ``` ### Gradient on the Announcement Banner Add a `style` key to the announcement config to apply a gradient background instead of the solid color: ```{.yaml filename="great-docs.yml"} announcement: content: "Version 2.0 is now available!" style: sky ``` When `style` is set, it overrides the solid-color `type` background with the animated gradient. The `type` key is still used for semantic class names but has no visual effect on the background when a gradient is active. ### Gradient on the Navbar Use the top-level `navbar_style` key to apply the animated gradient to the site's top navigation bar: ```{.yaml filename="great-docs.yml"} navbar_style: peach ``` In dark mode, text and icons are automatically adjusted to white for readability. ### Gradient on the Content Area Use the top-level `content_style` key to add a subtle radial glow at the top of the main content area: ```{.yaml filename="great-docs.yml"} content_style: lilac ``` The glow fades out smoothly and does not interfere with text or interactive elements. It uses the same preset names as the banner and navbar gradients. By default the glow appears on all pages. To restrict it to the homepage only, use the dictionary form with a `pages` key: ```{.yaml filename="great-docs.yml"} content_style: preset: lilac pages: homepage # "all" (default) or "homepage" ``` ### Combining All Three You can use the same preset or different presets for the banner, navbar, and content area. Here is an example that mixes two presets: ```{.yaml filename="great-docs.yml"} announcement: content: "New release!" style: sky navbar_style: sky content_style: preset: lilac pages: homepage ``` ## Accent Color The accent color is a site-wide tint used by shortcodes (like the `{{< hr >}}` horizontal rule), gradient presets, and other accent-colored elements. It sets the `--gd-accent` CSS custom property, which you can also reference in custom stylesheets. A single string applies the same color in both light and dark mode: ```{.yaml filename="great-docs.yml"} accent_color: "#6366f1" ``` For per-mode colors, use a dictionary: ```{.yaml filename="great-docs.yml"} accent_color: light: "#6366f1" dark: "#818cf8" ``` If you don't set an accent color, Great Docs uses its built-in defaults. ## Navbar Color If you prefer a solid color over an animated gradient, the `navbar_color` option sets a flat background on the navbar with automatic contrast-aware text. Great Docs uses the [APCA (Accessible Perceptual Contrast Algorithm)](https://github.com/Myndex/SAPC-APCA) to determine whether white or black text provides maximum readability against your chosen background. ### Single Color for Both Modes A plain string applies the same navbar color in both light and dark mode. Any CSS named color (e.g., `navy`, `tomato`, `teal`) or hex value works: ```{.yaml filename="great-docs.yml"} navbar_color: steelblue ``` ### Per-Mode Colors Use a dictionary with `light` and `dark` keys to set different navbar colors for each mode. You can also set only one mode, and the other keeps the default navbar styling: ```{.yaml filename="great-docs.yml"} navbar_color: light: "#2c3e50" dark: "#1a237e" ``` ### How Text Color is Chosen You do not need to specify a text color. Great Docs automatically picks white or black text (and adjusts icons, search button, toggle, and hover states) based on the APCA contrast algorithm. Dark backgrounds get white text; light backgrounds get black text. ### Precedence with `navbar_style` If both `navbar_style` (animated gradient) and `navbar_color` are set, the gradient takes precedence and `navbar_color` is ignored. To use a solid color, remove or comment out `navbar_style`: ```{.yaml filename="great-docs.yml"} # navbar_style: peach # commented out, so navbar_color takes effect navbar_color: "#2c3e50" ``` ## Custom Head Content {#include-in-header} Use `include_in_header` to inject custom HTML into the `<head>` of every page. This is useful for adding analytics scripts, custom meta tags, external stylesheets, or any other head content that needs to load before the page renders. A single string is treated as inline HTML: ```{.yaml filename="great-docs.yml"} include_in_header: '<link rel="stylesheet" href="https://example.com/custom.css">' ``` For multiple entries, use a list. Each item can be a string (inline HTML) or a dictionary with a `text` or `file` key: ```{.yaml filename="great-docs.yml"} include_in_header: - text: | <script> console.log("hello from great-docs"); </script> - text: '<meta name="custom" content="value">' - file: custom-head.html ``` Your entries are merged with Great Docs' own head injections (Font Awesome, theme scripts, etc.) so everything cooperates automatically. ## Logo Great Docs can display a logo in the navbar instead of the plain-text package name. Logos are automatically detected from conventional file locations, or you can configure them explicitly. ### Auto-Detection If you place logo files in your project using common naming conventions, Great Docs will find and use them automatically with no configuration needed: ``` my-package/ ├── logo.svg # Primary logo ├── assets/ │ ├── logo.svg # Also auto-detected │ └── logo-dark.svg # Dark-mode variant ``` Auto-detection checks these paths in priority order: 1. `logo.svg` / `logo.png` (project root) 2. `assets/logo.svg` / `assets/logo.png` 3. `docs/assets/logo.svg` / `docs/assets/logo.png` 4. `{package_name}_logo.svg` / `{package_name}_logo.png` If a file named `logo-dark.svg` (or `{stem}-dark.{ext}`) exists alongside the primary logo, it is automatically used for dark mode. ### Explicit Configuration For full control, configure the logo in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} logo: light: assets/logo.svg dark: assets/logo-dark.svg ``` You can also set additional options: ```{.yaml filename="great-docs.yml"} logo: light: assets/logo.svg dark: assets/logo-dark.svg alt: My Package # Alt text (defaults to display_name) href: https://example.com # Logo link target (defaults to site root) logo_show_title: true # Show text title alongside logo (default: false) ``` ### What Happens When a Logo Is Set When a logo is configured (or auto-detected): - the logo image replaces the text title in the navbar. - a dark-mode variant is used automatically when the user switches themes. - the text title is hidden by default (set `logo_show_title: true` to show both). - favicons are generated automatically from the logo (see below). ## Favicon Great Docs automatically generates a complete set of favicons for your site. If a logo is configured, favicons are derived from it with no extra setup needed. You can also specify a dedicated favicon image. ### Automatic Generation from Logo When a logo is set, Great Docs generates all standard favicon formats automatically: | File | Purpose | |------|---------| | `favicon.ico` | Classic favicon (16, 32, and 48px embedded) | | `favicon.svg` | Modern browsers (SVG, infinite scaling) | | `favicon-16x16.png` | Small icon contexts | | `favicon-32x32.png` | Standard tab icon | | `apple-touch-icon.png` | iOS home screen (180x180) | These files are created in the build directory and proper `<link>` tags are injected into every page's `<head>`. ### Dedicated Favicon If you want a different image for your favicon (for example, a simplified icon rather than the full logo), set the `favicon` option: ```{.yaml filename="great-docs.yml"} favicon: assets/favicon.svg ``` This generates the same set of raster variants as the logo-based approach, but uses your dedicated favicon source image instead. Both SVG and PNG source files are supported. ### Non-Square Source Images Source images do not need to be perfectly square. Non-square images are automatically centered on a transparent canvas, preserving the original aspect ratio. This means wide logos will not be distorted; they will be padded with transparency above and below. ## Hero Section The hero section is a prominent banner displayed at the top of the landing page, showcasing the package logo, name, tagline, and badges. It is generated automatically when a logo is present and gives your documentation a polished, professional look. ### Auto-Enable Behavior The hero section auto-enables when a logo is configured (or auto-detected). No explicit configuration is needed: if you have a logo, you get a hero. The hero displays: - the package logo (with dark-mode support) - the package display name - the package description from `pyproject.toml` - badges auto-extracted from the README (shields.io badges, etc.) ### Disabling the Hero To disable the hero entirely (for example, if you prefer your `index.qmd` or `README.md` rendered as-is): ```{.yaml filename="great-docs.yml"} hero: false ``` ### Customizing the Hero Each hero component can be overridden or suppressed individually. These examples add `enabled: true` since they have no logo configured — if you already have a logo (and therefore an auto-enabled hero), you can omit it: ```{.yaml filename="great-docs.yml"} hero: enabled: true # Needed here since no logo is configured name: "My Package" # Override the auto-detected name tagline: "A better way to build things" # Override the description logo_height: 120px # Default: 200px badges: false # Suppress badge display ``` Set any component to `false` to suppress it: ```{.yaml filename="great-docs.yml"} hero: enabled: true name: false # Hide the name (logo and tagline only) badges: false # No badges ``` ### Hero Logo vs. Navbar Logo By default, the hero uses the same logo as the navbar. But you may want a different image for the hero, for example a detailed wordmark instead of a compact lettermark. Set a separate hero logo with light/dark variants: ```{.yaml filename="great-docs.yml"} # Navbar: compact lettermark logo: light: assets/logo-lettermark.svg dark: assets/logo-lettermark-dark.svg # Hero: expanded wordmark hero: logo: light: assets/logo-wordmark.svg dark: assets/logo-wordmark-dark.svg logo_height: 150px ``` Or use a simple string for a single hero logo image: ```{.yaml filename="great-docs.yml"} hero: logo: assets/hero-logo.svg ``` ### Hero Logo Auto-Detection Great Docs can also auto-detect hero-specific logo files from conventional file locations, with no configuration needed. Place files using these naming conventions: ``` my-package/ ├── assets/ │ ├── logo-hero.svg # Hero logo (single image) │ ├── logo-hero-light.svg # Hero logo (light variant) │ └── logo-hero-dark.svg # Hero logo (dark variant) ``` Auto-detection checks these paths in priority order: 1. `logo-hero.svg` / `logo-hero.png` (project root) 2. `assets/logo-hero.svg` / `assets/logo-hero.png` 3. `logo-hero-light.svg` / `logo-hero-light.png` (project root) 4. `assets/logo-hero-light.svg` / `assets/logo-hero-light.png` If a file named `logo-hero-dark.svg` (or `logo-hero-dark.png`) exists alongside the primary hero logo, it is automatically used for dark mode. When hero logo files are detected, the hero section auto-enables even if no `logo` or `hero` config is set in `great-docs.yml`. The full logo fallback chain for the hero is: 1. explicit `hero.logo` in `great-docs.yml` 2. auto-detected hero logo files (`logo-hero.*`) 3. explicit top-level `logo` in `great-docs.yml` 4. auto-detected navbar logo files (`logo.*`) ### Explicit Badge List By default, badges are auto-extracted from the README. You can provide an explicit list instead: ```{.yaml filename="great-docs.yml"} hero: badges: - alt: PyPI version img: https://img.shields.io/pypi/v/my-package url: https://pypi.org/project/my-package/ - alt: License img: https://img.shields.io/badge/license-MIT-green url: https://opensource.org/licenses/MIT ``` ### Hero Section Summary | Option | Type | Default | Description | |--------|------|---------|-------------| | `hero` | `bool` / `dict` | auto | `false` to disable; `true` to force-enable; dict to customize (auto-enables with a logo) | | `hero.name` | `str` / `false` | display name | Package name shown in hero | | `hero.tagline` | `str` / `false` | description | Tagline shown below the name | | `hero.logo` | `str` / `dict` / `false` | auto-detect | Hero-specific logo (can have `light`/`dark` keys); auto-detects `logo-hero.*` files | | `hero.logo_height` | `str` | `200px` | CSS max-height for the hero logo | | `hero.badges` | `list` / `false` | `auto` | Explicit badge list or `false` to suppress | ## Navigation Icons [version-badge new 0.5] Add [Lucide](https://lucide.dev/) icons to navbar and sidebar entries for quick visual identification. Great Docs ships with the complete Lucide icon set (1,900+ icons) and resolves them to lightweight inline SVGs at build time. ### Basic Setup Map navigation labels to Lucide icon names under `nav_icons`. Use `navbar` for the top navigation bar and `sidebar` for left-sidebar items: ```{.yaml filename="great-docs.yml"} nav_icons: navbar: User Guide: book-open Reference: code-2 sidebar: Getting Started: rocket Configuration: settings ``` Each key is the **exact text** of the navigation label as it appears in the rendered site. The value is any [Lucide icon name](https://lucide.dev/icons/) (lowercase, hyphenated). ### Navbar Icons Icons in the navbar appear next to the top-level links (User Guide, Reference, Recipes, etc.): ```{.yaml filename="great-docs.yml"} nav_icons: navbar: User Guide: book-open Recipes: chef-hat Reference: code-2 ``` ### Sidebar Icons Sidebar icons appear next to items and section headers in the left navigation panel. These work for User Guide pages, custom sections, and Reference section headings: ```{.yaml filename="great-docs.yml"} nav_icons: sidebar: # User Guide pages Getting Started: rocket Configuration: settings Advanced Topics: graduation-cap # Reference sections Functions: zap Classes: layers # Custom section headers Tutorials: lightbulb ``` You don't need to assign an icon to every item, entries without a mapping simply display as normal text. ### Finding Icon Names Browse the full icon set at [lucide.dev/icons](https://lucide.dev/icons/). Use the search bar to find icons by concept: search "chart" for data visualization icons, "file" for document icons, "settings" for configuration icons, etc. To list all available icon names programmatically: ```python from great_docs._icons import list_icons print(list_icons()) # sorted list of 1,900+ names ``` ::: {.callout-tip} ### Icon Naming Tips Lucide names are lowercase and hyphen-separated. Common patterns: - **Actions**: `download`, `upload`, `copy`, `trash-2` - **Objects**: `file`, `folder`, `database`, `cloud` - **Concepts**: `settings`, `search`, `bell`, `heart` - **Numbered variants**: `code-2`, `trash-2` (alternate designs of the same concept) ::: ### Dark Mode Icons automatically adapt to dark mode. They use `stroke="currentColor"`, so they inherit the text color of their navigation context (no additional configuration is needed). ## Inline Icons [version-badge new 0.6] Beyond navbar and sidebar icons, you can place Lucide icons anywhere in your `.qmd` content using the `icon` shortcode. Icons scale with the surrounding text, sit on the baseline, and inherit the text color. ### Basic Usage ```{shortcodes="false"} {{< icon heart >}} ``` This renders inline: {{< icon heart >}} (sized to match the surrounding text). A few more examples: {{< icon rocket >}} `rocket`, {{< icon star >}} `star`, {{< icon check >}} `check`, {{< icon book-open >}} `book-open`. Icon names follow the same Lucide naming convention described above. ### Size By default icons are `1em` tall (matching the current font size). Use `size` to specify a different size in pixels (the value is converted to `em` units so the icon still scales with its context): ```{shortcodes="false"} {{< icon star size="12" >}} small {{< icon star >}} default (16px = 1em) {{< icon star size="24" >}} large {{< icon star size="32" >}} very large ``` Result: {{< icon star size="12" >}} small · {{< icon star >}} default · {{< icon star size="24" >}} large · {{< icon star size="32" >}} very large ### Accessibility By default icons are decorative (`aria-hidden="true"`). When an icon conveys meaning on its own, add a `label`: ```{shortcodes="false"} {{< icon alert-triangle label="Warning" >}} ``` This replaces `aria-hidden` with `aria-label="Warning" role="img"`, so screen readers announce the icon's purpose. ### In Context Icons work in headings, callouts, lists, tables, and blockquotes: - {{< icon file-text >}} Documentation pages - {{< icon code-2 >}} Source code references - {{< icon test-tube >}} Testing guides | Status | Icon | Description | |--------|------|-------------| | Complete | {{< icon check-circle >}} | Feature is stable | | In progress | {{< icon loader >}} | Under active development | | Planned | {{< icon calendar >}} | Scheduled for a future release | ::: {.callout-tip} ## {{< icon lightbulb >}} Pro Tip Use icons sparingly to draw attention to key information without cluttering the page. ::: ## Footer Attribution By default, Great Docs adds a small "Site created with Great Docs" attribution line in the page footer. To hide it: ```{.yaml filename="great-docs.yml"} attribution: false ``` ## Next Steps Great Docs gives you control over every visual aspect of your site, from broad choices like gradient themes and dark mode down to fine details like accent colors, icon placement, and footer attribution. Start with the defaults and customize as your project's identity evolves. - [Configuration](configuration.qmd) covers functional settings like API discovery, parsers, and GitHub integration - [Internationalization](internationalization.qmd) shows how translated labels interact with your site's visual design - [Custom Pages](custom-pages.qmd) explains how to add standalone HTML pages that inherit your theme - [Horizontal Rules](horizontal-rules.qmd) demonstrates the `hr` shortcode, which uses the accent color # Cross-Referencing Documentation becomes much more useful when readers can follow connections between related items. Without links, someone reading the `encode()` page has no easy way to discover that `decode()` exists, or that a higher-level `Pipeline` class ties everything together. Cross-references turn isolated pages into a connected web. This page covers that internal linking, and ends with citations: linking your prose outward to the papers, specifications, and books your work builds on. Great Docs provides a linking system called GDLS (Great Docs Linking System) that automatically creates clickable navigation between your API reference pages. GDLS operates at three levels, each adding a different kind of connectivity to your documentation. The first level is the `%seealso` directive, which adds structured "See Also" sections that link related items together. The second level is inline interlinks, which let you create Markdown-style links to API symbols anywhere in your prose. The third level is code autolinks, which automatically turn inline code references like `` `MyClass` `` into clickable links when they match a documented symbol. All three mechanisms resolve against the same inventory that Great Docs generates during the build, and they resolve while the page is being rendered. To preview which symbols are available for linking before you build, run: ```bash great-docs scan ``` This is useful for confirming the exact names you can reference in your docstrings. Your site publishes that inventory as `objects.inv` at its root, the format Sphinx and Quarto projects both read, so other projects can link into your documentation the same way you link into theirs. ## Linking to Another Project Configure the projects you want to reach under `interlinks.sources`, naming each one and the URL its documentation is served from: ```yaml interlinks: sources: numpy: url: https://numpy.org/doc/stable/ aliases: [np] ``` An external reference is then written exactly like an internal one: ```markdown See [](`numpy.ndarray`) for the array type, or [](`np.ndarray`) using the alias. ``` Code autolinks stay inside your own project. A bare `` `array` `` in your prose is left alone rather than linked into another project's documentation. See [Configuration](05-configuration.qmd) for the full set of fields a source accepts. ## When a Short Name Is Ambiguous You can reference an object by a short name, writing `` [](`Cache`) `` rather than `` [](`mypkg.store.Cache`) ``. If two documented objects would answer to the same short name, neither claims it: the reference renders unlinked rather than pointing at whichever object came first. Qualify the reference to fix it. The build reports each ambiguous name it drops, and `great-docs lint` reports each reference that hits one, so you do not have to find them by reading the built pages. Only your own objects compete for a short name. If a linked project publishes the same spelling, an unambiguous local name still wins and the external object remains reachable by its full name. An ambiguous local name stays unlinked even when an external object has that spelling. Qualify the source to link to the external object. A version built from an API snapshot or a git tag resolves references against that version's own API, so a name added since then stays unlinked in the older version's pages rather than pointing at a page it does not have. ## The `%seealso` Directive The most common cross-referencing need is connecting items that serve complementary roles: an encoder and a decoder, a reader and a writer, or a class and its factory function. The `%seealso` directive handles this by adding a "See Also" section at the bottom of a reference page. Place it anywhere in a docstring with a comma-separated list of related names: ```python def encode(data: bytes, encoding: str = "utf-8") -> str: """Encode bytes to a string. %seealso decode, transcode """ ... ``` Great Docs strips the directive from the rendered output and generates a "See Also" section with clickable links at the bottom of the page. Names can reference any exported symbol, including class methods using dotted notation: ```python class Validator: def check(self, data): """Run all validation checks. %seealso Validator.reset, Report """ ... ``` ### Adding Descriptions You can add a short description after each name, separated by a colon. When descriptions are present, the See Also section renders as a list with each link followed by its description. Without descriptions, the links appear as a compact comma-separated line. ```python def load(path: str) -> dict: """Load data from a file. %seealso save : Write data back to a file, validate : Check data integrity """ ... ``` You can mix entries with and without descriptions freely: ```python def transform(data: dict) -> dict: """Transform data before processing. %seealso validate : Check data integrity first, load, save """ ... ``` ### NumPy-style See Also Sections If your docstrings use the NumPy docstring format, you can write a standard See Also section instead of (or in addition to) the `%seealso` directive. Great Docs recognizes this format, preserves the descriptions, and merges it with any `%seealso` entries on the same page. Duplicate references are deduplicated automatically. ```python def connect(host: str, port: int = 5432): """Open a connection to the server. Parameters ---------- host The server hostname. port The port number. See Also -------- disconnect : Close an open connection. send : Transmit data over the connection. """ ... ``` Both formats produce the same rendered output. If a page has both a `%seealso` directive and a NumPy See Also section, the entries are merged and any duplicates are removed. ## Inline Interlinks Sometimes you need to mention another API item in the middle of a prose explanation rather than in a structured "See Also" section. Inline interlinks let you create Markdown-style links to API symbols anywhere in your docstring text. This is especially useful in class hierarchies and overview docstrings where you want to point readers to related pages. There are several forms: - write `` [](`~mypackage.MyClass`) `` to display just `MyClass`. The `~` prefix strips the package path and shows only the short name - write `` [](`mypackage.MyClass`) `` to display the full path `mypackage.MyClass` - write `` [see this class](`mypackage.MyClass`) `` to display `see this class` as the link text - write `` [see this class](`~mypackage.MyClass`) `` to also display `see this class`; when you supply custom link text in the brackets, it is always used as-is regardless of the `~` prefix Here is an example showing interlinks in practice: ```python class BaseStore: """Base class for all stores. Available implementations: - [](`~mypackage.DuckDBStore`): local storage with embedded search. - [](`~mypackage.ChromaDBStore`): vector storage using ChromaDB. See [](`mypackage.BaseStore`) for the full API, or [the DuckDB guide](`~mypackage.DuckDBStore`) for a walkthrough. """ ... ``` Interlinks work in any part of a docstring: the summary line, extended description, parameter descriptions, notes, or any other section. If a reference cannot be resolved (for example, a typo in the symbol name), the link text still renders but without a clickable link. ## Code Autolinks The first two levels (`%seealso` and interlinks) require you to opt in by writing specific syntax. Code autolinks take a different approach: they work automatically with no markup at all. When Great Docs encounters inline code in a docstring that matches a documented API symbol, it turns that code into a clickable link: ```python class Engine: """Core processing engine. Use `Pipeline` to chain multiple engines together. Call `run_pipeline()` to execute a full pipeline. """ ... ``` In the rendered output, `` `Pipeline` `` and `` `run_pipeline()` `` become clickable links to their respective reference pages. ### Shortening Prefixes For qualified names, you can control the display text with `~~` prefixes. The double tilde strips everything before the last component of the dotted path: | What you write | What renders | What it links to | |---|---|---| | `` `mypackage.MyClass` `` | `mypackage.MyClass` | MyClass page | | `` `mypackage.my_func()` `` | `mypackage.my_func()` | my_func page | | `` `~~mypackage.MyClass` `` | `MyClass` | MyClass page | | `` `~~mypackage.my_func()` `` | `my_func()` | my_func page | | `` `~~.mypackage.MyClass` `` | `.MyClass` | MyClass page | If the name does not match any documented symbol (e.g., `` `~~unknown_func()` ``), it renders as plain code with no link. ### What Gets Autolinked Any inline code that looks like an identifier or dotted path is a candidate for autolinking. Parentheses at the end are allowed. Code that contains arguments, spaces, or operators is not linked. Examples that will be linked (if the name exists in the API): - `` `MyClass` `` - `` `my_func()` `` - `` `mypackage.MyClass` `` Examples that will not be linked: - `` `my_func(x=1)` `` (contains arguments) - `` `a + b` `` (contains operators) - `` `-MyClass` `` (starts with an operator) When in doubt, write the name as you normally would in a docstring. If it resolves, it becomes a link; if not, it renders as plain code. ## Parentheses in Cross-References The three cross-referencing levels handle parentheses differently, so it helps to know the rules: **`%seealso`**: Write bare names without parentheses. Great Docs automatically appends `()` to functions and methods in the rendered "See Also" section based on each symbol's type. Writing `%seealso decode, MyClass` produces `decode()` and `MyClass` in the output, with the parentheses added only where appropriate. Set `interlinks.add_function_parentheses` to `false` if you would rather link the bare name. **Inline interlinks**: The target inside backticks should be the qualified name without parentheses. Write `` [](`~mypackage.my_func`) ``, not `` [](`~mypackage.my_func()`) ``. **Code autolinks**: Trailing `()` are optional and purely cosmetic. Both `` `my_func` `` and `` `my_func()` `` resolve to the same page. The parentheses are preserved in the display text but stripped during lookup. Use `()` when you want to signal to readers that something is callable: ```python class Pipeline: """Chain multiple engines together. Call `run()` to execute the pipeline, or inspect `config` for current settings. """ ... ``` In the rendered output, `run()` links to the `run` method page (with parentheses displayed) and `config` links to the `config` attribute page (without parentheses). ### Disabling Autolinks To prevent a specific piece of inline code from being autolinked, add the `{.gd-no-link}` class after the backtick span: ```markdown The `Config`{.gd-no-link} parameter is a plain dictionary, not the Config class. ``` This is useful when a word happens to match a documented symbol but you are referring to something else in context. You only need this occasionally; most autolinks are helpful and should be left in place. ## Best Practices for Linking Cross-references make documentation much more navigable, but a few guidelines help keep them useful rather than distracting. Use `%seealso` to connect items that serve complementary roles. If `encode()` and `decode()` are a natural pair, linking them together helps readers discover both. For larger groupings, a brief description after each name (using the colon syntax) gives context about why the link is relevant. Use inline interlinks when you mention another symbol in the middle of a prose explanation. This keeps reading flow natural while still giving readers a path to the referenced page. The shortened form (with `~`) is usually the best choice because fully qualified paths can be long and interrupt the sentence visually. Code autolinks require no effort on your part, since they happen automatically. But be aware that common words like `Config` or `Data` might match a symbol unexpectedly. If you notice unwanted links in the rendered output, add `{.gd-no-link}` to the specific code span. ## Citations & Bibliography Cross-references connect the pages *within* your documentation; citations connect your prose to the work it builds on (e.g., a paper, a specification, a book, etc.). Great Docs supports academic citations and a generated **References** section, driven by a single project-level bibliography. Point `bibliography:` at a `.bib` file (path relative to the project root): ```{.yaml filename="great-docs.yml"} bibliography: docs/references.bib ``` Then cite by key anywhere (no per-page frontmatter required): ```markdown Literate programming was introduced by Knuth [@knuth1984]. ``` That renders as "…by Knuth (Knuth 1984)", linked to a References section. At build time Great Docs copies the `.bib` into the build directory and wires it into the generated `_quarto.yml`, so the bibliography is available to *every* page: User Guide pages, custom sections, the homepage, and even the docstrings that become your API reference. ### Writing citations Citations use standard [Pandoc citation syntax](https://quarto.org/docs/authoring/citations.html#sec-citations). The citation key is the identifier from your `.bib` entry (`knuth1984` above), prefixed with `@`. | You write | Renders as | |-----------|------------| | `[@knuth1984]` | (Knuth 1984) | | `@knuth1984` | Knuth (1984) | | `[@knuth1984; @lamport1994]` | (Knuth 1984; Lamport 1994) | | `[see @knuth1984, pp. 33-35]` | (see Knuth 1984, 33–35) | | `[-@knuth1984]` | (1984) | Wrap a key in square brackets for a parenthetical citation, drop them for an in-text citation where the author becomes part of the sentence, separate multiple keys with semicolons, and add a prefix, locator, or leading `-` to suppress the author. ### The references section When a page contains at least one citation, Great Docs renders a **References** section listing every work cited. By default it appears at the end of the page. To place it somewhere specific, add an empty `#refs` div where you want it: ```markdown ## References ::: {#refs} ::: ``` Quarto fills that div with the reference list instead of appending one at the end, and uses your heading as-is (it won't add a second one). ### Multiple bibliography files Pass a list to combine several `.bib` files; all entries become citable from any page: ```{.yaml filename="great-docs.yml"} bibliography: - docs/references.bib - docs/software.bib ``` ### Citation style By default citations follow the Chicago author-date style. To use a different [CSL](https://citationstyles.org) style, point `csl:` at a `.csl` file (relative to the project root); Great Docs copies it into the build alongside the bibliography. Find styles in the [Zotero Style Repository](https://www.zotero.org/styles). ```{.yaml filename="great-docs.yml"} bibliography: docs/references.bib csl: docs/nature.csl ``` ### Localized headings If your site sets a [language](internationalization.qmd), the auto-generated references heading is localized automatically. So a French site (`site.language: fr`) renders **Les références**, with the entries themselves formatted for that language too. ::: {.callout-note} If citations render as literal `[@key]` text with no References section, the key doesn't match a `.bib` entry or the bibliography wasn't found. So check the key spelling and that `bibliography:` resolves from the project root. A missing file warns (`"Bibliography file not found"`) and the build continues without it. ::: ## Next Steps Cross-references turn a collection of standalone reference pages into a connected web of documentation. Use `%seealso` for structured navigation, interlinks for inline mentions, code autolinks for the rest, and a project-level `bibliography:` to cite external work. - [Writing Docstrings](writing-docstrings.qmd) covers how to write effective docstrings that work well with cross-referencing - [API Documentation](api-documentation.qmd) covers how API discovery and page organization work - [User Guides](user-guides.qmd) explains how to link from User Guide pages to API reference pages - [Internationalization](internationalization.qmd) localizes the References heading and the rest of the UI - [Linting](linting.qmd) can catch broken cross-references during the build ## Build & Deploy # Building & Previewing The `great-docs build` command is the main way you interact with Great Docs on a day-to-day basis. It reads your `great-docs.yml` configuration, discovers your package's API, generates Quarto source files, and renders everything into a static HTML site. This page explains what happens during a build, how to preview your site locally, and how to troubleshoot common issues. ## The Build Pipeline When you run `great-docs build`, the following steps execute in order: 1. The `great-docs/` output directory is created (or refreshed) with all required assets: stylesheets, JavaScript files for dark mode toggling, sidebar filtering, the GitHub stars widget, and other interactive features. 2. Your `great-docs.yml` is read. A `_quarto.yml` file is generated (or updated) in the output directory with the Quarto project configuration, including navbar links, sidebar structure, and theme settings. 3. A landing page (`index.qmd`) is generated from your project's `README.md`. If you have a logo configured, a hero section with the logo, package name, tagline, and badges is added automatically. 4. If a user guide directory exists (by default `user_guide/`), all `.qmd` files are copied into the output directory with numeric prefixes stripped from filenames. The sidebar is organized by `guide-section` frontmatter metadata. 5. If Click CLI documentation is enabled, Great Docs discovers your CLI commands and generates a reference page for each one. 6. Custom sections defined in `great-docs.yml` (examples, tutorials, blog posts, etc.) are processed and copied to the output directory. ::: {.version-only versions=">=0.6"} 7. If `custom_pages` is configured, or if the fallback `custom/` directory exists, custom HTML pages are discovered. Passthrough pages are converted into generated `.qmd` files and raw pages are copied through unchanged. ::: 8. If the changelog is enabled and a GitHub repository URL exists in `pyproject.toml`, GitHub Releases are fetched and a `changelog.qmd` file is generated. 9. The Agent Skills file (`skill.md`) is generated or copied. If you have a curated `SKILL.md` in `skills/<package-name>/`, it is used directly. Otherwise, a skill file is auto-generated from your package metadata. See [Agent Skills](38-agent-skills.qmd) for details. 10. `llms.txt` and `llms-full.txt` files are generated. These provide AI-friendly summaries of your package documentation. See [llms.txt](39-llms-txt.qmd) for details. 11. Source link metadata (`_source_links.json`) is generated, mapping each documented symbol to its file and line numbers on GitHub. 12. Quarto renders all the source files into HTML. A post-render script runs to apply final transformations: injecting source links, processing cross-references (GDLS), cleaning up Sphinx/RST artifacts, and generating companion Markdown (`.md`) files for each page. After all steps complete, the finished site is in `great-docs/_site/`. ## Preview Mode To view your site locally with live reload: ```{.bash filename="Terminal"} great-docs preview ``` This starts a local development server and opens your default browser. When you edit source files (user guide pages, docstrings, configuration), the site rebuilds automatically and the browser refreshes to show your changes. Preview mode is ideal during the writing process because it lets you see how content will look in the final rendered site without committing or deploying anything. ## Build Options The `great-docs build` command accepts several options that control its behavior. ### Watch Mode Watch mode keeps the build process running and automatically rebuilds when files change. This is similar to preview mode but without starting a local server: ```{.bash filename="Terminal"} great-docs build --watch ``` This is useful when you want to rebuild continuously but view the output in a different way (for example, opening the HTML files directly or using a separate static file server). ### Clean Build If you suspect stale files in the output directory are causing issues, you can force a completely fresh build. Delete the `great-docs/` directory and rebuild: ```{.bash filename="Terminal"} rm -rf great-docs/ && great-docs build ``` Since the `great-docs/` directory is ephemeral and fully generated from `great-docs.yml` plus your source files, deleting it is always safe. ## Build Output Structure After a successful build, the output directory has this layout: ```{.default filename="great-docs/"} great-docs/ ├── _quarto.yml # Generated Quarto config ├── index.qmd # Landing page ├── great-docs.scss # Theme stylesheet ├── *.js # Interactive features (dark mode, sidebar, etc.) ├── llms.txt # LLM-friendly summary ├── llms-full.txt # Full API docs for LLMs ├── skill.md # Agent Skills file ├── _source_links.json # GitHub source link metadata ├── reference/ # API reference pages │ ├── index.qmd │ ├── MyClass.qmd │ └── ... ├── user-guide/ # User guide pages (from user_guide/) ├── recipes/ # Recipe pages (from recipes/) ├── scripts/ │ └── post-render.py # HTML post-processing script └── _site/ # Final rendered HTML ├── index.html └── ... ``` The `_site/` subdirectory contains the final HTML output. This is the directory you deploy to your hosting service (GitHub Pages, Netlify, Vercel, etc.). Everything outside of `_site/` is intermediate Quarto source. You generally do not need to inspect these files, but they can be useful for debugging rendering issues. ## Building from a Remote Repository [version-badge new 0.11] {#from-repo} The `--from-repo` flag lets you build documentation for any Git-hosted package without cloning it yourself. Great Docs handles the entire workflow: cloning the repository, creating an isolated virtual environment, installing the package and its dependencies, running the full build pipeline, and copying the finished site to a local directory. ```{.bash filename="Terminal"} great-docs build --from-repo https://github.com/owner/package.git ``` The built site is copied to `./great-docs/_site/` by default. Use `--output-dir` to put it somewhere else: ```{.bash filename="Terminal"} great-docs build --from-repo https://github.com/owner/package.git --output-dir /tmp/my-site ``` ### Branch or Tag By default the repository's default branch is cloned. Use `--branch` to check out a specific branch or tag: ```{.bash filename="Terminal"} great-docs build --from-repo https://github.com/owner/package.git --branch v2.0.0 ``` ### Clone Depth Great Docs inspects the target project's `great-docs.yml` to decide how much Git history to fetch. If the project uses multi-version docs or page dates, a full clone is performed automatically. Otherwise a lightweight tag-only clone is used. Use `--shallow` to force a minimal `--depth 1` clone. This is the fastest option but disables versioned documentation and page dates: ```{.bash filename="Terminal"} great-docs build --from-repo https://github.com/owner/package.git --shallow ``` ### Previewing After Build Add `--preview` to start a local server and open the site in your browser as soon as the build finishes: ```{.bash filename="Terminal"} great-docs build --from-repo https://github.com/owner/package.git --preview ``` ### Previewing a Previously Built Site If you have already built a site with `--from-repo` (or received a site directory from someone else), use `great-docs preview --site-dir` to serve it without any project context: ```{.bash filename="Terminal"} great-docs preview --site-dir /tmp/my-site ``` This starts the same local HTTP server and opens your browser, just like the regular `great-docs preview` command. ## Previewing a PR or CI Build [version-badge new 0.16] {#pr-preview} When someone opens a pull request, reviewing the rendered docs usually means checking out the branch and rebuilding locally, or setting up a preview host (Netlify, Cloudflare Pages, per-PR GitHub Pages). But if your CI already builds and uploads the site as an artifact (as the [recommended workflow](14-deployment.qmd) does) you can fetch that exact build and view it locally (with no hosting setup): ```{.bash filename="Terminal"} great-docs preview --pr 302 # newest CI docs build for PR #302 great-docs preview --run 18273645521 # a specific workflow run great-docs preview --branch fix-mcp # newest build for a branch ``` Great Docs resolves the pull request to its most recent successful docs run, downloads the `docs-html` artifact, caches it locally, and serves it with the usual preview server. ### Authentication Downloading a workflow artifact requires a GitHub token with **Actions: read** (this is true even for public repositories). Great Docs looks for credentials in this order, so pick whichever is convenient: - `GITHUB_TOKEN` or `GH_TOKEN` in your environment - a `.env` file with `GITHUB_TOKEN=...` (auto-detected, or point at one with `--env-file`) - the [`gh`](https://cli.github.com/) CLI: run `gh auth login`, then add `--use-gh` to let `gh` perform the download end-to-end ```{.bash filename="Terminal"} gh auth login great-docs preview --pr 302 --use-gh ``` ::: {.callout-note} Great Docs never accepts a token as a command-line argument (it would leak into your shell history). Use an environment variable, a `.env` file, or `gh` instead. ::: ### Jumping to a specific page Use `--path` to open the browser directly at a page within the site instead of the home page, useful when a review comment is about one specific reference or guide: ```{.bash filename="Terminal"} great-docs preview --pr 302 --path reference/index.html ``` ### Other options | Option | Purpose | | --- | --- | | `--repo owner/repo` | Target a repo explicitly (default: detected from `git remote origin`). | | `--artifact <name>` | Fetch a differently-named artifact (default: `docs-html`). | | `--no-open` | Serve without launching a browser. | | `--refresh` | Ignore the local cache and re-download. | | `--port <n>` | Serve on a specific port. | ::: {.callout-warning} ## Fork pull requests A site built from a fork contains contributor-authored HTML and JavaScript, which your browser will execute when you preview it locally (the same trust level as reviewing their diff). Great Docs warns you when a build comes from a fork. ::: ::: {.callout-tip} ## Advertise it in CI If you scaffolded your CI with [`great-docs setup-github-pages`](14-deployment.qmd), this is already wired up: on every pull request the workflow prints a log notice **and** posts a sticky PR comment with the exact `great-docs preview` command, pinned to that run. To add it to a hand-maintained workflow, use the `great-docs ci` helpers. `ci notice` prints a log annotation; `ci pr-comment` posts (and keeps updated) a sticky comment on the pull request. Both pin the command to the run that produced the build with `--run`, so a reviewer reproduces exactly the build they're looking at: ```{.yaml filename=".github/workflows/docs.yml"} # In the build job (great-docs is already installed): - name: How to preview this build locally if: github.event_name == 'pull_request' run: great-docs ci notice --run ${{ github.run_id }} --pr ${{ github.event.number }} # In a separate job with 'permissions: pull-requests: write': - name: Post preview instructions to the PR run: pipx run great-docs ci pr-comment --run ${{ github.run_id }} --pr ${{ github.event.number }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` ::: ## Using the Python API In addition to the CLI, you can drive the build programmatically: ```{.python filename="Python"} from great_docs import GreatDocs docs = GreatDocs() docs.install() # Initialize the output directory docs.build() # Run the full build pipeline docs.preview() # Start the preview server ``` The `GreatDocs` class accepts a `project_path` argument if your working directory is not the project root: ```{.python filename="Python"} docs = GreatDocs(project_path="/path/to/my-project") docs.install() docs.build() ``` ## Troubleshooting ### Quarto Errors If the build fails during the Quarto rendering step, the error output will include Quarto's own messages. Common causes include: - A `.qmd` file with invalid YAML frontmatter. Check that all frontmatter blocks are enclosed between `---` markers and that the YAML is well-formed. - A reference to a file that does not exist. If you renamed or deleted a user guide page, make sure the `guide-section` frontmatter in other files does not depend on it. - A Quarto version incompatibility. Great Docs is tested with Quarto 1.4 and later. Run `quarto --version` to check your installed version. ### Missing API Reference Pages If some symbols are missing from the rendered API reference, run `great-docs scan` to see what Great Docs discovers. Items that appear in the scan output but not in the reference may be excluded by the `exclude` list in `great-docs.yml` or may not be listed in the `reference` config sections. ### Dynamic Introspection Failures If Great Docs reports an error during dynamic introspection, it will automatically retry with static analysis. If you see this retry message frequently, you can set `dynamic: false` in `great-docs.yml` to skip the dynamic pass entirely. See [Configuration](configuration.qmd) for details. ### Stale Output If your site looks correct in some places but outdated in others, the most reliable fix is a clean rebuild: delete the `great-docs/` directory and run `great-docs build` again. The output directory is fully regenerated each time, so there is no risk in deleting it. ## Build Timings [version-badge new 0.12] {#build-timings} Every time `great-docs build` runs, it records how long each page takes to render and writes the results to `great-docs/_site/build-timings.json`. This helps you identify slow pages that are bottlenecks in your build. ### Viewing Timings Use the `great-docs timings` command to display a sorted table (slowest pages first): ```{.bash filename="Terminal"} great-docs timings ``` ```{.default} Build time: 2026-05-06 14:32:01 Total: 47.2s across 38 pages Page Time ───────────────────────────────────────────────── reference/GT.qmd 12.4s ████████████ reference/GT.tab_style.qmd 6.1s ██████ user-guide/theming.qmd 4.8s █████ reference/GT.fmt_number.qmd 3.9s ████ ... ``` Pages served from the [Quarto freeze cache](freeze.qmd) are marked with a ❄ indicator. This view makes it easy to spot which pages are worth optimizing or splitting up. ### Filtering Results Show only the top N slowest pages: ```{.bash filename="Terminal"} great-docs timings --top 5 ``` For multi-version builds, filter by version: ```{.bash filename="Terminal"} great-docs timings --version 0.10 ``` These filters are useful when you only care about a specific slice of the build. ### Custom Output Directories If you built with a custom `--output-dir`, pass the same path: ```{.bash filename="Terminal"} great-docs timings --output-dir ./public ``` This ensures the command can locate `build-timings.json` regardless of where the site was rendered. ### JSON Output For scripting or CI integration, use `--json` to get the raw data: ```{.bash filename="Terminal"} great-docs timings --json ``` The JSON format is convenient for piping into other tools like `jq` or for building custom dashboards. ### CI Integration The `great-docs setup-github-pages` workflow automatically uploads `build-timings.json` as a separate artifact named **build-timings** in each CI run. You can download it from the workflow run's Artifacts section on GitHub to compare build performance over time. This makes it easier to track regressions and monitor improvements across commits. ## Next Steps The build pipeline is designed to be fast and predictable. For most projects, `great-docs build` is really all you need. When something goes wrong, the troubleshooting tips above probably cover the most common causes. - [Deployment](deployment.qmd) covers publishing your built site to GitHub Pages - [Configuration](configuration.qmd) covers all `great-docs.yml` options - [Link Checker](link-checker.qmd) explains how to validate links across your site # Deployment Great Docs makes it easy to publish your documentation to GitHub Pages with automatic builds on every push. ## Quick Setup Deploy to GitHub Pages with a single command: ```{.bash filename="Terminal"} great-docs setup-github-pages ``` This creates a complete GitHub Actions workflow at `.github/workflows/docs.yml`. ## What the Workflow Does The generated workflow includes three jobs: ### 1. Build Documentation - Checks out your repository - Sets up Python and Quarto - Installs dependencies (with caching) - Runs `great-docs build` - Uploads the built site as an artifact ### 2. Publish to GitHub Pages - Downloads the built artifact - Deploys to GitHub Pages - Only runs on pushes to your main branch ### 3. Preview for Pull Requests - Creates preview deployments for PRs - Lets reviewers see documentation changes before merging ## Enabling GitHub Pages After generating the workflow: 1. **Commit and push** the workflow file: ```{.bash filename="Terminal"} git add .github/workflows/docs.yml git commit -m "Add documentation workflow" git push ``` 2. **Enable GitHub Pages** in your repository: - Go to **Settings → Pages** - Set **Source** to `GitHub Actions` 3. **Trigger a build** by pushing to your main branch Your documentation will be published at: ``` https://[username].github.io/[repository]/ ``` ## Customization Options ### Different Main Branch ```{.bash filename="Terminal"} great-docs setup-github-pages --main-branch develop ``` ### Different Python Version ```{.bash filename="Terminal"} great-docs setup-github-pages --python-version 3.12 ``` ### Combined Options ```{.bash filename="Terminal"} great-docs setup-github-pages \ --main-branch develop \ --python-version 3.12 ``` ### Force Overwrite ```{.bash filename="Terminal"} great-docs setup-github-pages --force ``` ## Generated Workflow Here's what the generated workflow looks like: ```{.yaml filename=".github/workflows/docs.yml"} name: Documentation on: push: branches: [main] pull_request: branches: [main] jobs: build-docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Set up Python uses: actions/setup-python@v6 with: python-version: '3.11' - name: Set up Quarto uses: quarto-dev/quarto-actions/setup@v2 - name: Install dependencies run: | pip install great-docs pip install -e . - name: Build documentation run: great-docs build - name: Upload artifact uses: actions/upload-pages-artifact@v5 with: path: great-docs/_site include-hidden-files: true publish-docs: needs: build-docs if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest permissions: pages: write id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v5 ``` ## Manual Deployment If you prefer to deploy manually or use a different hosting service: ### Build Locally ```{.bash filename="Terminal"} great-docs build ``` ### Upload the Built Site The built site is in `great-docs/_site/`. Upload this directory to your hosting service: - **Netlify**: Drag and drop `great-docs/_site/` folder - **Vercel**: Point to `great-docs/_site` as output directory - **AWS S3**: Sync the `great-docs/_site/` folder to your bucket - **Any static host**: Copy contents of `great-docs/_site/` ## Subdirectory Deployments If your site is hosted at a subpath rather than a domain root (for example, `https://internal.example.com/docs/mypackage/`), you need to tell Quarto the base URL so it generates correct root-relative paths for CSS, JS, and navigation links. Set `site_url` in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} site_url: "https://internal.example.com/docs/mypackage/" ``` This writes `website.site-url` into the generated `_quarto.yml` during every build, so you never have to patch the config manually. ### What it fixes Without `site_url`, Quarto generates root-relative asset paths like `/site_libs/...` and `/reference/...`. When the site lives at a subpath, those paths resolve to the wrong location and the site appears broken (missing styles, broken navigation, 404s on the reference section, etc.). ### Versioned sites For multi-version builds, Great Docs automatically appends the version prefix to `site-url` for non-latest versions. If your `site_url` is: ``` https://internal.example.com/docs/mypackage/ ``` then version `0.2` (served at `/v/0.2/`) will use: ``` https://internal.example.com/docs/mypackage/v/0.2/ ``` No extra configuration is needed. ### When you don't need it If you deploy to a domain root (e.g., `https://yourpackage.github.io/` or a custom domain), you do not need to set `site_url`. Quarto's defaults work correctly in that case. ## Custom Domain To use a custom domain with GitHub Pages: 1. Add a `CNAME` file to your project root (it will be copied during build): ```{.default filename="CNAME"} docs.example.com ``` 2. Configure DNS with your domain registrar: - Add a CNAME record pointing to `[username].github.io` 3. In GitHub repository settings: - Go to **Settings → Pages** - Enter your custom domain - Enable "Enforce HTTPS" ## Troubleshooting ### Build Fails Check the GitHub Actions logs for errors. Common issues: - **Missing dependencies**: Ensure your `pyproject.toml` lists all dependencies - **Quarto version**: The workflow uses the latest Quarto; ensure compatibility - **Python version**: Make sure your code works with the specified Python version ### Pages Not Updating If your documentation seems stuck on an old version, there are several things to check. First, verify the workflow completed successfully in the Actions tab. Then confirm that your GitHub Pages source is set to "GitHub Actions" in repository settings. Sometimes it's simply browser caching. Try clearing your cache or viewing in incognito mode. ### Preview Not Working Pull request previews need a few things to be in place. The workflow must complete successfully, your repository needs appropriate permissions configured, and the `actions/deploy-pages` action must be allowed in your organization settings. Check each of these if previews aren't appearing on your PRs. ## Best Practices ### Keep Documentation in Sync Run `great-docs build` locally before pushing to catch errors early: ```bash great-docs build && open great-docs/_site/index.html ``` ### Use Pull Request Previews Review documentation changes in PRs before merging. This catches: - Broken links - Formatting issues - Missing content ### Version Your Documentation For versioned documentation, consider: - Separate branches for major versions - Using tools like `mike` for version switching - Tagging releases with corresponding docs ## Next Steps With Great Docs and GitHub Pages, you get automatic builds on every push, preview deployments for pull requests, zero-maintenance hosting, custom domain support, and HTTPS out of the box. Your documentation stays in sync with your code automatically. - [Building & Previewing](building.qmd) covers the full build pipeline and local preview - [Configuration](configuration.qmd) covers all `great-docs.yml` options - [SEO Optimization](seo.qmd) explains how to improve your site's search visibility ## Quality & Maintenance # Link Checker Great Docs includes a built-in link checker that scans your documentation and source code for broken links. This helps maintain the quality of your documentation by catching dead links before they frustrate your users. ## Quick Start Check all links in your project: ```{.bash filename="Terminal"} great-docs check-links ``` The command scans both your documentation files (`.qmd`, `.md`) and Python source code for URLs, then checks each one for validity. ## What Gets Checked The link checker extracts URLs from: - **Documentation files**: All `.qmd` and `.md` files in your docs directory - **Source code**: Python files in your package directory (docstrings, comments, string literals) - **README**: Your project's `README.md` file Each URL is checked with an HTTP HEAD request (falling back to GET if needed) to verify it returns a successful status code. ## Understanding the Output The link checker categorizes URLs into four groups: ### ✅ OK (2xx responses) Links that return successful HTTP status codes (200-299). These are working correctly. ### ⚠️ Redirects (3xx responses) Links that redirect to another URL. While these still work, you may want to update them to point directly to the final destination: ``` ⚠️ 301 https://old-url.com → https://new-url.com ``` ### ❌ Broken (4xx/5xx responses) Links that return error status codes. These need to be fixed: ``` ❌ 404 https://example.com/deleted-page (Not Found) ❌ 500 https://example.com/broken (Server Error) ``` ### ⏭️ Skipped Links that match ignore patterns and weren't checked. ## Command Options ### Check Only Documentation Skip source code and only check documentation files: ```{.bash filename="Terminal"} great-docs check-links --docs-only ``` ### Check Only Source Code Skip documentation and only check Python source files: ```{.bash filename="Terminal"} great-docs check-links --source-only ``` ### Verbose Output See progress for every URL being checked: ```{.bash filename="Terminal"} great-docs check-links --verbose ``` ### Custom Timeout Adjust the timeout for slow servers (default is 10 seconds): ```{.bash filename="Terminal"} great-docs check-links --timeout 5 ``` ### JSON Output Get results in JSON format for CI/CD integration: ```{.bash filename="Terminal"} great-docs check-links --json-output ``` ### Ignore Patterns Skip URLs matching specific patterns: ```{.bash filename="Terminal"} great-docs check-links -i "internal.company.com" -i "localhost" ``` Patterns can be literal strings or regular expressions: ```{.bash filename="Terminal"} # Ignore all GitHub anchor links great-docs check-links -i "github.com/.*#" # Ignore version-specific URLs great-docs check-links -i "docs\.example\.com/v\d+" ``` ## Default Ignore Patterns The link checker automatically skips certain URLs that are commonly used as examples or placeholders: | Pattern | Description | |---------|-------------| | `localhost` | Local development servers | | `127.0.0.1` | Local IP addresses | | `example.com` | RFC 2606 reserved domain | | `example.org` | RFC 2606 reserved domain | | `yoursite.com` | Common placeholder | | `YOUR-USERNAME` | GitHub template placeholder | | `[...]` | Bracket placeholders like `[username]` | | `.git@` or `.git$` | Git repository URLs with branches | ## Excluding URLs in Documentation In `.qmd` files, you can mark specific URLs for exclusion by adding `{.gd-no-link}` immediately after the URL. ```markdown Visit http://fake-example.com{.gd-no-link} for a placeholder example. See https://yoursite.com/api/endpoint{.gd-no-link} for the API format. ``` This is useful for: - **Example URLs** that are intentionally fake - **Template URLs** showing a pattern users should customize - **Placeholder URLs** in code examples The `{.gd-no-link}` directive uses Quarto's attribute syntax but doesn't render any visible styling (it simply tells the link checker to skip that URL). ::: {.callout-note} The `{.gd-no-link}` directive only works in `.qmd` files. For `.md` files or source code, use the `--ignore` command-line option instead. ::: ## Python API You can also use the link checker programmatically: ```python from great_docs import GreatDocs docs = GreatDocs() results = docs.check_links( include_source=True, include_docs=True, timeout=10.0, ignore_patterns=["localhost", "example.com"], verbose=False, ) print(f"Total links: {results['total']}") print(f"OK: {len(results['ok'])}") print(f"Redirects: {len(results['redirects'])}") print(f"Broken: {len(results['broken'])}") print(f"Skipped: {len(results['skipped'])}") # Handle broken links for item in results['broken']: print(f"Broken: {item['url']} - {item['error']}") # Handle redirects for item in results['redirects']: print(f"Redirect: {item['url']} → {item['location']}") ``` ### Return Value The `check_links()` method returns a dictionary with: | Key | Type | Description | |-----|------|-------------| | `total` | `int` | Total unique URLs found | | `ok` | `list[str]` | URLs returning 2xx status | | `redirects` | `list[dict]` | URLs returning 3xx status (with `url`, `status`, `location`) | | `broken` | `list[dict]` | URLs returning 4xx/5xx or errors (with `url`, `status`, `error`) | | `skipped` | `list[str]` | URLs matching ignore patterns | | `by_file` | `dict[str, list[str]]` | Mapping of file paths to URLs found in each | ## CI/CD Integration ### Exit Codes The `check-links` command returns: - **Exit code 0**: All links are valid (or only redirects/skipped) - **Exit code 1**: One or more broken links found This makes it easy to fail CI builds when broken links are detected. ### GitHub Actions Example Add link checking to your documentation workflow: ```yaml name: Check Documentation Links on: push: branches: [main] pull_request: branches: [main] schedule: # Run weekly to catch external link rot - cron: '0 0 * * 0' jobs: check-links: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Set up Python uses: actions/setup-python@v6 with: python-version: '3.11' - name: Install dependencies run: | pip install great-docs - name: Check links run: | great-docs check-links --docs-only --timeout 15 ``` ### Scheduled Checks External links can break over time ("link rot"). Consider running the link checker on a schedule to catch these issues: ```yaml on: schedule: # Every Sunday at midnight - cron: '0 0 * * 0' ``` ## Tips and Best Practices ### Start with Documentation Only If your source code has many URLs (e.g., in comments or docstrings), start by checking just documentation: ```{.bash filename="Terminal"} great-docs check-links --docs-only ``` ### Use Verbose Mode for Debugging When troubleshooting, verbose mode shows you exactly what's being checked: ```{.bash filename="Terminal"} great-docs check-links --verbose ``` ### Handle Rate Limiting Some websites rate-limit requests. If you're getting false positives, try: 1. Increasing the timeout: `--timeout 30` 2. Running the check less frequently in CI 3. Ignoring specific domains: `-i "api.example.com"` ### Fix Redirects Proactively While redirects still work, they: - Add latency for users clicking links - May eventually break if the redirect is removed - Indicate outdated references Update redirected links to point to their final destinations when practical. ### Document Intentional Placeholder URLs When using fake URLs in examples, mark them with `{.gd-no-link}` to make your intent clear and prevent false positives: ```markdown Replace `https://your-api.com/endpoint`{.gd-no-link} with your actual API URL. ``` ## Next Steps The link checker catches broken references before your readers do. Run it locally during development and in CI before every deploy to keep your documentation reliable. - [Proofreading](proofreading.qmd) checks spelling, grammar, and style across your documentation - [Docs Linting](linting.qmd) validates docstring directives, cross-references, and structural issues - [Building & Previewing](building.qmd) covers the full build pipeline ### Proofreading Good documentation requires accurate spelling and grammar. Great Docs includes a proofreading command that checks your documentation for spelling mistakes, grammar issues, and common writing problems using [Harper](https://github.com/Automattic/harper), a fast, privacy-focused grammar checker that runs entirely on your machine. ## Installing Harper The proofreader requires Harper to be installed separately. It's a single binary with no dependencies: ::: {.panel-tabset} ### macOS (Homebrew) ```bash brew install harper ``` ### Any Platform (Cargo) ```bash cargo install harper-cli ``` ### Manual Download Download pre-built binaries from the [Harper releases page](https://github.com/Automattic/harper/releases). ::: Verify the installation: ```bash harper-cli --version ``` ## What Gets Checked The proofreader scans all `.qmd` and `.md` files in your documentation site directory. It automatically skips: - **Fenced code blocks** - Content between ` ``` ` markers - **YAML frontmatter** - Content between `---` markers at the start of files Inline code (backticked text) is checked for typos. ## Basic Usage Run the proofreader from your project directory: ```bash great-docs proofread ``` This checks all documentation files and reports any issues found. By default, rules that tend to produce false positives in technical documentation are disabled. ## Filtering by File Check specific files or patterns: ```bash # Check one file great-docs proofread user-guide/getting-started.qmd # Check all files in a directory great-docs proofread recipes/ ``` ## Custom Dictionary ### Adding Words on the Command Line For project-specific terminology, add custom words using `-d`: ```bash great-docs proofread -d "griffe" -d "pkgdown" -d "navbar" ``` ### Built-in Technical Dictionary Great Docs includes a built-in dictionary of common technical terms (API, CLI, PyPI, navbar, docstring, etc.) that are automatically accepted. To disable this: ```bash great-docs proofread --no-builtin-dictionary ``` ## Strict Mode The default settings skip rules that often produce false positives in technical writing. To enable all Harper rules: ```bash great-docs proofread --strict ``` This is useful for final polishing or when writing prose-heavy content like blog posts. ## Spelling-Only or Grammar-Only Focus on just one type of check: ```bash # Only spelling errors great-docs proofread --spelling-only # Only grammar issues great-docs proofread --grammar-only ``` ## English Dialect Harper supports different English dialects. The default is American English: ```bash great-docs proofread --dialect British ``` Available dialects: `American` (default), `British`, `Australian`, `Canadian`. ## Output Formats ### Default Output The default output groups issues by file with context: ``` user-guide/getting-started.qmd: Line 12: "recieve" - Did you mean "receive"? Line 45: Consider using "use" instead of "utilize" ``` ### Compact Output For a condensed one-line-per-issue format: ```bash great-docs proofread --compact ``` ### JSON Output For programmatic processing or CI integration: ```bash great-docs proofread --json-output ``` ## CI/CD Integration ### GitHub Actions Add proofreading to your CI workflow: ```{.yaml filename=".github/workflows/docs.yml"} name: Documentation on: push: branches: [main] pull_request: branches: [main] jobs: proofread: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Install Harper run: cargo install harper-cli - name: Set up Python uses: actions/setup-python@v6 with: python-version: '3.12' - name: Install dependencies run: pip install great-docs - name: Proofread documentation run: great-docs proofread ``` ### Pre-commit Hook Add proofreading as a pre-commit hook: ```{.yaml filename=".pre-commit-config.yaml"} repos: - repo: local hooks: - id: proofread name: Proofread Documentation entry: great-docs proofread language: system types: [markdown] pass_filenames: false ``` ## Exit Codes | Code | Meaning | |------|---------| | 0 | No issues found | | 1 | Issues found or error occurred | ## Default Ignored Rules By default, these Harper rules are disabled because they frequently trigger on valid technical documentation patterns: - **Spacing rules** - Technical docs often have unconventional spacing around operators and in code - **Capitalization rules** - Many technical terms have specific capitalization (macOS, iOS) - **Compound word rules** - Technical terms like navbar, frontend, codebase are flagged as compounds - **Punctuation rules** - Quote marks and dashes in code examples differ from prose conventions Use `--strict` to enable all rules. ## Best Practices 1. **Install Harper in CI** - Use `cargo install harper-cli` in your workflow 2. **Run proofread in CI** to catch issues before they reach production 3. **Use `--strict` sparingly** - Default settings are tuned for technical docs 4. **Add project-specific terms** with `-d` for domain-specific vocabulary 5. **Combine with link checking** for comprehensive documentation QA: ```bash great-docs check-links && great-docs proofread ``` ## Programmatic Usage You can also use the proofreader programmatically: ```python from great_docs import GreatDocs docs = GreatDocs() # Basic proofread results = docs.proofread() for file_result in results: if file_result.issues: print(f"{file_result.file}: {len(file_result.issues)} issues") # With custom dictionary results = docs.proofread( custom_words=["griffe", "pkgdown"], ) # Strict mode (all rules enabled) results = docs.proofread(strict=True) # Process results for file_result in results: for issue in file_result.issues: print(f"Line {issue.line}: {issue.message}") if issue.suggestions: print(f" Suggestions: {issue.suggestions[:3]}") ``` ## Next Steps Proofreading catches the small errors that accumulate over time: misspellings, repeated words, and style inconsistencies. Run it alongside the link checker and linter to keep your documentation polished. - [Link Checker](link-checker.qmd) validates that all links in your documentation resolve correctly - [Docs Linting](linting.qmd) checks docstring directives, cross-references, and structural issues - [Configuration](configuration.qmd) covers custom dictionaries and proofreading settings in `great-docs.yml` # Changelog Users want to know what changed between versions, whether that's new features, bug fixes, or breaking changes. A well-maintained changelog builds trust and helps people decide when to upgrade. But keeping a separate changelog file in sync with your actual releases is tedious and error-prone. Great Docs solves this by automatically generating a Changelog page from your GitHub Releases. Each published release becomes a section on the page, with its title, date, body content, and a link back to the release on GitHub. If you keep your release notes up to date on GitHub, your documentation site reflects them without any extra work. ## How It Works When changelog generation is enabled (the default), `great-docs build` will: 1. **Detect your GitHub repository**: reads the `Repository` URL from `[project.urls]` in `pyproject.toml` 2. **Fetch releases**: calls the GitHub Releases API to retrieve published releases 3. **Generate the page**: writes a `changelog.qmd` file in the build directory with one section per release 4. **Add a navbar link**: adds a "Changelog" item to the site's top navigation bar The result is a fully rendered Changelog page that stays in sync with your GitHub Releases. No manual maintenance is needed, and the page is regenerated on every build. ## Prerequisites For changelog generation to work, Great Docs needs to know where your repository lives. Your `pyproject.toml` must include a `Repository` URL pointing to GitHub: ```{.toml filename="pyproject.toml"} [project.urls] Repository = "https://github.com/your-org/your-package" ``` If no GitHub URL is found, the changelog step is silently skipped and the build continues normally. ## Configuration The changelog works out of the box with sensible defaults. You only need to add a `changelog` section to `great-docs.yml` if you want to change the behavior: ```{.yaml filename="great-docs.yml"} changelog: enabled: true # Enable/disable changelog (default: true) max_releases: 50 # Maximum releases to include (default: 50) ``` ### Disabling the Changelog If you don't want a changelog page at all: ```{.yaml filename="great-docs.yml"} changelog: enabled: false ``` ### Limiting Releases For projects with many releases, you can cap how many appear: ```{.yaml filename="great-docs.yml"} changelog: max_releases: 20 ``` Releases are shown in reverse chronological order (newest first), so older releases are the ones omitted. ## Authentication The GitHub API allows unauthenticated requests but with a low rate limit (60 requests/hour). For most projects this is sufficient because the changelog is only fetched once per build. If you hit rate limits (particularly in CI environments with many concurrent builds), set a GitHub token: ```{.bash filename="Terminal"} export GITHUB_TOKEN=ghp_your_token_here ``` Great Docs checks for `GITHUB_TOKEN` or `GH_TOKEN` environment variables and uses whichever is set. A token raises the rate limit to 5,000 requests/hour. ::: {.callout-tip} ## GitHub Actions In GitHub Actions workflows, `GITHUB_TOKEN` is already available automatically. No extra setup is needed. ::: ## Standalone CLI Command You can generate the changelog independently of a full build. This is useful for testing your release notes formatting or regenerating just the changelog without rebuilding the entire site: ```{.bash filename="Terminal"} great-docs changelog ``` You can also override the max releases: ```{.bash filename="Terminal"} great-docs changelog --max-releases 10 ``` The output is written to the build directory, just as it would be during a full `great-docs build`. ## What Gets Included Not all GitHub Releases appear on the changelog page. Here is how each release type is handled: - **Published releases**: shown with their title, date, and body - **Pre-releases**: included but marked with a "(Pre-release)" badge - **Draft releases**: excluded (they aren't public yet) The release body is rendered as Markdown, so any formatting, lists, headings, or code blocks in your GitHub Release notes carry through to the documentation site. This means the changelog page looks just as rich as your release notes on GitHub. ## Generated Output The generated `changelog.qmd` page includes: - A title ("Changelog") and table of contents - An introductory line linking to the full GitHub Releases page - One `##` section per release, containing: - The release name as the heading - A metadata line with the publication date and a "View on GitHub" link - The full release body as Markdown Here's an example of what a section looks like: ```markdown ## Version 2.0.0 *2026-01-15* · [View on GitHub](https://github.com/org/pkg/releases/tag/v2.0.0) ### What's New - Added feature X - Improved performance of Y ### Breaking Changes - Removed deprecated `old_function()` ``` The page is self-contained: readers can browse all release notes in one place without leaving your documentation site. ## Edge Cases Great Docs is designed to handle common failure scenarios gracefully. The changelog is never a hard failure; the build always completes successfully. | Scenario | Behavior | |---|---| | No GitHub URL in `pyproject.toml` | Changelog step is skipped silently | | Repository exists but has no releases | No `changelog.qmd` is created; build continues normally | | GitHub API rate limit reached | Warning printed; partial results used if any were already fetched | | GitHub API returns 404 | Warning printed; changelog skipped | | Network error | Warning printed; changelog skipped | ## Next Steps The changelog is fully automatic: Great Docs fetches your GitHub Releases, formats them into a navigable page, and regenerates it on every build. If you keep your release notes up to date on GitHub, your documentation site reflects them without any extra work. - [Community Files](community-files.qmd) covers other auto-detected files like `CONTRIBUTING.md` and `ROADMAP.md` - [Deployment](deployment.qmd) covers publishing your docs (including the changelog) to GitHub Pages - [Link Checker](link-checker.qmd) validates that changelog links to GitHub are not broken - [Configuration](configuration.qmd) covers all available `great-docs.yml` options # Community Files Open-source projects rely on more than just code. Files like `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, and `SECURITY.md` set expectations for how people participate in and interact with a project. Most projects already have these files, but they often sit in the repository root where casual users never see them. Great Docs automatically detects these standard community files and turns them into styled pages on your documentation site. Each detected file gets its own page and a link in the **Community** section of the homepage's right sidebar. No configuration is needed. If the file exists, it becomes part of your site. ## Supported Files Great Docs recognizes the following community files: | File | Generated Page | Sidebar Link | |------|---------------|--------------| | `CONTRIBUTING.md` | `contributing.qmd` | "Contributor guidelines" | | `CODE_OF_CONDUCT.md` | `code-of-conduct.qmd` | "Code of conduct" | | `ROADMAP.md` [version-badge new 0.2] | `roadmap.qmd` | "Project roadmap" | | `SECURITY.md` [version-badge new 0.3] | `security.qmd` | "Security policy" | | `CITATION.cff` | `citation.qmd` | "Citing *package*" | These files follow the common conventions used by most open-source projects, so if you already have them, they'll work automatically. ## How It Works During `great-docs build`, each community file goes through a simple pipeline: 1. **Detects the file** in your project root (and `.github/` as a fallback) 2. **Strips the title** by removing the first `# ` heading line (since Great Docs adds its own title via frontmatter) 3. **Generates a `.qmd` file** in the build directory with appropriate frontmatter 4. **Adds a sidebar link** in the Community section of the homepage's right margin ::: {.callout-tip} ## Community file locations GitHub accepts `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, and `SECURITY.md` in your project root, `docs/`, or `.github/`. Great Docs searches only the project root and `.github/`, in that order. Both locations work without configuration. Great Docs generates `contributing.qmd`, `code-of-conduct.qmd`, and `security.qmd` from the files it finds, then links them from the homepage. Link to these generated pages instead of embedding the source files in another page. An include such as `{{{< include "../../../.github/CONTRIBUTING.md" >}}}` depends on the build directory's depth. ::: The original Markdown content is preserved, so any formatting, images, or links in your community files carry through to the documentation site. The generated `.qmd` files are recreated on every build, so changes to the source files are always picked up. ## Example To see how everything comes together, consider a project with these files: ``` my-package/ ├── .github/ │ └── SECURITY.md ├── CONTRIBUTING.md ├── CODE_OF_CONDUCT.md ├── ROADMAP.md ├── great-docs.yml └── pyproject.toml ``` Will produce a homepage sidebar like: ``` Community ├── Contributor guidelines ├── Code of conduct ├── Project roadmap ├── Security policy ``` Clicking any link navigates to the corresponding page. If any of these files are missing, the corresponding link is simply omitted. ## ROADMAP.md [version-badge new 0.2] A `ROADMAP.md` file communicates your project's future direction to users and contributors. This helps potential contributors understand where they can have the most impact and gives users confidence that the project is actively maintained. Common sections include: - **In Progress**: features currently being developed - **Near Term**: planned for the next release cycle - **Medium Term**: targeted for upcoming major versions - **Long Term**: aspirational features on the horizon ### Example Structure ```markdown # Roadmap A summary of planned features and improvements. ## In Progress ### Feature Name Brief description... ## Near Term ### Feature Name Brief description... ## Long Term ### Feature Name Brief description... ``` ::: {.callout-tip} ## Keep it forward-looking Focus on unshipped features. Shipped features are better documented in your Changelog (auto-generated from GitHub Releases) or release notes. ::: ## CONTRIBUTING.md A clear `CONTRIBUTING.md` lowers the barrier for new contributors. Without one, people who want to help may not know where to start or what process to follow. Common sections include: - development setup instructions - how to run tests - code style guidelines - pull request process - issue reporting guidelines ### Example Structure ```markdown # Contributing We welcome contributions! Here's how to get started. ## Development Setup 1. Clone the repo 2. Install dependencies: `pip install -e ".[dev]"` 3. Run tests: `pytest` ## Pull Request Process 1. Fork the repo and create a branch 2. Make your changes with tests 3. Submit a PR describing your changes ``` ## SECURITY.md [version-badge new 0.3] A `SECURITY.md` file tells users how to responsibly report security vulnerabilities. Without one, people who discover a vulnerability may open a public issue, exposing the problem before a fix is available. GitHub also recognizes this file and displays it under the **Security** tab of your repository. Great Docs looks for `SECURITY.md` in two locations (in order): 1. project root (`SECURITY.md`) 2. `.github/` directory (`.github/SECURITY.md`) ### Example Structure ```markdown # Security Policy ## Reporting a Vulnerability Please do not open a public issue. Instead, use the Report a vulnerability function on the Security tab. Your report should include: - a clear description of the vulnerability - steps to reproduce the issue - any relevant code snippets or proof-of-concept ## Coordinated Disclosure Once confirmed, we will notify you before public disclosure and credit you in the release notes. ``` ### Disabling the Security Page To detect `SECURITY.md` but not generate a page for it, set `show_security: false` in `great-docs.yml`: ```yaml site: show_security: false ``` ## CODE_OF_CONDUCT.md A code of conduct sets expectations for community behavior and signals that your project takes a welcoming environment seriously. Most projects adopt a standard like the [Contributor Covenant](https://www.contributor-covenant.org/) rather than writing one from scratch. ### Using the Contributor Covenant Download version 2.1 from the official site: ```bash curl -o CODE_OF_CONDUCT.md https://www.contributor-covenant.org/version/2/1/code_of_conduct/code_of_conduct.md ``` Then customize the contact email at the bottom of the file. ## CITATION.cff If your project has a `CITATION.cff` file, Great Docs generates a dedicated citation page (`citation.qmd`) and adds a "Citing *package*" link to the Community sidebar. The generated page includes a formatted author list, a text citation, and a BibTeX entry, all derived from the structured data in the CFF file. The `CITATION.cff` file is only used for the citation page. Author information displayed elsewhere on the site (such as the Developers section of the homepage sidebar) comes from `great-docs.yml` first, with `pyproject.toml` as a fallback. ### Example Structure ```{.yaml filename="CITATION.cff"} cff-version: 1.2.0 title: "My Package" message: "If you use this software, please cite it as below." type: software authors: - family-names: Smith given-names: Jane orcid: "https://orcid.org/0000-0002-1234-5678" version: 1.0.0 date-released: "2025-06-15" license: MIT repository-code: "https://github.com/example/my-package" ``` If a `repository-code` or `url` field is present, the citation page links back to the `CITATION.cff` file on GitHub. ## `.github/` Directory Fallback For `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, and `SECURITY.md`, Great Docs checks the `.github/` directory if the file isn't found in the project root. This matches GitHub's own convention for repository-level community health files, so projects that follow the GitHub standard layout work without changes. ## Fallback Behavior If a community file doesn't exist, the build continues without error. The corresponding link simply won't appear in the sidebar. You can add community files at any time and they'll be automatically detected on the next build. This means you can introduce community files gradually as your project matures. ## Package Info In addition to community files, Great Docs automatically generates a **Package Info** page that displays your package's declared dependencies. This page surfaces important metadata about what your package requires to run and what optional components are available. ### What It Shows The Package Info page includes: - runtime Dependencies: packages required to use your library (from `dependencies` in `pyproject.toml`) - optional Dependencies: extra packages grouped by feature (from `optional-dependencies`) - version Constraints: specifier ranges for each package (e.g., `>=1.24`, `>=2.0,<3.0`) - environment Markers: platform or Python version constraints (e.g., `python_version<'3.12'`) - last Published: the latest release date of each dependency on PyPI - PyPI Link: direct links to the PyPI page for each package Dependencies are presented in tables with one group per optional dependency set (e.g., `dev`, `docs`, `test`). ### Configuration The Package Info page is enabled by default. To disable it, add to `great-docs.yml`: ```{.yaml filename="great-docs.yml"} package_info_page: false ``` ### Accessing the Page The Package Info page is accessible via a "Package Info" link in the **Meta** section of the homepage sidebar (next to "Requires", "Provides-Extra", and "Site Tags"). The page is located at `package-info.html` and is also included in your site's navigation and search index. ### When To Use It This feature is useful for: - users evaluating your package's compatibility with their environment - CI/CD pipelines checking dependency requirements - developers understanding what optional features are available - dependency scanners and compliance tools ## Next Steps Community files give your project a professional, welcoming presence without any configuration. Adding a `CONTRIBUTING.md` or `CODE_OF_CONDUCT.md` to your repository is all it takes to get a styled page in your documentation site. - [Changelog](changelog.qmd) covers auto-generating a changelog from GitHub Releases - [Linting](linting.qmd) helps you catch broken links and other issues in community file pages - [SEO & Metadata](seo.qmd) explains how community pages are included in site metadata - [Configuration](configuration.qmd) covers all `great-docs.yml` options ## Site Content # Diagrams Some concepts are hard to explain with words alone. Architecture diagrams, workflow charts, and sequence diagrams communicate structure and flow far more effectively than prose. But maintaining diagrams as image files is fragile: they go out of date, they're hard to diff in version control, and they require external tools to edit. Great Docs supports two text-based diagram languages, both authored directly in fenced code blocks so your diagrams live alongside your prose in version control and update just as easily: - **[D2](https://d2lang.com)**: a modern diagramming language with a clean syntax and polished output. Great Docs renders D2 diagrams at build time into crisp SVGs, with separate light and dark versions that match your site's theme. - **[Mermaid](https://mermaid.js.org/)**: a widely used diagram language rendered in the browser, supporting flowcharts, sequence, class, state, Gantt, and pie charts. Both work seamlessly in light and dark mode, automatically adapting their colors for readability. ## D2 Diagrams [D2](https://d2lang.com) ("Declarative Diagramming") turns a concise text description into a polished diagram. Great Docs renders D2 blocks **at build time** using the `d2` command-line tool, producing a self-contained SVG for each diagram. ### Prerequisites D2 rendering requires the `d2` binary on your `PATH`. Install it once: ```bash # macOS (Homebrew) brew install d2 # or the official install script (macOS / Linux) curl -fsSL https://d2lang.com/install.sh | sh -s -- ``` See the [D2 install guide](https://d2lang.com/tour/install) for other platforms. If `d2` is not installed, Great Docs leaves the code block untouched and prints a warning, so builds never fail because of a missing binary (they simply skip diagram rendering until `d2` is available). ### Basic Usage To add a D2 diagram, use a fenced code block with `{d2}` as the language identifier: ````markdown ```{d2} Start -> Decision Decision -> Action: Yes Decision -> End: No ``` ```` This renders as: ```{d2} Start -> Decision Decision -> Action: Yes Decision -> End: No ``` Connections use `->` (or `<->`, `<-`, `--`), and text after a colon labels the connection. Declaring a shape is as simple as naming it. ### Shapes and Containers D2 supports a rich set of shapes and lets you nest related nodes inside containers using dot notation. Containers are ideal for grouping the pieces of a subsystem: ```{d2} build: Build Pipeline { parse -> generate generate -> render } deploy: Deploy { upload -> verify } build.render -> deploy.upload: publish ``` You can change any node's shape with the `shape` keyword: ```{d2} config: great-docs.yml { shape: document } db: Cache { shape: cylinder } config -> build -> db ``` ### Sequence Diagrams D2 renders sequence diagrams from the same syntax by setting `shape: sequence_diagram`. They're ideal for documenting API call flows or request/response cycles where order matters: ```{d2} shape: sequence_diagram User -> CLI: great-docs build CLI -> Core: GreatDocs.build() Core -> Core: Parse docstrings Core -> Quarto: quarto render Quarto -> Core: HTML output Core -> CLI: Build complete CLI -> User: Site ready ``` ### Options Fine-tune a diagram with `#|` option lines at the top of the block. These are stripped before the diagram is rendered: | Option | Description | Default | |--------------|----------------------------------------------------------|---------| | `theme` | D2 theme id used for the light rendering | `0` | | `dark-theme` | D2 theme id used for the dark rendering | `200` | | `layout` | Layout engine (`dagre`, `elk`, or `tala` if installed) | `dagre` | | `sketch` | `true` for a hand-drawn look | `false` | | `pad` | Padding in pixels around the diagram | `20` | | `scale` | Scale factor for the rendered output | auto | For example, a hand-drawn diagram with the ELK layout engine: ```{d2} #| sketch: true #| layout: elk Idea -> Draft -> Review -> Publish ``` Run `d2 themes` to see the full catalog of light and dark theme ids. ### Dark Mode Support Readers who switch between light and dark mode should not have to squint at a bright diagram on a dark background. Because Great Docs renders a dedicated dark-theme SVG for every D2 diagram, dark mode gets a genuinely dark diagram. The switch happens instantly when the reader toggles the theme, with no additional configuration required. ## Mermaid Diagrams [Mermaid](https://mermaid.js.org/) is rendered in the reader's browser and supports a broad set of diagram types. Great Docs pins Mermaid to its light theme and, in dark mode, presents each diagram inside a light background container so text and shapes stay clearly readable. ### Basic Usage To add a Mermaid diagram, use a fenced code block with `{mermaid}` as the language identifier: ````markdown ```{mermaid} graph LR A[Start] --> B{Decision} B -->|Yes| C[Action] B -->|No| D[End] ``` ```` This renders as: ```{mermaid} graph LR A[Start] --> B{Decision} B -->|Yes| C[Action] B -->|No| D[End] ``` ### Flowcharts Flowcharts are the most common diagram type in technical documentation. They're useful for documenting workflows, decision trees, or multi-step processes. Use `graph LR` for left-to-right flow or `graph TD` for top-down: ```{mermaid} graph TD A[great-docs init] --> B[Configure great-docs.yml] B --> C[Write docstrings] C --> D[great-docs build] D --> E{Preview OK?} E -->|Yes| F[Deploy to GitHub Pages] E -->|No| C ``` #### Flowchart Node Shapes Mermaid supports various node shapes: ```{mermaid} graph LR A[Rectangle] --> B(Rounded) B --> C{Diamond} C --> D([Stadium]) D --> E[[Subroutine]] E --> F[(Database)] ``` ### Sequence Diagrams Sequence diagrams show how components interact over time. They're ideal for documenting API call flows, request/response cycles, or system interactions where the order of operations matters: ```{mermaid} sequenceDiagram participant User participant CLI participant Core participant Quarto User->>CLI: great-docs build CLI->>Core: GreatDocs.build() Core->>Core: Parse docstrings Core->>Core: Generate .qmd files Core->>Quarto: quarto render Quarto-->>Core: HTML output Core-->>CLI: Build complete CLI-->>User: Site ready in great-docs/_site/ ``` The `participant` declarations control the column order. Solid arrows (`->>`) represent calls, and dashed arrows (`-->>`) represent returns. ### Class Diagrams Class diagrams are perfect for documenting object-oriented code structures: ```{mermaid} classDiagram class GreatDocs { +project_root: Path +config: Config +install() +build() +preview() } class Config { +package_name: str +exclude: list +logo: dict +load() +save() } GreatDocs --> Config : uses ``` Class diagrams support visibility modifiers (`+` public, `-` private, `#` protected) and relationship types (inheritance, composition, association). ### State Diagrams State diagrams help document state machines, lifecycle stages, or any system where items transition between well-defined states: ```{mermaid} stateDiagram-v2 [*] --> Draft Draft --> Review: Submit Review --> Approved: Accept Review --> Draft: Request changes Approved --> Published: Deploy Published --> [*] ``` The `[*]` node represents the start and end states. ### Gantt Charts Gantt charts are useful for documenting project timelines, release schedules, or migration plans: ```{mermaid} gantt title Documentation Release Schedule dateFormat YYYY-MM-DD section Phase 1 API Documentation :done, api, 2024-01-01, 2024-01-15 User Guide :done, guide, 2024-01-10, 2024-01-25 section Phase 2 CLI Reference :active, cli, 2024-01-20, 2024-02-05 Deployment Guide :deploy, 2024-02-01, 2024-02-10 ``` Tasks can be marked as `done`, `active`, or left unmarked for upcoming work. ### Pie Charts Pie charts provide a quick visual summary of proportions: ```{mermaid} pie title Documentation Coverage "API Reference" : 45 "User Guide" : 30 "Recipes" : 15 "CLI Docs" : 10 ``` Values are automatically converted to percentages. ### Dark Mode Support Great Docs automatically adjusts Mermaid diagrams for dark mode by displaying them in a light background container, ensuring text and shapes remain clearly readable. No additional configuration is required. ## Tips for Better Diagrams Text-based diagrams are easy to create, but a few practices help keep them clear and maintainable (whether you use D2 or Mermaid). ### Keep Diagrams Focused Each diagram should illustrate one concept. If a diagram becomes too complex, consider breaking it into multiple smaller diagrams. ### Use Descriptive Labels Node labels should be self-explanatory. Use action verbs for process steps and clear nouns for entities: ```{d2} Parse Config -> Discover Exports -> Generate Pages -> Render HTML ``` ### Choose a Direction that Matches the Flow Both languages let you set a direction. In D2, add `direction: right` (or `up`, `down`, `left`); in Mermaid, use `graph LR`, `graph TD`, and so on. Pick the direction that best matches the process you're documenting (left-to-right for pipelines, top-down for hierarchies and decision trees). ### Group Related Nodes Group related nodes with D2 containers (`name { ... }`) or Mermaid subgraphs: ```{mermaid} graph TD subgraph Build Process A[Parse] --> B[Generate] B --> C[Render] end subgraph Deploy D[Upload] --> E[Verify] end C --> D ``` For complete syntax references, see the [D2 documentation](https://d2lang.com/tour/intro) and the [Mermaid documentation](https://mermaid.js.org/intro/). Quarto also provides additional options for diagram sizing and placement in the [Quarto Diagrams guide](https://quarto.org/docs/authoring/diagrams.html). ## Next Steps Text-based diagrams let you visualize architecture, workflows, and relationships directly in your documentation. Because they're defined in text, they stay in version control, diff cleanly, and update alongside your prose. - [Authoring QMD Files](authoring-qmd-files.qmd) covers other content building blocks like callouts, tabsets, and code blocks - [Videos](videos.qmd) covers embedding YouTube, Vimeo, and Loom content - [Cross-Referencing](cross-referencing.qmd) explains how to link diagram pages to API reference items - [Theming & Appearance](theming.qmd) explains how diagrams inherit your site's color scheme ## Build & Deploy # SEO Optimization Documentation is only useful if people can find it. When someone searches for how to install your package or call a specific function, your docs should appear near the top of the results. Good SEO ensures that search engines can crawl, index, and accurately represent your pages. Great Docs includes comprehensive SEO features that are enabled by default and work automatically when you build your site. Sitemaps, canonical URLs, meta descriptions, structured data, and robots directives are all generated without any configuration. ## What's Included Great Docs generates and injects SEO-related files and metadata automatically: - **`sitemap.xml`**: helps search engines discover all your pages - **`robots.txt`**: guides crawler behavior and references your sitemap - **Canonical URLs**: prevents duplicate content issues - **Meta descriptions**: provides search result snippets - **JSON-LD structured data**: enables rich search results - **Page title templates**: consistent `Page Title | Site Name` format All of these are generated at build time. You can customize any of them or disable features you don't need. ## Auditing SEO Health After building your site, you can audit the generated output to verify that all SEO features are in place. Run the SEO audit command to check for issues: ```{.bash filename="Terminal"} great-docs seo ``` This produces a report like this: ``` ════════════════════════════════════════════════════════════ 📊 SEO Audit Results ════════════════════════════════════════════════════════════ ✅ sitemap.xml: 65 URLs indexed ✅ robots.txt: includes sitemap reference ✅ robots.txt: has user-agent rules ✅ Analyzed 65 HTML pages ✅ All pages have canonical URLs ✅ All pages have meta descriptions ✅ 10 pages have JSON-LD structured data ✅ All images have alt text ──────────────────────────────────────────────────────────── ✅ All SEO checks passed! ``` The audit checks every HTML page in the built site and reports missing or malformed SEO elements. ### Fixing Issues Use `--fix` to automatically generate missing SEO files: ```{.bash filename="Terminal"} great-docs seo --fix ``` This creates `sitemap.xml` and `robots.txt` if they're missing and patches any fixable issues in the built output. ### CI Integration For continuous integration, use `--json` for machine-readable output: ```{.bash filename="Terminal"} great-docs seo --json ``` ```json { "status": "pass", "pages_checked": 65, "issues": [], "warnings": [], "info": ["✅ sitemap.xml: 65 URLs indexed", "..."] } ``` The command exits with code `1` if critical issues are found, making it easy to fail CI builds on SEO problems. Pair this with `great-docs lint` and `great-docs links` for a comprehensive pre-deployment check. ## Configuration All SEO settings live under the `seo` key in `great-docs.yml`. Here's the full configuration with defaults: ```{.yaml filename="great-docs.yml"} seo: enabled: true # Master switch for all SEO features sitemap: enabled: true changefreq: homepage: weekly reference: monthly user_guide: monthly changelog: weekly default: monthly priority: homepage: 1.0 reference: 0.8 user_guide: 0.9 changelog: 0.6 default: 0.5 robots: enabled: true allow_all: true disallow: [] crawl_delay: null extra_rules: [] canonical: enabled: true base_url: null # Auto-detected from GitHub Pages title_template: "{page_title} | {site_name}" structured_data: enabled: true type: SoftwareSourceCode default_description: null # Falls back to package description ``` Most users won't need to change these defaults. They are optimized for typical Python documentation sites, and every feature can be toggled independently. ## Sitemap Configuration The sitemap tells search engines about all your pages and how often they change. Great Docs generates different priorities and change frequencies based on page type, so your most important content gets crawled first. ### Page Types Pages are automatically categorized based on their path in the built site: | Type | Example Paths | Default Priority | Default Changefreq | |------|---------------|------------------|-------------------| | `homepage` | `index.html` | 1.0 | weekly | | `user_guide` | `user-guide/*.html`, `recipes/*.html` | 0.9 | monthly | | `reference` | `reference/*.html` | 0.8 | monthly | | `changelog` | `changelog.html` | 0.6 | weekly | | `default` | Everything else | 0.5 | monthly | These defaults work well for most projects. The subsections below show how to override them if your site has different needs. ### Customizing Priorities Adjust priorities based on what's most important for your site: ```{.yaml filename="great-docs.yml"} seo: sitemap: priority: homepage: 1.0 user_guide: 0.9 # Your tutorials are most valuable reference: 0.7 # API docs are secondary ``` ### Customizing Change Frequencies If your reference documentation changes frequently: ```{.yaml filename="great-docs.yml"} seo: sitemap: changefreq: reference: weekly # API changes often changelog: daily # Frequent releases ``` ## Robots.txt Configuration The `robots.txt` file tells search engine crawlers which pages to index and where to find your sitemap. Great Docs generates one automatically, but you can customize it for more control over crawler behavior. ### Default Behavior By default, Great Docs generates a permissive `robots.txt`: ```{.txt filename="robots.txt"} # Robots.txt generated by Great Docs User-agent: * Allow: / Sitemap: https://username.github.io/repo/sitemap.xml ``` ### Blocking Paths To prevent indexing of specific paths (e.g., draft pages): ```{.yaml filename="great-docs.yml"} seo: robots: disallow: - /drafts/ - /_internal/ ``` ### Blocking AI Crawlers Some projects prefer to block AI training crawlers: ```{.yaml filename="great-docs.yml"} seo: robots: extra_rules: - "User-agent: GPTBot" - "Disallow: /" - "User-agent: CCBot" - "Disallow: /" ``` ### Setting Crawl Delay For sites with limited bandwidth: ```{.yaml filename="great-docs.yml"} seo: robots: crawl_delay: 10 # Seconds between requests ``` ## Canonical URLs Canonical URLs tell search engines which version of a page is the "official" one. This prevents duplicate content issues when your site is accessible via multiple URLs (for example, with and without a trailing slash, or through both a custom domain and `github.io`). ### Auto-Detection Great Docs automatically generates canonical URLs based on your GitHub repository. If your repo is `github.com/username/repo`, the canonical base URL will be: ``` https://username.github.io/repo/ ``` ### Manual Configuration For custom domains or non-GitHub hosting, set the base URL explicitly: ```{.yaml filename="great-docs.yml"} seo: canonical: base_url: https://docs.myproject.com/ ``` The trailing slash is important (Great Docs will add it if missing). Every page in the built site receives a `<link rel="canonical">` tag pointing to its full URL. ## Page Titles Great Docs applies a consistent title template to all pages, improving brand recognition in search results. ### Default Template The default template is `{page_title} | {site_name}`, which produces titles like: - `Installation | My Package` - `GreatDocs.build | My Package` - `Configuration | My Package` ### Custom Templates Change the separator or format: ```{.yaml filename="great-docs.yml"} seo: title_template: "{page_title} - {site_name}" ``` Or remove the site name entirely: ```{.yaml filename="great-docs.yml"} seo: title_template: "{page_title}" ``` ## Structured Data (JSON-LD) Structured data helps search engines understand what your site is about beyond plain text. Great Docs injects [JSON-LD](https://json-ld.org/) structured data into your pages, enabling rich search results with additional context about your software. ### What Gets Injected On the homepage and reference pages, Great Docs adds a schema block like this: ```json { "@context": "https://schema.org", "@type": "SoftwareSourceCode", "name": "My Package", "description": "A Python package for...", "codeRepository": "https://github.com/username/repo", "programmingLanguage": { "@type": "ComputerLanguage", "name": "Python" } } ``` ### Customizing the Schema Type For different types of documentation: ```{.yaml filename="great-docs.yml"} seo: structured_data: type: WebSite # Or: SoftwareApplication, APIReference, etc. ``` ### Disabling Structured Data If you prefer not to include JSON-LD: ```{.yaml filename="great-docs.yml"} seo: structured_data: enabled: false ``` ## Meta Descriptions Meta descriptions are the short summaries that appear below page titles in search results. A good description improves click-through rates because it tells searchers exactly what they'll find on the page. Great Docs generates these automatically from your content. ### Auto-Generation For each page, Great Docs extracts a description from: 1. the first meaningful paragraph in the page content 2. falls back to the default description if no suitable content is found ### Setting a Default Description Configure a fallback description for pages without extractable content: ```{.yaml filename="great-docs.yml"} seo: default_description: "Documentation for My Package, a Python library for..." ``` If not set, the package description from `pyproject.toml` is used as a fallback. ### Page-Level Descriptions For individual pages, add a `description` field in the YAML frontmatter: ```{.yaml filename="user_guide/01-installation.qmd"} --- title: "Installation" description: "How to install My Package using pip, conda, or from source." --- ``` ## Noindex for Internal Pages Not every page belongs in search results. Internal pages, drafts, or experimental features can clutter search results and confuse users. Great Docs automatically adds `noindex` directives to internal pages like the Skills page. ### Manual Noindex To prevent a specific page from being indexed, add to its frontmatter: ```{.yaml filename="drafts/experimental-feature.qmd"} --- title: "Experimental Feature" robots: "noindex, nofollow" --- ``` ## Disabling SEO Features If you handle SEO through other means (for example, a hosting platform that generates sitemaps for you), you can disable individual features or all of them at once. To completely disable SEO generation: ```{.yaml filename="great-docs.yml"} seo: enabled: false ``` Or disable specific features: ```{.yaml filename="great-docs.yml"} seo: sitemap: enabled: false robots: enabled: false canonical: enabled: false structured_data: enabled: false ``` ## Best Practices The automatic features cover the technical foundations. These recommendations help you get the most out of them. ### For Maximum SEO Effectiveness 1. set a base URL either through a GitHub repo or explicit configuration 2. write good descriptions: add `description:` to key pages' frontmatter 3. use descriptive titles that are clear (as concise page titles improve click-through rates) 4. add alt text to images: Great Docs audits this and will fix any missing alt text 5. run `great-docs seo` to audit before deployment and catch issues early ### For GitHub Pages If you're deploying to GitHub Pages, SEO works out of the box: 1. your canonical base URL is auto-detected from the repository 2. the sitemap is automatically referenced in `robots.txt` 3. all pages get proper canonical links ### For Custom Domains When using a custom domain, this configuration is useful: ```{.yaml filename="great-docs.yml"} seo: canonical: base_url: https://docs.myproject.com/ ``` And ensure your DNS is configured correctly (see [Adding a Custom Domain](../recipes/add-custom-domain.qmd)). ## Next Steps Good SEO makes your documentation discoverable. Great Docs handles the technical foundations (sitemaps, canonical URLs, meta tags, structured data) automatically, so you can focus on writing clear titles and descriptions that represent your content well. - [Social Cards](social-cards.qmd) controls how links appear when shared on social platforms - [Deployment](deployment.qmd) covers publishing to GitHub Pages with SEO settings applied - [Linting](linting.qmd) catches documentation quality issues that can also affect search relevance - [Configuration](configuration.qmd) covers all `great-docs.yml` options including SEO settings ## Quality & Maintenance # Docs Linting Documentation problems tend to be invisible until someone encounters them: a function with no docstring, a cross-reference pointing to a symbol that was renamed, or a directive that's misspelled. These issues don't produce build errors, so they can persist across many releases. Great Docs includes a built-in linter that analyzes your package's public API for documentation quality issues. It catches missing docstrings, broken cross-references, inconsistent formatting, and malformed directives before your users ever see them. ## Basic Usage Run the linter from your project directory: ```{.bash filename="Terminal"} great-docs lint ``` This produces a report like: ``` ════════════════════════════════════════════════════════════ 📋 Documentation Lint Results ════════════════════════════════════════════════════════════ Package: my_package Exports checked: 42 ✅ All documentation checks passed! ``` When issues are found, they are grouped by check type with clear indicators: ``` ──────────────────────────────────────────────────────────── missing-docstring [2 error(s), 3 warning(s)] ──────────────────────────────────────────────────────────── ❌ calculate_total: Public export 'calculate_total' has no docstring. ❌ DataProcessor: Public export 'DataProcessor' has no docstring. ⚠️ Widget.render: Public method 'Widget.render' has no docstring. ⚠️ Widget.update: Public method 'Widget.update' has no docstring. ⚠️ Widget.__repr__: Public method 'Widget.__repr__' has no docstring. ──────────────────────────────────────────────────────────── style-mismatch [1 warning(s)] ──────────────────────────────────────────────────────────── ⚠️ parse_config: Docstring appears to use 'google' style but project is configured for 'numpy'. ──────────────────────────────────────────────────────────── ❌ 2 error(s), 4 warning(s) ``` Errors represent problems that will produce gaps or broken content on the rendered site. Warnings flag inconsistencies that are worth investigating but won't break anything. ## Checks Performed The linter runs four categories of checks, each targeting a different class of documentation problem. All four run by default, and each can be run individually using `--check` (described below). ### Missing Docstrings Finds public exports and class methods that lack docstrings. | Finding | Severity | Description | |---------|----------|-------------| | `missing-docstring` | Error | A public export in `__all__` has no docstring | | `missing-docstring` | Warning | A public method on a documented class has no docstring | Private methods (names starting with `_`) and constructor dunders (`__init__`, `__new__`) are skipped automatically. The linter only flags symbols that would appear (or be expected to appear) in the rendered documentation. ### Broken Cross-References Cross-references to undocumented symbols produce dead links on the rendered site. The linter checks that each `%seealso` target names an object this project documents or a linked project publishes. The linter checks only docstrings that render in the reference. A `%seealso` in a hidden member, such as one from a class configured `members: false`, has no rendered page and produces no finding. | Finding | Severity | Description | |---------|----------|-------------| | `broken-xref` | Error | A reference names no object documented by this project or a linked source | | `ambiguous-xref` | Error | A reference names a short form claimed by two documented objects | | `unread-source` | Info | A linked source inventory could not be read, so `%seealso` was not checked | For example, this would flag an error: ```python def process(data): """ Process the input data. %seealso validate_input, transform_data """ ... ``` If `validate_input` is documented but `transform_data` is not, the linter reports `transform_data` as a broken cross-reference. This is especially useful after renaming or removing functions. A reference can also be ambiguous. If both `StoreCache` and `NetCache` document a `flush` method, neither claims the short name `flush`, so a reference to it renders unlinked: ``` 'flush' is claimed by demo.NetCache.flush and demo.StoreCache.flush, so the reference stays unlinked. Qualify it. ``` Writing `` [](`StoreCache.flush`) `` resolves it. The linter judges `%seealso` entries and inline references identically because the build resolves both through one index. It scans docstrings and documentation pages. References to linked projects use the same index. `%seealso numpy.ndarray` passes whenever the built page resolves it, by full name or source alias. Great Docs uses a fresh cached inventory or downloads one when needed. If it cannot read a source, its names are unavailable, so the linter reports `unread-source` and does not classify `%seealso` references as broken for that run. ### Style Consistency Detects docstrings that don't match your project's configured parser style. The `parser` setting in `great-docs.yml` determines which style is expected: ```{.yaml filename="great-docs.yml"} parser: numpy # or "google" or "sphinx" ``` | Finding | Severity | Description | |---------|----------|-------------| | `style-mismatch` | Warning | Docstring uses a different style than configured | The linter detects style by looking for characteristic patterns: - **NumPy**: Section headers with dashed underlines (`Parameters\n----------`) - **Google**: Section headers with colons (`Args:`, `Returns:`) - **Sphinx**: Field markers (`:param x:`, `:returns:`) Short docstrings without structured sections are not flagged, since they don't contain enough signal to determine a style. ### Directive Consistency Great Docs uses `%`-prefixed directives in docstrings for features like cross-references and documentation exclusion. This check catches misspelled or unrecognized directives that would otherwise be silently ignored. | Finding | Severity | Description | |---------|----------|-------------| | `unknown-directive` | Warning | A `%`-prefixed directive is not recognized | Great Docs recognizes these parser-independent directives: - Cross-reference and exclusion: `%seealso` (see [Cross-Referencing](cross-referencing.qmd)) and `%nodoc` (see [Writing Docstrings](writing-docstrings.qmd#nodoc-exclude-an-item-from-documentation)) - Callouts: `%note`, `%warning`, `%caution`, `%danger`, `%important`, `%tip`, and `%hint` - Version notices: `%versionadded`, `%versionchanged`, and `%deprecated` Numbered `.. [1]` citation markers work with every parser. Use `parser: sphinx` for reStructuredText directives and inline cross-reference roles such as `` :py:exc:`ValueError` ``. Any other `%`-prefixed token, such as `%internal`, is flagged as unknown. If you see a false positive, check for typos in the directive name. ## Running Specific Checks When diagnosing a particular class of issue, you can run a subset of checks instead of the full suite. Use `--check` to select only the checks you need (this option can be repeated): ```{.bash filename="Terminal"} # Only check for missing docstrings great-docs lint --check docstrings # Check cross-references and style together great-docs lint --check cross-refs --check style # Only check directive usage great-docs lint --check directives ``` Available check names: | Name | What it checks | |------|----------------| | `docstrings` | Missing docstrings on public exports and methods | | `cross-refs` | Broken `%seealso` references and ambiguous interlinks | | `style` | Docstring style consistency with configured parser | | `directives` | Unknown or malformed `%` directives | When no `--check` flags are given, all four categories run. ## JSON Output For CI/CD integration or programmatic analysis, use `--json` to get machine-readable output: ```{.bash filename="Terminal"} great-docs lint --json ``` This produces structured JSON: ```json { "status": "fail", "package": "my_package", "exports_checked": 42, "summary": { "errors": 2, "warnings": 4, "info": 0 }, "issues": [ { "check": "missing-docstring", "severity": "error", "symbol": "calculate_total", "message": "Public export 'calculate_total' has no docstring." }, { "check": "style-mismatch", "severity": "warning", "symbol": "parse_config", "message": "Docstring appears to use 'google' style but project is configured for 'numpy'." } ] } ``` The `status` field is one of: | Status | Meaning | |--------|---------| | `pass` | No errors or warnings | | `warn` | Warnings only (exit code 0) | | `fail` | At least one error (exit code 1) | You can filter the JSON output with `jq`: ```{.bash filename="Terminal"} # Show only errors great-docs lint --json | jq '.issues[] | select(.severity == "error")' # Count issues by check type great-docs lint --json | jq '.issues | group_by(.check) | map({check: .[0].check, count: length})' ``` The JSON format is stable across releases, so you can build tooling around it. ## Exit Codes The linter uses exit codes to indicate whether action is needed: | Code | Meaning | |------|---------| | `0` | No errors (warnings are allowed) | | `1` | At least one error was found | This means you can use `great-docs lint` directly in CI pipelines and it will fail the build only when there are errors. Warnings appear in the output but do not block the pipeline. ## CI/CD Integration Running the linter in CI ensures that documentation quality is enforced on every pull request, not just when someone remembers to check. ### GitHub Actions Add documentation linting to your CI workflow: ```{.yaml filename=".github/workflows/docs.yml"} name: Documentation on: push: branches: [main] pull_request: branches: [main] jobs: lint-docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Set up Python uses: actions/setup-python@v6 with: python-version: '3.12' - name: Install dependencies run: | pip install -e . pip install great-docs - name: Lint documentation run: great-docs lint ``` ### Pre-commit Hook Add linting as a pre-commit hook: ```{.yaml filename=".pre-commit-config.yaml"} repos: - repo: local hooks: - id: lint-docs name: Lint Documentation entry: great-docs lint language: system pass_filenames: false always_run: true ``` ### Combining with Other Quality Checks Run linting alongside other Great Docs quality tools in CI: ```{.yaml filename=".github/workflows/docs.yml"} - name: Lint documentation run: great-docs lint - name: Check links run: great-docs check-links - name: Proofread run: great-docs proofread - name: Audit SEO run: great-docs seo ``` Running all four together gives you a comprehensive pre-deployment quality gate. ## Next Steps The linter catches structural problems early: missing docstrings, malformed directives, broken cross-references, and style inconsistencies that would otherwise surface as confusing gaps in the rendered site. Run it in CI to enforce documentation quality alongside code quality. - [Link Checker](link-checker.qmd) validates that all links in the built site resolve correctly - [Proofreading](proofreading.qmd) checks spelling, grammar, and style in your prose - [Writing Docstrings](writing-docstrings.qmd) covers the docstring format and directives that the linter validates - [SEO Optimization](seo.qmd) audits generated metadata that complements documentation quality ## Site Content # Videos Videos can make tutorials, demos, and explainers far more effective than screenshots alone. Great Docs supports YouTube, Vimeo, and local video files with responsive layouts, lazy loading, and accessibility features built in. ## YouTube Use the following syntax to embed a YouTube video. You can use the regular watch URL, the short URL, or the embed URL (all three work): ```{shortcodes="false"} {{< video https://www.youtube.com/watch?v=wo9vZccmqwc >}} {{< video https://youtu.be/wo9vZccmqwc >}} {{< video https://www.youtube.com/embed/wo9vZccmqwc >}} ``` All three produce the same result. The video is responsive by default and it scales to fill the available width while maintaining a 16:9 aspect ratio. Here's a live example: {{< video https://www.youtube.com/watch?v=d8-Jyh-NaMw >}} ::: {.callout-tip} ## YouTube Controls YouTube embeds use the standard YouTube player, giving visitors full access to native controls including ad skipping, captions, playback speed, and quality settings. ::: ### Start Time To start playback at a specific point, use the `start` option (in seconds): ```{shortcodes="false"} {{< video https://youtu.be/wo9vZccmqwc start="116" >}} ``` ### Title and Accessibility Add a `title` for the iframe and an `aria-label` for screen readers: ```{shortcodes="false"} {{< video https://www.youtube.com/embed/wo9vZccmqwc title="What is the CERN?" aria-label="Video tour of CERN particle physics laboratory" >}} ``` ## Vimeo Vimeo videos work the same way: ```{shortcodes="false"} {{< video https://vimeo.com/548291297 >}} ``` Vimeo embeds are lazy-loaded automatically: the iframe content is deferred until the video scrolls near the viewport. ## Local Video Files To embed a video file stored alongside your documentation (e.g., a short screen recording), place the file in your project and reference it directly: ```{shortcodes="false"} {{< video demo.mp4 >}} ``` Local videos are rendered as HTML5 `<video>` elements. To host them alongside your `.qmd` files, place them in the `assets/` directory: ``` user_guide/ ├── 05-walkthrough.qmd └── assets/ └── demo.mp4 ``` Then reference from the `.qmd` file: ```{shortcodes="false"} {{< video assets/demo.mp4 >}} ``` ::: {.callout-note} Keep video files small. Git repositories aren't ideal for large binary files. For longer recordings, consider uploading to YouTube or Vimeo and embedding from there. ::: ## Aspect Ratio The default aspect ratio is 16:9. You can change it to one of the standard Bootstrap ratios: ```{shortcodes="false"} {{< video https://youtu.be/wo9vZccmqwc aspect-ratio="4x3" >}} ``` Available ratios: `1x1`, `4x3`, `16x9` (default), and `21x9`. ## Fixed Dimensions To disable responsive sizing and set explicit pixel dimensions: ```{shortcodes="false"} {{< video https://youtu.be/wo9vZccmqwc width="400" height="225" >}} ``` ## Cross-Referencing Videos To create a numbered, cross-referenceable video (like a figure), wrap it in a fenced div: ```{shortcodes="false"} ::: {#fig-demo} {{< video https://www.youtube.com/embed/wo9vZccmqwc >}} A short tour of the CERN facility. ::: See @fig-demo for the full walkthrough. ``` This assigns the video a figure number and caption, and `@fig-demo` creates a clickable cross-reference elsewhere on the page. ## Loom Loom videos aren't recognized by the video syntax directly. Instead, use the Loom embed URL in a raw HTML `<iframe>`: ```html <div class="quarto-video ratio ratio-16x9"> <iframe src="https://www.loom.com/embed/YOUR_VIDEO_ID" frameborder="0" allowfullscreen> </iframe> </div> ``` Replace `YOUR_VIDEO_ID` with the ID from your Loom share link (e.g., if the share link is `https://www.loom.com/share/abc123`, the ID is `abc123`). The `quarto-video ratio ratio-16x9` classes give it the same responsive container as other videos, and Great Docs will lazy-load the iframe automatically. ## Tips - **Ads**: YouTube may show ads on monetized videos, even in embeds. To guarantee an ad-free experience, upload to a channel you control with monetization disabled. - **Privacy**: Consider using `youtube-nocookie.com` embed URLs (e.g., `https://www.youtube-nocookie.com/embed/VIDEO_ID`) to reduce tracking. - **Multiple videos**: The thumbnail placeholder optimization means pages with many YouTube embeds still load quickly (only the thumbnails are fetched initially). ## Next Steps Embedded videos bring tutorials, demos, and walkthroughs to life without leaving the documentation site. Great Docs lazy-loads all video embeds for fast page loads, regardless of how many videos appear on a page. - [Diagrams](diagrams.qmd) covers Mermaid diagrams for visualizing architecture and workflows - [Authoring QMD Files](authoring-qmd-files.qmd) covers other rich content like callouts, tabsets, and code blocks - [Theming & Appearance](theming.qmd) explains how video containers adapt to your site's styling ## Config & Theming # Internationalization If your project has users around the world, presenting documentation in their language makes a real difference. Even when the actual content is in English, translating navigation labels, button text, and timestamps removes friction and signals that the project cares about accessibility. Great Docs can display all of its UI text in multiple languages. When you set a language in `great-docs.yml`, every button label, tooltip, relative timestamp, navbar link, and accessibility attribute across the site is automatically translated. ## Setting the Language Add the `language` key under `site` in your configuration file. The value is a [BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) language code: ```{.yaml filename="great-docs.yml"} site: language: fr ``` If you don't set a language, Great Docs defaults to English (`en`). Only a single language can be active at a time. ## Supported Languages Great Docs ships with translations for 23 languages. If yours is in the list, all you need is the `language` key in `great-docs.yml`: | Code | Language | |------|----------| | `en` | English (default) | | `fr` | French | | `de` | German | | `es` | Spanish | | `pt` | Portuguese | | `it` | Italian | | `nl` | Dutch | | `sv` | Swedish | | `da` | Danish | | `nb` | Norwegian Bokmål | | `is` | Icelandic | | `fi` | Finnish | | `ja` | Japanese | | `ko` | Korean | | `zh-Hans` | Chinese (Simplified) | | `zh-Hant` | Chinese (Traditional) | | `ru` | Russian | | `pl` | Polish | | `cs` | Czech | | `ro` | Romanian | | `tr` | Turkish | | `el` | Greek | | `hi` | Hindi | If your language isn't listed here and you'd like to contribute a translation, see the [How It Works](#how-it-works) section below for details on the translation pipeline. ## What Gets Translated Setting the language affects every piece of UI text that Great Docs generates. Here's a summary of what changes: ### Navbar Labels The top-level navigation links are translated automatically. For example, with `language: de`: - **User Guide** becomes **Benutzerhandbuch** - **Recipes** becomes **Rezepte** - **Reference** becomes **Referenz** - **Changelog** becomes **Änderungsprotokoll** ### Widget Text All interactive widgets use the configured language: - **Back-to-top button**: tooltip text - **Copy code button**: "Copy to clipboard" / "Copied!" labels - **Copy page menu**: all menu items and status messages - **Dark mode toggle**: "Switch to dark mode" / "Switch to light mode" tooltips - **Sidebar filter**: placeholder text and result counts - **Reference switcher**: "API Reference" / "CLI Reference" labels - **GitHub widget**: "Stars", "Forks", "Issues", "Pull Requests" labels - **Announcement banner**: dismiss button accessibility label - **Responsive tables**: scrollable table indicator - **Video embed**: play button and video labels ### Page Metadata The page metadata widget displays relative timestamps like "3 days ago" or "2 months ago". These time expressions are fully translated and support correct singular/plural forms for each language. The tooltip date format also adapts to match the configured locale. ### Table of Contents The "On this page" heading above the right-hand table of contents is translated to match your configured language. All of these translations are applied automatically. You don't need to provide any translation files or configure anything beyond the `language` key. ## Right-to-Left (RTL) Support ::: {.callout-note} RTL layout support for languages like Arabic and Hebrew is under active development and not yet available. The underlying translations exist, but the visual layout needs further work before these languages can be officially supported. ::: ## Placeholders and Plurals Translation strings aren't always simple substitutions. Some include dynamic values and need to handle singular and plural forms correctly. Great Docs handles both cases automatically at runtime: - **Placeholders** use `{name}` syntax: for example, `"Refreshed {time}"` becomes `"Actualisé {time}"` in French, where `{time}` is filled in with the relative timestamp. - **Plurals** use a `singular|plural` pipe format: for example, `"{n} day ago|{n} days ago"` becomes `"il y a {n} jour|il y a {n} jours"` in French, with the correct form selected based on the count. ## How It Works Understanding the translation pipeline can be helpful if you're contributing translations or debugging language issues: 1. you set `language` in `great-docs.yml` 2. during the build, Great Docs looks up all translation strings for that language from its internal dictionary 3. the full translation bundle is written into `_gd_options.json` 4. after Quarto renders each page, the post-render script injects a `<meta name="gd-i18n">` tag into the HTML `<head>` containing the JSON-encoded translations 5. each JavaScript widget reads from this meta tag using a shared `_gdT(key, fallback)` helper function If a translation is missing for a particular key, the English fallback is used automatically. This means partial translations are safe to ship: untranslated strings appear in English rather than as blank text or error messages. ## Next Steps Internationalization lets you serve documentation in your users' language with a single config setting. Great Docs translates all UI chrome (navigation, buttons, tooltips, timestamps) while you focus on translating the content that matters most. - [Configuration](configuration.qmd) covers the `language` setting and other `great-docs.yml` options - [Theming & Appearance](theming.qmd) explains how translated labels integrate with your site's visual design - [SEO Optimization](seo.qmd) covers how language settings affect search engine indexing - [Social Cards](social-cards.qmd) explains Open Graph metadata, which can include language attributes ## Build & Deploy # Social Cards When someone shares a link to your documentation on LinkedIn, Discord, Slack, Bluesky, Mastodon, X (Twitter), or other platforms, social card meta tags control the preview that appears. Great Docs automatically generates Open Graph and Twitter Card meta tags for every page so your links look polished rather than bare URLs. ## What's Generated For every page in your site, Great Docs injects two sets of `<meta>` tags into `<head>`: **Open Graph** (used by LinkedIn, Discord, Slack, Bluesky, Mastodon, Facebook, and most other platforms): ```html <meta property="og:type" content="website"> <meta property="og:title" content="Configuration | My Package"> <meta property="og:description" content="How to configure My Package..."> <meta property="og:url" content="https://user.github.io/pkg/user-guide/config.html"> <meta property="og:site_name" content="My Package"> <meta property="og:image" content="https://user.github.io/pkg/social-card.png"> ``` **Twitter/X Card** (used by X for its own preview cards): ```html <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:title" content="Configuration | My Package"> <meta name="twitter:description" content="How to configure My Package..."> <meta name="twitter:image" content="https://user.github.io/pkg/social-card.png"> <meta name="twitter:site" content="@myhandle"> ``` These tags are generated per-page with the correct title, description, and URL for each page. ## Zero-Config Defaults Social card tags are enabled by default. With no configuration at all, Great Docs will: - use the page `<title>` for `og:title` and `twitter:title` - extract a description from the page's meta description or first paragraph - fall back to the package description from `pyproject.toml` when no page-level description is available - build the `og:url` from your canonical base URL (auto-detected from GitHub Pages) - set `twitter:card` to `"summary"` (no image) or `"summary_large_image"` (when an image is configured) No changes to `great-docs.yml` are needed for basic social card previews. ## Adding a Social Card Image An image makes a dramatic difference in how your links appear. Without one, most platforms show a plain text card. With a well-designed image, your link gets a large visual preview that stands out in feeds and chat messages. ### Recommended Image Specifications | Property | Recommendation | |----------|---------------| | **Dimensions** | 1200 × 630 pixels (1.91:1 aspect ratio) | | **Minimum size** | 600 × 315 pixels | | **Maximum file size** | Under 1 MB (ideally under 300 KB) | | **Format** | PNG for graphics/text, JPEG for photos | | **Safe area** | Keep important content within the center 1080 × 565 pixels | The 1200 × 630 size is the universal sweet spot: it works well as a `summary_large_image` on X, fills the preview area on LinkedIn and Discord, and renders crisply on high-DPI screens. ### Configuring the Default Image Place your image in the project's `assets/` directory. This is the same directory Great Docs already copies into the build for logos, favicons, and other static files: ``` my-package/ ├── assets/ │ ├── social-card.png ← your social card image │ ├── logo.svg │ └── favicon.svg ├── my_package/ ├── great-docs.yml └── pyproject.toml ``` Then reference it in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} social_cards: image: assets/social-card.png ``` This single image is used as the default `og:image` and `twitter:image` for **every page** on your site. It's copied to the site root during build and referenced with an absolute URL. ### What to Put in the Image A good social card image typically includes: - your package logo or wordmark - the package name in large, readable text - a short tagline or description - a subtle background color or pattern that matches your brand Avoid putting page-specific information in the image since it's shared across all pages. Focus on making the package itself recognizable. ### Design Tips - **High contrast text**: white or light text on a dark background (or vice versa) ensures readability at small sizes - **Large text**: the image is often shown at 300-400 pixels wide in feeds; small text becomes unreadable - **Simple composition**: one logo, one title, one line of description is enough - **Test at small sizes**: preview your image at 300 × 157 pixels to see how it looks in a typical feed ## Configuration Reference The full `social_cards` configuration with all options: ```{.yaml filename="great-docs.yml"} social_cards: enabled: true # Master switch (default: true) image: assets/social-card.png # Default og:image path or URL twitter_site: "@myhandle" # Twitter/X site @handle twitter_card: summary_large_image # Card type override ``` ### Options You can enable or disable social card meta tag generation. The default is `true`. ```{.yaml filename="great-docs.yml"} # Disable social cards entirely social_cards: enabled: false ``` You can also use the shorthand form: ```{.yaml filename="great-docs.yml"} social_cards: false ``` The `image` key needs a path to a default image file (relative to the project root) or an absolute URL. This image is used as `og:image` and `twitter:image` for all pages. ```{.yaml filename="great-docs.yml"} # Local file (copied to site root during build) social_cards: image: assets/social-card.png # External URL (used as-is) social_cards: image: https://cdn.example.com/my-package-card.png ``` When an image is provided, the `twitter:card` type automatically switches from `"summary"` to `"summary_large_image"` for a bigger preview on X. The `twitter_site` key refers to the Twitter/X `@handle` for the site or organization. This appears in the card footer on X. ```{.yaml filename="great-docs.yml"} social_cards: twitter_site: "@posaboron" ``` The `@` prefix is optional (Great Docs will add it if missing). Regarding `twitter_card`, this overrides the Twitter card type. By default, Great Docs chooses automatically: - `"summary"` when no image is configured - `"summary_large_image"` when an image is configured Set this to force a specific type regardless of image presence: ```{.yaml filename="great-docs.yml"} social_cards: image: assets/social-card.png twitter_card: summary # Use small card even though an image exists ``` ## How Descriptions Are Extracted Social card descriptions are extracted automatically with this priority: 1. **Existing meta description**: if the page already has a `<meta name="description">` tag (from SEO processing or manual frontmatter), that text is reused 2. **First paragraph**: the first `<p>` in the page's `<main>` content with at least 30 characters of meaningful text 3. **Default description**: the `seo.default_description` value from `great-docs.yml`, or the package description from `pyproject.toml` For the best previews, add a `description` to important pages' frontmatter: ```{.yaml filename="user_guide/03-configuration.qmd"} --- title: "Configuration" description: "Complete guide to configuring Great Docs, including theming, navbar styles, and SEO settings." --- ``` ## Testing Your Social Cards After building your site, you can verify the meta tags are present by inspecting any HTML file: ```{.bash filename="Terminal"} grep -E 'og:|twitter:' great-docs/_site/index.html ``` To see how your links will actually appear on each platform, use these free preview tools: - **LinkedIn**: [LinkedIn Post Inspector](https://www.linkedin.com/post-inspector/) - **X (Twitter)**: [Twitter Card Validator](https://cards-dev.twitter.com/validator) - **Facebook**: [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/) - **General**: [Open Graph Debugger](https://opengraph.dev) (this shows previews for multiple platforms at once) These tools fetch your live URL, so you'll need to deploy your site first (or use a tunnel for local testing). ## Relationship to SEO Social cards work alongside the [SEO features](seo.qmd) but serve a different purpose: - **SEO** optimizes how your pages appear in search engine results (Google, Bing) - **Social cards** control how your links appear when shared on social platforms Both features can be enabled independently. Social cards use some of the same underlying data (canonical URLs, meta descriptions) but generate separate meta tags (`og:*` and `twitter:*`). ## Disabling Social Cards To turn off social card meta tags entirely you can use: ```{.yaml filename="great-docs.yml"} social_cards: false ``` Or equivalently: ```{.yaml filename="great-docs.yml"} social_cards: enabled: false ``` With either of these settings, the Open Graph and Twitter Card meta tags will not be injected into any pages. ## Next Steps Social cards control how your documentation looks when shared on Twitter, Slack, Discord, and other platforms. Great Docs generates the right meta tags automatically from your page titles and descriptions. - [SEO Optimization](seo.qmd) covers search engine visibility, sitemaps, and canonical URLs - [Configuration](configuration.qmd) covers all `great-docs.yml` options including social card settings - [Deployment](deployment.qmd) explains publishing to GitHub Pages where social cards take effect ## Site Content # Custom Static Pages Great Docs can auto-discover hand-written HTML pages and add them to your site with either minimal transformation or no transformation at all. This is useful for product landing pages, interactive demos, playgrounds, embedded widgets, and other content that does not fit naturally into a standard `.qmd` workflow. ## Configuring Source Directories Custom static pages are configured with `custom_pages` in `great-docs.yml`. ### Zero-config fallback If you do not set `custom_pages`, Great Docs falls back to a conventional `custom/` directory: ```{.default filename="project layout"} my-package/ ├── custom/ │ ├── py.html │ ├── playground.html │ └── assets/ │ └── chart.js ├── great-docs.yml └── ... ``` That is only the default on-ramp. You can override it. ### One custom page directory ```{.yaml filename="great-docs.yml"} custom_pages: marketing ``` This reads pages from `marketing/` and publishes them under `marketing/` in the built site. ### One directory with a custom URL prefix ```{.yaml filename="great-docs.yml"} custom_pages: dir: marketing output: py ``` This reads files from `marketing/` but publishes them under `py/`, which is useful when your source directory name and URL shape should differ. ### Multiple custom page directories ```{.yaml filename="great-docs.yml"} custom_pages: - dir: marketing output: py - dir: playgrounds output: demos ``` This lets a larger site keep different HTML surfaces in separate source trees while still controlling their deployed paths. ### Disable custom pages entirely ```{.yaml filename="great-docs.yml"} custom_pages: false ``` This disables the fallback `custom/` directory too. ## Two Layout Modes Custom HTML pages support two layout modes through YAML frontmatter. ### `layout: passthrough` Use passthrough mode when you want to keep your HTML body mostly intact but still render it inside the normal Great Docs shell. ```{.html filename="marketing/index.html"} --- title: Comet Apps for Python layout: passthrough navbar: true --- <section class="hero-banner"> <h1>Reactive Python apps</h1> <p>Build interactive apps with a custom landing page.</p> </section> ``` In passthrough mode, Great Docs will: - parse the frontmatter - generate an intermediate `.qmd` file in the build directory - keep your HTML body as the page content - render the page with the normal navbar, footer, search, theme, and scripts This is the right choice for pages like: - product landing pages - marketing-style homepages for a sub-area of your docs - richly designed pages that should still feel like part of the main documentation site ### `layout: raw` Use raw mode when the HTML should be served unchanged. ```{.html filename="playgrounds/playground.html"} --- layout: raw navbar: text: Playground after: User Guide --- <!DOCTYPE html> <html> <head> <title>Playground
Raw playground content
``` In raw mode, Great Docs will: - strip the frontmatter - copy the HTML file through to the final site output unchanged - exclude that file from Quarto rendering This is the right choice for pages like: - standalone widget hosts - JavaScript demos with their own document structure - third-party embeds that depend on exact HTML markup ## Navbar Integration Custom pages do not have to appear in the navbar, but they can opt in using frontmatter. ### Use the page title ```{.yaml filename="frontmatter"} navbar: true ``` This adds the page to the navbar using its `title`. ### Use custom text ```{.yaml filename="frontmatter"} navbar: Widget Lab ``` This adds the page to the navbar using the provided text. ### Control placement ```{.yaml filename="frontmatter"} navbar: text: Playground after: User Guide ``` This uses explicit link text and inserts the link after an existing navbar item. If no placement is specified, the link is inserted before `Reference`, which matches the current behavior for custom sections. ## Assets and Relative Paths Files under each configured custom-page directory that are not HTML are copied as project resources. For example: ```{.default filename="playgrounds/"} playgrounds/ ├── widget.html └── assets/ ├── chart.js └── styles.css ``` From `playgrounds/widget.html`, you can reference those files with relative paths: ```{.html filename="playgrounds/widget.html"} ``` If `playgrounds/` is configured with `output: demos`, those files are copied into the built site under `demos/assets/`. ## Coexisting with User Guides and Sections Custom static pages are meant for a different job than User Guide pages or configured sections. Use **User Guide pages** when: - the content is standard documentation prose - you want Quarto-native Markdown authoring - you want the usual sectioned sidebar behavior Use **Custom Sections** when: - you want a group of related pages with shared navigation - you want a navbar item plus a section sidebar - the content is still mostly `.qmd` or `.md` Use **Custom Static Pages** when: - the page is already HTML - the layout is highly bespoke - the page should behave like a landing page or demo surface - you need raw HTML delivery without Quarto transformation It is normal for one site to use all three together. ## What Happens During Build When `great-docs build` runs, Great Docs scans each configured custom-page directory after processing configured sections and before copying top-level `assets/`. The custom page pipeline: 1. walks each configured custom-page directory recursively 2. copies non-HTML files as resources 3. reads frontmatter from `.html` and `.htm` files 4. converts passthrough pages into generated `.qmd` files 5. copies raw pages through unchanged and excludes them from Quarto rendering 6. injects any opted-in custom pages into the navbar ## Example: Shiny-Style Landing Page If you want a page similar in spirit to `https://shiny.posit.co/py/`, passthrough mode is usually the better fit. ```{.html filename="marketing/index.html"} --- title: Comet Apps for Python layout: passthrough navbar: true ---

Reactive data apps in pure Python

Elegant, efficient, and ready for production.

Reactive

Automatic execution flow without callback boilerplate.

Efficient

Render outputs only when upstream inputs change.

Robust

Build on top of the modern Python web stack.

``` That gives you a custom layout while still preserving the site shell around it. ## Current Limitations This feature is intentionally narrow in its first version. - custom pages are HTML-based; Great Docs is not currently transforming arbitrary non-HTML page types here - there is no dedicated custom-page sidebar model yet - navbar integration is per-page frontmatter, not a separate config block These constraints keep the feature predictable while it matures. ## Next Steps Custom pages give you an escape hatch for content that doesn't fit the standard page model. Use them sparingly for landing pages, dashboards, or anything that needs full control over HTML and layout. - [Custom Sections](custom-sections.qmd) covers multi-page section navigation - [Configuration](configuration.qmd) covers the broader `great-docs.yml` model - [Building & Previewing](building.qmd) explains where custom pages fit in the build pipeline # Page Tags As a documentation site grows, the sidebar and search bar are not always enough to help readers find what they need. Tags offer a second axis of navigation, organized by topic rather than page order. A reader looking for everything related to "Testing" can find it in one place, even if those pages are spread across the User Guide, Recipes, and custom sections. Great Docs lets you categorize pages with tags for improved discoverability. Add tags to any user guide, recipe, or custom section page via frontmatter, and Great Docs will generate a tags index page, render tag pills above page titles, and support hierarchical tag organization. Tags are disabled by default. To enable them, add a `tags` section to `great-docs.yml`: ```{.yaml filename="great-docs.yml"} tags: enabled: true ``` Or use the shorthand: ```{.yaml filename="great-docs.yml"} tags: true ``` ## Adding Tags to Pages Add tags to any `.qmd` page using the `tags` key in YAML frontmatter: ```{.yaml filename="user_guide/03-configuration.qmd"} --- title: "Configuration" tags: [Python, Configuration, Getting Started] --- ``` Tags can be any string. They are case-sensitive, so `Python` and `python` are treated as different tags. ## Tags Index Page When tags are enabled, Great Docs automatically generates a `tags/index.qmd` page that lists every tag and the pages associated with it. A "Tags" link is added to the site's top navigation bar (positioned before "Reference"). Each tag becomes a heading on the index page, with links to all pages that use that tag. Section badges (e.g., "User Guide", "Recipes") appear next to each page link so readers can see where the page lives:
Configuration
Configuration User Guide
Getting Started
Installation User Guide
Quickstart User Guide
### Disabling the Index Page If you want tag pills on pages but don't want a dedicated index page: ```{.yaml filename="great-docs.yml"} tags: enabled: true index_page: false ``` ## Tag Pills on Pages By default, tagged pages display small pill-shaped links below the page title. Each pill links to the corresponding tag's section on the tags index page, helping readers discover related content:
Configuration
Python Configuration Getting Started
To disable the pills while keeping the tags index page: ```{.yaml filename="great-docs.yml"} tags: enabled: true show_on_pages: false ``` ## Tag Location By default, tag pills appear at the **top** of the page, just below the title (and subtitle, if present). You can move them to the **bottom** of the page instead, where they appear after the page metadata block (dates and author info) or under a horizontal rule if no metadata is present. Set the default location globally in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} tags: enabled: true location: bottom ``` Valid values are `top` (default) and `bottom`. ### Per-Page Overrides Individual pages can override the global setting using `tag-location` in their YAML frontmatter: ```{.yaml filename="user_guide/05-tips.qmd"} --- title: "Tips and Tricks" tags: [Python, Setup] tag-location: top --- ``` This is useful when most pages use bottom placement but a few key pages benefit from prominent top placement (or vice versa). ::: {.callout-tip} When tags are placed at the bottom, they are rendered *after* the page metadata (creation/modification dates and author info). If page metadata is not enabled, tags appear at the end of the main content under a horizontal rule. ::: ## Hierarchical Tags Tags support a hierarchy using the `/` separator. For example, `Python/Testing` creates a parent "Python" group with a "Testing" child. On the tags index page, hierarchical tags are rendered with nested headings: ```yaml --- title: "Unit Testing Guide" tags: [Python/Testing, Python/pytest, Best Practices] --- ``` This produces an index page structure like: ``` ## Best Practices - Unit Testing Guide ## Python ### Testing - Unit Testing Guide ### pytest - Unit Testing Guide ``` On the page itself, hierarchical tag pills display as segmented pills with the parent and leaf separated by a vertical divider. The full path is shown as a tooltip on hover:
Python Testing Python pytest Best Practices
### Literal Slashes in Tag Names If a tag name contains a literal `/` that should **not** be treated as a hierarchy separator, escape it with a backslash: `\/`. For example, `AI\/LLM` displays as "AI/LLM" without creating a hierarchy. ```yaml --- title: "Working with LLMs" tags: [AI\/LLM, Getting Started] --- ``` ::: {.callout-note} In YAML, leave the tag unquoted (e.g., `AI\/LLM`) so the backslash is preserved. Double-quoted YAML strings will consume the backslash as an escape character. ::: To disable hierarchical tag support entirely and treat all `/` characters as literal: ```{.yaml filename="great-docs.yml"} tags: enabled: true hierarchical: false ``` ## Shadow Tags Not all tags are meant for readers. Shadow tags let you use the tagging system for internal organization without exposing those labels publicly. Pages with shadow tags are still indexed internally, but the tags themselves are not rendered as pills on pages or shown on the tags index page. This is useful for editorial workflows. For example, you can tag pages as `needs-review` or `draft` without exposing those labels to readers. ```{.yaml filename="great-docs.yml"} tags: enabled: true shadow: - needs-review - draft - internal ``` A page can have both visible and shadow tags: ```yaml --- title: "Advanced Configuration" tags: [Configuration, API, needs-review] --- ``` In this example, "Configuration" and "API" appear as pills and on the index page, while "needs-review" is silently ignored in the public output. ## Tag Icons You can associate tags with icons from the [Lucide](https://lucide.dev/icons/) icon set (the same icon set used by `nav_icons`). Icons appear inside the tag pill and next to the tag heading on the index page. ```{.yaml filename="great-docs.yml"} tags: enabled: true icons: Python: code Tutorial: book-open API: file-code Testing: flask-conical ``` The icon names are Lucide icon names (lowercase, hyphenated). Browse the full catalogue at [lucide.dev/icons](https://lucide.dev/icons/). ## Full Configuration Reference Here is the complete `tags` configuration with all options and their defaults: ```{.yaml filename="great-docs.yml"} tags: enabled: false # Master switch (default: false) index_page: true # Generate a tags index page (default: true) show_on_pages: true # Show tag pills above page titles (default: true) location: top # Pill placement: "top" or "bottom" (default: "top") hierarchical: true # Support "/" as tag hierarchy separator (default: true) icons: {} # Tag → icon name mapping (default: empty) shadow: [] # Tags hidden from public view (default: empty) scoped: false # Scoped tag listings per section (default: false) ``` Individual pages can override `location` via `tag-location` in their YAML frontmatter. ## Which Pages Are Scanned? Great Docs scans for tags in `.qmd` files found in: - **User guide** pages (`user-guide/`) - **Recipes** pages (`recipes/`) - **Custom sections** (any section defined in `sections:` config) Index pages (`index.qmd`) in these directories are skipped. API reference pages and the changelog are not scanned for tags. ## Tips A few guidelines help keep your tag system useful as your documentation grows. - **Start simple**: begin with a flat list of 5-10 tags and add hierarchy later as your documentation grows. - **Be consistent**: establish a tag naming convention early (e.g., always use title case). - **Use shadow tags for workflow**: tags like `needs-update` or `v2-migration` help you track editorial tasks without cluttering the reader experience. - **Combine with search**: tags improve discoverability today, and will integrate with enhanced search in a future release. ## Next Steps Tags give readers a second way to navigate your documentation, organized by topic rather than page order. Start with a small set of well-chosen tags and expand as your content grows. - [Page Status Badges](page-status-badges.qmd) adds lifecycle indicators (new, updated, deprecated) to pages - [Custom Sections](custom-sections.qmd) covers organizing pages into named groups with sidebar navigation - [Internationalization](internationalization.qmd) covers language support for tag-related UI elements - [Configuration](configuration.qmd) covers all tag settings in `great-docs.yml` # Page Status Badges Documentation pages have a lifecycle. Some pages describe brand-new features, others cover APIs that are experimental and subject to change, and some document capabilities that are being phased out. Communicating this status helps readers set expectations before they invest time in a page. Great Docs lets you mark pages with a lifecycle status such as "New", "Beta", or "Deprecated". Status badges appear as colored indicators in two places: 1. **Below the page title**: a full badge with icon, label, and description 2. **In sidebar navigation**: a compact icon next to the link, with a tooltip on hover Status badges are disabled by default. To enable them, add a `page_status` section to `great-docs.yml`: ```{.yaml filename="great-docs.yml"} page_status: enabled: true ``` Or use the shorthand: ```{.yaml filename="great-docs.yml"} page_status: true ``` ## Adding a Status to a Page Set the `status` key in the YAML frontmatter of any user guide, recipe, or custom section page: ```{.yaml filename="user_guide/03-migration.qmd"} --- title: "Migration Guide" status: deprecated --- ``` The value must match one of the defined status keys (see below). Pages without a `status` key display no badge. ## Built-in Statuses Great Docs ships with five built-in statuses, each with a [Lucide](https://lucide.dev/icons/) icon, color, and description: | Key | Label | Icon | Color | Description | |----------------|----------------|---------------------|---------|-------------------------------------| | `new` | New | `sparkles` | Green | Recently added | | `updated` | Updated | `refresh-cw` | Blue | Recently updated | | `beta` | Beta | `flask-conical` | Amber | Beta feature | | `deprecated` | Deprecated | `triangle-alert` | Red | May be removed in a future release | | `experimental` | Experimental | `beaker` | Purple | API may change without notice | Here is how these five statuses look as page-level badges:
✦ New — Recently added
↻ Updated — Recently updated
⚗ Beta — Beta feature
⚠ Deprecated — May be removed in a future release
Experimental — API may change without notice
All built-in status labels and descriptions are automatically translated when the site uses a non-English language (see [Internationalization](internationalization.qmd)). ## Custom Statuses The five built-in statuses cover common lifecycle stages, but your team may have its own workflow. You can add your own statuses or override built-in ones via the `statuses` map in `great-docs.yml`: ```{.yaml filename="great-docs.yml"} page_status: enabled: true statuses: draft: label: "Draft" icon: pencil color: "#6b7280" description: "Work in progress" review: label: "In Review" icon: eye color: "#0ea5e9" description: "Awaiting technical review" ``` Each custom status definition accepts: | Key | Type | Required | Description | |---------------|--------|----------|-----------------------------------------------------------| | `label` | string | No | Display text (defaults to the key in title case) | | `icon` | string | No | Lucide icon name (e.g., `pencil`, `eye`) | | `color` | string | No | CSS color for the badge (defaults to `#6b7280`) | | `description` | string | No | Short explanation shown on the page badge and as a tooltip | Custom statuses use their literal `label` and `description` values in all languages. Only the five built-in statuses are translated automatically. Use the custom key in frontmatter just like a built-in status: ```{.yaml filename="user_guide/10-new-api.qmd"} --- title: "New API Design" status: draft --- ``` ## Overriding Built-in Statuses To change a built-in status (for example, switching the icon or color for `deprecated`), redefine it in `statuses`: ```{.yaml filename="great-docs.yml"} page_status: enabled: true statuses: deprecated: label: "Legacy" icon: archive color: "#9ca3af" description: "Superseded by a newer approach" ``` Your definition fully replaces the built-in default for that key. Any fields you omit fall back to their defaults (gray color, title-cased label, no icon). ## Controlling Where Badges Appear By default, badges are shown in both locations. You can disable either one independently if you prefer a subtler approach. ### Sidebar Only ```{.yaml filename="great-docs.yml"} page_status: enabled: true show_on_pages: false # No badge below the title show_in_sidebar: true # Icon in sidebar (default) ``` ### Page Title Only ```{.yaml filename="great-docs.yml"} page_status: enabled: true show_on_pages: true # Badge below the title (default) show_in_sidebar: false # No icon in sidebar ``` ## How It Looks ### On the Page The page-level badge appears directly below the title (and subtitle, if present). It displays the status icon, label, and description in the status color:
Getting Started
A quick introduction to the package
✦ New — Recently added
### In the Sidebar Sidebar links for pages with a status show a small colored pill after the link text. Hovering over the pill displays a tooltip with the full label and description:
Getting Started
Migration Guide
Configuration
New API Design
Pages without a status display no indicator, keeping the sidebar clean. ## Which Pages Are Scanned? Great Docs scans for `status` frontmatter in `.qmd` files found in: - **User guide** pages (`user-guide/`) - **Recipes** pages (`recipes/`) - **Custom sections** (any section defined in `sections:` config) API reference pages, the changelog, and index pages are not scanned. This keeps badges focused on content pages where lifecycle status is meaningful. ## Full Configuration Reference Here is the complete `page_status` configuration with all options and their defaults: ```{.yaml filename="great-docs.yml"} page_status: enabled: false # Master switch (default: false) show_in_sidebar: true # Show icon in sidebar links (default: true) show_on_pages: true # Show badge below page titles (default: true) statuses: # Status definitions (built-ins shown below) new: label: "New" icon: sparkles color: "#10b981" description: "Recently added" updated: label: "Updated" icon: refresh-cw color: "#3b82f6" description: "Recently updated" beta: label: "Beta" icon: flask-conical color: "#f59e0b" description: "Beta feature" deprecated: label: "Deprecated" icon: triangle-alert color: "#ef4444" description: "May be removed in a future release" experimental: label: "Experimental" icon: beaker color: "#8b5cf6" description: "API may change without notice" ``` ## Tips A few guidelines help keep status badges effective across your documentation. - **Use statuses sparingly**: a page should carry a status only when it communicates something actionable. If every page is "New", the badge loses its value. - **Remove stale statuses**: revisit `status: new` and `status: updated` periodically and remove them once the content is no longer recent. - **Combine with tags**: statuses and tags serve different purposes. Tags categorize content by topic; statuses communicate lifecycle. A page can have both. - **Custom statuses for workflows**: define statuses like `draft` or `review` to track editorial progress while keeping the documentation published. ## Next Steps Status badges communicate lifecycle information at a glance. They work best when used selectively for pages that are genuinely new, recently updated, or approaching deprecation. - [Page Tags](page-tags.qmd) categorizes pages by topic with filterable tag listings - [API Evolution](api-evolution.qmd) tracks changes across releases at the API level - [Internationalization](internationalization.qmd) covers how built-in badge labels are translated - [Configuration](configuration.qmd) covers all status badge settings in `great-docs.yml` ## Quality & Maintenance # API Evolution Great Docs can track how your package's public API changes across tagged releases. This is useful for understanding signature drift, detecting breaking changes, and generating visual migration aids for your users. ## Quick Start Compare two versions from the command line: ```{.bash filename="Terminal"} great-docs api-diff v0.1.0 v1.0.0 ``` This produces a summary showing added, removed, and changed symbols, with breaking-change detection and migration hints: ``` ════════════════════════════════════════════════════════════ API Diff: v0.1.0 → v1.0.0 Package: my_package ════════════════════════════════════════════════════════════ Added: 3 │ Removed: 1 │ Changed: 5 │ Breaking: 2 ────────────────────────────────────────────────────────── ✚ Added (3) ────────────────────────────────────────────────────────── + preview + scan + setup_github_pages ────────────────────────────────────────────────────────── ✖ Removed (1) [BREAKING] ────────────────────────────────────────────────────────── - generate_config hint: 'generate_config' was removed. Check the changelog for a replacement. ────────────────────────────────────────────────────────── ∆ Changed (5) ────────────────────────────────────────────────────────── ~ build ⚠ BREAKING ⚠ New parameter: watch Return type: (none) → int ``` Use `--json` for machine-readable output, perfect for CI checks: ```{.bash filename="Terminal"} great-docs api-diff v0.9.0 v1.0.0 --json ``` ## Tracking a Single Symbol Use `--symbol` to follow one function or class across every version: ```{.bash filename="Terminal"} great-docs api-diff v0.1.0 v1.0.0 --symbol build ``` Add `--changes-only` to skip versions where the signature was unchanged: ```{.bash filename="Terminal"} great-docs api-diff v0.1.0 v1.0.0 --symbol build --changes-only ``` ## Evolution Table The `--table` flag renders a positional parameter grid that shows exactly how a signature evolved. Each column is a version (where a change occurred), and each row is a positional parameter slot. Every cell is self-contained (it shows the parameter name, type, and default at that position) so insertions, reorderings, and removals are immediately visible. ```{.bash filename="Terminal"} # Plain-text table (for terminal) great-docs api-diff v0.1.0 v1.0.0 --symbol build --table --changes-only # HTML table with disclosure wrapper (for embedding in docs) great-docs api-diff v0.1.0 v1.0.0 --symbol build --table --html ``` ### Live Demo Below is a demonstration of how a `build()` function might evolve over four releases. The table is rendered from a JSON data file using the shortcode: ```{shortcodes="false"} {{< evolution build json="api-evolution-demo.json" >}} ``` {{< evolution build json="api-evolution-demo.json" >}} Reading this table left-to-right tells the story: - `v0.1.0`: there are two parameters, `project_path=` (required `str`) and `output_dir=` (with a string default). - `v0.3.0`: `project_path=` widens to `str | Path`. A new `watch=` parameter is appended. `output_dir=` changes its default to a `Path` object. - `v0.6.0`: `watch=` moves to position 2 (before `output_dir`), and a new `clean=` parameter is added. The return type changes from `None` to `int`. - `v1.0.0`: `project_path=` gets a default (`None`), `output_dir=`'s default changes to `"_site"`, and a new `verbose=` parameter is appended. Notice how this layout makes insertions and reorderings visible. In v0.6.0 you can see that `watch=` moved up and `output_dir=` moved down, which would be invisible in a row-per-parameter-name layout. ### Embedding in Pages To insert an evolution table directly into a User Guide page or any `.qmd` file, use the shortcode syntax: ```{shortcodes="false"} {{< evolution build >}} ``` This produces a self-contained HTML table (with embedded CSS) showing how `build()` evolved across all tagged releases. The table is generated at build time so no Python code blocks or manual HTML is required. #### Options You can customize the output with named arguments: ```{shortcodes="false"} {{< evolution symbol="build" old_version="v0.3.0" new_version="v1.0.0" >}} ``` | Option | Default | Description | |--------|---------|-------------| | (positional or `symbol`) | *required* | Symbol name to track | | `old_version` | first tag | Earliest version to include | | `new_version` | latest tag | Latest version to include | | `changes_only` | `"true"` | Only show versions where the signature changed | | `disclosure` | `"false"` | Wrap in a collapsible `
` element | | `summary` | auto | Custom label for the disclosure header | | `css` | `"true"` | Include the `