# Phase 9: Navigation Structure - Research

**Researched:** 2026-03-20
**Domain:** MkDocs nested navigation, llms.txt spec, static file serving in MkDocs
**Confidence:** HIGH

---

<user_constraints>
## User Constraints (from CONTEXT.md)

### Locked Decisions

**Page assignment:**
- Root (shared): `index.md`, `installation.md`, `quickstart.md` — all audiences
- User Guide section: `tutorial.md`, `concepts.md`, `paradigms.md`, `obsidian.md`, `agentic-workflows.md`, `commands.md`, `configuration.md`, `troubleshooting.md` — 8 pages
- Developer Guide section: `development.md`, `mcp.md` — 2 pages

**Section landing pages:**
- Create `docs/guide/index.md` — User Guide landing with intro + listing with one-line descriptions
- Create `docs/dev/index.md` — Developer Guide landing with intro + listing with one-line descriptions
- These are NEW files, not moved from existing content

**Navigation structure (exact YAML to use):**
```yaml
nav:
  - Home: index.md
  - Installation: installation.md
  - Quick Start: quickstart.md
  - User Guide:
    - guide/index.md
    - Tutorial: tutorial.md
    - Core Concepts: concepts.md
    - Knowledge Paradigms: paradigms.md
    - Obsidian Starter Kit: obsidian.md
    - Agentic Workflows: agentic-workflows.md
    - Command Reference: commands.md
    - Configuration: configuration.md
    - Troubleshooting: troubleshooting.md
  - Developer Guide:
    - dev/index.md
    - Contributing: development.md
    - MCP Server: mcp.md
```

**Pages stay in `docs/` root** — no file moves, no URL changes.

**llms.txt:**
- Place at `docs/llms.txt` — served at `/ztlctl/llms.txt`
- Format per llmstxt.org spec: H1 + blockquote summary + H2 sections with `[name](url): description` links
- Hand-authored, under 10KB
- MkDocs automatically copies non-Markdown files from docs_dir to site output — no special config needed

**llms-full.txt:**
- Generated by `scripts/gen_llms_full_txt.py` — walks `docs/*.md`, concatenates with section headers
- Placed at `docs/llms-full.txt` — served at `/ztlctl/llms-full.txt`
- Script runs as pre-commit or CI step (not part of MkDocs build)

### Claude's Discretion
- Exact wording of section landing page descriptions
- Whether to add a visual separator or icon between sections in nav
- llms-full.txt concatenation order (follow nav order is fine)

### Deferred Ideas (OUT OF SCOPE)
None — discussion stayed within phase scope
</user_constraints>

---

<phase_requirements>
## Phase Requirements

| ID | Description | Research Support |
|----|-------------|-----------------|
| UGDE-01 | Two-track navigation with User Guide and Developer Guide as top-level sections | MkDocs `nav:` nested structure drives sidebar grouping; no plugin required for standard section containers; section landing pages at `docs/guide/index.md` and `docs/dev/index.md` |
| AGNT-01 | `llms.txt` at docs root with project summary and section links per llmstxt.org spec | MkDocs auto-copies all non-Markdown files from docs_dir; `docs/llms.txt` served at `/ztlctl/llms.txt`; hand-authored per llmstxt.org H1+blockquote+H2 format |
| AGNT-02 | `llms-full.txt` with concatenated documentation content for single-context-load | Python script `scripts/gen_llms_full_txt.py` walks `docs/*.md`, concatenates in nav order; output at `docs/llms-full.txt` auto-served by MkDocs |
</phase_requirements>

---

## Summary

Phase 9 is a structural reorganization and agent-accessibility phase — no content pages are moved, no URLs change. The three deliverables are: (1) restructuring the MkDocs `nav:` section in `mkdocs.yml` to add two nested tracks, (2) creating two new section landing pages (`docs/guide/index.md` and `docs/dev/index.md`), and (3) authoring `docs/llms.txt` and generating `docs/llms-full.txt` with a Python script.

