Artifact 68de04e4745460c05e0416942148d1a176a50b21eb761cc8772e63cf0392aff8:
- File
docs/superpowers/plans/2026-04-26-docs-site-cf-deploy.md
— part of check-in
[e2a2f28861]
at
2026-04-26 07:52:11
on branch trunk
— docs site + landing + Cloudflare auto-deploy (#6)
* design: docs site + landing page + Cloudflare auto-deploy
Mirror dagnats's docs/landing infrastructure for libfossil: a single-page landing at site/index.html (forked CSS/HTML, content rewritten), a Hugo + Hextra docs site at docs/site/, gomarkdoc-generated SDK reference under docs/site/content/docs/reference/sdk/, llms.txt artifacts, and a wrangler.jsonc that lets Cloudflare's git integration auto-deploy on push to main. Existing docs/*.md files move under docs/site/content/docs/.
* design: correct landing-page path to Hugo layout override
dagnats's working landing page lives at docs/site/layouts/index.html (a Hugo home-page layout override), not at site/index.html. The top-level site/index.html in dagnats is an older draft that the build pipeline ignores. Match the working setup.
* design: align visual system + section list with live dagnats landing
The earlier description came from dagnats's stale top-level site/index.html (JetBrains Mono + Instrument Serif italic + ember/teal accents, 8 sections). The live Hugo layout that actually serves at / uses Geist Mono only, prefers-color-scheme dual-mode (warm cream / warm dark), a single ember accent, and 7 sections (Install, What it is, Why you might want it, How it fits together, Compared to neighbors, What it is not, Get going). Update the spec to match what we are actually mirroring.
* design: drop SDK regen from CF build to match dagnats exactly
Earlier draft had CF install Go + gomarkdoc and re-run docs-gen-sdk on every deploy. dagnats does not do that; it relies on the pre-commit hook to keep committed SDK pages in sync, and ships only Hugo + llms-gen + hugo --minify in the CF build. Match that: smaller, faster CF build, no Go-runtime assumption about Workers Builds, and a true 1:1 mirror.
* plan: docs site + landing + CF auto-deploy implementation steps
11 tasks covering Hugo+Hextra bootstrap, content moves, gomarkdoc SDK generation with pre-commit drift check, llms.txt artifacts, Makefile targets, landing page fork from dagnats's live Hugo home layout, wrangler.jsonc for CF Workers Static Assets, README update, and PR creation.
* docs(site): bootstrap Hugo + Hextra skeleton
* docs(site): move existing docs into Hugo content tree
* docs(site): fix links + H1s broken by docs-tree move
- Drop .md extensions on Hugo cross-doc links - Switch source-code references to absolute github.com/danmestas/libfossil URLs (relative ../ paths broke when files moved 3 dirs deeper) - Align H1 of architecture.md and migration-from-fossil.md with their frontmatter titles
* docs(site): add quickstart, examples, and SDK section stubs
* docs(site): tighten quickstart snippets + reference index
- Make the Sync example self-contained (open + sync, full main, real signatures) - Bridge from Clone to Open with a one-line prose link - Add a sentence to reference/_index.md so it does not render blank - Use the project's canonical "pure-Go, CGo-free" phrasing
* docs(site): add docs-gen-sdk Makefile target + commit generated SDK pages
* docs(site): pin gomarkdoc version + replace empty driver stubs with prose
- Add GOMARKDOC_VERSION Makefile variable so contributors don't drift on output format when a new gomarkdoc ships - Drop the two driver packages (modernc, ncruces) from gomarkdoc and hand-write _index.md pages explaining the register-on-import contract; the stubs were byte-stable but rendered as visibly broken documentation
* docs(site): add gen-llms-txt.sh + docs-gen-llms target
* docs(site): switch llms-full frontmatter strip from sed to awk
The sed range-negation pattern '/^---$/,/^---$/!p' silently re-opens a suppression range on any bare '---' in body content, eating Markdown horizontal rules and embedded YAML in fenced code blocks. The awk pattern strips the frontmatter only when it begins on line 1, leaving body content intact regardless of how many '---' lines it contains.
* hooks: pre-commit fails when SDK pages drift from code
* hooks: pre-commit re-installs gomarkdoc if it's the wrong version
The drift check's existing gate just looks for gomarkdoc on PATH. A contributor with an older gomarkdoc installed locally would have the gate pass and then run regeneration with their stale binary, producing either a silent false-negative or a confusing OUT-OF-DATE error with no version hint. Compare the installed version against GOMARKDOC_VERSION from Makefile and re-install on mismatch. Best-effort; offline contributors can still commit.
* docs(site): add docs-serve, docs-build, docs aggregate targets
* docs(site): make docs aggregate parallel-safe via explicit deps
The docs aggregate previously listed gen-sdk, gen-llms, and build as side-by-side prereqs. Make doesn't guarantee left-to-right ordering under -j, and gen-llms reads what gen-sdk writes, while build reads both. Encode the chain explicitly so 'make -j docs' is correct. Side benefit: 'make docs-build' standalone now produces a complete deployable site, matching contributor expectation.
* site(landing): fork dagnats home layout; rebrand chrome
* site(landing): rewrite §01–§07 content for libfossil
* site(landing): use .ascii class for diagram + fix §03 phrasing
* deploy: add wrangler.jsonc for CF Workers Static Assets
* docs: point README at the new docs site (user: [email protected], size: 37533) [annotate] [blame] [check-ins using]
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 configdocs/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 landingdocs/site/content/docs/quickstart.md— drafted from READMEdocs/site/content/docs/reference/_index.md,docs/site/content/docs/reference/sdk/_index.md— section stubsdocs/site/content/docs/reference/sdk/{libfossil,cli,db,db/driver/modernc,db/driver/ncruces,observer/otel,dst}/api.md— generated bygomarkdoc, committeddocs/site/content/examples/_index.md— examples section stubdocs/site/layouts/index.html— landing page (Hugo home override; forked from dagnats)scripts/gen-llms-txt.sh— llms.txt generatorwrangler.jsonc— CF Worker config
Changed:
Makefile— addsdocs-serve,docs-build,docs-gen-sdk,docs-gen-llms,docstargets.githooks/pre-commit— adds SDK-drift check.gitignore— adds Hugo + llms artifacts + downloadedhugobinaryREADME.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 intodocs/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 byhugo 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:
# 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
cd docs/site
hugo mod init github.com/danmestas/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
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/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/libfossil/edit/main/docs/site/content"
page:
width: wide
- [ ] Step 5: Write
docs/site/content/_index.md
---
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
---
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
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
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
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 ---.)
- [ ] Step 2: Move migration-from-fossil.md
git mv docs/migration-from-fossil.md docs/site/content/docs/migration-from-fossil.md
Prepend:
---
title: Migration from Fossil
weight: 30
---
- [ ] Step 3: Move extension-points.md
git mv docs/extension-points.md docs/site/content/docs/extension-points.md
Prepend:
---
title: Extension Points
weight: 40
---
- [ ] Step 4: Move testing.md
git mv docs/testing.md docs/site/content/docs/testing.md
Prepend:
---
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/*.mdpaths no longer exist
ls docs/*.md 2>/dev/null
# Expected: no output (all four moved)
- [ ] Step 7: Commit
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
---
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/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/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/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
---
title: Reference
weight: 100
---
- [ ] Step 3: Write
docs/site/content/docs/reference/sdk/_index.md
---
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
---
title: Examples
weight: 60
---
Runnable examples live in [`examples/`](https://github.com/danmestas/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
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
Makefileto adddocs-gen-sdk
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/
- [ ] Step 2: Run target to generate SDK pages
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
- [ ] 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.
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
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
#!/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/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/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
chmod +x scripts/gen-llms-txt.sh
- [ ] Step 3: Add
docs-gen-llmstarget toMakefile
In .PHONY: append docs-gen-llms. Append the target:
docs-gen-llms:
bash scripts/gen-llms-txt.sh
- [ ] Step 4: Run and verify
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
- [ ] Step 5: Commit
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:
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:
# 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
- [ ] Step 3: Verify hook passes when in sync
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~
- [ ] Step 4: Commit the hook change
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:
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
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
docsaggregate
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
make docs-serve
Expected: Hugo server starts on :1313. Stop with Ctrl-C.
- [ ] Step 5: Commit
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
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:
<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(replacingApache-2.0) - GitHub link href →
https://github.com/danmestas/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/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/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/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
make docs-serve
Open http://localhost:1313/. Expected:
- Topbar:
LIBFOSSILleft,v 0.4.1 · license MIT · github · docsright - 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–§07sections 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
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:
go install github.com/danmestas/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
.fossilfiles used by Fossil. It exposes a Go API for opening repos, reading the timeline, committing, and syncing over HTTP, plus alibfossilCLI driving the same code paths.No CGo means static binaries that cross-compile cleanly. A
GOOS=wasip1build 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
fossilbinary 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.Contextand 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 —
moderncfor pure Go,ncrucesfor 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
RepoAPI 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
fossilbinary. No subprocess, no parsing CLI output, no version drift between developer machines and CI. Read the timeline as[]Commitinstead 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.sodependency, 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
fossilbinary alongside.No hosting. libfossil reads and writes
.fossilfiles; 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 — five-minute tour. Browse the SDK reference — every package, every exported symbol. File issues at github.com/danmestas/libfossil.
Replace any code block in this section with:
go install github.com/danmestas/libfossil/cmd/libfossil@latest
Preserve the COPY button if dagnats uses one here.
- [ ] Step 8: Verify
make docs-serve
Open http://localhost:1313/. Walk through every section:
§01–§07numbering and anchor slugs intact- All seven section bodies show libfossil content (no
dagnatstext remaining) grep -ci 'dagnats' docs/site/layouts/index.htmlshould return0- Code blocks copy cleanly when you click COPY
- Internal links (
/docs/quickstart,/docs/reference/sdk,https://github.com/danmestas/libfossil) work - §04 diagram lays out without horizontal overflow
- Light/dark toggle still swaps cleanly
Stop the server.
- [ ] Step 9: Commit
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
{
"$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:
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
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
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:
## 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
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
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
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
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:
git log feat/docs-site-cf-deploy --oneline | head -20— every commit has a meaningful, conventional message.git log feat/docs-site-cf-deploy --grep='Co-Authored-By: Claude'returns nothing.make docsruns cleanly from a fresh checkout (test bygit stash && rm -rf docs/site/{public,static/llms*.txt,resources,_vendor} && make docs).- The pre-commit hook actually catches SDK drift (Task 6 Step 2 verified once; re-verify if any later task touched the hook).
- Landing page renders identically in light and dark mode; toggle the OS color scheme to confirm.
grep -ci 'dagnats' docs/site/layouts/index.htmlreturns0.