docs: add core.help implementation plan
5 tasks: Hugo scaffold, KB scanning, --target hugo sync, pipeline testing, BunnyCDN deployment config. Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
1e8a4131db
commit
d7e5215618
1 changed files with 642 additions and 0 deletions
642
docs/plans/2026-02-21-core-help-plan.md
Normal file
642
docs/plans/2026-02-21-core-help-plan.md
Normal file
|
|
@ -0,0 +1,642 @@
|
|||
# core.help Hugo Documentation Site — Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Build a Hugo + Docsy documentation site at core.help that aggregates markdown from 39 repos via `core docs sync --target hugo`.
|
||||
|
||||
**Architecture:** Hugo static site with Docsy theme, populated by extending `core docs sync` with a `--target hugo` flag that maps repo docs into Hugo's `content/` tree with auto-injected front matter. Deploy to BunnyCDN.
|
||||
|
||||
**Tech Stack:** Hugo (Go SSG), Docsy theme (Hugo module), BunnyCDN, `core docs sync` CLI
|
||||
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
The docs sync command lives in `/Users/snider/Code/host-uk/cli/cmd/docs/`. The site will be scaffolded at `/Users/snider/Code/host-uk/docs-site/`. The registry at `/Users/snider/Code/host-uk/.core/repos.yaml` already contains all 39 repos (20 PHP + 18 Go + 1 CLI) with explicit paths for Go repos.
|
||||
|
||||
Key files:
|
||||
- `/Users/snider/Code/host-uk/cli/cmd/docs/cmd_sync.go` — sync command (modify)
|
||||
- `/Users/snider/Code/host-uk/cli/cmd/docs/cmd_scan.go` — repo scanner (modify)
|
||||
- `/Users/snider/Code/host-uk/docs-site/` — Hugo site (create)
|
||||
|
||||
## Task 1: Scaffold Hugo + Docsy site
|
||||
|
||||
**Files:**
|
||||
- Create: `/Users/snider/Code/host-uk/docs-site/hugo.toml`
|
||||
- Create: `/Users/snider/Code/host-uk/docs-site/go.mod`
|
||||
- Create: `/Users/snider/Code/host-uk/docs-site/content/_index.md`
|
||||
- Create: `/Users/snider/Code/host-uk/docs-site/content/getting-started/_index.md`
|
||||
- Create: `/Users/snider/Code/host-uk/docs-site/content/cli/_index.md`
|
||||
- Create: `/Users/snider/Code/host-uk/docs-site/content/go/_index.md`
|
||||
- Create: `/Users/snider/Code/host-uk/docs-site/content/mcp/_index.md`
|
||||
- Create: `/Users/snider/Code/host-uk/docs-site/content/php/_index.md`
|
||||
- Create: `/Users/snider/Code/host-uk/docs-site/content/kb/_index.md`
|
||||
|
||||
This is the one-time Hugo scaffolding. No tests — just files.
|
||||
|
||||
**`hugo.toml`:**
|
||||
```toml
|
||||
baseURL = "https://core.help/"
|
||||
title = "Core Documentation"
|
||||
languageCode = "en"
|
||||
defaultContentLanguage = "en"
|
||||
|
||||
enableRobotsTXT = true
|
||||
enableGitInfo = false
|
||||
|
||||
[outputs]
|
||||
home = ["HTML", "JSON"]
|
||||
section = ["HTML"]
|
||||
|
||||
[params]
|
||||
description = "Documentation for the Core CLI, Go packages, PHP modules, and MCP tools"
|
||||
copyright = "Host UK — EUPL-1.2"
|
||||
|
||||
[params.ui]
|
||||
sidebar_menu_compact = true
|
||||
breadcrumb_disable = false
|
||||
sidebar_search_disable = false
|
||||
navbar_logo = false
|
||||
|
||||
[params.ui.readingtime]
|
||||
enable = false
|
||||
|
||||
[module]
|
||||
proxy = "direct"
|
||||
|
||||
[module.hugoVersion]
|
||||
extended = true
|
||||
min = "0.120.0"
|
||||
|
||||
[[module.imports]]
|
||||
path = "github.com/google/docsy"
|
||||
disable = false
|
||||
|
||||
[markup.goldmark.renderer]
|
||||
unsafe = true
|
||||
|
||||
[menu]
|
||||
[[menu.main]]
|
||||
name = "Getting Started"
|
||||
weight = 10
|
||||
url = "/getting-started/"
|
||||
[[menu.main]]
|
||||
name = "CLI Reference"
|
||||
weight = 20
|
||||
url = "/cli/"
|
||||
[[menu.main]]
|
||||
name = "Go Packages"
|
||||
weight = 30
|
||||
url = "/go/"
|
||||
[[menu.main]]
|
||||
name = "MCP Tools"
|
||||
weight = 40
|
||||
url = "/mcp/"
|
||||
[[menu.main]]
|
||||
name = "PHP Packages"
|
||||
weight = 50
|
||||
url = "/php/"
|
||||
[[menu.main]]
|
||||
name = "Knowledge Base"
|
||||
weight = 60
|
||||
url = "/kb/"
|
||||
```
|
||||
|
||||
**`go.mod`:**
|
||||
```
|
||||
module github.com/host-uk/docs-site
|
||||
|
||||
go 1.22
|
||||
|
||||
require github.com/google/docsy v0.11.0
|
||||
```
|
||||
|
||||
Note: Run `hugo mod get` after creating these files to populate `go.sum` and download Docsy.
|
||||
|
||||
**Section `_index.md` files** — each needs Hugo front matter:
|
||||
|
||||
`content/_index.md`:
|
||||
```markdown
|
||||
---
|
||||
title: "Core Documentation"
|
||||
description: "Documentation for the Core CLI, Go packages, PHP modules, and MCP tools"
|
||||
---
|
||||
|
||||
Welcome to the Core ecosystem documentation.
|
||||
|
||||
## Sections
|
||||
|
||||
- [Getting Started](/getting-started/) — Installation, configuration, and first steps
|
||||
- [CLI Reference](/cli/) — Command reference for `core` CLI
|
||||
- [Go Packages](/go/) — Go ecosystem package documentation
|
||||
- [MCP Tools](/mcp/) — Model Context Protocol tool reference
|
||||
- [PHP Packages](/php/) — PHP module documentation
|
||||
- [Knowledge Base](/kb/) — Wiki articles and deep dives
|
||||
```
|
||||
|
||||
`content/getting-started/_index.md`:
|
||||
```markdown
|
||||
---
|
||||
title: "Getting Started"
|
||||
linkTitle: "Getting Started"
|
||||
weight: 10
|
||||
description: "Installation, configuration, and first steps with the Core CLI"
|
||||
---
|
||||
```
|
||||
|
||||
`content/cli/_index.md`:
|
||||
```markdown
|
||||
---
|
||||
title: "CLI Reference"
|
||||
linkTitle: "CLI Reference"
|
||||
weight: 20
|
||||
description: "Command reference for the core CLI tool"
|
||||
---
|
||||
```
|
||||
|
||||
`content/go/_index.md`:
|
||||
```markdown
|
||||
---
|
||||
title: "Go Packages"
|
||||
linkTitle: "Go Packages"
|
||||
weight: 30
|
||||
description: "Documentation for the Go ecosystem packages"
|
||||
---
|
||||
```
|
||||
|
||||
`content/mcp/_index.md`:
|
||||
```markdown
|
||||
---
|
||||
title: "MCP Tools"
|
||||
linkTitle: "MCP Tools"
|
||||
weight: 40
|
||||
description: "Model Context Protocol tool reference — file operations, RAG, ML inference, process management"
|
||||
---
|
||||
```
|
||||
|
||||
`content/php/_index.md`:
|
||||
```markdown
|
||||
---
|
||||
title: "PHP Packages"
|
||||
linkTitle: "PHP Packages"
|
||||
weight: 50
|
||||
description: "Documentation for the PHP module ecosystem"
|
||||
---
|
||||
```
|
||||
|
||||
`content/kb/_index.md`:
|
||||
```markdown
|
||||
---
|
||||
title: "Knowledge Base"
|
||||
linkTitle: "Knowledge Base"
|
||||
weight: 60
|
||||
description: "Wiki articles, deep dives, and reference material"
|
||||
---
|
||||
```
|
||||
|
||||
**Verify:** After creating files, run from `/Users/snider/Code/host-uk/docs-site/`:
|
||||
```bash
|
||||
hugo mod get
|
||||
hugo server
|
||||
```
|
||||
The site should start and show the landing page with Docsy theme at `localhost:1313`.
|
||||
|
||||
**Commit:**
|
||||
```bash
|
||||
cd /Users/snider/Code/host-uk/docs-site
|
||||
git init
|
||||
git add .
|
||||
git commit -m "feat: scaffold Hugo + Docsy documentation site"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Extend scanRepoDocs to collect KB/ and README
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/snider/Code/host-uk/cli/cmd/docs/cmd_scan.go`
|
||||
|
||||
Currently `scanRepoDocs` only collects files from `docs/`. For the Hugo target we also need:
|
||||
- `KB/**/*.md` files (wiki pages from go-mlx, go-i18n)
|
||||
- `README.md` content (becomes the package _index.md)
|
||||
|
||||
Add a `KBFiles []string` field to `RepoDocInfo` and scan `KB/` alongside `docs/`:
|
||||
|
||||
```go
|
||||
type RepoDocInfo struct {
|
||||
Name string
|
||||
Path string
|
||||
HasDocs bool
|
||||
Readme string
|
||||
ClaudeMd string
|
||||
Changelog string
|
||||
DocsFiles []string // All files in docs/ directory (recursive)
|
||||
KBFiles []string // All files in KB/ directory (recursive)
|
||||
}
|
||||
```
|
||||
|
||||
In `scanRepoDocs`, after the `docs/` walk, add a second walk for `KB/`:
|
||||
|
||||
```go
|
||||
// Recursively scan KB/ directory for .md files
|
||||
kbDir := filepath.Join(repo.Path, "KB")
|
||||
if _, err := io.Local.List(kbDir); err == nil {
|
||||
_ = filepath.WalkDir(kbDir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if d.IsDir() || !strings.HasSuffix(d.Name(), ".md") {
|
||||
return nil
|
||||
}
|
||||
relPath, _ := filepath.Rel(kbDir, path)
|
||||
info.KBFiles = append(info.KBFiles, relPath)
|
||||
info.HasDocs = true
|
||||
return nil
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
**Tests:** The existing tests should still pass. No new test file needed — this is a data-collection change.
|
||||
|
||||
**Verify:** `cd /Users/snider/Code/host-uk/cli && GOWORK=off go build ./cmd/docs/...`
|
||||
|
||||
**Commit:**
|
||||
```bash
|
||||
git add cmd/docs/cmd_scan.go
|
||||
git commit -m "feat(docs): scan KB/ directory alongside docs/"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Add `--target hugo` flag and Hugo sync logic
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/snider/Code/host-uk/cli/cmd/docs/cmd_sync.go`
|
||||
|
||||
This is the main task. Add a `--target` flag (default `"php"`) and a new `runHugoSync` function that maps repos to Hugo's content tree.
|
||||
|
||||
**Add flag variable and registration:**
|
||||
|
||||
```go
|
||||
var (
|
||||
docsSyncRegistryPath string
|
||||
docsSyncDryRun bool
|
||||
docsSyncOutputDir string
|
||||
docsSyncTarget string
|
||||
)
|
||||
|
||||
func init() {
|
||||
docsSyncCmd.Flags().StringVar(&docsSyncRegistryPath, "registry", "", i18n.T("common.flag.registry"))
|
||||
docsSyncCmd.Flags().BoolVar(&docsSyncDryRun, "dry-run", false, i18n.T("cmd.docs.sync.flag.dry_run"))
|
||||
docsSyncCmd.Flags().StringVar(&docsSyncOutputDir, "output", "", i18n.T("cmd.docs.sync.flag.output"))
|
||||
docsSyncCmd.Flags().StringVar(&docsSyncTarget, "target", "php", "Target format: php (default) or hugo")
|
||||
}
|
||||
```
|
||||
|
||||
**Update RunE to pass target:**
|
||||
```go
|
||||
RunE: func(cmd *cli.Command, args []string) error {
|
||||
return runDocsSync(docsSyncRegistryPath, docsSyncOutputDir, docsSyncDryRun, docsSyncTarget)
|
||||
},
|
||||
```
|
||||
|
||||
**Update `runDocsSync` signature and add target dispatch:**
|
||||
```go
|
||||
func runDocsSync(registryPath string, outputDir string, dryRun bool, target string) error {
|
||||
reg, basePath, err := loadRegistry(registryPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch target {
|
||||
case "hugo":
|
||||
return runHugoSync(reg, basePath, outputDir, dryRun)
|
||||
default:
|
||||
return runPHPSync(reg, basePath, outputDir, dryRun)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Rename current sync body to `runPHPSync`** — extract lines 67-159 of current `runDocsSync` into `runPHPSync(reg, basePath, outputDir string, dryRun bool) error`. This is a pure extract, no logic changes.
|
||||
|
||||
**Add `hugoOutputName` mapping function:**
|
||||
```go
|
||||
// hugoOutputName maps repo name to Hugo content section and folder.
|
||||
// Returns (section, folder) where section is the top-level content dir.
|
||||
func hugoOutputName(repoName string) (string, string) {
|
||||
// CLI guides
|
||||
if repoName == "cli" {
|
||||
return "getting-started", ""
|
||||
}
|
||||
// Core CLI command docs
|
||||
if repoName == "core" {
|
||||
return "cli", ""
|
||||
}
|
||||
// Go packages
|
||||
if strings.HasPrefix(repoName, "go-") {
|
||||
return "go", repoName
|
||||
}
|
||||
// PHP packages
|
||||
if strings.HasPrefix(repoName, "core-") {
|
||||
return "php", strings.TrimPrefix(repoName, "core-")
|
||||
}
|
||||
return "go", repoName
|
||||
}
|
||||
```
|
||||
|
||||
**Add front matter injection helper:**
|
||||
```go
|
||||
// injectFrontMatter prepends Hugo front matter to markdown content if missing.
|
||||
func injectFrontMatter(content []byte, title string, weight int) []byte {
|
||||
// Already has front matter
|
||||
if bytes.HasPrefix(bytes.TrimSpace(content), []byte("---")) {
|
||||
return content
|
||||
}
|
||||
fm := fmt.Sprintf("---\ntitle: %q\nweight: %d\n---\n\n", title, weight)
|
||||
return append([]byte(fm), content...)
|
||||
}
|
||||
|
||||
// titleFromFilename derives a human-readable title from a filename.
|
||||
func titleFromFilename(filename string) string {
|
||||
name := strings.TrimSuffix(filepath.Base(filename), ".md")
|
||||
name = strings.ReplaceAll(name, "-", " ")
|
||||
name = strings.ReplaceAll(name, "_", " ")
|
||||
// Title case
|
||||
words := strings.Fields(name)
|
||||
for i, w := range words {
|
||||
if len(w) > 0 {
|
||||
words[i] = strings.ToUpper(w[:1]) + w[1:]
|
||||
}
|
||||
}
|
||||
return strings.Join(words, " ")
|
||||
}
|
||||
```
|
||||
|
||||
**Add `runHugoSync` function:**
|
||||
```go
|
||||
func runHugoSync(reg *repos.Registry, basePath string, outputDir string, dryRun bool) error {
|
||||
if outputDir == "" {
|
||||
outputDir = filepath.Join(basePath, "docs-site", "content")
|
||||
}
|
||||
|
||||
// Scan all repos
|
||||
var docsInfo []RepoDocInfo
|
||||
for _, repo := range reg.List() {
|
||||
if repo.Name == "core-template" || repo.Name == "core-claude" {
|
||||
continue
|
||||
}
|
||||
info := scanRepoDocs(repo)
|
||||
if info.HasDocs {
|
||||
docsInfo = append(docsInfo, info)
|
||||
}
|
||||
}
|
||||
|
||||
if len(docsInfo) == 0 {
|
||||
cli.Text("No documentation found")
|
||||
return nil
|
||||
}
|
||||
|
||||
cli.Print("\n Hugo sync: %d repos with docs → %s\n\n", len(docsInfo), outputDir)
|
||||
|
||||
// Show plan
|
||||
for _, info := range docsInfo {
|
||||
section, folder := hugoOutputName(info.Name)
|
||||
target := section
|
||||
if folder != "" {
|
||||
target = section + "/" + folder
|
||||
}
|
||||
fileCount := len(info.DocsFiles) + len(info.KBFiles)
|
||||
if info.Readme != "" {
|
||||
fileCount++
|
||||
}
|
||||
cli.Print(" %s → %s/ (%d files)\n", repoNameStyle.Render(info.Name), target, fileCount)
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
cli.Print("\n Dry run — no files written\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
cli.Blank()
|
||||
if !confirm("Sync to Hugo content directory?") {
|
||||
cli.Text("Aborted")
|
||||
return nil
|
||||
}
|
||||
|
||||
cli.Blank()
|
||||
var synced int
|
||||
for _, info := range docsInfo {
|
||||
section, folder := hugoOutputName(info.Name)
|
||||
|
||||
// Build destination path
|
||||
destDir := filepath.Join(outputDir, section)
|
||||
if folder != "" {
|
||||
destDir = filepath.Join(destDir, folder)
|
||||
}
|
||||
|
||||
// Copy docs/ files
|
||||
weight := 10
|
||||
docsDir := filepath.Join(info.Path, "docs")
|
||||
for _, f := range info.DocsFiles {
|
||||
src := filepath.Join(docsDir, f)
|
||||
dst := filepath.Join(destDir, f)
|
||||
if err := copyWithFrontMatter(src, dst, weight); err != nil {
|
||||
cli.Print(" %s %s: %s\n", errorStyle.Render("✗"), f, err)
|
||||
continue
|
||||
}
|
||||
weight += 10
|
||||
}
|
||||
|
||||
// Copy README.md as _index.md (if not CLI/core which use their own index)
|
||||
if info.Readme != "" && folder != "" {
|
||||
dst := filepath.Join(destDir, "_index.md")
|
||||
if err := copyWithFrontMatter(info.Readme, dst, 1); err != nil {
|
||||
cli.Print(" %s README: %s\n", errorStyle.Render("✗"), err)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy KB/ files to kb/{suffix}/
|
||||
if len(info.KBFiles) > 0 {
|
||||
// Extract suffix: go-mlx → mlx, go-i18n → i18n
|
||||
suffix := strings.TrimPrefix(info.Name, "go-")
|
||||
kbDestDir := filepath.Join(outputDir, "kb", suffix)
|
||||
kbDir := filepath.Join(info.Path, "KB")
|
||||
kbWeight := 10
|
||||
for _, f := range info.KBFiles {
|
||||
src := filepath.Join(kbDir, f)
|
||||
dst := filepath.Join(kbDestDir, f)
|
||||
if err := copyWithFrontMatter(src, dst, kbWeight); err != nil {
|
||||
cli.Print(" %s KB/%s: %s\n", errorStyle.Render("✗"), f, err)
|
||||
continue
|
||||
}
|
||||
kbWeight += 10
|
||||
}
|
||||
}
|
||||
|
||||
cli.Print(" %s %s\n", successStyle.Render("✓"), info.Name)
|
||||
synced++
|
||||
}
|
||||
|
||||
cli.Print("\n Synced %d repos to Hugo content\n", synced)
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyWithFrontMatter copies a markdown file, injecting front matter if missing.
|
||||
func copyWithFrontMatter(src, dst string, weight int) error {
|
||||
if err := io.Local.EnsureDir(filepath.Dir(dst)); err != nil {
|
||||
return err
|
||||
}
|
||||
content, err := io.Local.Read(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
title := titleFromFilename(src)
|
||||
result := injectFrontMatter([]byte(content), title, weight)
|
||||
return io.Local.Write(dst, string(result))
|
||||
}
|
||||
```
|
||||
|
||||
**Add imports** at top of file:
|
||||
```go
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"forge.lthn.ai/core/go/pkg/cli"
|
||||
"forge.lthn.ai/core/go/pkg/i18n"
|
||||
"forge.lthn.ai/core/go/pkg/io"
|
||||
"forge.lthn.ai/core/go/pkg/repos"
|
||||
)
|
||||
```
|
||||
|
||||
**Verify:** `cd /Users/snider/Code/host-uk/cli && GOWORK=off go build ./cmd/docs/...`
|
||||
|
||||
**Commit:**
|
||||
```bash
|
||||
git add cmd/docs/cmd_sync.go
|
||||
git commit -m "feat(docs): add --target hugo sync mode for core.help"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Test the full pipeline
|
||||
|
||||
**No code changes.** Run the pipeline end-to-end.
|
||||
|
||||
**Step 1:** Sync docs to Hugo:
|
||||
```bash
|
||||
cd /Users/snider/Code/host-uk
|
||||
core docs sync --target hugo --dry-run
|
||||
```
|
||||
Verify all 39 repos appear with correct section mappings.
|
||||
|
||||
**Step 2:** Run actual sync:
|
||||
```bash
|
||||
core docs sync --target hugo
|
||||
```
|
||||
|
||||
**Step 3:** Build and preview:
|
||||
```bash
|
||||
cd /Users/snider/Code/host-uk/docs-site
|
||||
hugo server
|
||||
```
|
||||
Open `localhost:1313` and verify:
|
||||
- Landing page renders with section links
|
||||
- Getting Started section has CLI guides
|
||||
- CLI Reference section has command docs
|
||||
- Go Packages section has 18 packages with architecture/development/history
|
||||
- PHP Packages section has PHP module docs
|
||||
- Knowledge Base has MLX and i18n wiki pages
|
||||
- Navigation works, search works
|
||||
|
||||
**Step 4:** Fix any issues found during preview.
|
||||
|
||||
**Commit docs-site content:**
|
||||
```bash
|
||||
cd /Users/snider/Code/host-uk/docs-site
|
||||
git add content/
|
||||
git commit -m "feat: sync initial content from 39 repos"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: BunnyCDN deployment config
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/snider/Code/host-uk/docs-site/hugo.toml`
|
||||
|
||||
Add deployment target:
|
||||
|
||||
```toml
|
||||
[deployment]
|
||||
[[deployment.targets]]
|
||||
name = "production"
|
||||
URL = "s3://core-help?endpoint=storage.bunnycdn.com®ion=auto"
|
||||
```
|
||||
|
||||
Add a `Taskfile.yml` for convenience:
|
||||
|
||||
**Create:** `/Users/snider/Code/host-uk/docs-site/Taskfile.yml`
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
dev:
|
||||
desc: Start Hugo dev server
|
||||
cmds:
|
||||
- hugo server --buildDrafts
|
||||
|
||||
build:
|
||||
desc: Build static site
|
||||
cmds:
|
||||
- hugo --minify
|
||||
|
||||
sync:
|
||||
desc: Sync docs from all repos
|
||||
dir: ..
|
||||
cmds:
|
||||
- core docs sync --target hugo
|
||||
|
||||
deploy:
|
||||
desc: Build and deploy to BunnyCDN
|
||||
cmds:
|
||||
- task: sync
|
||||
- task: build
|
||||
- hugo deploy --target production
|
||||
|
||||
clean:
|
||||
desc: Remove generated content (keeps _index.md files)
|
||||
cmds:
|
||||
- find content -name "*.md" ! -name "_index.md" -delete
|
||||
```
|
||||
|
||||
**Verify:** `task dev` starts the site.
|
||||
|
||||
**Commit:**
|
||||
```bash
|
||||
git add hugo.toml Taskfile.yml
|
||||
git commit -m "feat: add BunnyCDN deployment config and Taskfile"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependency Sequencing
|
||||
|
||||
```
|
||||
Task 1 (Hugo scaffold) — independent, do first
|
||||
Task 2 (scan KB/) — independent, can parallel with Task 1
|
||||
Task 3 (--target hugo) — depends on Task 2
|
||||
Task 4 (test pipeline) — depends on Tasks 1 + 3
|
||||
Task 5 (deploy config) — depends on Task 1
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
After all tasks:
|
||||
1. `core docs sync --target hugo` populates `docs-site/content/` from all repos
|
||||
2. `cd docs-site && hugo server` renders the full site
|
||||
3. Navigation has 6 sections: Getting Started, CLI, Go, MCP, PHP, KB
|
||||
4. All existing markdown renders correctly with auto-injected front matter
|
||||
5. `hugo build` produces `public/` with no errors
|
||||
Loading…
Add table
Reference in a new issue