# libfossil Docs Site + Cloudflare Auto-Deploy Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Add a Hugo + Hextra documentation site, a self-contained landing page, auto-generated Go SDK reference, and Cloudflare Workers Static Assets auto-deploy — mirroring the sibling project `dagnats` and serving from a single Cloudflare Worker.

**Architecture:** All web content lives under `docs/site/`. Hugo + Hextra theme (via Hugo modules) renders the docs site; a `layouts/index.html` override at the same site renders the landing page at `/`. SDK reference is generated by `gomarkdoc` from Go doc comments and committed to the repo; a pre-commit hook keeps it in sync with code. Cloudflare Workers' git integration auto-deploys on push to `main` using an inline build defined in `wrangler.jsonc` (download Hugo → run llms-txt script → `hugo --minify` → serve `docs/site/public/` via Workers Static Assets). No GitHub Action handles deploy.

**Tech Stack:** Hugo extended v0.160.0, Hextra theme via Hugo modules, gomarkdoc, bash, `wrangler` (Cloudflare Workers Static Assets), Geist Mono via Google Fonts (loaded by the landing page).

**Branch:** `feat/docs-site-cf-deploy` (already created and contains the spec).

**Spec:** `docs/superpowers/specs/2026-04-25-docs-site-cf-deploy-design.md`.

**Commit policy:** No `Co-Authored-By: Claude` trailers. No `Generated with Claude Code` PR footers. Per-project user preference.

---

## File structure

All paths relative to repo root.

**New:**
- `docs/site/hugo.yaml` — Hugo + Hextra config
- `docs/site/go.mod`, `docs/site/go.sum` — Hugo module pins (Hextra)
- `docs/site/content/_index.md` — site root frontmatter (body empty; layout override handles rendering)
- `docs/site/content/docs/_index.md` — docs section landing
- `docs/site/content/docs/quickstart.md` — drafted from README
- `docs/site/content/docs/reference/_index.md`, `docs/site/content/docs/reference/sdk/_index.md` — section stubs
- `docs/site/content/docs/reference/sdk/{libfossil,cli,db,db/driver/modernc,db/driver/ncruces,observer/otel,dst}/api.md` — generated by `gomarkdoc`, committed
- `docs/site/content/examples/_index.md` — examples section stub
- `docs/site/layouts/index.html` — landing page (Hugo home override; forked from dagnats)
- `scripts/gen-llms-txt.sh` — llms.txt generator
- `wrangler.jsonc` — CF Worker config

**Changed:**
- `Makefile` — adds `docs-serve`, `docs-build`, `docs-gen-sdk`, `docs-gen-llms`, `docs` targets
- `.githooks/pre-commit` — adds SDK-drift check
- `.gitignore` — adds Hugo + llms artifacts + downloaded `hugo` binary
- `README.md` — points at the docs site

**Deleted (after move):**
- `docs/architecture.md`, `docs/extension-points.md`, `docs/migration-from-fossil.md`, `docs/testing.md` (moved into `docs/site/content/docs/`)

**Reference for forks/copies:** sibling project at `../dagnats/`. The plan calls out specific paths to copy from when relevant.

---

## Task 1: Bootstrap Hugo + Hextra docs site

**Files:**
- Create: `docs/site/hugo.yaml`
- Create: `docs/site/go.mod`, `docs/site/go.sum` (auto-generated by `hugo mod`)
- Create: `docs/site/content/_index.md`
- Create: `docs/site/content/docs/_index.md`
- Modify: `.gitignore`

- [ ] **Step 1: Add gitignore entries**

Append to `.gitignore`:

```
# Hugo build artifacts
docs/site/public/
docs/site/resources/
docs/site/.hugo_build.lock
docs/site/_vendor/

# Generated llms.txt artifacts (built at deploy time, not committed)
docs/site/static/llms.txt
docs/site/static/llms-full.txt

# Downloaded Hugo binary (used by CF and local manual builds)
docs/site/hugo
hugo
```

- [ ] **Step 2: Install Hugo extended locally (one-time)**

Hugo extended ≥0.160 is required for the Hextra theme. If `hugo version` does not report `extended`, install it:

```bash
# macOS via Homebrew (installs the latest extended)
brew install hugo

# Or pin to v0.160.0 to match the CF build
curl -sSL https://github.com/gohugoio/hugo/releases/download/v0.160.0/hugo_extended_0.160.0_darwin-universal.tar.gz \
  | tar xz hugo -C /tmp \
  && sudo mv /tmp/hugo /usr/local/bin/hugo
hugo version    # expect: hugo v0.160.0+extended ...
```

Linux/WSL: substitute `linux-amd64` for `darwin-universal` and `/usr/local/bin/hugo` for the destination.

- [ ] **Step 3: Initialize the Hugo module + pull Hextra**

```bash
cd docs/site
hugo mod init github.com/danmestas/go-libfossil/docs/site
hugo mod get github.com/imfing/hextra
cd -
```

This creates `docs/site/go.mod` and `docs/site/go.sum`. (These are Hugo's module files; they are independent of the project's main `go.mod` at the repo root.)

