Great Docs Great Docs
  • User Guide
  • Recipes
  • Reference
  • Changelog

Skills

A skill is a package of structured files that teaches an AI coding agent how to work with a specific tool or framework. This project ships multiple skills — use the switcher below to browse each one. Install a skill in your agent and it will be able to run commands, edit configuration, write content, and troubleshoot problems without step-by-step guidance from you.

Any agent — install all with npx:

npx skills add https://posit-dev.github.io/great-docs/

CLI — install all skills in a project:

great-docs skill install great-docs

Codex / OpenCode

Tell the agent to fetch these skill files:
https://posit-dev.github.io/great-docs/.well-known/agent-skills/great-docs/SKILL.md
https://posit-dev.github.io/great-docs/.well-known/agent-skills/write-user-guide/SKILL.md
https://posit-dev.github.io/great-docs/.well-known/agent-skills/revise-docstrings/SKILL.md
https://posit-dev.github.io/great-docs/.well-known/agent-skills/configure-site/SKILL.md
https://posit-dev.github.io/great-docs/.well-known/agent-skills/author-skills/SKILL.md

Or browse the skill files below.

SKILL LAYOUT

great-docs/
├── SKILL.md
├── references/
│   ├── cli-reference.md
│   ├── common-errors.md
│   └── config-reference.md
├── scripts/
│   ├── run-build.sh
│   └── setup-env.sh
└── assets/
    └── config-template.yaml

SKILL.md

---
name: great-docs
description: >
  Generate documentation sites for Python packages with Great Docs.
  Covers init, build, preview, configuration (great-docs.yml), API
  reference, CLI docs, user guides, theming, deployment, and the
  llms.txt agent-context files. Use when creating, configuring,
  building, or troubleshooting Python package documentation.
license: MIT
compatibility: Requires Python >=3.11, Quarto CLI installed.
metadata:
  author: rich-iannone
  version: "2.0"
  tags:
    - documentation
    - python-packages
    - quarto
    - api-reference
    - static-site
---

# Great Docs

A docs generator for Python packages. Introspects your API, renders
reference pages, and produces a Quarto-based static site with user
guides, CLI docs, theming, and more.

## Quick start

```bash
pip install great-docs
# Quarto must also be installed: https://quarto.org/docs/get-started/

cd my-package/        # directory with pyproject.toml
great-docs init       # create great-docs.yml, discover API
great-docs build      # full build -> great-docs/_site/
great-docs preview    # local server on port 3000
```

## Skill directory structure

This skill ships with companion files for agent consumption:

```
skills/great-docs/
├── SKILL.md                ← This file
├── references/
│   ├── config-reference.md ← All great-docs.yml options
│   ├── cli-reference.md    ← CLI commands and arguments
│   └── common-errors.md    ← Error patterns and fixes
├── scripts/
│   ├── setup-env.sh        ← Environment bootstrap script
│   └── run-build.sh        ← Build with validation
└── assets/
    └── config-template.yaml ← Starter great-docs.yml
```

## When to use what

| Need                      | Use                                     |
| ------------------------- | --------------------------------------- |
| Start a new docs site     | `great-docs init`                       |
| Full build from scratch   | `great-docs build`                      |
| Rebuild after edits       | `great-docs build --no-refresh`         |
| Live preview              | `great-docs preview`                    |
| See discoverable API      | `great-docs scan --verbose`             |
| Change docstring parser   | `parser: google` in great-docs.yml      |
| Add CLI reference         | `cli: {enabled: true, module: pkg.cli}` |
| Add a gradient navbar     | `navbar_style: sky`                     |
| Exclude internal symbols  | `exclude: [_InternalClass]`             |
| Add user guide pages      | Create `user_guide/05-topic.qmd`        |
| Add recipes               | Create `recipes/07-topic.qmd`           |
| Set up GitHub Pages CI    | `great-docs setup-github-pages`         |
| Use static analysis       | `dynamic: false` (for tricky imports)   |
| Generate agent skill file | `skill: {enabled: true}`                |

## Core concepts

### Configuration (`great-docs.yml`)

Single YAML file at the project root controls everything. All keys
are optional — sensible defaults are auto-detected from
`pyproject.toml` and package structure.

**Full config reference**: See [references/config-reference.md](references/config-reference.md)

### Build pipeline

The `build` command runs 13 steps in order:

1. Prepare build directory (copy assets, JS, SCSS)
2. Copy user guide from `user_guide/`
3. Copy project `assets/`
4. Refresh API reference (introspect package)
5. Generate `llms.txt` and `llms-full.txt`
6. Generate `skill.md` (if enabled)
7. Generate source links JSON
8. Generate changelog (from GitHub Releases)
9. Generate CLI reference (if enabled)
10. Process user guide (frontmatter, sidebar)
11. Process custom sections
12. Render API reference (`.qmd` files)
13. Run `quarto render` -> `_site/` HTML output

The `great-docs/` directory is **ephemeral** — regenerated on every
build. Never edit files inside it directly.

### Two rendering modes

- **Dynamic** (default): imports the package at runtime for full
  introspection. Requires `pip install -e .` first.
- **Static** (`dynamic: false`): uses griffe for AST-based analysis.
  Use when the package has circular imports, lazy loading, or
  compiled extensions.

Dynamic mode auto-falls-back to static if the import fails.

### Docstring directives

Custom directives inside docstrings use `%` prefix:

```python
def my_function():
    """
    Description.

    %seealso func_a, func_b: related functions, ClassC
    %nodoc
    """
```

- `%seealso name1, name2: desc` — Cross-references in rendered docs
- `%nodoc` — Exclude this item from documentation

## Workflows

### New documentation site

```
Task Progress:
- [ ] Step 1: Install prerequisites
- [ ] Step 2: Initialize configuration
- [ ] Step 3: Customize config
- [ ] Step 4: Build and preview
- [ ] Step 5: Verify output
```

**Step 1**: Ensure `great-docs` and `quarto` are installed. The
target package must be importable (`pip install -e .`).

**Step 2**: Run `great-docs init` from the project root (where
`pyproject.toml` lives). This creates `great-docs.yml`.

**Step 3**: Edit `great-docs.yml` to customize. See
[references/config-reference.md](references/config-reference.md) or
[assets/config-template.yaml](assets/config-template.yaml) for all
options.

**Step 4**: Run `great-docs build` then `great-docs preview`.

**Step 5**: Check the site at `http://localhost:3000`. If errors
occur, see [references/common-errors.md](references/common-errors.md).

### Adding content

**User guide page**: Create `user_guide/NN-title.qmd` with a
2-digit numeric prefix. Auto-discovered on next build.

**Recipe**: Create `recipes/NN-title.qmd`. Same numeric prefix
convention.

**Custom section**: Add to `great-docs.yml`:

```yaml
sections:
  - title: Examples
    dir: examples
```

### Customizing appearance

```yaml
# great-docs.yml
navbar_style: sky # gradient: sky, peach, lilac, mint, etc.
content_style: lilac # content area glow
dark_mode_toggle: true # toggle switch in navbar
logo: assets/logo.svg # or {light: ..., dark: ...}
hero: true # landing page hero section
announcement:
  content: "v2 is out!"
  type: info
  dismissable: true
```

### Troubleshooting a build

1. Run `great-docs build` and read the error output
2. Check [references/common-errors.md](references/common-errors.md) for
   the error pattern
3. Fix the config or source file
4. Rebuild with `great-docs build --no-refresh` (faster, skips API
   rediscovery)
5. If the error persists, try `great-docs build` with full refresh

## Reference files

### Config reference (`references/config-reference.md`)

Complete list of every `great-docs.yml` option with types, defaults,
and examples. Organized by category: metadata, GitHub, navigation,
theming, content, features, and advanced.

### CLI reference (`references/cli-reference.md`)

All CLI commands with arguments and usage examples:

| Command              | Purpose                     |
| -------------------- | --------------------------- |
| `init`               | Create config, discover API |
| `build`              | Full build pipeline         |
| `preview`            | Local dev server            |
| `scan`               | Preview discoverable API    |
| `config`             | Generate template config    |
| `uninstall`          | Remove config and build dir |
| `setup-github-pages` | Create CI/CD workflow       |

### Common errors (`references/common-errors.md`)

Error patterns, causes, and fixes for the most frequent build
failures — import errors, missing exports, config mismatches,
Quarto issues, and more.

## Scripts

### `scripts/setup-env.sh`

Bootstrap a development environment:

```bash
#!/usr/bin/env bash
set -euo pipefail
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pip install great-docs
quarto --version || echo "ERROR: Quarto not installed"
```

### `scripts/run-build.sh`

Build with validation:

```bash
#!/usr/bin/env bash
set -euo pipefail
great-docs build
echo "Build complete. Site at great-docs/_site/"
ls great-docs/_site/index.html && echo "OK: index.html exists"
```

## Configuration template

The `assets/config-template.yaml` provides a starter config with
annotated options. Copy it as `great-docs.yml` and customize.

## Gotchas

1. **Run from project root.** All commands must run from the
   directory containing `great-docs.yml` (and `pyproject.toml`).
2. **`module` vs package name.** The `module` key is the Python
   importable name, not the PyPI name. For `py-shiny`, set
   `module: shiny`.
3. **Circular imports.** Set `dynamic: false` for packages with
   lazy loading or circular aliases.
4. **User guide ordering.** Files need numeric prefixes
   (`00-intro.qmd`, `01-install.qmd`) for deterministic order.
5. **Don't edit `great-docs/` directly.** It's regenerated on every
   build. Edit source files instead.
6. **Quarto required.** If `quarto` is not on `PATH`, the build
   fails at step 13.
7. **Package must be importable.** In dynamic mode, run
   `pip install -e .` before building.

## Capabilities and boundaries

**What agents can configure:**

- All `great-docs.yml` settings
- User guide `.qmd` pages in `user_guide/`
- Recipe `.qmd` pages in `recipes/`
- Custom section `.qmd` pages
- Logo, favicon, and other assets
- Custom CSS/SCSS overrides
- Docstring directives (`%seealso`, `%nodoc`)

**Requires human setup:**

- `pip install great-docs` and Quarto installation
- `pip install -e .` for the target package
- GitHub Pages or hosting deployment
- Custom domain DNS
- GitHub access tokens (for changelog)

## Related skills

This is the general-purpose skill for Great Docs. For deeper
guidance on specific tasks, use these companion skills:

| Task                        | Skill               | When to use                                                   |
| --------------------------- | ------------------- | ------------------------------------------------------------- |
| Write user guide pages      | `write-user-guide`  | Creating or editing `.qmd` pages in `user_guide/`             |
| Improve docstrings          | `revise-docstrings` | Auditing or rewriting Python docstrings for the API reference |
| Configure the site          | `configure-site`    | Customizing `great-docs.yml` theming, features, and layout    |
| Create or distribute skills | `author-skills`     | Writing SKILL.md files, setting up multi-skill distribution   |

## Resources

