← FILE // BLOG.AGIFTOFFLAME.COM
ENTRY // 2026-05-25READ // 5 MIN#devlog#homelab#linux#incus#fastapi#pwa#typescript#nextjs

Weekly work log: 2026-05-18 → 2026-05-25

This past week was one of those weeks where you look back on Sunday and think: did I actually do all that? The answer is apparently yes.

Quick rundown.


Project 1 — Larvitar migration

The old setup was Proxmox + TrueNAS running on repurposed hardware. That's gone now. The new primary lab machine is a desktop running Debian trixie bare metal, and I am not looking back.

The RTX 5070 caused the first headache: it requires the open kernel module (nvidia-open). Fine in principle, except Secure Boot was not having it. Had to go through the full mokutil flow — generate a Machine Owner Key, enroll it via the MOK boot prompt on reboot, and let the system trust the unsigned driver. One of those things that is obvious in hindsight and completely opaque when you first hit it.

Incus replaced the old Proxmox/LXC stack. It's lighter and the CLI is pleasant. Services are migrated, running, and behaving themselves.

Jellyfin came back online with hardware acceleration via NVENC. The RTX 5070 handles transcoding with essentially no effort, which is a satisfying upgrade.

The new host is larvitar. The router (sage) needed nftables rule updates, SSH config touched across every machine I work from, and Pi-hole DNS entries so larvitar resolves cleanly on the network. Migration complete.


Project 2 — Kindred infrastructure hardening

Kindred is a personal project — FastAPI + PostgreSQL + Redis + nginx, running on my own hardware. It entered maintenance mode this week, meaning: no new features, infrastructure made solid, left running.

Two meaningful things happened to it this week.

First: the PostgreSQL data directory is now on a dedicated NVMe, mounted bare metal (not containerized). This is a deliberate performance choice — no container overhead on the database path.

Second: Cloudflare Turnstile is now wired into the registration flow. Backend validation + frontend widget. The interesting part was the CSP surgery in nginx.conf — I needed to allow challenges.cloudflare.com as both a script source and a frame source without blowing up the existing directives. Careful, incremental changes. It's working.

Encrypted at rest, tiered backups in place.

One thing that did not happen: an event delegation rewrite in app.js that I had in progress. Got eaten by a git stash. It's on the list; it's not broken, just an unfinished refactor sitting there staring at me.


Project 3 — Rijbewijs Vrij

rijbewijs-vrij is a free, open-source Belgian Category B theory exam prep app. Vanilla JS + HTML/CSS, no account, no ads. I put 12 commits into it this week.

Theme + i18n landed first: light/dark/auto theme switcher, language dropdown, all UI strings extracted into a typed ui.ts. French and German button labels were broken — fixed.

Wegcode reader: a full Belgian Highway Code reader with article deep-linking, so you can navigate to any specific article by URL. Mobile had a header overflow issue (two-row wrapping) that took some careful layout work to kill. Text contrast and traversal navigation in the reader also got cleaned up.

Quiz expansion: configurable question count, question set grown to 154 questions, road sign images shown inline in practice tests. More data fixes followed: the SPD-003 rule applies to Wallonia/Brussels, not Flanders — that was wrong. Amendment footnote blocks were leaking into the Wegcode parser output and had to be stripped. Multi-image support added per question.

The last commit of the week was probably my favourite: legal references in practice test results now link directly to the relevant Wegcode article. Small affordance, big usability win.


Project 4 — the-bestest-number-system-converter

Built this one from scratch in a single day (2026-05-22). TypeScript + Vite, no framework.

It converts between Binary, Octal, Decimal, Hex, Base32, Base64, Base64url, and plain Text (UTF-8). All outputs update simultaneously on input. Prefix auto-strip (0b / 0o / 0x). Bit/byte length display. Copy-to-clipboard on every output card. Dark/light theme. Mental Tricks page with hand-conversion techniques for every base pair.

Full EN/NL translation the same day. The interesting part: the converter was originally throwing raw English strings as errors. To localize error messages properly I had to refactor it to throw a typed ConvertError instead, then catch and translate at the display layer.

The code review pass was also the same day. Highlights: re-throwing non-ConvertError errors instead of swallowing them silently, currentLang unexported so a getLang() getter was added, info bar labels wrapped in named spans instead of brittle childNodes[0] indexing, and the options loop inverted to iterate BASES and query by value. The kind of review pass that leaves the code visibly cleaner.


Project 5 — agiftofflame.com

The personal site. Built from scratch on 2026-05-24. Next.js 16, React 19, Tailwind v4, TypeScript.

Post-industrial / brutalist aesthetic: monospace masthead, stencil labels, hard rules, grid overlay. CSS custom properties as design tokens (--canvas, --ink, --flag, and friends). Manual light/dark/system theme switcher implemented via localStorage + useSyncExternalStore.

Build-time GitHub API fetch pulls featured public repos (rijbewijs-vrij, the-bestest-number-system-converter, antigravity-rpc) and renders them as project cards. Kindred gets a CLASSIFIED WIP card because it's private and I thought that was funny.

CI/CD: GitHub Actions builds the Next.js standalone output, rsyncs it to the VPS, restarts agiftofflame.service, and smoke-tests http://127.0.0.1:3000/. GITHUB_SHA is injected at build time and displayed in the header/footer as a rev indicator.


Project 6 — blog.agiftofflame.com

This blog. Hi.

Scaffolded from create-next-app on 2026-05-24 and immediately ported the design system from agiftofflame.com. @next/mdx with remark-frontmatter, remark-gfm, and rehype-pretty-code for syntax-highlighted MDX posts. Blog index, dynamic post route, RSS feed, sitemap, robots. Filesystem-based post loader in src/lib/posts.ts reads MDX frontmatter.

Seeded with three archive posts migrated from the old Hugo blog. Deploys to the same VPS on port 3001 via the same rsync + service restart + smoke test pipeline.

You are reading a post on it right now. I am choosing to view this as proof of concept.


Meta

VDAB course started 2026-05-18 — professional sysadmin certification track. The week leading up to it was spent closing open infrastructure loops and deciding what to work on during the course. Kindred moving to maintenance mode was part of that: it's stable, it's running, I don't want to be mid-feature when my attention is needed elsewhere.

Everything is self-hosted. VPS, bare-metal desktop, Pi-hole DNS, the whole stack. I don't trust clouds with my data and I can't afford to trust clouds with my uptime.


Solid week. Tired. Here's Bocchi.

Bocchi