- [ ] **Step 4: Write `docs/site/hugo.yaml`**

```yaml
title: libfossil
baseURL: ""

module:
  imports:
    - path: github.com/imfing/hextra

markup:
  goldmark:
    renderer:
      unsafe: true
  highlight:
    noClasses: false

menu:
  main:
    - name: Docs
      pageRef: /docs
      weight: 1
    - name: SDK
      pageRef: /docs/reference/sdk
      weight: 2
    - name: Examples
      pageRef: /examples
      weight: 3
    - name: Search
      weight: 4
      params:
        type: search
    - name: GitHub
      weight: 5
      url: "https://github.com/danmestas/go-libfossil"
      params:
        icon: github

params:
  navbar:
    displayTitle: true
    displayLogo: false

  theme:
    default: system
    displayToggle: true

  search:
    enable: true
    type: flexsearch
    flexsearch:
      index: content
      tokenize: forward

  footer:
    displayCopyright: true
    displayPoweredBy: false

  editURL:
    enable: true
    base: "https://github.com/danmestas/go-libfossil/edit/main/docs/site/content"

  page:
    width: wide
```

- [ ] **Step 5: Write `docs/site/content/_index.md`**

```markdown
---
title: libfossil
layout: landing
---
```

(Body intentionally empty: `docs/site/layouts/index.html` from Task 8 takes precedence for the home page.)

- [ ] **Step 6: Write `docs/site/content/docs/_index.md`**

```markdown
---
title: Documentation
cascade:
  type: docs
---

libfossil is a pure-Go library and CLI for reading and writing Fossil SCM repositories. Zero CGo. Static binaries. WASM-ready.

Start with the [Quickstart](./quickstart) for a five-minute tour. The [Architecture](./architecture) page explains how the pieces fit. The [SDK reference](./reference/sdk) is generated from Go doc comments.
```

- [ ] **Step 7: Verify Hugo serves the stub site**

```bash
cd docs/site && hugo server --port 1313
```

Expected: Hugo prints `Web Server is available at http://localhost:1313/`. Open that URL: nav shows `libfossil`, `Docs`, `SDK`, `Examples`, `Search`, `GitHub`. Visiting `/docs/` shows the cascade page rendered with the body text from Step 6.

Stop the server with Ctrl-C.

- [ ] **Step 8: Commit**

```bash
git add .gitignore docs/site/hugo.yaml docs/site/go.mod docs/site/go.sum docs/site/content/_index.md docs/site/content/docs/_index.md
git commit -m "docs(site): bootstrap Hugo + Hextra skeleton"
```

The pre-commit hook runs the existing test suite (~45s) on every commit; expect it to pass with no code changes.

---

## Task 2: Move existing markdown into Hugo content tree

**Files:**
- Move: `docs/architecture.md` → `docs/site/content/docs/architecture.md`
- Move: `docs/extension-points.md` → `docs/site/content/docs/extension-points.md`
- Move: `docs/migration-from-fossil.md` → `docs/site/content/docs/migration-from-fossil.md`
- Move: `docs/testing.md` → `docs/site/content/docs/testing.md`

For each file: `git mv` the file, then prepend a five-line YAML frontmatter block at the top so Hextra has a stable title and weight for nav ordering.

Frontmatter weights (lower = earlier in nav):

| File | Title | Weight |
|---|---|---|
| `quickstart.md` (Task 3) | Quickstart | 10 |
| `architecture.md` | Architecture | 20 |
| `migration-from-fossil.md` | Migration from Fossil | 30 |
| `extension-points.md` | Extension Points | 40 |
| `testing.md` | Testing | 50 |

- [ ] **Step 1: Move architecture.md and prepend frontmatter**

```bash
git mv docs/architecture.md docs/site/content/docs/architecture.md
```

Then open `docs/site/content/docs/architecture.md` and insert at the very top, before any existing content:

```markdown
---
title: Architecture
weight: 20
---

```

(Note the blank line after the closing `---`.)

- [ ] **Step 2: Move migration-from-fossil.md**

```bash
git mv docs/migration-from-fossil.md docs/site/content/docs/migration-from-fossil.md
```

Prepend:

```markdown
---
title: Migration from Fossil
weight: 30
---

```

- [ ] **Step 3: Move extension-points.md**

```bash
git mv docs/extension-points.md docs/site/content/docs/extension-points.md
```

Prepend:

```markdown
---
title: Extension Points
weight: 40
---

```

- [ ] **Step 4: Move testing.md**

```bash
git mv docs/testing.md docs/site/content/docs/testing.md
```

Prepend:

```markdown
---
title: Testing
weight: 50
---

```

- [ ] **Step 5: Verify nav order**

Run `cd docs/site && hugo server` and visit `/docs/`. Expected nav order under "Docs": Architecture, Migration from Fossil, Extension Points, Testing. (Quickstart with weight 10 is added in Task 3.) Click each one and verify the body content renders.

- [ ] **Step 6: Verify the old `docs/*.md` paths no longer exist**

