---
phase: 35-documentation-site
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - docs/conf.py
  - .github/workflows/Docs.yml
  - .github/workflows/PullRequestCI.yml
  - README.md
  - .planning/REQUIREMENTS.md
  - .planning/ROADMAP.md
autonomous: true
requirements: [DOCS-01, DOCS-02, DOCS-03, DOCS-04]

must_haves:
  truths:
    - "Sphinx build succeeds with -W (warnings-as-errors) flag"
    - "GitHub Pages deployment workflow exists and triggers on push to main"
    - "PR CI validates docs build before merge"
    - "README contains link to documentation site"
    - "REQUIREMENTS.md and ROADMAP.md reflect actual framework (Sphinx + Shibuya, not mkdocs/Zensical)"
  artifacts:
    - path: "docs/conf.py"
      provides: "Sphinx config with githubpages extension, no broken intersphinx"
      contains: "sphinx.ext.githubpages"
    - path: ".github/workflows/Docs.yml"
      provides: "GitHub Pages deployment workflow"
      contains: "actions/deploy-pages@v4"
    - path: ".github/workflows/PullRequestCI.yml"
      provides: "PR docs build check job"
      contains: "docs-check"
    - path: "README.md"
      provides: "Documentation badge and link"
      contains: "anentropic.github.io/duckdb-semantic-views"
  key_links:
    - from: ".github/workflows/Docs.yml"
      to: "docs/_build/html"
      via: "sphinx-build output uploaded as pages artifact"
      pattern: "upload-pages-artifact"
    - from: ".github/workflows/PullRequestCI.yml"
      to: "docs/conf.py"
      via: "sphinx-build -W validates config"
      pattern: "sphinx-build.*-W"
---

<objective>
Deploy the existing Sphinx documentation site to GitHub Pages with automated CI/CD, add PR build validation, and update README with documentation link.

Purpose: The documentation content is already written (19 RST pages, 0 undocumented symbols). This plan adds the deployment infrastructure so docs are publicly accessible and stay valid through CI checks.
Output: Docs.yml workflow, PullRequestCI.yml docs-check job, fixed conf.py, README badge/link, updated planning metadata.
</objective>

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

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/35-documentation-site/35-CONTEXT.md
@.planning/phases/35-documentation-site/35-RESEARCH.md
@docs/conf.py
@docs/pyproject.toml
@.github/workflows/Build.yml
@.github/workflows/PullRequestCI.yml
@README.md
@Justfile
</context>

<tasks>

<task type="auto">
  <name>Task 1: Fix Sphinx config and update planning metadata</name>
  <files>docs/conf.py, .planning/REQUIREMENTS.md, .planning/ROADMAP.md</files>
  <read_first>
    - docs/conf.py (current extensions list, intersphinx_mapping)
    - .planning/REQUIREMENTS.md (DOCS-01 text to update per D-12)
    - .planning/ROADMAP.md (Phase 35 framework line to update per D-13)
  </read_first>
  <action>
**docs/conf.py changes (per D-01, D-02):**

1. Add `"sphinx.ext.githubpages"` to the `extensions` list. This extension automatically creates a `.nojekyll` file in the build output, which prevents GitHub Pages from processing files through Jekyll. The final extensions list should be:
```python
extensions = [
    "sphinx_design",
    "sphinx.ext.githubpages",
]
```

2. Remove the `sphinx.ext.intersphinx` extension from the `extensions` list entirely. No RST files use `:external:` or cross-project references to DuckDB docs (verified by grep). The DuckDB docs site does not publish a Sphinx `objects.inv` file, so the mapping `"duckdb": ("https://duckdb.org/docs", None)` always 404s and causes `-W` (warnings-as-errors) builds to fail.

3. Remove the entire `intersphinx_mapping` dictionary and its comment block (lines 28-32 in current file).

**REQUIREMENTS.md changes (per D-12):**

Update DOCS-01 text from:
```
- [ ] **DOCS-01**: Zensical project configured with `zensical.toml` and `docs/` directory structure
```
to:
```
- [ ] **DOCS-01**: Sphinx + Shibuya docs configured with `docs/conf.py` and `docs/pyproject.toml`
```

**ROADMAP.md changes (per D-13):**

