---
phase: 09-navigation-structure
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - docs/llms.txt
  - docs/llms-full.txt
  - scripts/gen_llms_full_txt.py
autonomous: true
requirements:
  - AGNT-01
  - AGNT-02

must_haves:
  truths:
    - "docs/llms.txt exists and follows llmstxt.org spec (H1 + blockquote + H2 sections with URL links)"
    - "All URLs in docs/llms.txt use the correct base URL (https://thatdevstudio.github.io/ztlctl/) with trailing slashes"
    - "docs/llms-full.txt exists and contains concatenated content from all 13 docs pages in nav order"
    - "scripts/gen_llms_full_txt.py runs without error and regenerates docs/llms-full.txt"
    - "Both .txt files are automatically included in mkdocs build output (site/llms.txt, site/llms-full.txt)"
  artifacts:
    - path: "docs/llms.txt"
      provides: "Agent-readable docs index per llmstxt.org spec"
      contains: "# ztlctl"
    - path: "docs/llms-full.txt"
      provides: "Full docs corpus concatenated for single-context-load"
      min_lines: 50
    - path: "scripts/gen_llms_full_txt.py"
      provides: "Generation script for llms-full.txt"
      exports: ["main"]
  key_links:
    - from: "scripts/gen_llms_full_txt.py"
      to: "docs/llms-full.txt"
      via: "OUTPUT.write_text() in main()"
      pattern: "OUTPUT.write_text"
    - from: "docs/llms.txt"
      to: "https://thatdevstudio.github.io/ztlctl/"
      via: "absolute URLs with trailing slashes in link list items"
      pattern: "thatdevstudio.github.io/ztlctl"
---

<objective>
Create the two agent-accessibility files for the docs site: `docs/llms.txt` (hand-authored per llmstxt.org spec) and `docs/llms-full.txt` (generated by `scripts/gen_llms_full_txt.py`). Both are static files that MkDocs auto-copies to the site output.

Purpose: AI agents need a machine-readable index of the documentation corpus. llms.txt provides a compact discovery file; llms-full.txt enables single-request full corpus loading.
Output: docs/llms.txt, docs/llms-full.txt, scripts/gen_llms_full_txt.py — both .txt files served by the live site.
</objective>

<execution_context>
@/Users/shparki/.claude/get-shit-done/workflows/execute-plan.md
@/Users/shparki/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/09-navigation-structure/09-CONTEXT.md
@.planning/phases/09-navigation-structure/09-RESEARCH.md

<interfaces>
<!-- llmstxt.org format spec:
  Line 1: # ProjectName
  Line 2: (blank)
  Line 3+: > blockquote summary (one or two lines)
  Then: ## Section headers with - [Name](url): description list items
-->

<!-- Site URL base: https://thatdevstudio.github.io/ztlctl/ -->
<!-- MkDocs uses_directory_urls: true (default) — URLs have trailing slash -->
<!-- URL pattern: https://thatdevstudio.github.io/ztlctl/tutorial/ (not tutorial.html) -->

<!-- NAV ORDER (matches locked mkdocs.yml nav from 09-CONTEXT.md):
  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
-->
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Author docs/llms.txt per llmstxt.org spec</name>
  <files>docs/llms.txt</files>
  <read_first>
    - .planning/phases/09-navigation-structure/09-RESEARCH.md (Pattern 3: llms.txt format, URL pitfall section, full llms.txt example)
    - .planning/phases/09-navigation-structure/09-CONTEXT.md (locked decisions for llms.txt)
    - mkdocs.yml (site_url to confirm base URL)
  </read_first>
  <action>
Create `docs/llms.txt` with the following exact content. This is hand-authored and follows the llmstxt.org specification: H1 project name, blockquote summary, then H2 sections with markdown link lists.

URL pattern: MkDocs default `use_directory_urls: true` produces trailing-slash URLs. The site_url is `https://thatdevstudio.github.io/ztlctl/`. Use this exact pattern for all URLs.