```bash
ls docs/*.md 2>/dev/null
# Expected: no output (all four moved)
```

- [ ] **Step 7: Commit**

```bash
git add docs/site/content/docs/
git commit -m "docs(site): move existing docs into Hugo content tree"
```

---

## Task 3: Add quickstart, examples, and SDK section stubs

**Files:**
- Create: `docs/site/content/docs/quickstart.md`
- Create: `docs/site/content/docs/reference/_index.md`
- Create: `docs/site/content/docs/reference/sdk/_index.md`
- Create: `docs/site/content/examples/_index.md`

- [ ] **Step 1: Write `docs/site/content/docs/quickstart.md`**

````markdown
---
title: Quickstart
weight: 10
---

A five-minute tour of libfossil: install the CLI, clone a repo, and read its history from Go.

## Install

```sh
go install github.com/danmestas/go-libfossil/cmd/libfossil@latest
libfossil --help
```

The binary is statically linked. No CGo required.

## Clone a repository

```sh
libfossil clone https://example.com/repo.fossil ./repo.fossil
```

## Open from Go

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/danmestas/go-libfossil"
)

func main() {
    repo, err := libfossil.Open("repo.fossil")
    if err != nil {
        log.Fatal(err)
    }
    defer repo.Close()

    timeline, err := repo.Timeline(context.Background(), 10)
    if err != nil {
        log.Fatal(err)
    }
    for _, c := range timeline {
        fmt.Println(c.UUID, c.Comment)
    }
}
```

## Sync over HTTP

```go
import "github.com/danmestas/go-libfossil"

t := libfossil.NewHTTPTransport("https://example.com/repo.fossil")
if err := repo.Sync(ctx, t); err != nil {
    log.Fatal(err)
}
```

## Next steps

- [Architecture](../architecture) — how the pieces fit
- [Migration from Fossil](../migration-from-fossil) — command mapping from upstream
- [SDK reference](../reference/sdk) — every package, every exported symbol
````

(If the actual `Timeline` signature or `NewHTTPTransport` factory does not match what's in the codebase, update the snippet against the real exports — verify by reading `libfossil.go` before writing.)

- [ ] **Step 2: Write `docs/site/content/docs/reference/_index.md`**

```markdown
---
title: Reference
weight: 100
---
```

- [ ] **Step 3: Write `docs/site/content/docs/reference/sdk/_index.md`**

```markdown
---
title: SDK
weight: 10
---