In the Phase 35 section, change the line:
```
**Framework**: mkdocs-material (MkDocs + Material for MkDocs theme)
```
to:
```
**Framework**: Sphinx + Shibuya theme
```

Also update the success criterion #1 from:
```
1. Running `mkdocs build` locally produces a complete static site from `docs/` directory
```
to:
```
1. Running `just docs-build` locally produces a complete static site in `docs/_build/html/`
```
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && uv run --project docs sphinx-build -b html -W docs /tmp/claude/docs-test-build 2>&1 | tail -5</automated>
  </verify>
  <acceptance_criteria>
    - docs/conf.py contains `"sphinx.ext.githubpages"` in extensions list
    - docs/conf.py does NOT contain `sphinx.ext.intersphinx`
    - docs/conf.py does NOT contain `intersphinx_mapping`
    - sphinx-build -W exits with code 0 (no warnings)
    - .planning/REQUIREMENTS.md DOCS-01 line contains "Sphinx + Shibuya docs configured with `docs/conf.py` and `docs/pyproject.toml`"
    - .planning/ROADMAP.md Phase 35 contains "Sphinx + Shibuya theme" (not "mkdocs-material")
    - .planning/ROADMAP.md Phase 35 success criterion 1 contains "just docs-build" (not "mkdocs build")
  </acceptance_criteria>
  <done>Sphinx builds cleanly with -W flag. Planning metadata reflects actual framework.</done>
</task>

<task type="auto">
  <name>Task 2: Create Docs.yml deployment workflow and add docs-check to PullRequestCI.yml</name>
  <files>.github/workflows/Docs.yml, .github/workflows/PullRequestCI.yml</files>
  <read_first>
    - .github/workflows/Build.yml (existing workflow naming/structure pattern)
    - .github/workflows/PullRequestCI.yml (current jobs to extend)
    - docs/pyproject.toml (Python dependency management)
    - Justfile (docs-build recipe for build command reference)
  </read_first>
  <action>
**Create `.github/workflows/Docs.yml` (per D-04, D-05, D-06, D-08):**

Create a new file `.github/workflows/Docs.yml` with the following exact content:

```yaml
name: Docs

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - uses: astral-sh/setup-uv@v7
        with:
          enable-cache: true

      - name: Build documentation
        run: uv run --project docs sphinx-build -b html -W docs docs/_build/html

      - name: Setup Pages
        uses: actions/configure-pages@v5

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: docs/_build/html

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4
```

Key design decisions:
- `on.push.branches: [main]` only, per D-05 (milestone branches do NOT deploy)
- `concurrency.cancel-in-progress: false` to avoid canceling in-progress deployments (unlike Build.yml which uses `true`)
- Permissions at workflow level: `pages: write` and `id-token: write` required for OIDC-based deployment
- Two-job pattern: `build` (sphinx-build + upload artifact) then `deploy` (deploy to Pages)
- Uses `uv run --project docs` per D-08, matching Justfile `docs-build` recipe
- `-W` flag makes warnings into errors so broken cross-references fail the build
- `workflow_dispatch` allows manual re-deployment

**Add `docs-check` job to `.github/workflows/PullRequestCI.yml` (per D-07, D-08):**

Append a new job `docs-check` after the existing `ducklake-ci-check` job. Add the following YAML block at the end of the `jobs:` section:

```yaml
  docs-check:
    name: Docs build check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - uses: astral-sh/setup-uv@v7
        with:
          enable-cache: true

      - name: Build docs (warnings as errors)
        run: uv run --project docs sphinx-build -b html -W docs docs/_build/html
```