MkDocs `nav:` config drives sidebar hierarchy independently of filesystem layout. All 13 existing pages stay at `docs/*.md` with no moves, avoiding all URL-change concerns. Section containers in MkDocs nav are non-clickable by default; the `guide/index.md` listed first inside the section becomes the practical landing page. The `mkdocs-section-index` plugin would make the section header itself clickable, but the CONTEXT.md decision uses the standard pattern (landing page as first child) which works without any additional plugin.

For agent accessibility: MkDocs automatically copies every non-Markdown file from `docs_dir` into the built site, so `docs/llms.txt` and `docs/llms-full.txt` require zero additional MkDocs configuration to be served. The Python generation script for `llms-full.txt` is a simple file-walker with no external dependencies beyond the standard library.

**Primary recommendation:** Restructure `mkdocs.yml` nav, create 2 section landing pages, hand-author `docs/llms.txt`, write and run `scripts/gen_llms_full_txt.py`. No new dependencies required.

---

## Standard Stack

### Core
| Library | Version | Purpose | Why Standard |
|---------|---------|---------|--------------|
| mkdocs | 1.6.1 (pinned in CI) | Site build and nav rendering | Already installed; phase only touches nav config |
| mkdocs-shadcn | 0.10.2 (pinned in CI) | Theme; renders sidebar from `nav:` | Already installed; no theme changes needed |
| mkdocs-redirects | 1.2.2 (pinned in CI) | Redirect handling | Already wired with empty `redirect_maps: {}`; no new redirects needed (no file moves) |

### Supporting
| Library | Version | Purpose | When to Use |
|---------|---------|---------|-------------|
| python-frontmatter | any | Parse YAML frontmatter in `gen_llms_full_txt.py` | Cleaner than regex for frontmatter; already available in uv env (check before adding) |

**Installation:** No new dependencies required. All tools already installed from Phase 8.

**Note on `python-frontmatter`:** Verify it's in the existing environment before adding. If absent, the script can use a simple regex-based frontmatter strip (5 lines of Python) to avoid adding a dependency.

---

## Architecture Patterns

### Recommended Project Structure (Phase 9 additions only)

```
docs/
├── index.md              # Unchanged — shared landing page
├── installation.md       # Unchanged — stays at root
├── quickstart.md         # Unchanged — stays at root
├── tutorial.md           # Unchanged — stays at root (now under User Guide in nav)
├── concepts.md           # Unchanged
├── paradigms.md          # Unchanged
├── obsidian.md           # Unchanged
├── agentic-workflows.md  # Unchanged
├── commands.md           # Unchanged
├── configuration.md      # Unchanged
├── troubleshooting.md    # Unchanged
├── development.md        # Unchanged — stays at root (now under Developer Guide in nav)
├── mcp.md                # Unchanged
├── guide/
│   └── index.md          # NEW — User Guide landing page
├── dev/
│   └── index.md          # NEW — Developer Guide landing page
├── llms.txt              # NEW — hand-authored, per llmstxt.org spec
└── llms-full.txt         # NEW — generated by scripts/gen_llms_full_txt.py

scripts/
└── gen_llms_full_txt.py  # NEW — walks docs/, concatenates in nav order

mkdocs.yml                # MODIFIED — nav: section restructured
```

### Pattern 1: MkDocs Nested Nav with Section Landing Page

**What:** MkDocs `nav:` supports nested lists where a section key (e.g., `User Guide:`) is a container for child page entries. A section header itself has no URL (it is not clickable). The first child listed under a section is effectively the "landing page" for that section — users click the section header and land on the first child.

**When to use:** All multi-page sections. The locked nav structure from CONTEXT.md already follows this pattern correctly.

**Key insight:** The unlabeled entry `- guide/index.md` (no explicit label) uses the page's own `title:` metadata as its nav label. MkDocs reads the first H1 heading or an explicit `title:` in the page's metadata block.

