diff --git a/docs/OVERVIEW.md b/docs/OVERVIEW.md
new file mode 100644
index 0000000..fd9568c
--- /dev/null
+++ b/docs/OVERVIEW.md
@@ -0,0 +1,153 @@
+# Kontra β Project Overview
+
+> **Kontra** is a self-hosted news-opinion site engine. Content is plain Markdown in a git repo;
+> a single static Go binary renders it into a fast, SEO-friendly editorial site; a Decap CMS admin
+> (authenticated with Gitea OAuth) lets editors work in the browser; and a git-driven pull loop
+> publishes changes live within ~30 seconds of a save.
+
+**Live:** https://kontra.lab.audasmedia.com.au Β· **Admin:** https://admin.kontra.lab.audasmedia.com.au/web/admin/
+**Repo (public):** https://gitea.lab.audasmedia.com.au/sam/kontra
+
+> πΊ **Interactive architecture map:** https://maps.lab.audasmedia.com.au/kontra_day/docs/kontra-architecture-map.html
+> (pan/zoom, search, route tracing, dark/light themes)
+
+---
+
+## What it is
+
+A complete, self-hosted news/opinion publishing platform designed to run on the home lab:
+
+- **Markdown-first content** β articles are `.md` files with YAML front-matter. No database to manage.
+- **One static binary** β Go (golang) + templ + htmx + design-token CSS. No runtime, no Node, no PHP.
+- **Three edit paths** β Obsidian vault, Neovim/CLI, or the Decap CMS browser editor. All converge on one git repo.
+- **Git is the API** β full history, rollback, branch review, backups included.
+- **Autopublish** β `git push` β container pulls every 30s β live. Proven for add + delete.
+- **Self-hosted everything** β Gitea (origin), Garage S3 (media), Caddy (TLS), Decap (admin), Docker (runtime).
+
+## Architecture (Mermaid)
+
+```mermaid
+flowchart LR
+ subgraph editors["Content Editors"]
+ O[Obsidian vault
/obsidian/kontra_content] -->|git push| G
+ N[Neovim / CLI] -->|git push| G
+ D[Decap CMS
admin.kontra.lab] -->|OAuth + git commit| G
+ end
+
+ subgraph gitea["Gitea (192.168.20.35 :3001 Docker)"]
+ G[(sam/kontra-content
markdown origin of truth)]
+ end
+
+ subgraph prod["Kontra container (192.168.20.13 :8600 Docker)"]
+ P[git pull loop
every 30s] -->|restart on change| B
+ B[Go binary
templ + htmx + Goldmark]
+ B --> MD[(Markdown render
front-matter + shortcodes)]
+ end
+
+ subgraph media["Media (Garage S3 on .13)"]
+ S3[(Garage S3
kontra-day bucket)]
+ end
+
+ G -->|"SSH git"| P
+ B -->|"shortcode: media"| S3
+ B -->|"emits HTML"| CB[Caddy master
.35 :80/:443]
+ CB -->|"reverse_proxy :8600"| B
+
+ subgraph net["Network"]
+ CB -->|https| WWW[kontra.lab.audasmedia.com.au]
+ CB -->|https| ADM[admin.kontra.lab.audasmedia.com.au]
+ end
+
+ WWW -->|browser| B
+ ADM -->|browser| D
+```
+
+**Interactive version:** [maps.lab](https://maps.lab.audasmedia.com.au/kontra_day/docs/kontra-architecture-map.html) Β·
+Rendered PNG: `docs/diagrams/kontra-architecture.png` Β· Mermaid source: `docs/kontra-architecture.mmd`
+
+## How to use it
+
+### As an editor
+1. Open **https://admin.kontra.lab.audasmedia.com.au/web/admin/** β **Login with Gitea** (needs push access to `sam/kontra-content`).
+2. **Articles** collection: create/edit, set subject/kicker/excerpt/featured, write Markdown body, Save. Wait ~30 s β the site updates.
+
+Or edit files directly: Obsidian vault (`/home/sam/obsidian/kontra_content`) or clone
+`ssh://git@gitea.lab.audasmedia.com.au:2222/sam/kontra-content.git`, edit, push.
+
+### Content model
+```
+content/
+βββ config/site.yaml # site name, tagline, nav order
+βββ subjects//
+β βββ _subject.yaml # name, template, accent color
+β βββ .md # article
+βββ pages/.md
+```
+Template resolution: page front-matter β subject `_subject.yaml` β site config β fallback.
+Media: `{{media:file.jpg}}` (Garage S3), `{{embed:vimeo:ID}}`.
+
+### As an operator
+- Restart/redeploy: `ssh sam@192.168.20.13` β `cd /home/sam/Docker/Containers/kontra && docker compose up -d --build`
+- Pull loop: `entrypoint.sh` in the container (git pull every 30s, restart on change).
+- Logs: `docker logs -f kontra`
+- Content: `/var/www/kontra_day/content` on .13 (rw mount into container).
+
+## Tools used
+
+| Tool | Role | Where |
+|---|---|---|
+| Go (golang) 1.26 | App language β one static binary | `app/` |
+| templ v0.3 | HTML templates compile-to-Go | `app/src/*.templ` |
+| htmx | Server-rendered interactivity | templates |
+| goldmark | CommonMark renderer | `app/src/content.go` |
+| goccy/go-yaml | Front-matter/config parsing | `app/src/content.go` |
+| Decap CMS | Browser admin | `app/src/web/admin/` |
+| Gitea | Git origin (both repos) | .35 Docker :3001 |
+| Garage S3 | Media (`kontra-day` bucket) | .13 Docker :3900 |
+| Caddy | TLS + routing | .35 :80/:443 |
+| Docker / compose | Runtime container | .13 |
+| Design tokens (CSS vars) | Theming from `DESIGN.md` | `app/src/web/assets/kontra.css` |
+| Mermaid + Archify | Docs + interactive map | `docs/` |
+| Obsidian Git | Vault auto-push | .27 |
+
+## Where things are
+
+| Thing | Location |
+|---|---|
+| App source + deploy + docs | `/home/sam/home_network/web_sites/kontra_day/` (.27) |
+| Public repo | `https://gitea.lab.audasmedia.com.au/sam/kontra` |
+| Content repo (origin) | `https://gitea.lab.audasmedia.com.au/sam/kontra-content` |
+| Production content clone | `.13:/var/www/kontra_day/content` |
+| Docker project | `.13:/home/sam/Docker/Containers/kontra/` |
+| Obsidian vault | `/home/sam/obsidian/kontra_content` |
+| Interactive map | `https://maps.lab.audasmedia.com.au/kontra_day/docs/` |
+| Plan/decisions | `PLAN.md` |
+| Design system | `DESIGN.md` |
+
+## Configs for the future (handover notes)
+
+### Networking
+- Master Caddy (.35, `/Docker/Containers/caddy/Caddyfile`) β both `kontra.labβ¦` and `admin.kontraβ¦` β `reverse_proxy 192.168.20.13:8600`.
+- .13 Caddy config is back to pre-Kontra. **Kontra runs in Docker β do not re-add to configuration.nix** (NixOS system units are Nix-store-managed).
+
+### Gitea / OAuth
+- OAuth app `decap-kontra` (non-confidential / PKCE) in Gitea β Settings β Applications.
+- Gitea CORS enabled for the admin origin (`GITEA__cors__*` in `/Docker/Containers/gitea/docker-compose.yml`).
+- Decap `config.yml`: `backend: name: gitea`, simple workflow (no editorial workflow PRs β Gitea backend limitation).
+
+### Secrets
+- Gitea deploy token + API base: `.env` at repo root (.27), **gitignored, never commit**. chmod 600.
+
+### Deploy specifics
+- Docker image builds Go+templ in-image; runner is slim. Port 8600.
+- Container mounts content (rw) + `/home/sam/.ssh/id_ed25519` (ro) for the pull.
+- Pull loop uses `exec` so the server PID is always direct (prior nested-subshell bug caused "address already in use" on restart β fixed).
+
+### Known-good state (verified 2026-09-09)
+- Add/delete content β live in ~30 s. Clean restarts.
+- Front page, `/articles/`, `/subjects/` all 200.
+- Admin renders Decap login; "Login with Gitea" OAuth flow works.
+
+---
+
+*Portfolio/showcase: https://gitea.lab.audasmedia.com.au/sam/kontra (public) β README includes the interactive map, stack, and deploy story. Map: https://maps.lab.audasmedia.com.au/kontra_day/docs/kontra-architecture-map.html*
\ No newline at end of file