|
| 1 | +# AGENTS.md — Tales |
| 2 | + |
| 3 | +Guidance for agentic coding assistants working in this repository. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Project Overview |
| 8 | + |
| 9 | +A personal static blog by Dewald Viljoen, built with **Hugo** and deployed to **GitHub Pages**. The theme (`themes/tales/`) is a custom local theme derived from `smol`. No npm, no bundler, no CSS framework — deliberately minimal. |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +## Build & Dev Commands |
| 14 | + |
| 15 | +There is no Makefile or npm scripts. All commands use the Hugo CLI directly. |
| 16 | + |
| 17 | +| Purpose | Command | |
| 18 | +|---|---| |
| 19 | +| Dev server (published posts only) | `hugo server` | |
| 20 | +| Dev server (including drafts) | `hugo server -D` | |
| 21 | +| Production build | `hugo --gc --minify` | |
| 22 | +| Create a new post | `hugo new content/posts/YYYY-MM-DD-slug.md` | |
| 23 | + |
| 24 | +There are **no lint, format, or test commands**. Hugo itself validates templates at build/serve time — errors are printed to the terminal. |
| 25 | + |
| 26 | +**The dev server is the primary feedback loop.** Always verify changes by checking the running server at `http://localhost:1313`. |
| 27 | + |
| 28 | +### Nix Dev Environment |
| 29 | + |
| 30 | +The repo uses Nix flakes + direnv. If the Nix shell is active (via `direnv allow` or `nix develop`), `hugo` and `go` are available automatically. |
| 31 | + |
| 32 | +### CI/CD |
| 33 | + |
| 34 | +GitHub Actions (`.github/workflows/hugo.yaml`) builds with: |
| 35 | +```bash |
| 36 | +hugo --gc --minify --baseURL "${{ steps.pages.outputs.base_url }}/" |
| 37 | +``` |
| 38 | +Pinned to **Hugo 0.155.3 extended**. Sets `HUGO_ENVIRONMENT=production`. |
| 39 | + |
| 40 | +--- |
| 41 | + |
| 42 | +## Project Structure |
| 43 | + |
| 44 | +``` |
| 45 | +content/ |
| 46 | + _index.md # Homepage (YAML front matter, no body content) |
| 47 | + about/_index.md # About page (YAML, layout: about) |
| 48 | + posts/ |
| 49 | + 00-post-ideas.md # Draft scratchpad — never publish |
| 50 | + YYYY-MM-DD-slug.md # Blog posts |
| 51 | +themes/tales/ |
| 52 | + layouts/ |
| 53 | + _default/ # Base templates (baseof, single, list, summary, about) |
| 54 | + about/ # About-specific layout overrides |
| 55 | + index.html # Homepage layout |
| 56 | + partials/ # header, footer, pagination, contact |
| 57 | + _default/_markup/ # render-image.html (wraps images in <figure>) |
| 58 | + static/css/style.css # All styles — single file, no build step |
| 59 | +static/images/ # Site-level static assets |
| 60 | +hugo.toml # Site config, params, menus |
| 61 | +``` |
| 62 | + |
| 63 | +--- |
| 64 | + |
| 65 | +## Content Conventions |
| 66 | + |
| 67 | +### Post Files |
| 68 | + |
| 69 | +- **Location:** `content/posts/` |
| 70 | +- **Filename format:** `YYYY-MM-DD-kebab-case-slug.md` — date prefix is mandatory, keeps posts sorted naturally in the filesystem. |
| 71 | +- **Example:** `2025-02-10-nixos-setup.md` |
| 72 | + |
| 73 | +### Front Matter |
| 74 | + |
| 75 | +Posts use **TOML** delimiters (`+++`): |
| 76 | + |
| 77 | +```toml |
| 78 | ++++ |
| 79 | +title = 'Post Title Here' |
| 80 | +date = 2025-02-10T10:00:00Z |
| 81 | +draft = false |
| 82 | +tags = ['nixos', 'linux'] |
| 83 | ++++ |
| 84 | +``` |
| 85 | + |
| 86 | +Section index files (`_index.md`) use **YAML** delimiters (`---`): |
| 87 | + |
| 88 | +```yaml |
| 89 | +--- |
| 90 | +title: "Page Title" |
| 91 | +description: "Short description" |
| 92 | +--- |
| 93 | +``` |
| 94 | + |
| 95 | +Rules: |
| 96 | +- `title` and `date` are always required on posts. |
| 97 | +- `draft = true` hides a post from the live site (`hugo server -D` still shows it locally). |
| 98 | +- `tags` are optional, lowercase, kebab-case strings. |
| 99 | +- Dates use ISO 8601 with time and UTC offset: `2025-02-10T10:00:00Z`. |
| 100 | +- Do **not** set `draft = false` on `00-post-ideas.md` — it is a scratchpad, not a post. |
| 101 | + |
| 102 | +### The `hugo new` Archetype |
| 103 | + |
| 104 | +Running `hugo new content/posts/YYYY-MM-DD-slug.md` scaffolds a TOML front matter file from `archetypes/default.md`. The title is auto-derived from the filename. |
| 105 | + |
| 106 | +--- |
| 107 | + |
| 108 | +## Hugo Templates |
| 109 | + |
| 110 | +### Layout Hierarchy |
| 111 | + |
| 112 | +- All page templates define a `{{ define "main" }}` block injected into `baseof.html`. |
| 113 | +- `baseof.html` owns `<html>`, `<head>`, header/footer partials, and the inline JS for the theme toggle. |
| 114 | +- Never add `<html>`, `<head>`, or `<body>` tags to layout files other than `baseof.html`. |
| 115 | + |
| 116 | +### Indentation |
| 117 | + |
| 118 | +Hard **tabs** throughout all `.html` template files. Do not use spaces. |
| 119 | + |
| 120 | +### Partials |
| 121 | + |
| 122 | +Call partials with the `.html` suffix for consistency: |
| 123 | +```html |
| 124 | +{{ partial "contact.html" . }} |
| 125 | +{{ partial "pagination.html" . }} |
| 126 | +``` |
| 127 | + |
| 128 | +Pass `.` (current context) unless a specific context is needed. |
| 129 | + |
| 130 | +### Site Params |
| 131 | + |
| 132 | +Social/contact links and section config live in `hugo.toml` under `[params]`. Access them in templates with `{{ .Site.Params.github }}` etc. Always wrap optional params in `{{ with }}`: |
| 133 | + |
| 134 | +```html |
| 135 | +{{ with .Site.Params.github }}<a href="{{ . }}">GitHub</a>{{ end }} |
| 136 | +``` |
| 137 | + |
| 138 | +### Hugo Template Patterns |
| 139 | + |
| 140 | +- Use `{{ $var := value }}` for local variables. |
| 141 | +- Use `{{ range }}...{{ end }}` for iteration. |
| 142 | +- Use `{{ with }}...{{ end }}` for nil-safe access (preferred over `{{ if }}`). |
| 143 | +- Date formatting uses Go reference time: `"2006-01-02"` for date-only, `"2006-01-02 15:04:05"` for datetime. |
| 144 | +- Use `| relURL` or `| relLangURL` for internal links; `| urlize` for slugifying tag names. |
| 145 | + |
| 146 | +--- |
| 147 | + |
| 148 | +## CSS Conventions |
| 149 | + |
| 150 | +Single file: `themes/tales/static/css/style.css`. No preprocessor, no build step. |
| 151 | + |
| 152 | +### Custom Properties |
| 153 | + |
| 154 | +All colours are defined as CSS custom properties on `:root`. The full set: |
| 155 | + |
| 156 | +```css |
| 157 | +--bgcolor, --fontcolor, --linkcolor, --visitedcolor, |
| 158 | +--precolor, --prebgcolor, --hrcolor, --mutedcolor |
| 159 | +``` |
| 160 | + |
| 161 | +Always use these variables — never hardcode colour values. |
| 162 | + |
| 163 | +### Theme System |
| 164 | + |
| 165 | +- Default: light (`:root`) |
| 166 | +- OS dark preference: `@media (prefers-color-scheme: dark)` |
| 167 | +- Manual override: `[data-theme="dark"]` / `[data-theme="light"]` on `<html>` |
| 168 | + |
| 169 | +When adding new components, define colours using the existing variables so dark/light mode works automatically. |
| 170 | + |
| 171 | +### Naming |
| 172 | + |
| 173 | +- Kebab-case class names: `.site-header`, `.latest-post`, `.latest-post-label` |
| 174 | +- No component prefix or BEM syntax — flat, descriptive names |
| 175 | +- Semantic HTML elements styled directly where appropriate (`article`, `footer`, `figure`, etc.) |
| 176 | + |
| 177 | +### File Organisation |
| 178 | + |
| 179 | +Add new styles under a clearly commented section header: |
| 180 | +```css |
| 181 | +/* New component name */ |
| 182 | +.new-component { ... } |
| 183 | +``` |
| 184 | + |
| 185 | +The existing section order is: variables → base → links → headings → code → specific components → header → footer → theme toggle → responsive. |
| 186 | + |
| 187 | +### Typography & Layout |
| 188 | + |
| 189 | +- Body: `14px/1.6 monospace` — the monospace aesthetic is intentional, do not change. |
| 190 | +- Max-width: `800px`, centred with `margin: auto`. |
| 191 | +- Single responsive breakpoint at `max-width: 600px`. |
| 192 | + |
| 193 | +--- |
| 194 | + |
| 195 | +## Hugo Config (`hugo.toml`) |
| 196 | + |
| 197 | +- Format: TOML throughout. |
| 198 | +- `baseURL`: `https://dewaldv.com/` |
| 199 | +- `languageCode`: `en-GB` — use British English in all UI strings. |
| 200 | +- Site title: `DEWALD VILJOEN` (all caps) — do not change casing. |
| 201 | +- `params.mainSections = ["posts"]` — required for the homepage post list and latest-post callout. |
| 202 | +- Social params (`github`, `linkedin`, `email`) are the single source of truth for contact details. Update them here, not in templates or content. |
| 203 | + |
| 204 | +--- |
| 205 | + |
| 206 | +## Git Conventions |
| 207 | + |
| 208 | +Commit messages follow **Conventional Commits** with one custom type: |
| 209 | + |
| 210 | +``` |
| 211 | +feat: new site feature or template change |
| 212 | +fix: bug fix |
| 213 | +chore: deps, config, formatting, maintenance |
| 214 | +post: adding or updating a blog post or content file |
| 215 | +``` |
| 216 | + |
| 217 | +Format: `<type>: <short imperative description>` (no capital, no period). |
| 218 | + |
| 219 | +Examples: |
| 220 | +``` |
| 221 | +feat: add latest post callout to homepage |
| 222 | +fix: use list layout for about page |
| 223 | +chore: update flake dependencies |
| 224 | +post: start nixos setup post |
| 225 | +``` |
| 226 | + |
| 227 | +--- |
| 228 | + |
| 229 | +## Common Pitfalls |
| 230 | + |
| 231 | +- **`_index.md` uses the list layout**, not single — section index files are branch bundles. Use `layout:` front matter or a section-specific layout file in `layouts/<section>/` to override. |
| 232 | +- **`mainSections` must be set** in `hugo.toml` — without it, the homepage and latest-post callout will be empty. |
| 233 | +- **Drafts require `-D` flag** — `hugo server` without `-D` will not show draft posts. |
| 234 | +- **Post filename must have a date prefix** — `YYYY-MM-DD-slug.md` is the established convention; do not create posts without it. |
| 235 | +- **Do not publish `00-post-ideas.md`** — it is a scratchpad and must remain `draft = true`. |
0 commit comments