**Example (from CONTEXT.md):**
```yaml
# mkdocs.yml nav section
nav:
  - User Guide:
    - guide/index.md          # First child = landing page; label from page title
    - Tutorial: tutorial.md
    - Core Concepts: concepts.md
```

**Theme note:** mkdocs-shadcn follows standard MkDocs nav mechanics. The section container renders as a sidebar heading; child pages appear as collapsible items beneath it.

### Pattern 2: MkDocs Static File Auto-Copy

**What:** MkDocs copies every file from `docs_dir` to `site/` during build, regardless of whether it appears in `nav:`. Non-Markdown files (`.txt`, `.json`, `.pdf`, etc.) are copied verbatim. No `extra_files` or plugin configuration is needed.

**For llms.txt and llms-full.txt:** Place at `docs/llms.txt` and `docs/llms-full.txt`. After `mkdocs build`, the files appear at `site/llms.txt` and `site/llms-full.txt`. GitHub Pages serves the `site/` directory, so the URLs are:
- `https://thatdevstudio.github.io/ztlctl/llms.txt`
- `https://thatdevstudio.github.io/ztlctl/llms-full.txt`

**Important:** These are NOT at the site root (`https://thatdevstudio.github.io/llms.txt`) — they are under the `/ztlctl/` baseurl path. This is consistent with the llms.txt spec requirement of placing it "at the project's documentation root," which for a GitHub Pages project at a subpath is `/ztlctl/llms.txt`. The CONTEXT.md already accounts for this.

### Pattern 3: llms.txt Format (per llmstxt.org spec)

**What:** The file is plain Markdown with a prescribed structure:

```markdown
# ztlctl

> A local knowledge operating system for human users and AI agents.
> Zettelkasten-based CLI and MCP tool for building personal knowledge graphs.

## Getting Started

- [Home](https://thatdevstudio.github.io/ztlctl/): Landing page and project overview
- [Installation](https://thatdevstudio.github.io/ztlctl/installation/): Install via pip, uv, or Homebrew
- [Quick Start](https://thatdevstudio.github.io/ztlctl/quickstart/): Your first vault in under 5 minutes

## User Guide

- [Tutorial](https://thatdevstudio.github.io/ztlctl/tutorial/): Step-by-step walkthrough of core workflows
- [Core Concepts](https://thatdevstudio.github.io/ztlctl/concepts/): Content types, lifecycle states, vault structure
- [Knowledge Paradigms](https://thatdevstudio.github.io/ztlctl/paradigms/): Second-brain vs knowledge garden approaches
- [Obsidian Starter Kit](https://thatdevstudio.github.io/ztlctl/obsidian/): Obsidian integration setup and sync
- [Agentic Workflows](https://thatdevstudio.github.io/ztlctl/agentic-workflows/): AI agent orchestration patterns
- [Command Reference](https://thatdevstudio.github.io/ztlctl/commands/): All CLI commands and flags
- [Configuration](https://thatdevstudio.github.io/ztlctl/configuration/): Config file options and vault settings
- [Troubleshooting](https://thatdevstudio.github.io/ztlctl/troubleshooting/): Common issues and solutions

## Developer Guide

- [Contributing](https://thatdevstudio.github.io/ztlctl/development/): Architecture overview and contribution workflow
- [MCP Server](https://thatdevstudio.github.io/ztlctl/mcp/): MCP tools, resources, and agent integration
```

**URL pattern for MkDocs:** MkDocs generates clean URLs with trailing slash by default (e.g., `tutorial/` not `tutorial.html`). Use trailing-slash URLs in llms.txt to match the deployed site.

### Pattern 4: llms-full.txt Generation Script

**What:** A standalone Python script that walks `docs/*.md` in nav order, strips YAML frontmatter, and concatenates content with section headers as separators.