This job runs on every PR (same triggers as existing jobs). It validates the docs build but does NOT deploy. The `-W` flag ensures any broken references or warnings are caught before merge.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && cat .github/workflows/Docs.yml | grep -c "deploy-pages" && cat .github/workflows/PullRequestCI.yml | grep -c "docs-check"</automated>
  </verify>
  <acceptance_criteria>
    - .github/workflows/Docs.yml exists
    - Docs.yml contains `name: Docs`
    - Docs.yml contains `branches: [main]` under on.push (not milestone branches)
    - Docs.yml contains `cancel-in-progress: false`
    - Docs.yml contains `pages: write` in permissions
    - Docs.yml contains `id-token: write` in permissions
    - Docs.yml contains `actions/checkout@v4`
    - Docs.yml contains `actions/setup-python@v5`
    - Docs.yml contains `astral-sh/setup-uv@v7`
    - Docs.yml contains `actions/configure-pages@v5`
    - Docs.yml contains `actions/upload-pages-artifact@v3`
    - Docs.yml contains `actions/deploy-pages@v4`
    - Docs.yml contains `uv run --project docs sphinx-build -b html -W docs docs/_build/html`
    - Docs.yml contains `path: docs/_build/html` under upload-pages-artifact
    - Docs.yml contains `workflow_dispatch` trigger
    - Docs.yml deploy job has `environment: name: github-pages`
    - PullRequestCI.yml contains a `docs-check:` job
    - PullRequestCI.yml docs-check job contains `sphinx-build -b html -W`
    - PullRequestCI.yml docs-check job contains `astral-sh/setup-uv@v7`
    - PullRequestCI.yml docs-check job does NOT contain `deploy-pages` or `upload-pages-artifact`
  </acceptance_criteria>
  <done>Docs.yml deploys to GitHub Pages on main push. PullRequestCI.yml validates docs build on PRs. Both use uv, both use -W flag.</done>
</task>

<task type="auto">
  <name>Task 3: Add documentation badge and link to README</name>
  <files>README.md</files>
  <read_first>
    - README.md (current content, badge placement, structure)
  </read_first>
  <action>
**Update README.md (per D-09, D-10, D-11):**

1. Add a documentation badge at the very top of README.md, on the line immediately after the `# DuckDB Semantic Views` heading. Insert:

```markdown
[![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://anentropic.github.io/duckdb-semantic-views/)
```

2. Add a "Documentation" section in the README body. Insert it after the "DDL reference" section (after the closing triple-backtick of the DDL code block) and before the "Building" section. The new section should be:

```markdown
## Documentation

Full documentation: [anentropic.github.io/duckdb-semantic-views](https://anentropic.github.io/duckdb-semantic-views/)

Includes getting started tutorial, DDL and query reference, how-to guides for advanced features (FACTS, derived metrics, role-playing dimensions, fan traps), and architecture explanation.
```

3. Update the version line (currently `v0.5.3 -- early-stage, not yet on the community registry.`) to `v0.5.4 -- early-stage, not yet on the community registry.` to reflect the current milestone.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && grep -c "anentropic.github.io/duckdb-semantic-views" README.md && grep -c "shields.io/badge/docs" README.md</automated>
  </verify>
  <acceptance_criteria>
    - README.md contains `[![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://anentropic.github.io/duckdb-semantic-views/)` on a line after the heading
    - README.md contains `## Documentation` section
    - README.md contains the URL `https://anentropic.github.io/duckdb-semantic-views/` in the Documentation section body
    - README.md contains `v0.5.4` (not `v0.5.3`)
    - The badge line appears before the first paragraph of body text
    - The Documentation section appears after "## DDL reference" and before "## Building"
  </acceptance_criteria>
  <done>README has docs badge at top and Documentation section with link to GitHub Pages site.</done>
</task>

</tasks>

<verification>
Phase verification (all must pass):

1. `uv run --project docs sphinx-build -b html -W docs /tmp/docs-verify` exits 0 (clean Sphinx build)
2. `just test-all` passes (no regressions from conf.py or README changes)
3. `.github/workflows/Docs.yml` exists with correct structure
4. `.github/workflows/PullRequestCI.yml` contains docs-check job
5. `README.md` contains documentation badge and link
6. `.planning/REQUIREMENTS.md` DOCS-01 references Sphinx + Shibuya
7. `.planning/ROADMAP.md` Phase 35 references Sphinx + Shibuya

**Manual step (not automated, user handles after merge to main):**
- Enable GitHub Pages in repo Settings > Pages > Source = "GitHub Actions"
- First push to main after merge will trigger Docs.yml workflow
</verification>

<success_criteria>
- Sphinx builds with -W (warnings-as-errors) without failures
- Docs.yml workflow will deploy docs to GitHub Pages on push to main
- PullRequestCI.yml validates docs build on every PR
- README contains visible link to documentation site
- Planning metadata accurately reflects Sphinx + Shibuya (not mkdocs/Zensical)
</success_criteria>

<output>
After completion, create `.planning/phases/35-documentation-site/35-01-SUMMARY.md`
</output>
