abualruz-homelab: the site and the infra that runs it
Astro 6 + Svelte 5 personal site served from a homelab mirror via Caddy and Docker, built phase by phase with a published agent playbook.
This is the meta-project: the site you’re reading this on, the homelab infrastructure that mirrors it, and the agent playbook that built both. It’s also, in a very literal sense, an ongoing experiment in whether you can ship a production-quality personal site using AI coding agents as your primary labor force and not end up with a codebase you’re ashamed of.
The answer, so far, is yes — with significant asterisks.
Why it exists
Two reasons. The first is boring: I needed a personal site. I’ve been meaning to have one for years, and “meaning to” is the graveyard where side projects go to haunt you. The second is more interesting: I wanted a real project — not a toy, not a tutorial, not a “hello world with a deploy button” — to stress-test the agent-assisted development workflow I’d been building with Fulcrum.
A personal site is perfect for this. The requirements are real. The design decisions matter. There’s actual content to write, actual performance budgets to meet, actual CSP headers to get wrong in embarrassing ways and then fix. But the blast radius of mistakes is entirely mine, which means I can move faster and fail more visibly than I could on a client engagement.
Every Phase ships with a progress log and a lessons doc. This isn’t documentation theater — those docs are inputs to the next agent run. The Chief-of-Staff reads the lessons doc before dispatching work on Phase N+1. The discipline of writing them down is the discipline of making the next phase faster.
How it works
The site is Astro 6 with Svelte 5 for interactive islands. Astro does what it’s supposed to do: near-zero JavaScript for static pages, selective hydration for the bits that need it. Svelte 5’s runes model is genuinely good — the reactive primitives are cleaner than React hooks for the kind of small, focused interactivity a personal site needs.
Content is MDX files in a structured collection schema validated by Zod at build time. Topics are an enum (defined once in src/data/topics.ts, consumed by both the schema and the hub pages), so a typo in a frontmatter field fails the build loudly instead of silently producing a 404. I’ve come to love build-time schema validation for content sites. The feedback loop is fast and the errors are specific.
The homelab mirror runs on a single box on my home network behind a Caddy reverse proxy. Docker Compose manages the services; Caddy handles TLS termination and the site’s static file serving. The content security policy lives in a _headers file served with the static assets — Caddy passes them through unchanged, which is the right division of responsibility.
Deployment is a GitHub Actions workflow that builds the Astro site, pushes the output to the server, and restarts the Docker service. It’s not fancy. It doesn’t need to be. The deploy pipeline that makes you feel clever is usually the one that breaks at 11pm when you’re trying to ship a fix.
What’s interesting
The phase-based shipping model was not part of the original plan. It emerged from the first agent run, which produced a Phase 0 that was more coherent than anything I’d have designed up front — a minimal viable site with a content schema, a working build, and a deploy pipeline — and a follow-up doc that listed the things that needed to happen next. That structure turned out to be load-bearing.
The interesting property of “every phase has a lessons doc” is that it forces you to articulate what you learned before you’ve completely forgotten the context. That sounds obvious, but in practice most project retrospectives happen three weeks after the work is done, when the specifics have faded and you’re producing generalities. Writing the lessons doc the same day the phase ships produces much more specific observations. “The CSP unsafe-inline stopgap needs to be resolved before Astro’s meta CSP approach is stable enough to use” is a useful note. “CSP is complicated” is not.
The Svelte 5 + Astro combination also forced me to think carefully about what needed to be interactive and what didn’t. The default assumption in modern web development is that everything is interactive; Astro inverts that, and working within that constraint produced a site that’s faster than it would have been if I’d reached for a SPA framework.
What I’d change
The homelab mirror is on a single machine with no failover. That’s a deliberate choice — complexity you don’t need is complexity that will bite you — but it also means the site goes down when I do hardware maintenance, which happens more often than I’d like to admit. A second machine in active-passive failover with Caddy as the front door is on the list for a future phase.
The CSP story is still a work in progress. The current _headers file uses unsafe-inline as a stopgap while Astro’s native meta-tag CSP approach matures. That’s a known debt item, tracked, and it’ll ship when the upstream situation is stable enough to depend on.
The thing I’m most interested in for future phases: using the site itself as the output surface for the agent workflow. Right now, the progress logs and lessons docs live in markdown files that I read. What I want is a structured agent memory layer — Fulcrum, obviously — that ingests those docs as L0 sources and surfaces the curated lessons automatically when the COS is planning the next phase. The infra is already there. I just have to wire it up properly.
That’s the real meta-project: building the tools, then using the tools to build the project, then feeding the project’s lessons back into the tools. The loop is starting to close.