# Le Daily Squirrel — Project Status **Date:** 2026-07-04 **Repo:** `AutomationWise/leDailySquirrel` on Forgejo (`gf.automationwise.com`) **Production:** https://news.opelousas.org (Cloudflare Pages, project `news-opelousas-org`) A satirical daily newspaper for Opelousas — vintage faded-newsprint aesthetic, edition-based publishing, self-hosted GitOps pipeline, with AI journalist agents planned as the content authors. --- ## Architecture | Piece | Where | Notes | |---|---|---| | Git forge (Forgejo 9) | `kiln` (Fedora), rootless Podman Quadlet | HTTP `127.0.0.1:3000` behind Caddy at `gf.automationwise.com`; SSH on host port `3022` (LAN only, blocked at edge) | | Reverse proxy | Caddy on `kiln` | Owns 80/443, auto TLS; also fronts Vaultwarden and Tuwunel | | CI runner | `kiln`, Podman Quadlet (`forgejo-runner` 3.4.1) | Org-level runner `kiln-worker`, label `ubuntu-latest:docker://node:20-bookworm`, uses host Podman socket (`UserNS=keep-id`, `SecurityLabelDisable=true`, socket path identical inside/outside container) | | Static site generator | Eleventy v3.1.6 | Input `content/`, includes `../_includes`, output `dist/` | | Hosting | Cloudflare Pages, Direct Upload mode | Deployed via `wrangler pages deploy dist --project-name=news-opelousas-org --branch main` from `.forgejo/workflows/deploy.yml` on push to `main` | | Dev box | `anvil` | Git remote over SSH: `ssh://git@gf.automationwise.com:3022/...` with `~/.ssh/config` host override to kiln's LAN IP (NAT hairpin workaround) | **Secrets:** `CF_ACCOUNT_ID` + `CF_API_TOKEN` in Forgejo repo Actions secrets. Token permissions: Account→Cloudflare Pages→Edit, Account→Workers Scripts→Edit, User→User Details→Read, scoped to the account. ## Site mechanics - **Editions** live at `content/editions/YYYY-MM-DD/index.md`; URLs are `/editions/YYYY-MM-DD/`. - **Front matter:** `layout: edition`, `edition_number` (int), `volume` (int — must be a number, the `roman` filter converts; storing "I" breaks it), `date`, `status: draft|published`, `title`. - **Collections** (`eleventy.config.js`): `publishedEditions` (all published, newest first), `currentEdition` (newest one only). - **Homepage** (`content/index.njk`): paginates over `currentEdition` (size 1) and renders it at `/` — render, not redirect. `content/index.11tydata.js` maps `title`, `date`, `edition_number`, `volume` up from the paginated item. - **Filters:** `newsDate` (UTC-forced long date — fixes the CST off-by-one-day), `roman` (int → Roman numeral). - **404:** `content/404.md` → `dist/404.html`. Required — without it Cloudflare Pages SPA-fallbacks every unknown path to `/` with a 200 (this was the "every URL shows the current edition" bug). Todo → more Squirreliness. - **Masthead:** inline SVG (Inkscape export, single path, mm-scale coordinates, `viewBox="0 0 381 170"`). Fill flows from `fill="var(--ink)"` on the `` (path's inline `fill` style removed). CSS `squirrel-flip` animation rotates it 180° on a 50/50 duty cycle (~24s period), with a `prefers-reduced-motion` opt-out. - **Lifecycle tooling:** `make publication` (scaffolds next edition, enforces one open draft, creates `edition//open` branch), `make publish` (seds `status: draft` → `published`), `make build` / `make serve`. ## Hard-won gotchas (do not relearn these) - Quadlet units can't be `systemctl enable`d — the `[Install]` block in the `.container` file handles boot; just `daemon-reload` + `start`. Lingering is enabled for the user on kiln. - Rootless Podman + SELinux: never `:Z` a socket mount; socket path must match host↔container when the runner asks the host to mount it into job containers. - Wrangler CI deploys need `--branch main` or they land as Preview, not Production. - Eleventy config must be a **single** `module.exports`; run builds from repo root only. - Front matter beats directory data files (`editions.json`) — data bugs hide there. ## Current status **Working end-to-end:** push to `main` → runner builds → Cloudflare production deploy. Volume renders as Roman numerals, archive URLs serve the correct historical edition, fake URLs 404, custom domain live, SVG masthead in place with periodic flip. **In development / not yet done:** 1. **Edition immutability (freeze-at-publish)** — designed, not implemented. Plan: `make publish` builds once, snapshots rendered HTML to committed `frozen/editions//`, marks source `frozen: true`; `editions.11tydata.js` returns `permalink: false` for frozen editions; `addPassthroughCopy({ "frozen/editions": "editions" })` serves snapshots verbatim. Homepage stays dynamic; only `/editions//` freezes. Past editions from the pre-freeze era are expendable (still in dev). 2. **Archive ledger** — no `/archive/` (or `/editions/`) index page listing past editions yet. 3. **AI journalist pipeline** — the actual point of the project. Agents ingest daily material, write articles in the three-column structure, and open PRs against the open `edition//open` draft branch. Likely `imp` (OpenClaw on liminal) via NadirClaw routing, following the spec-first handoff pattern. Not started. 4. **Maintenance-mode toggle** — deferred; plan is a Cloudflare Page Rule redirect to a `/maintenance/` page. 5. **Masthead spacing polish** — minor viewBox/padding nudges deferred. ## Suggested next steps, in order 1. Implement the freeze-at-publish flow while there's only throwaway content to test against (touching `publish.sh`, `eleventy.config.js`, new `content/editions/editions.11tydata.js`). 2. Build the archive index page off `collections.publishedEditions`. 3. Define the agent contract: article markdown format, column assignment, front-matter rules, PR-to-draft-branch workflow — then wire the first agent.