**Implementation approach:**
```python
# scripts/gen_llms_full_txt.py
"""Generate docs/llms-full.txt by concatenating all docs pages in nav order."""
import re
from pathlib import Path

DOCS_DIR = Path(__file__).parent.parent / "docs"
OUTPUT = DOCS_DIR / "llms-full.txt"

# Nav order matching the locked nav structure from mkdocs.yml
NAV_ORDER = [
    ("Getting Started", ["index.md", "installation.md", "quickstart.md"]),
    ("User Guide", [
        "guide/index.md", "tutorial.md", "concepts.md", "paradigms.md",
        "obsidian.md", "agentic-workflows.md", "commands.md",
        "configuration.md", "troubleshooting.md",
    ]),
    ("Developer Guide", ["dev/index.md", "development.md", "mcp.md"]),
]

def strip_frontmatter(text: str) -> str:
    """Remove YAML frontmatter block if present."""
    if text.startswith("---"):
        end = text.find("---", 3)
        if end != -1:
            return text[end + 3:].lstrip("\n")
    return text

def main() -> None:
    parts = []
    for section_name, files in NAV_ORDER:
        parts.append(f"# {section_name}\n")
        for filename in files:
            filepath = DOCS_DIR / filename
            if filepath.exists():
                content = filepath.read_text(encoding="utf-8")
                parts.append(strip_frontmatter(content))
                parts.append("\n\n---\n\n")
    OUTPUT.write_text("".join(parts), encoding="utf-8")
    print(f"Written: {OUTPUT}")

if __name__ == "__main__":
    main()
```

**Run:** `python scripts/gen_llms_full_txt.py`

**Output:** Committed to `docs/llms-full.txt`. MkDocs copies it to `site/llms-full.txt` on build.

### Anti-Patterns to Avoid

- **Adding `mkdocs-section-index` plugin:** Not needed. The CONTEXT.md nav structure uses first-child-as-landing-page, which is standard MkDocs. The plugin makes the section header itself clickable, which is not required here.
- **Moving doc files into `docs/guide/` or `docs/dev/` directories:** The CONTEXT.md explicitly locks against file moves. MkDocs nav grouping is config-driven, not directory-driven. Files stay in `docs/` root.
- **Using `extra_files` or `static_templates` config for llms.txt:** Unnecessary. MkDocs auto-copies all files from docs_dir including .txt files.
- **Hardcoding nav order in gen_llms_full_txt.py differently from mkdocs.yml:** The script's NAV_ORDER must match the `nav:` in mkdocs.yml exactly — keep them in sync.

---

## Don't Hand-Roll

| Problem | Don't Build | Use Instead | Why |
|---------|-------------|-------------|-----|
| YAML frontmatter parsing | Custom regex parser | `python-frontmatter` or simple 5-line regex strip | Edge cases in YAML strings; standard library re is sufficient for the simple case |
| llms.txt URL generation | Dynamic URL assembly from file paths | Hand-authored absolute URLs | 13 pages is static; automation adds complexity without benefit at this scale |
| Section-clickable nav | `mkdocs-section-index` plugin | Standard first-child landing page pattern | CONTEXT.md locks the nav structure; plugin not needed |

**Key insight:** At 13 pages, automation saves nothing. Hand-authoring `llms.txt` is faster and more reliable than building a generator.

---

## Common Pitfalls

### Pitfall 1: Section Header Non-Clickability

**What goes wrong:** In standard MkDocs (without `mkdocs-section-index`), section containers in `nav:` are not clickable links. Clicking `User Guide` in the sidebar does nothing unless a child page is active. Users expect clicking a section header to navigate somewhere.

**Why it happens:** MkDocs treats sections and pages as mutually exclusive. A section key is a visual container only.

**How to avoid:** The CONTEXT.md nav structure already handles this correctly — `guide/index.md` is listed as the first child under `User Guide:`. Users click "User Guide" in the sidebar and see the index page listed first. With mkdocs-shadcn, the first child is immediately visible when the section is expanded.