Special cases:
- Home page: `https://thatdevstudio.github.io/ztlctl/` (root, no slug)
- Section landing pages guide/index.md → `https://thatdevstudio.github.io/ztlctl/guide/`
- Section landing pages dev/index.md → `https://thatdevstudio.github.io/ztlctl/dev/`
- All other pages: `https://thatdevstudio.github.io/ztlctl/{slug}/` (slug = filename without .md)

Write this content to `docs/llms.txt`:

```
# ztlctl

> A local knowledge operating system for human users and AI agents.
> Zettelkasten-based CLI and MCP tool for building personal knowledge graphs — capture, link, query, and surface knowledge from a local SQLite vault.

## 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

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

## Developer Guide

- [Developer Guide](https://thatdevstudio.github.io/ztlctl/dev/): Developer Guide section overview and navigation
- [Contributing](https://thatdevstudio.github.io/ztlctl/development/): Architecture overview, branch workflow, and contribution process
- [MCP Server](https://thatdevstudio.github.io/ztlctl/mcp/): MCP tools, resources, prompts, and agent integration patterns
```

No YAML frontmatter. No trailing blank line after last entry. File should be under 10KB (this is well under).
  </action>
  <verify>
    <automated>test -f /Users/shparki/Documents/Workspace/thatdev/ztlctl/docs/llms.txt &amp;&amp; head -1 /Users/shparki/Documents/Workspace/thatdev/ztlctl/docs/llms.txt | grep "# ztlctl" &amp;&amp; grep -c "## Getting Started" /Users/shparki/Documents/Workspace/thatdev/ztlctl/docs/llms.txt &amp;&amp; grep -c "## User Guide" /Users/shparki/Documents/Workspace/thatdev/ztlctl/docs/llms.txt &amp;&amp; grep -c "## Developer Guide" /Users/shparki/Documents/Workspace/thatdev/ztlctl/docs/llms.txt &amp;&amp; grep -c "thatdevstudio.github.io/ztlctl" /Users/shparki/Documents/Workspace/thatdev/ztlctl/docs/llms.txt &amp;&amp; echo "PASS"</automated>
  </verify>
  <acceptance_criteria>
    - `test -f docs/llms.txt` passes
    - `head -1 docs/llms.txt` outputs `# ztlctl`
    - File contains `## Getting Started` section
    - File contains `## User Guide` section
    - File contains `## Developer Guide` section
    - File contains a blockquote line starting with `>`
    - `grep -c "thatdevstudio.github.io/ztlctl" docs/llms.txt` is at least 14 (one URL per page + section landings)
    - File is under 10KB: `wc -c docs/llms.txt | awk '{print ($1 < 10240)}'` outputs 1
    - No YAML frontmatter (file does not start with `---`)
  </acceptance_criteria>
  <done>docs/llms.txt exists with H1 project name, blockquote summary, and three H2 sections (Getting Started, User Guide, Developer Guide) each containing markdown link items with absolute trailing-slash URLs.</done>
</task>

<task type="auto">
  <name>Task 2: Write gen_llms_full_txt.py and generate docs/llms-full.txt</name>
  <files>scripts/gen_llms_full_txt.py, docs/llms-full.txt</files>
  <read_first>
    - .planning/phases/09-navigation-structure/09-RESEARCH.md (Pattern 4: complete script implementation, NAV_ORDER, pitfall 4 on order drift)
    - .planning/phases/09-navigation-structure/09-CONTEXT.md (llms-full.txt decisions)
  </read_first>
  <action>
**Step 1: Create scripts/ directory if it does not exist, then write scripts/gen_llms_full_txt.py.**

The `scripts/` directory exists already (check with `ls scripts/`). Write the script with this exact content:

```python
"""Generate docs/llms-full.txt by concatenating all docs pages in nav order.

Keep NAV_ORDER in sync with the nav: section in mkdocs.yml.
Run: python scripts/gen_llms_full_txt.py
"""
from __future__ import annotations

import re
from pathlib import Path

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

# Nav order matching mkdocs.yml nav: section exactly.
# IMPORTANT: Keep this in sync with mkdocs.yml nav: when nav changes.
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 (--- ... --- at file start)."""
    if text.startswith("---"):
        end = text.find("---", 3)
        if end != -1:
            return text[end + 3 :].lstrip("\n")
    return text


def main() -> None:
    parts: list[str] = []
    for section_name, files in NAV_ORDER:
        parts.append(f"# {section_name}\n\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")
            else:
                print(f"WARNING: {filepath} not found — skipping")
    OUTPUT.write_text("".join(parts), encoding="utf-8")
    print(f"Written: {OUTPUT}")


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

**Step 2: Run the script to generate docs/llms-full.txt.**

From the project root:
```bash
python scripts/gen_llms_full_txt.py
```

This creates `docs/llms-full.txt`. The file should contain content from all available docs pages. If any pages are missing (e.g., `docs/guide/index.md` if Plan 01 hasn't run yet), the script prints a WARNING and continues — it does not fail on missing files.

If `docs/guide/index.md` and `docs/dev/index.md` don't exist yet (Plan 01 parallel), the script will warn for those two files but still generate llms-full.txt with the 13 original pages. The file will be regenerated as part of the phase completion verification after both plans finish.

**Step 3: Verify the output.**

```bash
test -f docs/llms-full.txt
wc -l docs/llms-full.txt
grep "# Getting Started" docs/llms-full.txt
grep "# User Guide" docs/llms-full.txt
grep "# Developer Guide" docs/llms-full.txt
```

The file should have at minimum several hundred lines (all 13 existing docs pages concatenated) and the three section headers.
  </action>
  <verify>
    <automated>cd /Users/shparki/Documents/Workspace/thatdev/ztlctl &amp;&amp; python scripts/gen_llms_full_txt.py &amp;&amp; test -f docs/llms-full.txt &amp;&amp; grep -c "# Getting Started" docs/llms-full.txt &amp;&amp; grep -c "# User Guide" docs/llms-full.txt &amp;&amp; grep -c "# Developer Guide" docs/llms-full.txt &amp;&amp; wc -l docs/llms-full.txt &amp;&amp; echo "PASS"</automated>
  </verify>
  <acceptance_criteria>
    - `test -f scripts/gen_llms_full_txt.py` passes
    - `python scripts/gen_llms_full_txt.py` exits 0 with no Python errors
    - `test -f docs/llms-full.txt` passes
    - `grep "# Getting Started" docs/llms-full.txt` matches
    - `grep "# User Guide" docs/llms-full.txt` matches
    - `grep "# Developer Guide" docs/llms-full.txt` matches
    - `wc -l docs/llms-full.txt` shows at least 100 lines (13 pages worth of content)
    - Script uses `strip_frontmatter()` to remove YAML frontmatter before concatenating
    - Script's NAV_ORDER matches the locked nav structure from 09-CONTEXT.md
    - No external dependencies added (script uses only stdlib: re, pathlib)
  </acceptance_criteria>
  <done>scripts/gen_llms_full_txt.py exists and runs cleanly. docs/llms-full.txt exists with the three nav-order section headers and concatenated content from all reachable docs pages.</done>
</task>

</tasks>

<verification>
After plan completes:
1. `test -f docs/llms.txt` passes
2. `head -1 docs/llms.txt` outputs `# ztlctl`
3. `test -f docs/llms-full.txt` passes
4. `test -f scripts/gen_llms_full_txt.py` passes
5. `python scripts/gen_llms_full_txt.py` exits 0
6. `mkdocs build --strict` still passes (both .txt files appear in site/ output)
7. `test -f site/llms.txt && test -f site/llms-full.txt` passes (MkDocs auto-copies them)
</verification>

<success_criteria>
- docs/llms.txt follows llmstxt.org spec with H1, blockquote summary, and three H2 sections with URL link lists
- All 14 URLs in llms.txt (3 getting started + section landings + 8 user guide + 2 developer) use the correct base URL with trailing slashes
- docs/llms-full.txt contains concatenated content from all 13 existing docs pages with section headers
- scripts/gen_llms_full_txt.py uses stdlib only, strips frontmatter, and follows NAV_ORDER matching mkdocs.yml
- Both files appear in site/ output after mkdocs build
</success_criteria>

<output>
After completion, create `.planning/phases/09-navigation-structure/09-02-SUMMARY.md`
</output>