Auto-generated Go API reference. One page per package, generated by [gomarkdoc](https://github.com/princjef/gomarkdoc) from doc comments.

Run `make docs-gen-sdk` to regenerate. The pre-commit hook fails if the working tree drifts.
```

- [ ] **Step 4: Write `docs/site/content/examples/_index.md`**

```markdown
---
title: Examples
weight: 60
---

Runnable examples live in [`examples/`](https://github.com/danmestas/go-libfossil/tree/main/examples) in the repo. (This page will index them once the directory is populated.)
```

- [ ] **Step 5: Verify**

`cd docs/site && hugo server`. Visit `/docs/`: nav order is Quickstart → Architecture → Migration from Fossil → Extension Points → Testing → Reference (with SDK as a child). Visit `/docs/quickstart/` and verify code blocks render with syntax highlighting. Visit `/examples/` and confirm the placeholder renders.

- [ ] **Step 6: Commit**

```bash
git add docs/site/content/docs/quickstart.md docs/site/content/docs/reference/ docs/site/content/examples/
git commit -m "docs(site): add quickstart, examples, and SDK section stubs"
```

---

## Task 4: gomarkdoc Makefile target + initial SDK generation

**Files:**
- Modify: `Makefile`
- Create: `docs/site/content/docs/reference/sdk/{libfossil,cli,db,db/driver/modernc,db/driver/ncruces,observer/otel,dst}/api.md`

- [ ] **Step 1: Update `Makefile` to add `docs-gen-sdk`**

In the existing `.PHONY:` line at the top of `Makefile`, append `docs-gen-sdk`:

```makefile
.PHONY: test test-drivers test-otel test-all vet build setup-hooks docs-gen-sdk
```

Append the target at the bottom of the file:

```makefile
docs-gen-sdk:
	@command -v gomarkdoc >/dev/null 2>&1 || go install github.com/princjef/gomarkdoc/cmd/gomarkdoc@latest
	gomarkdoc --output docs/site/content/docs/reference/sdk/libfossil/api.md         ./
	gomarkdoc --output docs/site/content/docs/reference/sdk/cli/api.md               ./cli/
	gomarkdoc --output docs/site/content/docs/reference/sdk/db/api.md                ./db/
	gomarkdoc --output docs/site/content/docs/reference/sdk/db/driver/modernc/api.md ./db/driver/modernc/
	gomarkdoc --output docs/site/content/docs/reference/sdk/db/driver/ncruces/api.md ./db/driver/ncruces/
	gomarkdoc --output docs/site/content/docs/reference/sdk/observer/otel/api.md     ./observer/otel/
	gomarkdoc --output docs/site/content/docs/reference/sdk/dst/api.md               ./dst/
```

- [ ] **Step 2: Run target to generate SDK pages**

```bash
make docs-gen-sdk
```

Expected: gomarkdoc auto-installs (if missing), then writes seven markdown files. Verify:

```bash
find docs/site/content/docs/reference/sdk -name api.md | wc -l
# Expected: 7
```

- [ ] **Step 3: Verify Hextra renders the generated pages**

`gomarkdoc` writes plain markdown without YAML frontmatter. The `cascade.type: docs` from `docs/_index.md` covers theme treatment, and the page title comes from gomarkdoc's `# package` first heading.

```bash
cd docs/site && hugo server
```

Visit `/docs/reference/sdk/libfossil/api/`. Expected: full package API renders — exported types, functions, methods — with monospace headings. The page title in the nav should read the package name (e.g., "libfossil").

If the title in the sidebar shows the file path instead of the package name (theme quirk), prepend `--- title: <pkg> ---` frontmatter to each `api.md`. Otherwise leave them as gomarkdoc emits them — keeps regeneration idempotent.

- [ ] **Step 4: Commit**

```bash
git add Makefile docs/site/content/docs/reference/sdk/
git commit -m "docs(site): add docs-gen-sdk Makefile target + commit generated SDK pages"
```

---

## Task 5: gen-llms-txt.sh + Makefile target

**Files:**
- Create: `scripts/gen-llms-txt.sh`
- Modify: `Makefile`

- [ ] **Step 1: Write `scripts/gen-llms-txt.sh`**

```bash
#!/usr/bin/env bash
set -euo pipefail

SITE_DIR="docs/site"
STATIC_DIR="$SITE_DIR/static"

mkdir -p "$STATIC_DIR"

# llms.txt: curated summary
cat > "$STATIC_DIR/llms.txt" << 'HEADER'
# libfossil

> Pure-Go library and CLI for Fossil SCM repositories.
> Zero CGo. Static binaries. WASM-ready.

## Key Concepts
- Repo — open .fossil SQLite-backed repository handle
- Transport — pluggable sync interface (HTTP, custom)
- Driver — pluggable SQLite implementation (modernc, ncruces)
- Observer — hooks for sync/checkout/commit (OpenTelemetry-ready)
- DST — deterministic simulation harness for fault injection

## Quick Start
1. go install github.com/danmestas/go-libfossil/cmd/libfossil@latest
2. libfossil clone <url> repo.fossil
3. Open from Go: repo, err := libfossil.Open("repo.fossil")
4. Sync: repo.Sync(ctx, transport)

## Go SDK Packages
- libfossil — Repo handle, Open/Create, public API
- cli/ — Kong command structs (embeddable)
- db/ — SQLite abstraction with pluggable drivers
- db/driver/modernc — pure-Go SQLite (default)
- db/driver/ncruces — Wasm-friendly SQLite
- observer/otel — OpenTelemetry integration
- dst/ — deterministic simulation harness

## Documentation
Full docs: https://github.com/danmestas/go-libfossil/tree/main/docs/site
HEADER

# llms-full.txt: all content concatenated, frontmatter stripped
echo "# libfossil Documentation (Full)" > "$STATIC_DIR/llms-full.txt"
echo "" >> "$STATIC_DIR/llms-full.txt"
echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$STATIC_DIR/llms-full.txt"
echo "" >> "$STATIC_DIR/llms-full.txt"

find "$SITE_DIR/content" -name "*.md" -type f | sort | while read -r file; do
    echo "---" >> "$STATIC_DIR/llms-full.txt"
    echo "# Source: $file" >> "$STATIC_DIR/llms-full.txt"
    echo "" >> "$STATIC_DIR/llms-full.txt"
    sed -n '/^---$/,/^---$/!p' "$file" >> "$STATIC_DIR/llms-full.txt"
    echo "" >> "$STATIC_DIR/llms-full.txt"
done

echo "Generated llms.txt and llms-full.txt in $STATIC_DIR/"
```

- [ ] **Step 2: Make it executable**

```bash
chmod +x scripts/gen-llms-txt.sh
```

- [ ] **Step 3: Add `docs-gen-llms` target to `Makefile`**

In `.PHONY:` append `docs-gen-llms`. Append the target:

```makefile
docs-gen-llms:
	bash scripts/gen-llms-txt.sh
```

- [ ] **Step 4: Run and verify**

```bash
make docs-gen-llms
```

Expected last line: `Generated llms.txt and llms-full.txt in docs/site/static/`

```bash
head -2 docs/site/static/llms.txt
# Expected:
# # libfossil
# (blank line)

wc -l docs/site/static/llms-full.txt
# Expected: > 100 lines (concatenated content from quickstart + 4 moved docs + 7 SDK pages + section indexes)

grep -c '^# Source: ' docs/site/static/llms-full.txt
# Expected: number equal to all .md files under content/, i.e. > 12
```

- [ ] **Step 5: Commit**

```bash
git add scripts/gen-llms-txt.sh Makefile
git commit -m "docs(site): add gen-llms-txt.sh + docs-gen-llms target"
```

The generated `static/llms*.txt` files are gitignored (Task 1 Step 1).

---

## Task 6: Pre-commit hook drift check for SDK pages

**Files:**
- Modify: `.githooks/pre-commit`

The existing hook runs unit tests, vet, otel sub-module, and a binary build. Add an SDK-drift check after the binary build and before the final "all passed" line.

- [ ] **Step 1: Add SDK drift check**

Open `.githooks/pre-commit`. After the line `run_test "cmd/libfossil" go build ./cmd/libfossil/` and before `echo "=== pre-commit: all passed ==="`, insert:

```sh
echo "=== pre-commit: docs SDK drift ==="
if ! command -v gomarkdoc >/dev/null 2>&1; then
	if ! go install github.com/princjef/gomarkdoc/cmd/gomarkdoc@latest 2>/dev/null; then
		echo "  gomarkdoc: SKIPPED (install failed; commit allowed)"
	fi
fi
if command -v gomarkdoc >/dev/null 2>&1; then
	if make -s docs-gen-sdk >/dev/null 2>&1; then
		if git diff --quiet -- docs/site/content/docs/reference/sdk; then
			echo "  SDK pages: in sync"
		else
			echo "  SDK pages: OUT OF DATE"
			echo ""
			echo "  Run 'make docs-gen-sdk' and commit the result."
			echo ""
			git diff --stat -- docs/site/content/docs/reference/sdk
			exit 1
		fi
	else
		echo "  docs-gen-sdk: SKIPPED (target not available)"
	fi
fi
```

The graceful skips (gomarkdoc install fails, target absent) keep the hook usable on fresh clones before Task 4 has run; once everything is wired, the drift check is enforced.

- [ ] **Step 2: Verify hook catches drift**

Pick any exported symbol in the codebase with a doc comment. Edit its comment to add a sentinel word, then attempt to commit:

```bash
# Example: edit any doc comment in libfossil.go (adjust to whatever's actually there)
grep -n '^// ' libfossil.go | head -3
# Pick a line, append a word to that comment line via your editor
# e.g. change "// Open opens a repo." to "// Open opens a repo. SENTINEL"

git add libfossil.go
git commit -m "test: drift to verify hook"
```

Expected: hook prints `SDK pages: OUT OF DATE`, shows `git diff --stat`, exits 1, commit aborted.

Restore:
```bash
git checkout -- libfossil.go
```

- [ ] **Step 3: Verify hook passes when in sync**

```bash
git commit --allow-empty -m "test: verify hook clean"
```

Expected: all sections pass, including `SDK pages: in sync`. Then drop the test commit:

```bash
git reset HEAD~
```

- [ ] **Step 4: Commit the hook change**

```bash
git add .githooks/pre-commit
git commit -m "hooks: pre-commit fails when SDK pages drift from code"
```

---

## Task 7: Add docs-serve, docs-build, docs aggregate targets

**Files:**
- Modify: `Makefile`

- [ ] **Step 1: Update `.PHONY:` and append targets**

In `.PHONY:` append `docs-serve docs-build docs`. Append at the bottom of the file:

```makefile
docs-serve:
	cd docs/site && hugo server -D --port 1313

docs-build:
	cd docs/site && hugo --minify

docs: docs-gen-sdk docs-gen-llms docs-build
	@echo "=== docs: built into docs/site/public/ ==="
```

- [ ] **Step 2: Verify `docs-build`**

```bash
make docs-build
ls docs/site/public/index.html docs/site/public/docs/index.html
# Expected: both exist

grep -o '<title>[^<]*</title>' docs/site/public/index.html
# Expected: <title>libfossil</title>  (will change in Task 8 once landing layout exists)
```

- [ ] **Step 3: Verify `docs` aggregate**

```bash
make docs
```

Expected: `docs-gen-sdk` runs (no diff if already in sync), `docs-gen-llms` runs, `docs-build` runs, final line `=== docs: built into docs/site/public/ ===`.

- [ ] **Step 4: Verify `docs-serve`**

```bash
make docs-serve
```

Expected: Hugo server starts on `:1313`. Stop with Ctrl-C.

- [ ] **Step 5: Commit**

```bash
git add Makefile
git commit -m "docs(site): add docs-serve, docs-build, docs aggregate targets"
```

---

## Task 8: Fork landing page — chrome (topbar, hero, metadata, footer)

**Files:**
- Create: `docs/site/layouts/index.html`

Strategy: copy dagnats's live Hugo home layout verbatim, then perform targeted text replacements on the chrome regions (topbar, hero, metadata table, footer, `<head>` title/meta). The seven `§NN` content sections still contain dagnats prose at the end of this task; Task 9 rewrites them.

- [ ] **Step 1: Copy the dagnats layout**

```bash
cp ../dagnats/docs/site/layouts/index.html docs/site/layouts/index.html
```

(Adjust the source path if dagnats lives elsewhere relative to libfossil.)

- [ ] **Step 2: Replace `<head>` title and description**

In `docs/site/layouts/index.html`, replace the existing `<title>` and `<meta name="description">` lines with:

```html
<title>libfossil — pure-Go Fossil SCM library</title>
<meta name="description" content="libfossil — pure-Go library and CLI for Fossil SCM repositories. Zero CGo, static binaries, WASM-ready.">
```

- [ ] **Step 3: Replace topbar**

Find the topbar region (near the top of `<body>`, contains `DAGNATS` left wordmark and version/license/github/docs on the right). Replace:
- `DAGNATS` → `LIBFOSSIL`
- Version label → `v 0.4.1`
- License label → `license MIT` (replacing `Apache-2.0`)
- GitHub link href → `https://github.com/danmestas/go-libfossil`
- Docs link href → `/docs/` (already a relative URL in dagnats; verify it still points to `/docs/`)

- [ ] **Step 4: Replace hero**

Find the hero block (`<h1>dagnats</h1>` plus a paragraph tagline). Replace:
- `<h1>dagnats</h1>` → `<h1>libfossil</h1>`
- Tagline paragraph text → `A pure-Go library for Fossil SCM repositories. Zero CGo. Static binaries. WASM-ready.`

- [ ] **Step 5: Replace spec-sheet metadata table**

Find the metadata table (six rows: PROJECT, LANGUAGE, RUNTIME DEPS, BINARIES, LICENSE, STATUS). Replace right-column values:

| Key | Value |
|---|---|
| PROJECT | libfossil — pure-Go Fossil SCM library |
| LANGUAGE | Go (module github.com/danmestas/go-libfossil) |
| RUNTIME DEPS | none · pluggable SQLite drivers (modernc · ncruces) |
| BINARIES | 1 (libfossil CLI) |
| LICENSE | MIT |
| STATUS | v0.4.1 · alpha · breaking changes possible |

If dagnats's table embeds a `<code>` link (e.g., `github.com/danmestas/dagnats`), update that link target to `github.com/danmestas/go-libfossil`.

- [ ] **Step 6: Replace footer**

Find the footer at the bottom of the page. Replace its text with:

```
libfossil · MIT · v0.4.1 · 2026 · github.com/danmestas/go-libfossil
```

(If the dagnats footer uses a `<a>` for the repo link, preserve the link; just swap the URL and label.)

- [ ] **Step 7: Verify the chrome renders**

```bash
make docs-serve
```

Open `http://localhost:1313/`. Expected:
- Topbar: `LIBFOSSIL` left, `v 0.4.1 · license MIT · github · docs` right
- Hero: "libfossil" plus the new tagline
- Metadata table: rows with libfossil values from Step 5
- Footer: the libfossil text from Step 6
- The seven `§01`–`§07` sections still show dagnats content (Task 9 fixes them)
- Toggle your OS color scheme: page swaps between cream-paper and dark-paper

`grep -c 'dagnats' docs/site/layouts/index.html` should show several remaining dagnats references — those live in the §NN content blocks and are Task 9's job.

Stop the server.

- [ ] **Step 8: Commit**

```bash
git add docs/site/layouts/index.html
git commit -m "site(landing): fork dagnats home layout; rebrand chrome"
```

---

## Task 9: Landing page — rewrite §01–§07 content for libfossil

**Files:**
- Modify: `docs/site/layouts/index.html`

Each step rewrites one `<section>` block. The blocks are identifiable by `<span class="num">§NN</span>` and the `<h2>` slug anchor (`install`, `overview`, `why`, `architecture`, `comparison`, `limits`, `start`). Preserve the surrounding HTML structure (section tags, classes, COPY buttons, code-block markup, anchor IDs) and only replace text content.

- [ ] **Step 1: §01 Install**

Replace the install code block content with:

```sh
go install github.com/danmestas/go-libfossil/cmd/libfossil@latest
libfossil --help
```

Replace the prose below the code block with:

> That's the entire install. The binary is pure Go, statically linked, and CGo-free — drop it on any Linux/macOS/Windows host with no runtime dependency.

Keep the COPY-on-click button on the code block.

- [ ] **Step 2: §02 What it is**

Replace prose with two paragraphs:

> libfossil is a pure-Go reader and writer for Fossil SCM repositories — the SQLite-backed `.fossil` files used by [Fossil](https://fossil-scm.org). It exposes a Go API for opening repos, reading the timeline, committing, and syncing over HTTP, plus a `libfossil` CLI driving the same code paths.

> No CGo means static binaries that cross-compile cleanly. A `GOOS=wasip1` build runs in browsers and edge runtimes. Two SQLite drivers (`modernc`, `ncruces`) are swappable depending on whether you need pure-Go ergonomics or smaller WASM footprints.

- [ ] **Step 3: §03 Why you might want it**

Replace prose with:

> Two reasons to reach for libfossil instead of shelling out to the upstream `fossil` binary or using CGo bindings.

> **You're embedding Fossil into a Go service.** Build pipelines, code-search indexers, mirror servers, and AI-agent tools that read repository history all benefit from a library API instead of subprocess parsing. No exec calls, no version drift between hosts, observable through Go's standard `context.Context` and OpenTelemetry hooks.

> **You're shipping to constrained targets.** Static binaries cross-compile in seconds; CGo bindings don't. WASM compilation works out of the box. The cost is a slightly slower SQLite (modernc is pure Go); the upside is everywhere-runs without a build farm.

- [ ] **Step 4: §04 How it fits together**

If dagnats's section uses an SVG diagram (`<svg class="diagram">…</svg>`), replace its node labels with libfossil's. If it uses a `<pre>` ASCII block, replace with this ASCII (preserving any wrapping `<pre>` and class):

```
┌─────────┐     ┌──────────┐     ┌────────────┐
│   CLI   │ ──▶ │   Repo   │ ──▶ │ DB Driver  │
└─────────┘     └────┬─────┘     │ modernc /  │
                     │            │ ncruces    │
                     ▼            └────────────┘
              ┌──────────┐
              │Transport │
              │  (HTTP)  │
              └──────────┘
                     │
                     ▼
              ┌──────────┐
              │ Observer │
              │  (OTel)  │
              └──────────┘
```

Replace prose with:

> Three pluggable axes. The **DB driver** decides how SQLite runs — `modernc` for pure Go, `ncruces` for smaller WASM footprints. The **Transport** decides how sync talks to a remote — HTTP today, custom transports for unusual networks. **Observers** hook into sync, checkout, and commit events for telemetry and auditing.

> The CLI is a Kong-based wrapper over the same `Repo` API exposed to library users. Embedding the CLI commands into another Go binary is a one-import operation.

- [ ] **Step 5: §05 Compared to neighbors**

Replace prose with three short blocks:

> **vs. shelling out to the `fossil` binary.** No subprocess, no parsing CLI output, no version drift between developer machines and CI. Read the timeline as `[]Commit` instead of regex-grepping text. Trades: the upstream binary still has features libfossil hasn't reimplemented; you can't reuse Fossil's GUI.

> **vs. CGo bindings to the C libfossil library.** No CGo toolchain, no `libsqlite3.so` dependency, static binaries cross-compile cleanly, WASM works. Trades: pure-Go SQLite is slower than C SQLite (~2-3× on heavy queries); a few low-level Fossil internals are not yet exposed.

> **vs. plain `git`.** Different VCS — pick libfossil only if your repos are Fossil. Use go-git for git.

- [ ] **Step 6: §06 What it is not**

Replace prose with three points:

> **No GUI.** Fossil ships an embedded web UI; libfossil does not. If you need it, run the upstream `fossil` binary alongside.

> **No hosting.** libfossil reads and writes `.fossil` files; it does not run an HTTP server that serves them to other Fossil clients (yet). Mirroring works as a sync target, not a host.

> **No magic schema migrations.** libfossil tracks the upstream Fossil schema; if upstream introduces a breaking change, libfossil needs updating before you can open the new format.

- [ ] **Step 7: §07 Get going**

Replace prose with:

> Read the [Quickstart](/docs/quickstart) — five-minute tour. Browse the [SDK reference](/docs/reference/sdk) — every package, every exported symbol. File issues at [github.com/danmestas/go-libfossil](https://github.com/danmestas/go-libfossil).

Replace any code block in this section with:

```sh
go install github.com/danmestas/go-libfossil/cmd/libfossil@latest
```

Preserve the COPY button if dagnats uses one here.

- [ ] **Step 8: Verify**

```bash
make docs-serve
```

Open `http://localhost:1313/`. Walk through every section:
- `§01`–`§07` numbering and anchor slugs intact
- All seven section bodies show libfossil content (no `dagnats` text remaining)
- `grep -ci 'dagnats' docs/site/layouts/index.html` should return `0`
- Code blocks copy cleanly when you click COPY
- Internal links (`/docs/quickstart`, `/docs/reference/sdk`, `https://github.com/danmestas/go-libfossil`) work
- §04 diagram lays out without horizontal overflow
- Light/dark toggle still swaps cleanly

Stop the server.

- [ ] **Step 9: Commit**

```bash
git add docs/site/layouts/index.html
git commit -m "site(landing): rewrite §01–§07 content for libfossil"
```

---

## Task 10: wrangler.jsonc + local CF build simulation

**Files:**
- Create: `wrangler.jsonc`

- [ ] **Step 1: Write `wrangler.jsonc`**

```jsonc
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "libfossil-docs",
  "compatibility_date": "2026-04-25",
  "observability": { "enabled": true },
  "assets": { "directory": "./docs/site/public" },
  "build": {
    "command": "curl -sSL https://github.com/gohugoio/hugo/releases/download/v0.160.0/hugo_extended_0.160.0_linux-amd64.tar.gz | tar xz hugo && bash scripts/gen-llms-txt.sh && cd docs/site && ../../hugo --minify"
  },
  "compatibility_flags": ["nodejs_compat"]
}
```

- [ ] **Step 2: Locally simulate the CF build**

Cloudflare's build environment is Linux; we cannot use the exact curl URL on macOS. Substitute the local Hugo to verify the rest of the pipeline:

```bash
rm -rf docs/site/public docs/site/static/llms.txt docs/site/static/llms-full.txt
bash scripts/gen-llms-txt.sh
( cd docs/site && hugo --minify )
```

- [ ] **Step 3: Verify deployable artifacts**

```bash
ls docs/site/public/index.html docs/site/public/docs/index.html docs/site/public/llms.txt docs/site/public/llms-full.txt
# All four should exist.

grep -o '<title>[^<]*</title>' docs/site/public/index.html
# Expected: <title>libfossil — pure-Go Fossil SCM library</title>

grep -c 'libfossil' docs/site/public/index.html
# Expected: > 20 matches

grep -c 'dagnats' docs/site/public/index.html
# Expected: 0
```

- [ ] **Step 4: Commit**

```bash
git add wrangler.jsonc
git commit -m "deploy: add wrangler.jsonc for CF Workers Static Assets"
```

---

## Task 11: Update README + open PR

**Files:**
- Modify: `README.md`

- [ ] **Step 1: Update or add a "Documentation" section in `README.md`**

Find any existing "Documentation" section. If it lists the four `docs/*.md` files individually, replace that list with a pointer to the docs site:

```markdown
## Documentation

Full documentation: **https://libfossil-docs.<your-cf-subdomain>.workers.dev** _(set the actual URL after the CF dashboard is connected)_.

Local preview: `make docs-serve`, then visit http://localhost:1313/.

Markdown sources: [`docs/site/content/`](./docs/site/content/).
```

If no "Documentation" section exists, add one near the top after the project blurb.

- [ ] **Step 2: Audit for stale links to moved docs**

```bash
grep -nE '\(docs/(architecture|extension-points|migration-from-fossil|testing)\.md\)' README.md
```

For each match, update the path to either `docs/site/content/docs/<file>.md` (GitHub source) or to the served URL once known. Resolve any matches found.

- [ ] **Step 3: Final dry-run of the full pipeline**

```bash
make docs
git status
```

Expected: `docs` target completes; `git status` reports `working tree clean` (the pre-commit hook would have caught any drift on previous commits).

- [ ] **Step 4: Push the branch**

```bash
git add README.md
git commit -m "docs: point README at the new docs site"
git push -u origin feat/docs-site-cf-deploy
```

- [ ] **Step 5: Open the PR**

```bash
gh pr create --title "docs site + landing + Cloudflare auto-deploy" --body "$(cat <<'EOF'
## Summary

- Adds Hugo + Hextra docs site at `docs/site/`
- Adds Hugo home-page layout override (`docs/site/layouts/index.html`) for the landing page, mirroring the dagnats live design (mono-only, dual-mode, single ember accent, 7 numbered sections)
- Moves the four existing `docs/*.md` files under `docs/site/content/docs/`
- Adds `gomarkdoc`-generated SDK reference under `docs/site/content/docs/reference/sdk/` (committed; pre-commit hook fails on drift)
- Adds `scripts/gen-llms-txt.sh` for `/llms.txt` and `/llms-full.txt`
- Adds `wrangler.jsonc` for Cloudflare Workers Static Assets auto-deploy via CF's git integration

## Operational follow-ups (manual, after merge)

1. Cloudflare dashboard → Workers & Pages → Create → Connect to Git → select this repo
2. Production branch = `main`; build/output come from `wrangler.jsonc`
3. Default URL: `libfossil-docs.<your-cf-subdomain>.workers.dev`. Attach a custom domain when ready.
4. Update `README.md` and `hugo.yaml`'s `baseURL` once the final URL is known.

## Test plan

- [ ] `make docs` builds without errors
- [ ] `make docs-serve` shows the landing at `/`, docs at `/docs/`, SDK at `/docs/reference/sdk/`
- [ ] Pre-commit hook fails when SDK pages drift, passes when in sync
- [ ] After CF connects to the repo, the deployed URL serves the same content as local
EOF
)"
```

Per project policy, do NOT add a "Generated with Claude Code" footer to the PR body, and do NOT auto-merge. The user merges manually after review.

---

## Self-review checklist (engineer running this plan)

After all tasks complete, before opening the PR:

1. `git log feat/docs-site-cf-deploy --oneline | head -20` — every commit has a meaningful, conventional message.
2. `git log feat/docs-site-cf-deploy --grep='Co-Authored-By: Claude'` returns nothing.
3. `make docs` runs cleanly from a fresh checkout (test by `git stash && rm -rf docs/site/{public,static/llms*.txt,resources,_vendor} && make docs`).
4. The pre-commit hook actually catches SDK drift (Task 6 Step 2 verified once; re-verify if any later task touched the hook).
5. Landing page renders identically in light and dark mode; toggle the OS color scheme to confirm.
6. `grep -ci 'dagnats' docs/site/layouts/index.html` returns `0`.