**Warning signs:** If `guide/index.md` is not listed first inside the section, users have no clear landing page for the section.

### Pitfall 2: llms.txt URLs Must Match Deployed Site URL Pattern

**What goes wrong:** MkDocs generates clean URLs with trailing slashes (e.g., `/ztlctl/tutorial/` not `/ztlctl/tutorial.html`). Writing `llms.txt` URLs without trailing slashes produces links that redirect correctly but may confuse some URL-strict LLM consumers.

**Why it happens:** MkDocs default behavior is `use_directory_urls: true`, which creates `tutorial/index.html` and serves it at `/tutorial/`.

**How to avoid:** Use trailing-slash URLs in `llms.txt`. Check `site_url` in `mkdocs.yml` — it is `https://thatdevstudio.github.io/ztlctl/`, confirming the subpath.

**Verification:** `mkdocs build --strict` and check `site/` output structure to confirm URL patterns before authoring `llms.txt`.

### Pitfall 3: `guide/` and `dev/` Subdirectories Must Exist

**What goes wrong:** MkDocs will fail at build time if `nav:` references `guide/index.md` but the `docs/guide/` directory does not exist.

**Why it happens:** `nav:` entries are file paths relative to `docs_dir`. MkDocs validates all referenced files exist.

**How to avoid:** Create `docs/guide/` and `docs/dev/` directories with their `index.md` files before running `mkdocs build --strict`.

### Pitfall 4: llms-full.txt Concatenation Order Drift

**What goes wrong:** `scripts/gen_llms_full_txt.py` hardcodes NAV_ORDER. When `mkdocs.yml` nav is updated, the script must be updated to match. If they diverge, `llms-full.txt` presents content in a different order than the site navigation, confusing agents.

**Why it happens:** There is no automated coupling between `mkdocs.yml` and the Python script.

**How to avoid:** Keep NAV_ORDER as a single constant at the top of the script. Add a comment: "Keep in sync with mkdocs.yml nav: section." Run the script immediately after any nav change.

### Pitfall 5: `docs/plans/` Already Excluded

**What goes wrong:** Trying to add `plans/` to `exclude_docs:` when it is already there.

**Why it happens:** Confusion about what Phase 8 already completed.

**How to avoid:** `mkdocs.yml` already has `exclude_docs: |` with `plans/`. No change needed for Phase 9. The 13 internal planning files in `docs/plans/` are already excluded from the build.

---

## Code Examples

### mkdocs.yml nav section (complete, locked)

```yaml
# Source: CONTEXT.md locked decisions
nav:
  - Home: index.md
  - Installation: installation.md
  - Quick Start: quickstart.md
  - User Guide:
    - guide/index.md
    - Tutorial: tutorial.md
    - Core Concepts: concepts.md
    - Knowledge Paradigms: paradigms.md
    - Obsidian Starter Kit: obsidian.md
    - Agentic Workflows: agentic-workflows.md
    - Command Reference: commands.md
    - Configuration: configuration.md
    - Troubleshooting: troubleshooting.md
  - Developer Guide:
    - dev/index.md
    - Contributing: development.md
    - MCP Server: mcp.md
```

### Section landing page structure (docs/guide/index.md)

```markdown
# User Guide

ztlctl's User Guide is for knowledge workers building personal knowledge systems — whether you're a researcher, writer, product manager, or student. These guides show you how to think in zettelkasten, capture ideas, build connections, and retrieve knowledge on demand.

**Not sure where to start?** Try the [Quick Start](../quickstart.md) or the [Tutorial](../tutorial.md).

## In This Guide

| Page | What it covers |
|------|----------------|
| [Tutorial](../tutorial.md) | Hands-on walkthrough: create notes, link them, run a session |
| [Core Concepts](../concepts.md) | Content types, lifecycle states, and vault structure |
| [Knowledge Paradigms](../paradigms.md) | Second-brain vs knowledge garden — which fits your workflow |
| [Obsidian Starter Kit](../obsidian.md) | Set up Obsidian as a visual frontend for your vault |
| [Agentic Workflows](../agentic-workflows.md) | Orchestrate AI agents with ztlctl as their note substrate |
| [Command Reference](../commands.md) | Every CLI command and flag |
| [Configuration](../configuration.md) | Config file options, vault settings, and environment variables |
| [Troubleshooting](../troubleshooting.md) | Common problems and solutions |
```