- [Full documentation](https://posit-dev.github.io/great-docs/)
- [llms.txt](llms.txt) — Indexed API reference for LLMs
- [llms-full.txt](llms-full.txt) — Comprehensive documentation for LLMs
- [Configuration guide](https://posit-dev.github.io/great-docs/user-guide/03-configuration.html)
- [GitHub repository](https://github.com/posit-dev/great-docs)

references/cli-reference.md

# CLI Reference — great-docs

## Contents

- Global options
- init
- build
- preview
- scan
- config
- uninstall
- setup-github-pages

All commands accept `--project-path PATH` to target a different directory.

## Global options

```
great-docs [OPTIONS] COMMAND [ARGS]
```

| Option                | Description                                       |
| --------------------- | ------------------------------------------------- |
| `--project-path PATH` | Path to project root (default: current directory) |
| `--version`           | Show version and exit                             |
| `--help`              | Show help and exit                                |

## init

One-time setup: create `great-docs.yml` and auto-discover API.

```bash
great-docs init
great-docs init --force   # reset existing config
```

| Option    | Description                         |
| --------- | ----------------------------------- |
| `--force` | Overwrite existing `great-docs.yml` |

Creates `great-docs.yml` with detected package name, module, parser
style, and API sections. Safe to run multiple times (no-op if config
exists unless `--force`).

## build

Full build pipeline: prepare → render → build HTML.

```bash
great-docs build
great-docs build --no-refresh   # skip API rediscovery (faster)
great-docs build --watch        # rebuild on file changes
```

| Option         | Description                                  |
| -------------- | -------------------------------------------- |
| `--watch`      | Watch for changes and rebuild incrementally  |
| `--no-refresh` | Skip API reference rediscovery (uses cached) |

Output goes to `great-docs/_site/`. Build streams progress in
real-time.

## preview

Start a local development server.

```bash
great-docs preview
great-docs preview --port 8080
```

| Option   | Default | Description |
| -------- | ------- | ----------- |
| `--port` | `3000`  | Server port |

Serves `great-docs/_site/` with live reload. Run `build` first if
the site doesn't exist yet.

## scan

Preview which API items will be documented.

```bash
great-docs scan
great-docs scan --verbose   # show methods and attributes
```

| Option      | Description                               |
| ----------- | ----------------------------------------- |
| `--verbose` | Show member details (methods, attributes) |

Useful for verifying what `great-docs init` will discover before
committing to a build.

## config

Generate a template `great-docs.yml`.

```bash
great-docs config
great-docs config --force   # overwrite existing
```

| Option    | Description                    |
| --------- | ------------------------------ |
| `--force` | Overwrite existing config file |

Similar to `init` but only creates the config file without
running any discovery or setup.

## uninstall

Remove `great-docs.yml` and the `great-docs/` build directory.

```bash
great-docs uninstall
```

Preserves source files (`user_guide/`, `recipes/`, `assets/`).

## setup-github-pages

Create a GitHub Actions workflow for automated deployment.

```bash
great-docs setup-github-pages
great-docs setup-github-pages --main-branch main --python-version 3.12
```

| Option             | Default  | Description                     |
| ------------------ | -------- | ------------------------------- |
| `--main-branch`    | `"main"` | Branch that triggers deployment |
| `--python-version` | `"3.12"` | Python version in CI            |
| `--force`          | —        | Overwrite existing workflow     |

Creates `.github/workflows/docs.yml` configured for GitHub Pages
deployment with proper caching and Quarto installation.

references/common-errors.md

# Common Errors — great-docs

## Contents

- Import and discovery errors
- Configuration errors
- Build and rendering errors
- Quarto errors
- Deployment errors

## Import and discovery errors

### `Cannot find an object named X`

**Cause**: Object listed in API config but not exported from `__init__.py`.

**Fix**: Add `from .module import X` to the package's `__init__.py`.

### `dynamic: true` fails with ImportError

**Cause**: Package is not importable in the current environment.

**Fix**: Run `pip install -e .` in the project root, or set
`dynamic: false` in `great-docs.yml` to use static analysis.

### No API items discovered

**Cause**: Package has no public exports in `__init__.py`.

**Fix**: Ensure public classes and functions are imported in
`__init__.py` or listed in `__all__`.

### Wrong items documented

**Cause**: Re-exported third-party symbols treated as own API.

**Fix**: Add unwanted items to `exclude` list in `great-docs.yml`:

```yaml
exclude:
  - ThirdPartyClass
  - imported_helper
```

## Configuration errors

### `module` not found

**Cause**: `module` key doesn't match the importable package name.

**Fix**: Use the Python import name, not the PyPI install name.
For `pip install py-shiny`, set `module: shiny`.

### Parser mismatch (garbled docstrings)

**Cause**: Docstring style doesn't match `parser` setting.

**Fix**: Set `parser` to match your docstrings:

```yaml
parser: numpy    # Parameters\n----------\narg : type
parser: google   # Args:\n    arg (type): desc
parser: sphinx   # :param arg: desc\n:type arg: type
```

### CLI reference not generated

**Cause**: `cli.module` points to wrong module or the Click app
isn't findable.

**Fix**: Verify `cli.module` and `cli.name`:

```yaml
cli:
  enabled: true
  module: my_package.cli # must contain a Click group/command
  name: my-cli # the CLI entry point name
```

## Build and rendering errors

### `great-docs/` directory has stale content

**Cause**: Edited files inside `great-docs/` directly.

**Fix**: Delete `great-docs/` and rebuild. Never edit the build
directory — it's overwritten on every build.

### User guide pages in wrong order

**Cause**: Missing or inconsistent numeric prefixes.

**Fix**: Use 2-digit prefixes: `00-intro.qmd`, `01-install.qmd`,
`02-quickstart.qmd`. Gaps are fine (`00`, `05`, `10`).

### Missing cross-references

**Cause**: `%seealso` directive references items not in the API.

**Fix**: Ensure referenced items are exported and not in `exclude`.

### Source links point to wrong branch

**Cause**: `source.branch` doesn't match the repository default.

**Fix**:

```yaml
source:
  branch: main # or "master", "develop", etc.
```

## Quarto errors

### `quarto: command not found`

**Cause**: Quarto is not installed or not on PATH.

**Fix**: Install from https://quarto.org/docs/get-started/ and
ensure `quarto --version` works in the terminal.

### Quarto render fails with YAML error

**Cause**: Generated `_quarto.yml` has invalid syntax, usually
from special characters in config values.

**Fix**: Check `great-docs.yml` for unquoted special characters.
Wrap values with colons, brackets, or quotes in double quotes:

```yaml
announcement:
  content: "Version 2.0: now with more features!"
```

### Quarto render fails with missing bibliography

**Cause**: `.qmd` files reference a .bib file that doesn't exist.

**Fix**: Remove the `bibliography` field from .qmd frontmatter or
create the referenced `.bib` file.

## Deployment errors

### GitHub Pages shows 404

**Cause**: Workflow deploys from wrong directory or branch.

**Fix**: Run `great-docs setup-github-pages` to regenerate the
workflow. Ensure GitHub Pages is configured to deploy from
GitHub Actions (Settings → Pages → Source → GitHub Actions).

### Site URL incorrect in links

**Cause**: `site-url` not set in Quarto config.

**Fix**: Great Docs auto-detects this from `pyproject.toml` URLs.
Add a `Documentation` URL:

```toml
[project.urls]
Documentation = "https://my-org.github.io/my-package/"
```

### Changelog empty

**Cause**: No GitHub Releases exist, or `GITHUB_TOKEN` not
available in CI.

**Fix**: Create at least one GitHub Release, or set
`changelog: {enabled: false}` to disable.

references/config-reference.md

# Configuration Reference — great-docs.yml

## Contents

- Metadata and package info
- GitHub and source links
- Navigation and theming
- Logo, favicon, and hero
- Content organization
- Features
- Advanced

All keys are optional. Defaults are auto-detected from `pyproject.toml`.

## Metadata and package info

| Key            | Type        | Default       | Description                                             |
| -------------- | ----------- | ------------- | ------------------------------------------------------- |
| `module`       | `str`       | auto-detected | Python importable name (not PyPI name)                  |
| `display_name` | `str`       | package name  | Custom site title                                       |
| `parser`       | `str`       | `"numpy"`     | Docstring style: `"numpy"`, `"google"`, `"sphinx"`      |
| `dynamic`      | `bool`      | `true`        | `true`: runtime introspection; `false`: static (griffe) |
| `exclude`      | `list[str]` | `[]`          | Items to hide from API docs                             |
| `auto_include`    | `list[str]` | `[]`          | Force-include names that match the auto-exclude list    |
| `no_auto_exclude` | `bool`      | `false`       | Bypass the built-in auto-exclude list entirely          |

## GitHub and source links

| Key                | Type   | Default       | Description                          |
| ------------------ | ------ | ------------- | ------------------------------------ |
| `repo`             | `str`  | auto-detected | GitHub repository URL                |
| `github_style`     | `str`  | `"widget"`    | `"widget"` (shows stars) or `"icon"` |
| `source.enabled`   | `bool` | `true`        | Show "View source" links             |
| `source.branch`    | `str`  | `"main"`      | Git branch for source links          |
| `source.path`      | `str`  | auto-detected | Path to package source               |
| `source.placement` | `str`  | `"repo"`      | Where source links point             |

## Navigation and theming

| Key                | Type            | Default | Description                                                                              |
| ------------------ | --------------- | ------- | ---------------------------------------------------------------------------------------- |
| `navbar_style`     | `str`           | none    | Gradient preset: `"sky"`, `"peach"`, `"lilac"`, `"slate"`, `"honey"`, `"dusk"`, `"mint"` |
| `navbar_color`     | `str` or `dict` | none    | Solid color: `"#1a1a2e"` or `{light: "#fff", dark: "#1a1a2e"}`                           |
| `content_style`    | `str` or `dict` | none    | Content glow: `"lilac"` or `{preset: "sky", pages: "homepage"}`                          |
| `dark_mode_toggle` | `bool`          | `true`  | Dark mode toggle in navbar                                                               |
| `attribution`      | `bool`          | `true`  | "Built with Great Docs" footer                                                           |

## Logo, favicon, and hero

| Key       | Type             | Default        | Description                                                 |
| --------- | ---------------- | -------------- | ----------------------------------------------------------- |
| `logo`    | `str` or `dict`  | auto-detected  | Logo path or `{light: ..., dark: ...}`                      |
| `favicon` | `str`            | auto-generated | Favicon path (generated from logo if SVG)                   |
| `hero`    | `bool` or `dict` | auto           | Hero section on homepage. `{enabled: true, tagline: "..."}` |

Logo auto-detection looks for `assets/logo.svg`, `assets/logo-dark.svg`, etc.

## Content organization

| Key          | Type           | Default       | Description                                             |
| ------------ | -------------- | ------------- | ------------------------------------------------------- |
| `homepage`   | `str`          | `"index"`     | `"index"` (README) or `"user_guide"` (first guide page) |
| `user_guide` | auto or `dict` | auto-discover | User guide content source                               |
| `reference`  | auto or `list` | auto-discover | API reference sections                                  |
| `sections`   | `list[dict]`   | `[]`          | Custom pages: `[{title: "Examples", dir: "examples"}]`  |

## Features

| Key                        | Type   | Default | Description                             |
| -------------------------- | ------ | ------- | --------------------------------------- |
| `cli.enabled`              | `bool` | `false` | Generate CLI reference from Click app   |
| `cli.module`               | `str`  | —       | Module containing the Click app         |
| `cli.name`                 | `str`  | —       | CLI command name                        |
| `changelog.enabled`        | `bool` | `true`  | Generate changelog from GitHub Releases |
| `markdown_pages`           | `bool` | `false` | Generate downloadable `.md` pages       |
| `sidebar_filter.enabled`   | `bool` | `true`  | Search/filter in API reference sidebar  |
| `sidebar_filter.min_items` | `int`  | `10`    | Minimum items to show filter box        |
| `skill.enabled`            | `bool` | `false` | Generate SKILL.md for agent consumption |
| `skill.file`               | `str`  | —       | Path to hand-written SKILL.md           |

## Advanced

| Key                 | Type            | Default         | Description                                                                         |
| ------------------- | --------------- | --------------- | ----------------------------------------------------------------------------------- |
| `announcement`      | `str` or `dict` | none            | Banner: `"text"` or `{content: "...", type: "info", dismissable: true, url: "..."}` |
| `authors`           | `list[dict]`    | `[]`            | Author metadata: `{name, affiliation, github, orcid}`                               |
| `funding`           | `dict`          | none            | Funding/copyright: `{funder: "...", award: "..."}`                                  |
| `include_in_header` | `list[str]`     | `[]`            | Custom HTML/CSS/JS includes                                                         |
| `site`              | `dict`          | Quarto defaults | Quarto theme, TOC, grid settings                                                    |
| `jupyter`           | `str`           | `"python3"`     | Jupyter kernel for executable code cells                                            |

## Example: minimal config

```yaml
# great-docs.yml
parser: numpy
```

## Example: fully customized config

```yaml
# great-docs.yml
module: my_package
display_name: My Package
parser: google
dynamic: true
exclude:
  - _InternalClass
  - _helper_fn

navbar_style: sky
content_style: lilac
dark_mode_toggle: true

logo:
  light: assets/logo.svg
  dark: assets/logo-dark.svg
hero:
  enabled: true
  tagline: "Beautiful documentation for Python"

announcement:
  content: "v2.0 released!"
  type: info
  dismissable: true

cli:
  enabled: true
  module: my_package.cli
  name: my-cli

changelog:
  enabled: true

sections:
  - title: Examples
    dir: examples

skill:
  enabled: true
```

scripts/run-build.sh

#!/usr/bin/env bash
# Build and validate a great-docs site
set -euo pipefail

echo "Building documentation..."
great-docs build

# Validate output
SITE_DIR="great-docs/_site"

if [[ ! -d "$SITE_DIR" ]]; then
    echo "ERROR: Build directory $SITE_DIR not found"
    exit 1
fi

if [[ ! -f "$SITE_DIR/index.html" ]]; then
    echo "ERROR: index.html not found in $SITE_DIR"
    exit 1
fi

echo "Build complete. Site at $SITE_DIR/"

# Count generated pages
PAGE_COUNT=$(find "$SITE_DIR" -name "*.html" | wc -l | tr -d ' ')
echo "Generated $PAGE_COUNT HTML pages"

# Check for key outputs
for file in llms.txt llms-full.txt; do
    if [[ -f "great-docs/$file" ]]; then
        echo "OK: $file exists"
    else
        echo "WARN: $file not found"
    fi
done

echo "Done."

scripts/setup-env.sh

#!/usr/bin/env bash
# Setup development environment for great-docs
set -euo pipefail

echo "Creating virtual environment..."
python -m venv .venv
source .venv/bin/activate

echo "Installing package in editable mode..."
pip install -e ".[dev]"

echo "Installing great-docs..."
pip install great-docs

echo "Checking Quarto..."
if command -v quarto &> /dev/null; then
    echo "Quarto $(quarto --version) found"
else
    echo "ERROR: Quarto not installed. Visit https://quarto.org/docs/get-started/"
    exit 1
fi

echo "Validating package import..."
PACKAGE=$(python -c "
import tomllib
with open('pyproject.toml', 'rb') as f:
    d = tomllib.load(f)
pkg = d.get('project', {}).get('name', '').replace('-', '_')
print(pkg)
")
python -c "import ${PACKAGE}; print('Import OK: ${PACKAGE}')"

echo "Environment ready."

assets/config-template.yaml

# great-docs.yml starter configuration
# Copy to your project root and customize.
# All keys are optional — remove what you don't need.

# ── Package identity ──────────────────────────────────────────
# module: my_package          # Python importable name (auto-detected)
# display_name: My Package    # Custom site title
# parser: numpy               # Docstring style: numpy, google, sphinx
# dynamic: true               # false = static analysis (for tricky imports)

# ── Exclusions ────────────────────────────────────────────────
# exclude:
#   - _InternalClass
#   - _helper_fn

# ── Theming ───────────────────────────────────────────────────
# navbar_style: sky           # Gradient: sky, peach, lilac, slate, honey, dusk, mint
# navbar_color: "#1a1a2e"     # Solid color (overrides navbar_style)
# content_style: lilac        # Content area glow
# dark_mode_toggle: true      # Dark mode toggle in navbar
# attribution: true           # "Built with Great Docs" footer

# ── Logo and hero ─────────────────────────────────────────────
# logo: assets/logo.svg       # Or: {light: assets/logo.svg, dark: assets/logo-dark.svg}
# favicon: assets/favicon.png # Auto-generated from logo if SVG
# hero:
#   enabled: true
#   tagline: "Beautiful docs for your Python package"

# ── Announcement banner ───────────────────────────────────────
# announcement:
#   content: "v2.0 released!"
#   type: info                # info, warning, success
#   dismissable: true
#   url: https://example.com/changelog

# ── GitHub ────────────────────────────────────────────────────
# repo: https://github.com/my-org/my-package
# github_style: widget        # widget (shows stars) or icon

# ── Source links ──────────────────────────────────────────────
# source:
#   enabled: true
#   branch: main
#   path: my_package           # Path to source (auto-detected)

# ── Content ───────────────────────────────────────────────────
# homepage: index              # index (README) or user_guide
# sections:
#   - title: Examples
#     dir: examples

# ── CLI documentation ─────────────────────────────────────────
# cli:
#   enabled: true
#   module: my_package.cli     # Module with Click app
#   name: my-cli               # CLI command name

# ── Changelog ─────────────────────────────────────────────────
# changelog:
#   enabled: true              # Auto-generate from GitHub Releases

# ── Sidebar filter ────────────────────────────────────────────
# sidebar_filter:
#   enabled: true
#   min_items: 10              # Show filter when sidebar has 10+ items

# ── Agent skill ───────────────────────────────────────────────
# skill:
#   enabled: true
#   file: skills/my-package/SKILL.md  # Path to hand-written SKILL.md

SKILL LAYOUT

write-user-guide/
├── SKILL.md
└── references/
    ├── page-anatomy.md
    └── writing-guidelines.md

SKILL.md

---
name: write-user-guide
description: >
  Write and maintain narrative user-guide pages for a Great Docs site.
  Covers page creation, QMD frontmatter, section grouping, sidebar
  ordering, callouts, executable code cells, cross-references, and
  content guidelines. Use when adding, reorganizing, or improving
  user-guide content.
license: MIT
compatibility: Requires Great Docs >=0.8, Quarto CLI installed.
metadata:
  author: rich-iannone
  version: "1.0"
  tags:
    - documentation
    - user-guide
    - quarto
    - content-authoring
---

# Write User Guide

Skill for authoring user-guide pages in a Great Docs documentation
site. User guides provide narrative documentation (tutorials,
conceptual explanations, and task walkthroughs) that complement
the auto-generated API reference.

## Quick start

```bash
mkdir -p user_guide
cat > user_guide/00-introduction.qmd << 'EOF'
---
title: "Introduction"
guide-section: "Getting Started"
tags: [Getting Started]
---

# Introduction

Welcome to the project. This guide walks you through...
EOF

great-docs build
```

## Skill directory structure

```
skills/write-user-guide/
├── SKILL.md
└── references/
    ├── page-anatomy.md
    └── writing-guidelines.md
```

## When to use this skill

| Need                         | Action                                         |
| ---------------------------- | ---------------------------------------------- |
| Add a new guide page         | Create `user_guide/NN-topic.qmd`               |
| Reorder pages                | Rename numeric prefixes                        |
| Group pages into sections    | Set `guide-section` in frontmatter             |
| Add an interactive example   | Use `{.python}` code cells in the `.qmd`        |
| Cross-reference another page | Use `[text](../user-guide/page.qmd)` links     |
| Embed a callout              | Use `:::{.callout-tip}` / `:::{.callout-note}` |
| Add images                   | Place in `assets/` and reference from QMD      |

## Core concepts

### File naming convention

Every page in `user_guide/` must have a two-digit numeric prefix
that controls sidebar ordering:

```
user_guide/
├── 00-introduction.qmd     # appears first
├── 01-installation.qmd
├── 02-quickstart.qmd
├── 03-authoring-qmd-files.qmd
└── 04-writing-docstrings.qmd
```

Great Docs strips the prefix for clean URLs:
`00-introduction.qmd` → `user-guide/introduction.html`.

### QMD frontmatter

Every user-guide page starts with YAML frontmatter:

```yaml
---
title: "Writing Docstrings"
guide-section: "Getting Started"
tags: [API, Content]
---
```

**Required keys:**

| Key     | Description                    |
| ------- | ------------------------------ |
| `title` | Page heading and sidebar label |

**Optional keys:**

| Key             | Description                                        |
| --------------- | -------------------------------------------------- |
| `guide-section` | Group pages under a sidebar section header         |
| `tags`          | Content tags for discoverability                   |
| `bread-crumbs`  | Set `false` to hide breadcrumb navigation          |
| `status`        | Page status badge: `experimental`, `new`, `stable` |

### Guide sections

Pages with the same `guide-section` value are grouped together in
the sidebar under a collapsible section heading:

```
Getting Started
├── Introduction
├── Installation
└── Quick Start
Site Content
├── Authoring QMD Files
├── Writing Docstrings
└── User Guides
```

If no `guide-section` is set, the page appears at the top level.

### Page body structure

A well-structured page follows this outline:

```markdown
# Page Title

Opening paragraph: 2-3 sentences explaining what this page covers
and why the reader cares.

## First Major Section

Narrative prose. Keep paragraphs short (3-5 sentences).

### Subsection

More detail. Use tables, code blocks, and callouts to break up text.

## Second Major Section

...
```

**Guidelines:**

- Start every page with a single `#` heading matching the `title`.
- Use `##` for major sections, `###` for subsections.
- Keep the hierarchy flat; avoid `####` if possible.
- Lead each section with a sentence explaining what follows.
- End with a summary or "next steps" when appropriate.

### Callouts

Quarto callouts highlight important information:

```markdown
:::{.callout-tip}

## Pro tip

You can combine `guide-section` with `tags` to make pages
discoverable from multiple angles.
:::

:::{.callout-warning}

## Watch out

Renaming a page file changes its URL. Update any cross-references.
:::

:::{.callout-note}
This feature requires Great Docs 0.8 or later.
:::
```

Available types: `note`, `tip`, `warning`, `caution`, `important`.

### Executable code cells

Embed live Python examples that run during the build:

````markdown
```{.python}
import great_docs
gd = great_docs.GreatDocs()
print(gd.project_path)
```
````

**`{.python}` vs `{.python}`**: this distinction is critical.

- `{.python}` (no dot) creates an **executable** code cell. Quarto
  runs it through the Jupyter kernel during the build and captures
  the output.
- `{.python}` (with a dot) creates a **display-only** code block.
  Quarto syntax-highlights it but never executes it.

Use `{.python}` when the output matters (tables, plots, printed
values). Use `{.python}` for illustrative snippets where execution
is unnecessary or undesirable.

Additional cell-level controls:

- Use `#| eval: false` to show code without executing it.
- Use `#| echo: false` to show only the output.

### Table previews and explorers

When a page involves sample datasets or transformed DataFrames,
use the built-in table widgets instead of raw `print()` output.

**Shortcodes** (for static data files in `assets/data/`):

```markdown


```

**Python API** (for DataFrames produced in executable cells):

````markdown
```{.python}
from great_docs import tbl_preview, tbl_explorer

tbl_preview(df)           # compact head/tail preview
tbl_explorer(df)          # interactive: sort, filter, paginate
```
````

Use `tbl-preview` (or `tbl_preview()`) for a quick glance at a
dataset. Use `tbl-explorer` (or `tbl_explorer()`) when readers
need to sort, search, or paginate the data. Both accept Pandas
DataFrames, Polars DataFrames, and file paths (CSV, TSV, Parquet,
Arrow, JSONL).

### Cross-references

Link to other pages in the site:

```markdown
See the [Configuration](../user-guide/configuration.qmd) page.
See the [API reference](../reference/GreatDocs.qmd) page.
```

Use relative paths from the rendered output location
(`great-docs/user-guide/`), not the source.

### Images and assets

Place images in `assets/` at the project root:

```markdown
![Architecture diagram](../assets/architecture.png)
```

Great Docs copies the `assets/` directory into the build
automatically.

## Workflows

### Adding a new page

```
Task Progress:
- [ ] Step 1: Choose a filename
- [ ] Step 2: Write frontmatter
- [ ] Step 3: Write content
- [ ] Step 4: Build and preview
```

**Step 1**: Pick the next numeric prefix. If the last file is
`08-user-guides.qmd`, name your file `09-new-topic.qmd`.

**Step 2**: Add frontmatter with `title`, `guide-section`, and
optional `tags`.

**Step 3**: Write the body using the page structure guidelines
above.

**Step 4**: Run `great-docs build && great-docs preview` and check
the sidebar ordering and rendered content.

### Reorganizing existing pages

1. Rename files to adjust numeric prefixes.
2. Update `guide-section` values to regroup.
3. Rebuild. Great Docs regenerates the sidebar automatically.
4. Check for broken cross-references.

### Converting a README into a guide page

1. Copy the README content into a new `.qmd` file.
2. Add frontmatter with `title` and `guide-section`.
3. Replace any GitHub-flavored Markdown extensions with Quarto
   equivalents (e.g., `> [!NOTE]` → `:::{.callout-note}`).
4. Rebuild and verify.

## Gotchas

1. **Numeric prefixes control ordering by default.** Without them,
   pages sort alphabetically. Alternatively, you can omit prefixes
   and define an explicit page order in `great-docs.yml`.
2. **Don't skip numbers.** Gaps are fine (`01`, `03`, `05`) but
   large jumps make it hard to insert pages later.
3. **Title must match the `#` heading.** If `title: "Foo"` but
   the body starts with `# Bar`, the sidebar says "Foo" but the
   page says "Bar".
4. **`guide-section` is case-sensitive.** `"Getting Started"` and
   `"getting started"` create separate sections.
5. **Don't nest directories.** All pages must be directly in
   `user_guide/`, not in subdirectories.
6. **Hyphens, not underscores, in filenames.** Great Docs converts
   underscores to hyphens in URLs, so `my_page.qmd` becomes
   `my-page.html`.
7. **Lists need a blank line before them.** A bullet or numbered
   list that immediately follows a paragraph (no blank line) will
   not be parsed as a list by Quarto; it renders as plain text.

references/page-anatomy.md

# Page Anatomy — User Guide Pages

A Great Docs user-guide page is a Quarto Markdown (`.qmd`) file with
three layers: frontmatter, body content, and optional executable code.

## Frontmatter block

```yaml
---
title: "Page Title"
guide-section: "Section Name"
tags: [Tag1, Tag2]
bread-crumbs: true
status: new
---
```

### Frontmatter keys

| Key                | Required | Type     | Default        | Description                                         |
| ------------------ | -------- | -------- | -------------- | --------------------------------------------------- |
| `title`            | yes      | `str`    |                | Page title shown in sidebar and heading             |
| `guide-section`    | no       | `str`    |                | Groups pages under a sidebar section                |
| `tags`             | no       | `list`   | `[]`           | Content tags for the page-tags widget               |
| `tag-location`     | no       | `str`    | (site default) | Override tag badge position: `top` or `bottom`      |
| `status`           | no       | `str`    |                | Status badge: `experimental`, `new`, `stable`       |
| `bread-crumbs`     | no       | `bool`   | `true`         | Show or hide breadcrumb navigation                  |
| `description`      | no       | `str`    |                | Page description for metadata and social cards      |
| `image`            | no       | `str`    |                | Social-card / Open Graph image path                 |
| `toc`              | no       | `bool`   | `true`         | Show or hide the table of contents                  |
| `toc-depth`        | no       | `int`    | `2`            | Heading depth for TOC entries                       |
| `page-navigation`  | no       | `bool`   | `true`         | Show or hide prev/next navigation links             |
| `freeze`           | no       | `bool`   | `false`        | Cache code cell output across builds                |
| `layout`           | no       | `str`    | `passthrough`  | Page layout mode: `passthrough` or `raw`            |
| `body-classes`     | no       | `str`    |                | Extra CSS classes added to the page body             |
| `code-fold`        | no       | `bool`   | `false`        | Collapse code blocks by default (page-wide)         |
| `code-summary`     | no       | `str`    | `"Code"`       | Label for collapsed code blocks (page-wide)         |

## Body content

The body uses standard Quarto Markdown:

```
# Heading 1          — page title (should match `title`)
## Heading 2         — major section
### Heading 3        — subsection
#### Heading 4       — rarely needed; avoid if possible

**Bold**, *italic*, `inline code`

- Bullet list
- Another item

1. Numbered list
2. Another item

| Col A | Col B |
| ----- | ----- |
| val   | val   |

> Blockquote

:::{.callout-note}
Callout body
:::

[Link text](url)
![Alt text](image-path)
```

## Executable code cells

~~~
```{.python}
#| label: example
#| echo: true
#| eval: true
import mypackage
mypackage.hello()
```
~~~

### Cell options

| Option         | Default | Description                                      |
| -------------- | ------- | ------------------------------------------------ |
| `label`        |         | Unique identifier for the cell (for references)  |
| `eval`         | `true`  | Execute the cell during build                    |
| `echo`         | `true`  | Show the source code in output                   |
| `output`       | `true`  | Show the cell output                             |
| `warning`      | `true`  | Show warnings emitted during execution           |
| `code-fold`    | `false` | Collapse the code block (reader can expand)      |
| `code-summary` | `Code`  | Label on the collapsed code toggle               |
| `fig-cap`      |         | Caption for figure output                        |
| `fig-width`    |         | Width of figure output (inches)                  |
| `fig-height`   |         | Height of figure output (inches)                 |
| `tbl-cap`      |         | Caption for table output                         |
| `classes`      |         | Extra CSS classes on the output container        |

## File location

```
project-root/
├── user_guide/
│   ├── 00-introduction.qmd
│   ├── 01-installation.qmd
│   └── ...
├── great-docs.yml
└── pyproject.toml
```

The numeric prefix (`00-`, `01-`, ...) controls sidebar ordering.
Great Docs strips it for clean URLs.

references/writing-guidelines.md

# Writing Guidelines — User Guide Content

## Voice and tone

- **Second person** ("you") for instructions.
- **Active voice** preferred over passive.
- **Present tense** for descriptions, imperative for instructions.
- Keep sentences short (under 25 words when possible).
- One idea per paragraph.
- **No emoji.** Never use emoji in generated prose.
- **No em dashes.** Use commas, semicolons, colons, or
  parentheses instead. Restructure the sentence if needed.
- **Always introduce a list.** Every bullet or numbered list
  must be preceded by a sentence or phrase that introduces it.

## Structure

### Opening paragraph

Every page starts with 2-3 sentences that answer:

1. What does this page cover?
2. Why should the reader care?

Do not start with "This page explains..." — jump straight into the
value proposition.

**Good:**

> Your docstrings are the single biggest input to your API reference.
> A well-written docstring becomes a polished reference page with
> almost no extra effort.

**Avoid:**

> This page will explain how to write docstrings for your package.

### Sections

- Use `##` for major topics, `###` for details.
- Keep sections focused — one concept per `##`.
- Lead each section with a sentence summarizing what follows.
- End long pages with a "Next steps" or "Summary" section.

### Code examples

- Show the minimal example that demonstrates the concept.
- Use realistic values (not `foo`, `bar`, `baz`).
- Prefer executable cells (`{.python}`) when the output helps.
- Use `{.yaml filename="great-docs.yml"}` for config examples.
- Include comments only when the code is not self-explanatory.

### Tables

Use tables for reference-style information (options, parameters,
comparison matrices). Keep columns to 3-4 maximum.

### Data tables and DataFrames

When a page shows sample data or the output of a DataFrame
transformation, prefer the built-in table widgets over raw
`print()` output:

- `tbl_preview(df)` or `` for a
  compact head/tail view.
- `tbl_explorer(df)` or `` for an
  interactive table with sorting, filtering, and pagination.

Both accept Pandas DataFrames, Polars DataFrames, and file paths
(CSV, TSV, Parquet, Arrow, JSONL). Use `tbl-preview` by default;
reach for `tbl-explorer` when readers benefit from interacting
with the data.

### Callouts

| Type          | Use for                                      |
| ------------- | -------------------------------------------- |
| `.callout-tip`      | Best practices, shortcuts, pro tips    |
| `.callout-note`     | Additional context, version notes      |
| `.callout-warning`  | Common mistakes, breaking changes      |
| `.callout-important`| Critical information, must-reads       |
| `.callout-caution`  | Destructive actions, data loss risks   |

Use callouts sparingly — more than 2-3 per page dilutes their impact.

## Common mistakes

1. **Walls of text.** Break prose with code blocks, tables, or
   callouts every 3-4 paragraphs.
2. **Missing frontmatter.** Every `.qmd` needs at least `title`.
3. **Deep heading nesting.** If you reach `####`, the page probably
   needs splitting into two pages.
4. **Stale cross-references.** After renaming a file, search the
   entire `user_guide/` directory for old references.
5. **Overly long pages.** If a page exceeds ~800 words, consider
   splitting it. Each page should cover one focused topic.
6. **Orphaned lists.** A list that appears without any introductory
   text feels abrupt. Always write a lead-in sentence or phrase
   before the first bullet or number.
7. **Em dashes in prose.** Quarto renders them fine, but the
   project style avoids them. Use commas, semicolons, colons, or
   parentheses instead.

SKILL LAYOUT

revise-docstrings/
├── SKILL.md
└── references/
    ├── docstring-checklist.md
    └── style-examples.md

SKILL.md

---
name: revise-docstrings
description: >
  Review and improve Python docstrings for Great Docs API reference
  generation. Covers NumPy and Google style conventions, parameter
  documentation, return types, examples, cross-references, and
  Great Docs directives (%seealso, %nodoc). Use when auditing,
  writing, or fixing docstrings in a Python package.
license: MIT
compatibility: Requires Great Docs >=0.8, Quarto CLI installed.
metadata:
  author: rich-iannone
  version: "1.0"
  tags:
    - documentation
    - docstrings
    - python
    - api-reference
---

# Revise Docstrings

Skill for reviewing and improving Python docstrings so they render
correctly and completely in a Great Docs API reference site.

## Quick start

```bash
# Preview what Great Docs will document
great-docs scan --verbose

# Build and check the rendered reference
great-docs build && great-docs preview
```

## Skill directory structure

```
skills/revise-docstrings/
├── SKILL.md
└── references/
    ├── docstring-checklist.md
    └── style-examples.md
```

## When to use this skill

| Need                               | Action                                  |
| ---------------------------------- | --------------------------------------- |
| Audit docstring completeness       | Run checklist on each public symbol     |
| Convert Google→NumPy (or reverse)  | Reformat following style-examples.md    |
| Add missing parameter descriptions | Fill in Parameters section              |
| Add a live example                 | Use Examples section with `>>>` prompts |
| Cross-reference related symbols    | Add `%seealso` directive                |
| Hide an internal symbol            | Add `%nodoc` directive                  |
| Fix rendering issues               | Check against common pitfalls below     |

## Core concepts

### Docstring formats

Great Docs supports two formats. Set the parser in config:

```yaml
# great-docs.yml
parser: numpy # or "google"
```

Both produce identical rendered output. Use whichever your codebase
already uses.

### NumPy style

````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, authenticates
    with default credentials, and returns an active connection handle.

    Parameters
    ----------
    host
        Hostname or IP address of the database server.
    port
        TCP port number. Defaults to `5432`.

    Returns
    -------
    Connection
        An authenticated connection ready for queries.

    Raises
    ------
    ConnectionError
        If the server is unreachable.

    Examples
    --------
    Connect to a local server and run a simple query:

    ```{.python}
    conn = connect("localhost")
    conn.execute("SELECT 1")
    ```

    See Also
    --------
    disconnect : Close a connection.

    Notes
    -----
    The connection uses TLS by default when port 5433 is specified.
    """
````

### Google style

````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, authenticates
    with default credentials, and returns an active connection handle.

    Args:
        host: Hostname or IP address of the database server.
        port: TCP port number. Defaults to `5432`.

    Returns:
        An authenticated connection ready for queries.

    Raises:
        ConnectionError: If the server is unreachable.

    Examples:
        Connect and run a query:

        ```{.python}
        conn = connect("localhost")
        conn.execute("SELECT 1")
        ```
    """
````

### Sections recognized by Great Docs

| Section          | NumPy header | Google header | Purpose                                |
| ---------------- | ------------ | ------------- | -------------------------------------- |
| Summary          | first line   | first line    | One-line description                   |
| Extended summary | body text    | body text     | Multi-paragraph explanation            |
| Parameters       | `Parameters` | `Args:`       | Function/method arguments              |
| Returns          | `Returns`    | `Returns:`    | Return value description               |
| Raises           | `Raises`     | `Raises:`     | Exceptions that may be raised          |
| Examples         | `Examples`   | `Examples:`   | Usage examples (Quarto cells or `>>>`) |
| Notes            | `Notes`      | `Notes:`      | Implementation details                 |
| See Also         | `See Also`   | —             | Related symbols                        |
| Warns            | `Warns`      | —             | Warnings issued                        |
| References       | `References` | `References:` | Citations or links                     |

### Great Docs directives

Special inline directives using `%` prefix:

```python
def my_function():
    """
    Description.

    %seealso other_func, SomeClass: related utilities
    %nodoc
    """
```

| Directive  | Effect                                              |
| ---------- | --------------------------------------------------- |
| `%seealso` | Renders a "See Also" box with cross-reference links |
| `%nodoc`   | Excludes this symbol from the API reference         |

### Type annotations vs docstring types

- **Prefer type annotations** in the function signature.
- Great Docs reads annotations automatically — no need to duplicate
  types in the docstring. Write bare parameter names (e.g., `host`
  not `host : str`) and let the signature annotation render on the
  reference page.
- If you _do_ add a type in the docstring (e.g., `host : str`), it
  **overwrites** the annotation in the rendered output. This can be
  useful to show a simplified form (e.g., `str or Path` instead of
  `str | pathlib.Path`), but it creates a maintenance risk: the
  docstring type and the annotation can drift apart silently.
- **Rule of thumb:** omit docstring types unless the annotation is
  confusing to readers. Keep one source of truth.

## Workflows

### Auditing a package's docstrings

```
Task Progress:
- [ ] Step 1: List public API
- [ ] Step 2: Check each symbol
- [ ] Step 3: Fix issues
- [ ] Step 4: Rebuild and verify
```

**Step 1**: Run `great-docs scan --verbose` to see every symbol
Great Docs will document.

**Step 2**: For each symbol, run through the checklist in
[references/docstring-checklist.md](references/docstring-checklist.md).

**Step 3**: Fix missing or incorrect sections. Use
[references/style-examples.md](references/style-examples.md) as
a template.

**Step 4**: Rebuild with `great-docs build` and check the rendered
pages in the browser.

### Writing a docstring from scratch

1. Start with a one-line summary (imperative mood: "Connect to...",
   "Return the...", "Parse the...").
2. Add an extended summary if the one-liner is insufficient.
3. Document every parameter with name, type, and description.
4. Document the return value.
5. Add `Raises` if the function can raise exceptions.
6. Add an `Examples` section with Quarto code cells (preferred)
   or `>>>` prompts. Use `{.python}` for executable cells,
   `{.python}` for display-only. Wrap cells with short prose.
7. Add `%seealso` for closely related symbols.

### Fixing a rendering issue

Common rendering problems and their fixes:

| Problem                         | Cause                          | Fix                                         |
| ------------------------------- | ------------------------------ | ------------------------------------------- |
| Parameter not showing           | Wrong indentation              | Align to 4 spaces under section header      |
| Code block not rendering        | Missing blank line before code | Add blank line above cell or `>>>`          |
| Type mismatch warning           | Annotation ≠ docstring type    | Remove type from docstring, keep annotation |
| Symbol missing from reference   | Not exported in `__init__.py`  | Add import to `__init__.py`                 |
| Entire docstring shown as prose | Wrong parser setting           | Check `parser:` in great-docs.yml           |

## Gotchas

1. **One-line summary is required.** Without it, the API reference
   page shows no description at all.
2. **Blank line after summary.** NumPy style requires a blank line
   between the summary and the extended summary.
3. **Indentation matters.** Parameters must be indented consistently
   (4 spaces for NumPy, nested under `Args:` for Google).
4. **Don't mix styles.** All docstrings in a package must use the
   same format. Mixing causes parsing failures.
5. **`%nodoc` hides completely.** Use `exclude` in config for
   selective hiding without modifying source code.
6. **Prefer Quarto cells over `>>>` prompts.** `{.python}` cells
   render output automatically and support prose between steps.
   Use `{.python}` for non-executable illustration.
7. **Class docstrings go on the class, not `__init__`.** Great Docs
   reads the class-level docstring for the class page.

references/docstring-checklist.md

# Docstring Checklist

Run through this checklist for every public symbol in the package.

## Functions and methods

- [ ] One-line summary in imperative mood ("Return the...", not
      "Returns the...")
- [ ] Extended summary if behavior is non-obvious
- [ ] Every parameter documented with description
- [ ] Type annotations present in the signature (not just docstring)
- [ ] `Returns` section with type and description
- [ ] `Raises` section for each exception that can be raised
- [ ] At least one `Examples` entry — prefer Quarto `{.python}` cells
      with prose; `>>>` prompts are acceptable for simple cases
- [ ] `%seealso` directive for closely related functions
- [ ] No private parameters documented (leading `_`)
- [ ] Default values mentioned in parameter descriptions

## Classes

- [ ] Class-level docstring (not on `__init__`)
- [ ] One-line summary describing what the class represents
- [ ] Constructor parameters documented under `Parameters`
- [ ] Key public methods mentioned in extended summary or `Notes`
- [ ] `Examples` showing basic instantiation and usage

## Properties

- [ ] One-line summary describing what the property returns
- [ ] Type annotation on the `@property` return
- [ ] `Returns` section if the value is complex

## Module-level constants

- [ ] Docstring or inline comment explaining the constant's purpose
- [ ] Type annotation

## Common issues to flag

- Docstring says "Returns" but function returns `None`
- Parameter name in docstring doesn't match signature
- Missing blank line between summary and extended summary
- Inconsistent style (NumPy in some files, Google in others)
- Examples that import from internal modules (`_private`)
- Stale parameter documentation after a signature change

references/style-examples.md

# Style Examples — Docstring Templates

## Function — NumPy style

```python
def read_csv(
    path: str | Path,
    delimiter: str = ",",
    header: bool = True,
) -> DataFrame:
    """
    Read a CSV file into a DataFrame.

    Parses the file at *path* using the specified delimiter and returns a
    DataFrame. The first row is treated as column headers by default.

    Parameters
    ----------
    path
        Path to the CSV file. Supports local paths and `s3://` URIs.
    delimiter
        Column separator character. Defaults to `","`.
    header
        If `True`, the first row is used as column names. If `False`, columns
        are numbered `0, 1, 2, ...`.

    Returns
    -------
    DataFrame
        Parsed tabular data with one row per record.

    Raises
    ------
    FileNotFoundError
        If *path* does not exist.
    ValueError
        If the file contains no data rows.

    Examples
    --------
    Read a simple CSV file and inspect its shape:

    ```{.python}
    df = read_csv("data/sales.csv")
    df.shape
    ```

    Use a tab delimiter for TSV files:

    ```{.python}
    df = read_csv("data/tsv_file.tsv", delimiter="\t")
    ```

    See Also
    --------
    write_csv : Write a DataFrame to CSV.
    read_parquet : Read Parquet files.

    Notes
    -----
    Large files (>1 GB) are read in chunks internally. Memory usage stays
    bounded regardless of file size.
    """
```

### Parameter types — when to include them

In NumPy-style docstrings the parameter name can optionally carry a
type after a colon (`path : str or Path`). When the function
signature already has a type annotation, **omit the type from the
docstring** — Great Docs reads the annotation automatically and
renders it on the reference page.

If you *do* add a type in the docstring, it **overwrites** the
annotation in the rendered output. This is occasionally useful (e.g.,
to show a simplified union like `str or Path` instead of
`str | pathlib.Path`), but it creates a maintenance burden: the
docstring type and the annotation can drift out of sync silently.

**Rule of thumb:** leave parameter lines as bare names and let the
annotations speak for themselves. Add a docstring type only when the
rendered annotation would confuse readers.

## Examples — Quarto code cells

Great Docs renders docstrings through Quarto, so the Examples section
can use Quarto code cells instead of `>>>` prompts. This gives you
executable output, syntax highlighting, and the ability to weave
prose between cells.

### Executable cell

Use `{.python}` (curly braces, no dot) to make a cell that runs
during the build. The output is captured and rendered inline:

```
    Examples
    --------
    Read a CSV and check the row count:

    ```{.python}
    df = read_csv("data/sales.csv")
    df.shape
    ```
```

Quarto executes the cell, so readers see both the code and its
result — no need to hardcode output.

### Non-executable cell

Use `{.python}` (dot prefix) when the code is illustrative but
should not run (e.g., it depends on external resources or is
expensive):

```
    Examples
    --------
    Read a remote Parquet file:

    ```{.python}
    df = read_parquet("s3://bucket/warehouse/events.parquet")
    ```
```

The cell renders with syntax highlighting but no execution.

### Mixing cells with prose

Wrap each cell in a short sentence or two of context. This produces
a mini-tutorial on the reference page:

```
    Examples
    --------
    Open a connection to the default local server:

    ```{.python}
    conn = connect("localhost")
    ```

    Run a query and fetch results as a list of rows:

    ```{.python}
    rows = conn.execute("SELECT id, name FROM users LIMIT 5")
    rows
    ```

    Always close the connection when finished:

    ```{.python}
    conn.close()
    ```
```

### When to use `>>>` prompts

The traditional `>>>` style still works and is fine for simple,
self-contained snippets. Prefer Quarto cells when:

- The example benefits from rendered output (tables, plots)
- You want prose between steps
- The example has multiple logical steps

## Function — Google style

```python
def read_csv(
    path: str | Path,
    delimiter: str = ",",
    header: bool = True,
) -> DataFrame:
    """Read a CSV file into a DataFrame.

    Parses the file at *path* using the specified delimiter and returns a
    DataFrame. The first row is treated as column headers by default.

    Args:
        path: Path to the CSV file. Supports local paths and `s3://` URIs.
        delimiter: Column separator character. Defaults to `","`.
        header: If `True`, the first row is used as column names. If `False`,
            columns are numbered `0, 1, 2, ...`.

    Returns:
        Parsed tabular data with one row per record.

    Raises:
        FileNotFoundError: If *path* does not exist.
        ValueError: If the file contains no data rows.

    Examples:
        Read a CSV and check its shape:

        ```{.python}
        df = read_csv("data/sales.csv")
        df.shape
        ```
    """
```

## Class — NumPy style

```python
class Connection:
    """
    A database connection handle.

    Wraps a TCP socket to the database server and provides methods for
    executing queries, managing transactions, and streaming result sets.

    Parameters
    ----------
    host
        Server hostname or IP address.
    port
        TCP port. Defaults to `5432`.
    timeout
        Connection timeout in seconds. Defaults to `30.0`.

    Examples
    --------
    Create a connection and run a query:

    ```{.python}
    conn = Connection("localhost")
    result = conn.execute("SELECT 1")
    conn.close()
    ```

    See Also
    --------
    connect : Factory function for creating connections.
    ConnectionPool : Manage a pool of reusable connections.
    """

    def __init__(self, host: str, port: int = 5432, timeout: float = 30.0):
        ...
```

## Property — NumPy style

```python
@property
def is_connected(self) -> bool:
    """
    Check whether the connection is still alive.

    Returns
    -------
    bool
        `True` if the connection is open and responsive.
    """
```

## Directive usage

```python
def internal_helper():
    """
    Normalize column names.

    %nodoc
    """

def public_function():
    """
    Transform the dataset.

    %seealso other_transform, Pipeline: related transformation tools
    """
```

SKILL LAYOUT

configure-site/
├── SKILL.md
└── references/
    ├── feature-matrix.md
    └── theming-options.md

SKILL.md

---
name: configure-site
description: >
  Configure a Great Docs documentation site through great-docs.yml.
  Covers theming (navbar gradients, content glow, dark mode), hero
  sections, logos, announcements, sidebar options, page tags, page
  status badges, SEO, analytics, and deployment settings. Use when
  customizing site appearance, enabling features, or tuning build
  behavior.
license: MIT
compatibility: Requires Great Docs >=0.8, Quarto CLI installed.
metadata:
  author: rich-iannone
  version: "1.0"
  tags:
    - documentation
    - configuration
    - theming
    - deployment
---

# Configure Site

Skill for customizing a Great Docs documentation site through
`great-docs.yml`. All configuration is centralized in this single
YAML file at the project root.

## Quick start

```bash
# Generate a starter config
great-docs init

# Or generate a full template with all options
great-docs config > great-docs.yml

# Edit, then rebuild
great-docs build && great-docs preview
```

## Skill directory structure

```
skills/configure-site/
├── SKILL.md
└── references/
    ├── theming-options.md
    └── feature-matrix.md
```

## When to use this skill

| Need                      | Config key                              |
| ------------------------- | --------------------------------------- |
| Add a gradient navbar     | `navbar_style: sky`                     |
| Set a solid navbar color  | `navbar_color: "#1a1a2e"`               |
| Add content area glow     | `content_style: lilac`                  |
| Add a logo                | `logo: assets/logo.svg`                 |
| Add light/dark logos      | `logo: {light: ..., dark: ...}`         |
| Set a favicon             | `favicon: assets/favicon.svg`           |
| Enable hero section       | `hero: true` or `hero: {enabled: true}` |
| Add starfield animation   | `hero: {starfield: true}`               |
| Show announcement banner  | `announcement: {content: "...", ...}`   |
| Enable dark mode toggle   | `dark_mode_toggle: true`                |
| Enable page tags          | `tags: {enabled: true}`                 |
| Enable page status badges | `page_status: true`                     |
| Configure sidebar filter  | `sidebar_filter: {enabled: true}`       |
| Set display name          | `display_name: "My Package"`            |
| Exclude symbols from docs | `exclude: [PrivateClass]`               |
| Enable CLI documentation  | `cli: {enabled: true, module: ...}`     |
| Set docstring parser      | `parser: numpy`                         |
| Use static analysis       | `dynamic: false`                        |
| Enable link checker       | Built-in: `great-docs check-links`      |
| Add analytics             | `include_in_header: [{text: ...}]`      |
| Enable multi-version docs | `versions: [{label: ..., tag: ...}]`    |

## Core concepts

### Configuration file location

`great-docs.yml` must be at the project root, alongside
`pyproject.toml`. Great Docs reads it automatically on every
command.

### Configuration categories

The config file is organized into logical groups:

1. **Package metadata** — `module`, `display_name`, `parser`,
   `dynamic`, `exclude`
2. **GitHub integration** — `repo`, `github_style`, `source`
3. **Navigation & theming** — `navbar_style`, `navbar_color`,
   `content_style`, `dark_mode_toggle`, `nav_icons`
4. **Branding** — `logo`, `favicon`, `hero`, `announcement`
5. **Content** — `sections`, `cli`, `tags`, `page_status`,
   `sidebar_filter`
6. **Build & publish** — `versions`, `skill`, `changelog`, `seo`,
   `include_in_header`
7. **Author metadata** — `authors`, `funding`

### Theming presets

Great Docs ships with named gradient presets for the navbar and
content area. See
[references/theming-options.md](references/theming-options.md) for
the full palette.

```yaml
navbar_style: sky       # gradient navbar
content_style: lilac    # content glow

# Or limit content glow to the homepage only:
content_style:
  preset: lilac
  pages: homepage
```

Available presets: `sky`, `peach`, `prism`, `lilac`, `slate`,
`honey`, `dusk`, `mint`.

### Logo configuration

```yaml
# Single logo for both themes
logo: assets/logo.svg

# Separate light/dark logos
logo:
  light: assets/logo-light.svg
  dark: assets/logo-dark.svg
```

### Hero section

The hero is the large landing area on the homepage:

```yaml
hero:
  enabled: true
  tagline: "Your tagline here."
  starfield: true # animated starfield canvas
```

Or use the shorthand: `hero: true` (uses package description as
the tagline).

### Announcement banner

```yaml
announcement:
  content: "v2 is out! <a href='...'>Read more</a>"
  type: info # info, warning, success, danger
  style: mint # gradient preset (optional)
  dismissable: true # show close button
```

Shorthand: `announcement: "Your message here"`.

### Page tags

```yaml
tags:
  enabled: true
  icons:
    Getting Started: rocket
    Configuration: cog
    API: file-code
```

Pages opt in via frontmatter: `tags: [Getting Started, API]`.

### Page status badges

```yaml
page_status: true
```

Pages set their status in frontmatter:

```yaml
---
title: "New Feature"
status: experimental # experimental, new, stable, deprecated
---
```

### Navigation icons

Add Lucide icons to navbar and sidebar labels:

```yaml
nav_icons:
  navbar:
    User Guide: book-open
    Reference: code
  sidebar:
    Installation: download
    Quick Start: rocket
```

### Multi-version documentation

```yaml
versions:
  - label: "2.0 (dev)"
    tag: dev
    version: "2.0.0"
    prerelease: true
  - label: "1.0"
    tag: "1.0"
    git_ref: v1.0.0
    latest: true
  - label: "0.9"
    tag: "0.9"
    git_ref: v0.9
    eol: true # end-of-life badge
```

### SEO

```yaml
seo:
  sitemap: true
  canonical:
    base_url: https://your-package.readthedocs.io/
  meta:
    description: "Custom meta description"
```

### Excluding symbols

```yaml
exclude:
  - _InternalClass
  - deprecated_function
  - Config # re-exported third-party type
```

## Workflows

### Setting up a new site's appearance

```
Task Progress:
- [ ] Step 1: Choose a navbar style
- [ ] Step 2: Set content glow
- [ ] Step 3: Add logo and favicon
- [ ] Step 4: Configure hero section
- [ ] Step 5: Build and preview
```

**Step 1**: Pick a `navbar_style` preset. Preview each by building.

**Step 2**: Set `content_style` to a complementary preset.

**Step 3**: Add SVG or PNG logo files to `assets/` and configure
the `logo` key. Set `favicon` similarly.

**Step 4**: Enable `hero` with a tagline. Add `starfield: true`
for the animated background.

**Step 5**: Run `great-docs build && great-docs preview`.

### Enabling a feature

1. Find the relevant config key (use the table above or
   [references/feature-matrix.md](references/feature-matrix.md)).
2. Add it to `great-docs.yml`.
3. Rebuild with `great-docs build`.
4. Check the rendered output in the browser.

### Migrating from a minimal config

If you started with `great-docs init` and want to add more features:

1. Run `great-docs config` to see all available options.
2. Copy the sections you want into your existing `great-docs.yml`.
3. Customize values.
4. Rebuild.

## Gotchas

1. **YAML indentation matters.** Use 2-space indentation. Tabs
   cause parse errors.
2. **`module` is the import name.** For PyPI package `py-shiny`,
   set `module: shiny`, not `module: py-shiny`.
3. **Preset names are case-sensitive.** Use lowercase: `sky`, not
   `Sky`.
4. **`hero: true` is shorthand.** For full control, use the dict
   form with `enabled`, `tagline`, and `starfield` keys.
5. **Logo paths are relative to the project root.** Not relative
   to `great-docs.yml`.
6. **`content_style` on homepage only.** Use the dict form with
   `pages: homepage` to avoid the glow on every page.
7. **Changes require rebuild.** Config changes are not hot-reloaded.
   Always run `great-docs build` after editing `great-docs.yml`.
8. **Version `git_ref` must exist.** The tag or branch must exist
   in the Git repository or the versioned build will fail.

references/feature-matrix.md

# Feature Matrix — great-docs.yml

Quick reference for every toggleable feature and its config key.

## Features enabled by default

| Feature                | Config key             | Default | How to disable       |
| ---------------------- | ---------------------- | ------- | -------------------- |
| API reference          | (always on)            | —       | Cannot be disabled   |
| Dark mode toggle       | `dark_mode_toggle`     | `true`  | Set to `false`       |
| Skill generation       | `skill.enabled`        | `true`  | Set to `false`       |
| Changelog              | `changelog.enabled`    | `true`  | Set to `false`       |
| Source links           | `source.enabled`       | `true`  | Set to `false`       |
| Attribution footer     | `attribution`          | `true`  | Set to `false`       |
| `.well-known` skills   | `skill.well_known`     | `true`  | Set to `false`       |
| Dynamic introspection  | `dynamic`              | `true`  | Set to `false`       |

## Features disabled by default

| Feature                | Config key              | How to enable                       |
| ---------------------- | ----------------------- | ----------------------------------- |
| Navbar gradient        | `navbar_style`          | Set to a preset name                |
| Solid navbar color     | `navbar_color`          | Set to a hex color                  |
| Content glow           | `content_style`         | Set to a preset name                |
| Hero section           | `hero.enabled`          | Set to `true`                       |
| Announcement banner    | `announcement`          | Set content string or dict          |
| CLI documentation      | `cli.enabled`           | Set to `true`                       |
| Page tags              | `tags.enabled`          | Set to `true`                       |
| Page status badges     | `page_status`           | Set to `true`                       |
| Sidebar filter         | `sidebar_filter.enabled`| Set to `true`                       |
| Page timestamps        | `site.show_dates`       | Set to `true`                       |
| Back-to-top button     | `back_to_top`           | Set to `true`                       |
| Keyboard navigation    | `keyboard_nav`          | Set to `true`                       |
| Navigation icons       | `nav_icons`             | Add navbar/sidebar icon mappings    |
| Multi-version docs     | `versions`              | Add version entries list            |
| SEO sitemap            | `seo.sitemap`           | Set to `true`                       |
| Social cards           | `seo.social_cards`      | Set to `true`                       |
| Custom sections        | `sections`              | Add section entries list            |
| Authors sidebar        | `authors`               | Add author entries list             |
| Funding info           | `funding`               | Add funding dict                    |
| Logo                   | `logo`                  | Set path or light/dark dict         |
| Favicon                | `favicon`               | Set path                            |
| Display name           | `display_name`          | Set string                          |
| Analytics              | `include_in_header`     | Add script tags                     |

## Feature dependencies

Some features require other features or external setup:

| Feature              | Requires                                   |
| -------------------- | ------------------------------------------ |
| CLI docs             | Click-based CLI module                     |
| Multi-version docs   | Git tags/branches for each version         |
| Source links         | GitHub repository URL (auto-detected)      |
| Changelog            | GitHub Releases on the repository          |
| Navigation icons     | Lucide icon names                          |
| Page status badges   | `status` key in page frontmatter           |
| Page tags            | `tags` key in page frontmatter             |
| SEO sitemap          | `seo.canonical.base_url` must be set       |

references/theming-options.md

# Theming Options — Great Docs

## Navbar gradient presets

Set with `navbar_style` in `great-docs.yml`.

| Preset   | Description                              |
| -------- | ---------------------------------------- |
| `sky`    | Blue gradient — professional, calm       |
| `peach`  | Warm peach/coral — friendly, inviting    |
| `prism`  | Multi-color rainbow — vibrant, playful   |
| `lilac`  | Purple/lavender — elegant, creative      |
| `slate`  | Gray/steel — minimal, serious            |
| `honey`  | Gold/amber — warm, earthy                |
| `dusk`   | Deep blue/purple — dramatic, modern      |
| `mint`   | Green/teal — fresh, clean                |

## Content area glow presets

Set with `content_style` in `great-docs.yml`. Uses the same palette
names as navbar presets.

```yaml
# All pages
content_style: lilac

# Homepage only
content_style:
  preset: lilac
  pages: homepage
```

## Solid navbar color

Use `navbar_color` instead of `navbar_style` for a flat color:

```yaml
# Same color for both themes
navbar_color: "#1a1a2e"

# Different colors per theme
navbar_color:
  light: "#ffffff"
  dark: "#1a1a2e"
```

`navbar_style` and `navbar_color` are mutually exclusive. If both
are set, `navbar_style` wins.

## Dark mode

```yaml
dark_mode_toggle: true   # show toggle switch in navbar (default)
dark_mode_toggle: false  # hide toggle, use system preference only
```

All gradient presets and content glows have dark-mode variants that
activate automatically.

## Custom CSS

For fine-grained control, add a custom SCSS/CSS file:

```yaml
include_in_header:
  - text: |
      <link rel="stylesheet" href="custom.css">
```

Place `custom.css` in the project root or `assets/` directory.
Override Great Docs CSS variables for targeted changes:

```css
/* custom.css */
:root {
  --gd-navbar-bg: #2d3748;
  --gd-navbar-text: #e2e8f0;
}
```

## Combining options

Typical aesthetic combinations:

| Style         | Navbar     | Content    | Hero       |
| ------------- | ---------- | ---------- | ---------- |
| Professional  | `sky`      | `sky`      | no starfield|
| Playful       | `prism`    | `peach`    | starfield   |
| Minimal       | `slate`    | none       | no starfield|
| Elegant       | `dusk`     | `lilac`    | starfield   |
| Nature        | `mint`     | `mint`     | no starfield|

SKILL LAYOUT

author-skills/
├── SKILL.md
└── references/
    ├── config-reference.md
    └── skill-anatomy.md

SKILL.md

---
name: author-skills
description: >
  Author, configure, and distribute Agent Skills for a Great Docs
  site. Covers the three scenarios: automatic skill generation,
  adding a single hand-written skill, and distributing multiple
  named skills with a switcher page. Use when creating, editing,
  or configuring SKILL.md files for package documentation.
license: MIT
compatibility: Requires Great Docs >=0.8, Quarto CLI installed.
metadata:
  author: rich-iannone
  version: "1.0"
  tags:
    - skills
    - agent-skills
    - distribution
    - configuration
---

# Author Skills

Skill for creating and distributing Agent Skills through a Great
Docs documentation site. An Agent Skill is a structured Markdown
file (`SKILL.md`) that gives AI coding agents context about a
package, its API, and best practices.

Great Docs supports three scenarios for skills, each with a
different level of effort and control.

## The three scenarios

### Scenario 1: Automatic generation

Great Docs generates a `skill.md` automatically from your
package metadata, API reference sections, and `great-docs.yml`
config. This is the zero-effort default.

**How it works**: during `great-docs build`, the tool reads your
`pyproject.toml` (for name, description, license, Python version),
your API reference sections, and any `skill.*` config keys. It
produces a skill file with installation instructions, an API
overview, gotchas, best practices, and resource links.

**Config options that enrich the auto-generated skill:**

```yaml
# great-docs.yml
skill:
  enabled: true # default; set false to skip
  well_known: true # publish to .well-known/agent-skills/
  gotchas:
    - "Column expressions are lazy; call .collect() to materialize."
    - "Method chaining returns a new object; the original is not mutated."
  best_practices:
    - "Prefer method chaining over intermediate variables."
  decision_table:
    - need: "Create a table from a dict"
      use: "GT(data)"
    - need: "Format currency values"
      use: "fmt_currency()"
  extra_body: "skills/extra-skill-content.md"
```

**When to use this scenario**: you want a skill page with minimal
effort and are satisfied with auto-generated content derived from
your API reference.

### Scenario 2: Single hand-written skill

Write a `SKILL.md` by hand (or with LLM assistance) and point
`great-docs.yml` at it. Great Docs copies it into the build and
generates the Skills page from it.

**Directory layout:**

```
project-root/
├── skills/
│   └── my-package/
│       ├── SKILL.md
│       └── references/
│           ├── api-patterns.md
│           └── gotchas.md
└── great-docs.yml
```

**Config:**

```yaml
# great-docs.yml
skill:
  file: skills/my-package/SKILL.md
```

Great Docs copies the file to `<docs>/skill.md`, places it
under `.well-known/agent-skills/<name>/SKILL.md`, and generates
the Skills page with install instructions and the full skill
content.

**When to use this scenario**: you want full editorial control
over the skill content, including custom sections, curated
examples, and reference files that go beyond what automatic
generation can produce.

### Scenario 3: Multiple named skills

Distribute several focused skills from a single site. Each skill
gets its own panel on the Skills page (with a switcher bar) and
its own entry in `.well-known/agent-skills/index.json` for
`npx skills add` discovery.

**Directory layout:**

```
project-root/
├── skills/
│   ├── my-package/
│   │   ├── SKILL.md
│   │   └── references/
│   ├── write-guides/
│   │   ├── SKILL.md
│   │   └── references/
│   └── review-code/
│       ├── SKILL.md
│       └── references/
└── great-docs.yml
```

**Config:**

```yaml
# great-docs.yml
skill:
  skills:
    - name: my-package
      file: skills/my-package/SKILL.md
    - name: write-guides
      file: skills/write-guides/SKILL.md
    - name: review-code
      file: skills/review-code/SKILL.md
```

The first entry becomes the primary `skill.md` at the site root.
All entries appear in the switcher bar and are individually
installable via `npx skills add`.

**When to use this scenario**: your project has distinct
focus-area skills (e.g., one for general usage, one for
contributing, one for configuration) and you want users to
install exactly what they need.

## Quick start

Create a hand-written skill in three steps:

````bash
mkdir -p skills/my-package/references

cat > skills/my-package/SKILL.md << 'SKILL_EOF'
---
name: my-package
description: >
  Use the my-package Python library. Covers installation, core API,
  and common patterns.
license: MIT
compatibility: Requires Python >=3.11.
metadata:
  author: your-name
  version: "1.0"
  tags:
    - python
    - my-package
---

# my-package

Short description of what the package does and when to use it.

## Installation

```bash
pip install my-package
````

## When to use what

| Need            | Use              |
| --------------- | ---------------- |
| Create a widget | `Widget()`       |
| Style a widget  | `widget.style()` |

## API overview

### Core

- `Widget()`: Create a new widget.
- `Widget.style()`: Apply styling to a widget.

## Gotchas

1. **Immutable by default.** Methods return new objects.
2. **Lazy evaluation.** Call `.render()` to produce output.

## Best practices

- Prefer method chaining over intermediate variables.
- Use type hints in all public API calls.
  SKILL_EOF

````

Then add one line to `great-docs.yml`:

```yaml
skill:
  file: skills/my-package/SKILL.md
````

Run `great-docs build` and verify the Skills page.

## Skill directory structure

```
skills/author-skills/
├── SKILL.md
└── references/
    ├── skill-anatomy.md
    └── config-reference.md
```

## Writing a SKILL.md

### Frontmatter

Every SKILL.md starts with YAML frontmatter:

```yaml
---
name: my-package
description: >
  One-paragraph description of the skill (max 1024 characters).
license: MIT
compatibility: Requires Python >=3.11.
metadata:
  author: your-github-handle
  version: "1.0"
  tags:
    - python
    - relevant-topic
---
```

The required and optional keys are documented in the
`references/skill-anatomy.md` companion file.

### Body structure

A well-structured skill follows this outline:

```
# Package Name
Opening paragraph (what, when, why).

## Installation
pip install command.

## When to use what
Decision table mapping needs to API calls.

## API overview
Sections matching your API reference, with one-line summaries.

## Gotchas
Numbered list of common pitfalls.

## Best practices
Bullet list of recommended patterns.

## Resources
Links to docs, llms.txt, and source code.
```

### Reference files

Place companion Markdown files in a `references/` subdirectory
alongside the SKILL.md. These files are copied into
`.well-known/agent-skills/<name>/references/` and are available
to agents that install the skill.

Use reference files for content that is too detailed for the
main SKILL.md: style guides, checklists, pattern libraries,
and decision matrices.

### Writing tips

Follow these guidelines when writing skill content:

- Write for an LLM reader, not a human. Be explicit about
  distinctions that a model might confuse (e.g., `{.python}` vs
  `{.python}`).
- Use concrete examples over abstract descriptions.
- Keep the decision table ("When to use what") actionable:
  each row should map a task to a specific function or method.
- Avoid emoji, em dashes, and starting a list without
  introductory text.
- Keep the SKILL.md under 2000 lines. Move detailed reference
  material into companion files.

## Workflows

### Adding a skill to an existing site

1. Create the `skills/<name>/` directory with a `SKILL.md`.
2. Optionally add a `references/` subdirectory with companion
   files.
3. Set `skill.file` in `great-docs.yml` to point at the SKILL.md.
4. Run `great-docs build` and check the Skills page.

### Converting from automatic to hand-written

1. Run `great-docs build` to generate the automatic `skill.md`.
2. Copy the generated file from `<docs>/skill.md` into
   `skills/<name>/SKILL.md`.
3. Edit the content: add custom sections, rewrite descriptions,
   curate the decision table.
4. Set `skill.file` in `great-docs.yml`.
5. Rebuild.

### Adding a second skill (switching to multi-skill mode)

1. Create a second `skills/<name>/` directory with its SKILL.md.
2. Replace the `skill.file` key with `skill.skills` in
   `great-docs.yml`:

   ```yaml
   skill:
     skills:
       - name: original-skill
         file: skills/original-skill/SKILL.md
       - name: new-skill
         file: skills/new-skill/SKILL.md
   ```

3. Rebuild. The Skills page now shows a switcher bar with both
   skills.

### Testing skill installation

Verify your skill is discoverable:

```bash
# Check the published skill
great-docs check-skill

# List all skills in the .well-known manifest
great-docs list-skills

# Test npx installation (after deploying)
npx skills add <site-url>
```

## Discovery and distribution

Great Docs publishes skills at two well-known paths for
auto-discovery by `npx skills add` and other agent tooling:

```
<site>/.well-known/agent-skills/<name>/SKILL.md
<site>/.well-known/agent-skills/index.json
```

The `index.json` manifest lists all skills with their name,
description, and relative path. In multi-skill mode, each skill
gets its own entry.

The root-level `<site>/skill.md` always contains the primary
skill (the first entry in `skill.skills`, or the only skill).

## Gotchas

1. **`skill.skills` overrides `skill.file`.** If both are set,
   `skill.skills` takes precedence and `skill.file` is ignored.
2. **The `name` field must be unique.** Each skill in
   `skill.skills` needs a distinct `name`. Duplicates cause the
   later entry to overwrite the earlier one in `.well-known/`.
3. **Reference files must be in `references/`.** Only files under
   the `references/` subdirectory (relative to the SKILL.md) are
   copied into `.well-known/`. Files elsewhere are ignored.
4. **Use hyphens in skill names, not underscores.** The `name`
   field becomes a URL path segment
   (`.well-known/agent-skills/<name>/`), and hyphens are the
   standard web convention for URL slugs. Match the directory
   name: `skills/my-skill/` with `name: my-skill`.
5. **The first skill in `skill.skills` is special.** It becomes
   the primary `skill.md` at the site root and is the default
   panel shown on the Skills page.
6. **Set `skill.enabled: false` to disable entirely.** This
   suppresses both automatic generation and hand-written skill
   processing.

references/config-reference.md

# Config Reference -- Skill Settings

All skill-related settings live under the `skill:` key in
`great-docs.yml`. This reference covers every option.

## Top-level skill keys

```yaml
skill:
  enabled: true
  file: skills/my-package/SKILL.md
  well_known: true
  gotchas: []
  best_practices: []
  decision_table: []
  extra_body: null
  skills: []
```

### Key reference

| Key              | Type          | Default | Description                                             |
| ---------------- | ------------- | ------- | ------------------------------------------------------- |
| `enabled`        | `bool`        | `true`  | Enable or disable skill generation entirely             |
| `file`           | `str \| null` | `null`  | Path to a hand-written SKILL.md (relative to project root) |
| `well_known`     | `bool`        | `true`  | Publish skills to `.well-known/agent-skills/` for discovery |
| `gotchas`        | `list[str]`   | `[]`    | Gotcha strings appended to auto-generated skill         |
| `best_practices` | `list[str]`   | `[]`    | Best-practice strings appended to auto-generated skill  |
| `decision_table` | `list[dict]`  | `[]`    | Manual "When to use what" rows for auto-generated skill |
| `extra_body`     | `str \| null` | `null`  | Path to extra Markdown appended to auto-generated body  |
| `skills`         | `list[dict]`  | `[]`    | Multi-skill entries (overrides `file` when non-empty)   |

## Scenario configs

### Scenario 1: Automatic generation (default)

No `skill:` config needed. Great Docs generates a skill from
package metadata and API sections.

To enrich the auto-generated skill, add optional keys:

```yaml
skill:
  gotchas:
    - "Column selectors are strings, not bare identifiers."
  best_practices:
    - "Prefer method chaining over intermediate variables."
  decision_table:
    - need: "Create a table"
      use: "GT(data)"
    - need: "Format numbers"
      use: "fmt_number()"
  extra_body: "skills/extra-content.md"
```

### Scenario 2: Single hand-written skill

```yaml
skill:
  file: skills/my-package/SKILL.md
```

When `file` is set, automatic generation is skipped. The
referenced SKILL.md is copied verbatim to `<docs>/skill.md`.

### Scenario 3: Multiple named skills

```yaml
skill:
  skills:
    - name: my-package
      file: skills/my-package/SKILL.md
    - name: write-guides
      file: skills/write-guides/SKILL.md
    - name: review-code
      file: skills/review-code/SKILL.md
```

Each entry requires two keys:

| Key    | Type  | Description                                      |
| ------ | ----- | ------------------------------------------------ |
| `name` | `str` | Unique skill identifier (used in URLs and paths) |
| `file` | `str` | Path to the SKILL.md (relative to project root)  |

## Precedence rules

Great Docs evaluates skill config in this order:

1. If `skill.enabled` is `false`, no skill is generated.
2. If `skill.skills` is non-empty, multi-skill mode is used.
   The `skill.file` key is ignored.
3. If `skill.file` is set, the hand-written file is used.
4. If a curated skill exists at `skills/<package-name>/SKILL.md`,
   it is used automatically (no config needed).
5. Otherwise, a skill is auto-generated from package metadata.

## Discovery output

After a build, skills are published at these paths:

```
<docs>/
├── skill.md                                    # primary skill
├── skills.qmd                                  # rendered Skills page
└── .well-known/
    └── agent-skills/
        ├── index.json                          # discovery manifest
        ├── my-package/
        │   ├── SKILL.md
        │   └── references/
        │       └── ...
        └── write-guides/
            ├── SKILL.md
            └── references/
                └── ...
```

The `index.json` manifest lists each skill with its `name`,
`description`, and relative path to the SKILL.md. Agent tooling
like `npx skills add` reads this manifest to offer skill
installation.

references/skill-anatomy.md

# Skill Anatomy

A SKILL.md file has two parts: YAML frontmatter and a Markdown
body. This reference covers every supported field.

## Frontmatter

```yaml
---
name: my-package
description: >
  One-paragraph description of the skill. Maximum 1024 characters.
  Should explain what the skill covers and when to use it.
license: MIT
compatibility: Requires Python >=3.11.
metadata:
  author: github-handle
  version: "1.0"
  tags:
    - python
    - relevant-topic
---
```

### Frontmatter keys

| Key             | Required | Type     | Max length | Description                                        |
| --------------- | -------- | -------- | ---------- | -------------------------------------------------- |
| `name`          | yes      | `str`    | 64 chars   | Skill identifier; lowercase with hyphens (e.g., `my-skill`) |
| `description`   | yes      | `str`    | 1024 chars | What the skill covers and when to use it            |
| `license`       | no       | `str`    |            | SPDX license identifier (e.g., `MIT`, `Apache-2.0`) |
| `compatibility` | no       | `str`    |            | Runtime requirements (Python version, CLI tools)    |
| `metadata`      | no       | `object` |            | Container for `author`, `version`, and `tags`       |

### Metadata sub-keys

| Key       | Type     | Description                                    |
| --------- | -------- | ---------------------------------------------- |
| `author`  | `str`    | GitHub handle or name of the skill author      |
| `version` | `str`    | Semantic version of the skill content          |
| `tags`    | `list`   | Searchable tags for skill discovery            |

## Body sections

The body is standard Markdown. The following sections are
conventional for Agent Skills, though none are strictly required.

### Recommended section order

| Section             | Heading level | Purpose                                          |
| ------------------- | ------------- | ------------------------------------------------ |
| Package title       | `#`           | Package name as the top-level heading            |
| Opening paragraph   |               | 2-3 sentences: what, when, why                   |
| Installation        | `##`          | `pip install` command                            |
| When to use what    | `##`          | Decision table mapping tasks to API calls        |
| API overview        | `##`          | Section-by-section API listing with summaries    |
| Gotchas             | `##`          | Numbered list of common pitfalls                 |
| Best practices      | `##`          | Bullet list of recommended patterns              |
| Resources           | `##`          | Links to docs, llms.txt, source code             |

### Decision table format

The "When to use what" table maps user needs to specific API
calls. Each row should be actionable:

```markdown
| Need                    | Use                  |
| ----------------------- | -------------------- |
| Create a table from CSV | `GT(pd.read_csv())` |
| Format as percentage    | `fmt_percent()`      |
| Add a footnote          | `tab_footnote()`     |
```

### API overview format

List functions with one-line summaries. Group by API reference
section:

```markdown
## API overview

### Table creation

- `GT(data)`: Create a display table from a DataFrame.
- `GT.as_raw_html()`: Render to an HTML string.

### Formatting

- `fmt_number()`: Format numeric columns.
- `fmt_currency()`: Format as currency values.
```

### Gotchas format

Use a numbered list. Lead each item with a bold label:

```markdown
## Gotchas

1. **Immutable objects.** Methods return new GT objects.
2. **Column selectors are strings.** Pass column names as
   strings, not bare identifiers.
```

## Reference files

Companion files live in a `references/` subdirectory alongside
the SKILL.md:

```
skills/my-package/
├── SKILL.md
└── references/
    ├── style-guide.md
    ├── pattern-library.md
    └── checklist.md
```

Reference files are plain Markdown (no frontmatter required).
They are copied into `.well-known/agent-skills/<name>/references/`
during the build, making them available to agents that install
the skill.

Use reference files for detailed content that would make the
main SKILL.md too long: style examples, checklists, decision
matrices, and extended pattern libraries.

Developed by Rich Iannone and Tomasz Kalinowski. Supported by Posit Software, PBC.
Site created with Great Docs (74673e3).