Skip to content
go-libfossil libfossil Docs Site + Cloudflare Auto-Deploy Implementation Plan
Login

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:

Changed:

Deleted (after move):

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:

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

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

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

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.)

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
---
title: libfossil
layout: landing
---

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

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

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:

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

---
title: Architecture
weight: 20
---

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

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

Prepend:

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

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

Prepend:

---
title: Extension Points
weight: 40
---

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

Prepend:

---
title: Testing
weight: 50
---

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.

ls docs/*.md 2>/dev/null
# Expected: no output (all four moved)
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:

---
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.)

---
title: Reference
weight: 100
---
---
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.
---
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.)

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.

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:

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

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

Append the target at the bottom of the file:

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/
make docs-gen-sdk

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

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

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.

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.

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:

#!/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/"
chmod +x scripts/gen-llms-txt.sh

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

docs-gen-llms:
	bash scripts/gen-llms-txt.sh
make docs-gen-llms

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

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

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.

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

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.

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

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

git checkout -- libfossil.go

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

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

git reset HEAD~
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:

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

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/ ==="
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)
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/ ===.

make docs-serve

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

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

Files:

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.

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

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

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

<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.">

Find the topbar region (near the top of <body>, contains DAGNATS left wordmark and version/license/github/docs on the right). Replace:

Find the hero block (<h1>dagnats</h1> plus a paragraph tagline). Replace:

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.

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.)

make docs-serve

Open http://localhost:1313/. Expected:

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.

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:

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.

Replace the install code block content with:

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.

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

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.

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.

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.

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.

Replace prose with:

Read the Quickstart — five-minute tour. Browse the SDK reference — every package, every exported symbol. File issues at github.com/danmestas/go-libfossil.

Replace any code block in this section with:

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

Preserve the COPY button if dagnats uses one here.

make docs-serve

Open http://localhost:1313/. Walk through every section:

Stop the server.

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:

{
  "$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"]
}

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:

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 )
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
git add wrangler.jsonc
git commit -m "deploy: add wrangler.jsonc for CF Workers Static Assets"

Task 11: Update README + open PR

Files:

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

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

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.

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).

git add README.md
git commit -m "docs: point README at the new docs site"
git push -u origin feat/docs-site-cf-deploy
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.