### Section landing page structure (docs/dev/index.md)

```markdown
# Developer Guide

The Developer Guide is for contributors and integrators — those building plugins, extending ztlctl's capabilities, or integrating it into agent systems via MCP.

## In This Guide

| Page | What it covers |
|------|----------------|
| [Contributing](../development.md) | Architecture overview, branch workflow, and contribution process |
| [MCP Server](../mcp.md) | MCP tools, resources, prompts, and agent integration patterns |
```

### Validation command

```bash
mkdocs build --strict
```

Run after every structural change. `--strict` treats warnings as errors — catches missing files in `nav:`, broken internal links, and config problems.

---

## State of the Art

| Old Approach | Current Approach | When Changed | Impact |
|--------------|------------------|--------------|--------|
| Jekyll + Just the Docs (frontmatter-driven nav) | MkDocs + mkdocs-shadcn (config-driven nav) | Phase 8 | Nav structure is now in `mkdocs.yml`, not page frontmatter |
| Flat 13-page nav (Phase 8 result) | Two-track nested nav (Phase 9) | This phase | Users see User Guide / Developer Guide as distinct sections |
| No agent accessibility files | llms.txt + llms-full.txt at docs root | This phase | Agents can discover and load full docs in one request |

**Note on prior ARCHITECTURE.md:** The milestone research (`.planning/research/ARCHITECTURE.md`) describes a Jekyll/Just the Docs architecture. This is now outdated — Phase 8 migrated to MkDocs. The nav patterns described there (frontmatter `parent:` fields, `has_children:`, etc.) do NOT apply to MkDocs. The current MkDocs approach uses only the `nav:` section in `mkdocs.yml`.

---

## Open Questions

1. **Does mkdocs-shadcn render the unlabeled `- guide/index.md` entry using the page's H1 or metadata title?**
   - What we know: Standard MkDocs uses the first H1 heading or a `title:` in metadata as the nav label for unlabeled entries
   - What's unclear: mkdocs-shadcn may have custom label resolution behavior
   - Recommendation: After creating `docs/guide/index.md`, run `mkdocs serve` locally and verify the label renders as "User Guide" (matching the H1). If not, add explicit label: `- User Guide: guide/index.md`

2. **Should `llms.txt` use trailing-slash or no-trailing-slash URLs?**
   - What we know: MkDocs default `use_directory_urls: true` produces trailing-slash URLs; `mkdocs.yml` does not override this
   - What's unclear: Whether mkdocs-shadcn overrides `use_directory_urls`
   - Recommendation: Run `mkdocs build --strict` and inspect `site/` output to confirm URL structure before authoring `llms.txt`

---

## Validation Architecture

### Test Framework
| Property | Value |
|----------|-------|
| Framework | pytest 8.x (already installed) |
| Config file | `pyproject.toml` `[tool.pytest.ini_options]` |
| Quick run command | `uv run pytest tests/ -x -q` |
| Full suite command | `uv run pytest` |

### Phase Requirements → Test Map

