Problem: node and cross-cutting narratives lived at the repo root
(containers/, vms/, infrastructure/, host .md files), interleaved with the
machine-readable substrate.
Change:
- Move containers/ -> knowledge/wiki/containers/, vms/ -> knowledge/wiki/vms/,
infrastructure/ -> knowledge/wiki/infrastructure/, hosts/{hubris,strong}.md ->
knowledge/wiki/hosts/, infrastructure/references/ -> knowledge/sources/references/,
GLOSSARY.md -> knowledge/GLOSSARY.md.
- Add knowledge/{index.md,log.md,sources/index.md} scaffolding.
- Rewrite all relative links repo-wide via a path-resolving mapper (inbound +
outbound + between-moved-files), including .hermes/, runbooks, operations,
investigations, plans, README, AGENTS.
- Repoint inventory.yaml doc_page fields and regenerate hosts/*.yaml (which
embed doc_page); update oikos/gen-topology.py output path, candidate doc
paths, and footer links; update code-comment doc paths.
Substrate untouched in place: inventory.yaml, hosts/*.yaml (regenerated,
idempotent), oikos/ code, mcp/, secrets/, bin/.
Verification:
- Logical broken-link set identical to pre-move baseline (net 128 -> 127; the
topology regen fixed one, introduced none). Remaining are pre-existing refs
to destroyed/archived nodes, out of scope for this move.
- gen-topology.py --check exit 0 (in sync); cards carry knowledge/wiki/ doc paths.
- build_host_files.py idempotent; all inventory doc_page targets resolve.
- MCP contract verified: get_page/search_docs/get_changelog resolve moved pages.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.4 KiB
128 — trmnl
Self-hosted middleware for TRMNL e-ink plugins. TRMNL cloud polls it; it fetches/shapes live data into JSON the plugin's Liquid template renders.
At a glance
- Hostname:
trmnl - IP:
192.168.8.211 - Privilege: unprivileged
- Resources: 1 core / 768 MiB RAM / 8 GiB rootfs (Debian 13)
- Mounts: none
- Public hostname:
trmnl.hubris.network(via VPS ingress)
Role
Runs one FastAPI aggregator (server.app:app, port 9851) that mounts a router per plugin from the dtoro/terminalito repo. First consumer: munich-home (/munich-home/dashboard) — weather (Open-Meteo), MVG transit, Google Calendar, plus server-side Kita/quote logic. Talks out to the public internet for those APIs; TRMNL cloud polls it inbound every 15 min. Bearer-token gated (TRMNL_POLL_TOKEN); /health is open.
Service / port map
| Service | Listen | Notes |
|---|---|---|
trmnl-plugins |
0.0.0.0:9851 |
uvicorn aggregator; EnvironmentFile=/etc/trmnl-plugins/env |
Storage / config paths
/opt/terminalito— git checkout (origin = internal giteahttp://192.168.8.121:3000/dtoro/terminalito.git)/opt/terminalito/server/.venv— venv/etc/trmnl-plugins/env—TRMNL_POLL_TOKEN(+ Google/MVG creds once enrolled)/etc/systemd/system/trmnl-plugins.service
Auto-deploy
Wired — auto-deploy Shape B, webhook id 12 on dtoro/terminalito → http://192.168.8.211:9797/deploy (terminalito-deploy.service). Push to main → server/deploy/deploy.sh (git pull + pip + reinstall units + restart trmnl-plugins). Secret /etc/terminalito-deploy/secret; git creds /etc/terminalito-deploy/git-credentials wired as a repo-local credential.helper. Manual: pct exec 128 -- /opt/terminalito/server/deploy/deploy.sh.
Secrets
Not yet SOPS-enrolled. The poll token is set directly in /etc/trmnl-plugins/env. Google Calendar + MVG creds are pending: enroll via homelab client add trmnl + bootstrap, add secrets/trmnl-oauth.yaml, then server/deploy/render-env.sh builds the env from homelab secret trmnl-oauth. Until then calendar/transit cards degrade to empty; weather works.
Related
- Caddy (121) — LAN reverse proxy (
trmnl.hubris.network → 192.168.8.211:9851) - VPS ingress — public edge (cert mirror + traefik router)
- DNS (107) — Technitium A record
trmnl → 192.168.8.175(LAN path via Caddy) - Gitea (104) — source repo
dtoro/terminalito - Plan: 2026-06-24 TRMNL plugins LXC
Changelog
2026-06-24 — auto-deploy + LAN DNS wired
Gitea Shape-B deploy pipeline (webhook id 12, :9797) — push to dtoro/terminalito redeploys; verified end-to-end. Technitium A record trmnl.hubris.network → 192.168.8.175 added on dns (107) (propagated to the NetBird managed zone via dns-sync), so LAN clients take the short path through Caddy (121). See auto-deploy.
2026-06-24 — public path live
Verified end-to-end from the internet: https://trmnl.hubris.network/munich-home/dashboard → 200 with token, 401 without; /health 200. The provision-time outage was the netbird home-lab-network (192.168.8.0/24) route having no active routing peer — the mac-mini routing peer's netbird daemon was down (artifacto/blog were 504 too). Bringing netbird up on mac-mini restored the route; the edge recovered with no config change. See ingress / mesh.
2026-06-24 — provisioned
LXC 128 created (Debian 13, unprivileged, 192.168.8.211). Deployed trmnl-plugins.service on :9851 from dtoro/terminalito. Caddy block added (dtoro/caddy-conf) + LE cert via IONOS DNS-01; verified /health 200 and /munich-home/dashboard (live weather) through Caddy. Cert mirrored to VPS (trmnl.fullchain.crt/trmnl.privkey.key) + traefik router trmnl-public → 192.168.8.211:9851 added to /opt/traefik-dynamic.yaml. Public path pending: VPS↔home netbird route was down at provision time (No networks available, 3/6 peers — artifacto/blog also 504); resolves when the mesh route recovers. LAN pending: Technitium A record not yet added. Not SOPS-enrolled; Google/MVG creds pending.