| Req ID | Behavior | Test Type | Automated Command | File Exists? |
|--------|----------|-----------|-------------------|-------------|
| UGDE-01 | `mkdocs.yml` nav has User Guide and Developer Guide sections with correct pages | smoke | `mkdocs build --strict` (build verification) | ✅ |
| UGDE-01 | `docs/guide/index.md` and `docs/dev/index.md` exist with real content | smoke | `mkdocs build --strict` | ❌ Wave 0 |
| AGNT-01 | `docs/llms.txt` exists and matches llmstxt.org format | unit | `pytest tests/docs/test_llms_txt.py -x` | ❌ Wave 0 |
| AGNT-01 | All URLs in `docs/llms.txt` reference files that exist in `docs/` | unit | `pytest tests/docs/test_llms_txt.py::test_urls_resolve -x` | ❌ Wave 0 |
| AGNT-02 | `docs/llms-full.txt` exists and contains content from all 13 pages | unit | `pytest tests/docs/test_llms_full_txt.py -x` | ❌ Wave 0 |
| AGNT-02 | `gen_llms_full_txt.py` runs without error and produces output | smoke | `python scripts/gen_llms_full_txt.py && test -f docs/llms-full.txt` | ❌ Wave 0 |

### Sampling Rate
- **Per task commit:** `mkdocs build --strict`
- **Per wave merge:** `uv run pytest tests/docs/ -x`
- **Phase gate:** `mkdocs build --strict` + full test suite green before `/gsd:verify-work`

### Wave 0 Gaps
- [ ] `docs/guide/` directory with `index.md` — covers UGDE-01 (create during implementation)
- [ ] `docs/dev/` directory with `index.md` — covers UGDE-01 (create during implementation)
- [ ] `tests/docs/test_llms_txt.py` — covers AGNT-01: file exists, H1 present, H2 sections present, all URLs resolve to docs files
- [ ] `tests/docs/test_llms_full_txt.py` — covers AGNT-02: file exists, contains content from each of the 13 pages
- [ ] `scripts/gen_llms_full_txt.py` — covers AGNT-02 generation

---

## Sources

### Primary (HIGH confidence)
- [MkDocs Configuration](https://www.mkdocs.org/user-guide/configuration/) — `nav:` structure, `exclude_docs:`, static file auto-copy behavior
- [MkDocs Writing Your Docs](https://www.mkdocs.org/user-guide/writing-your-docs/) — section/page mutual exclusivity, nav section index behavior
- `mkdocs.yml` in repo — current state (MkDocs 1.6.1, shadcn 0.10.2, 13 flat pages)
- `09-CONTEXT.md` — locked decisions for all implementation choices
- [llmstxt.org specification](https://llmstxt.org/) — H1/blockquote/H2 format, Optional section

### Secondary (MEDIUM confidence)
- [mkdocs-section-index plugin](https://github.com/oprypin/mkdocs-section-index) — confirms standard MkDocs does NOT make section headers clickable without this plugin (used to confirm the CONTEXT.md approach is correct without it)
- [mkdocs-shadcn pages docs](https://asiffer.github.io/mkdocs-shadcn/pages/) — confirms theme follows standard MkDocs nav mechanics
- `.planning/research/FEATURES.md` — llms.txt spec details, verified against llmstxt.org
- `.planning/research/PITFALLS.md` — pitfall patterns (adapted for MkDocs context; Jekyll-specific sections noted as not applicable)

### Tertiary (LOW confidence — for awareness only)
- `mkdocs-llmstxt-md` plugin — auto-generation approach; not recommended (CONTEXT.md locks hand-authored llms.txt and script-generated llms-full.txt)

---

## Metadata

**Confidence breakdown:**
- Standard stack: HIGH — all tools already installed and pinned from Phase 8
- Architecture: HIGH — MkDocs nav behavior verified against official docs; section index page pattern confirmed
- llms.txt format: HIGH — verified against llmstxt.org spec
- Static file serving: HIGH — MkDocs docs explicitly confirm non-Markdown files are copied automatically
- Pitfalls: HIGH — verified against MkDocs docs and confirmed via prior research

**Research date:** 2026-03-20
**Valid until:** 2026-06-20 (MkDocs 1.x stable; llmstxt.org spec is stable community standard)
