sequin.au: Writing the Lab into Existence
There is a particular kind of home lab project that starts as a footnote.
The network got segmented. That needed documenting. The documentation needed somewhere to live. That place needed to be a real website, not a Confluence instance on the LAN that nobody outside the building can read. And so: a blog. Built with the same methodology as everything else in the lab. Deployed with the same infrastructure. Documented here, as the final entry in its own origin story.
This is that post.
Why Astro
Astro 6 is a static site generator that compiles Markdown to HTML at build time and ships zero JavaScript to the browser by default. For a technical blog that is primarily text and code blocks, this is the correct set of trade-offs. The output is fast, portable, and indexable. The authoring workflow is Markdown files in a content/blog/ directory.
The alternative was a hosted platform. Substack, Ghost, Hashnode. The reason to reject all of them is the same reason the rest of the lab runs on its own infrastructure: control. Custom domain, custom DNS, no third-party analytics, no algorithmic feed, no “we’ve updated our terms” emails. The content lives in a git repository. The blog can be migrated by pointing a new static host at the same build output.
One decision worth noting: the site uses vanilla CSS with custom properties rather than Tailwind or a component library. The reason is duration. CSS custom properties will work in ten years without a toolchain update. Utility class frameworks accumulate technical debt at the pace of their major version releases. A home lab blog does not need a build-time CSS preprocessor.
The Deployment Stack
Firebase Hosting was chosen for one reason: Google’s global CDN is fast, and the free tier is generous for a blog that hasn’t been discovered yet.
The deployment chain:
npm run build # Astro compiles content/ → dist/
firebase deploy --only hosting # dist/ → Firebase CDN
The custom domain points to Firebase via GoDaddy DNS:
- Two A records at the apex (
sequin.au→ Firebase IP addresses) - A TXT record for Firebase domain verification
- A second custom domain entry for
www.sequin.au
Firebase minted the TLS certificate automatically. The certificate minting took about four minutes. The “Site Not Found” error that appeared immediately after DNS propagation was caused by a missing "site" property in firebase.json — the deploy had gone to the default Firebase hosting site, not the one attached to sequin.au. Three lines of config fixed it.
These are the kinds of bugs that exist to teach you exactly how the system works.
The Blog as Infrastructure
The posts in this series are a form of infrastructure documentation — the kind that explains not just what was built, but why decisions were made the way they were and what the outcomes were. This matters for the same reason the lab constitution matters: a system you can’t explain is a system you can’t maintain.
Some of what this series captures:
- Why the network has five VLANs (IoT isolation, blast radius reduction)
- Why Step-CA issues three-year certificates (annual renewals at scale are an operational tax)
- Why LiteLLM runs on GCP rather than locally (the proxy survives local infrastructure failures)
- Why MCP servers use stdio transport (SSE has reliability problems in Docker environments)
- Why LangGraph won over alternatives (state machine routing matches how infrastructure agents actually think)
None of this was written anywhere. It existed in memory and git commit messages. The act of writing these posts surfaced architectural decisions that had been implicit and made them explicit. Two of those decisions, on reflection, could have been made differently. One of them probably should have been.
That’s the value of documentation written after the fact rather than as specification: you already know how it turned out.
The Spec-Driven Development Loop Closes
The blog was built using the same SDD process described in the previous post. The spec named the requirements: Astro 6, Firebase Hosting, vanilla CSS, custom domain, ten-post series covering the lab’s history. The plan named the architecture. The tasks.md listed the implementation steps.
The implementation agent — Claude Code — executed the tasks without embellishment. When the Astro 6 content collection API had changed from the scaffold’s expectations (the content config file moved, post.slug became post.id, render() moved to a named import), the errors were specific and fixable. When Firebase rejected the project display name because it contained a period, the fallback was clear.
The ten posts were researched from memory files, git history, file modification dates, and system documentation. The dates are accurate. The technical details are accurate. The satirical tone is, at minimum, consistent.
What’s Next
The lab is not finished. Labs are definitionally not finished — they are states of ongoing configuration drift, deliberate improvement, and occasional experiments that work better than expected and become permanent fixtures before anyone decides whether they should.
Some things on the backlog:
- The network topology agent (the first real autonomous LangGraph agent — querying Juniper, cross-referencing pfSense, identifying anomalies)
- Monitoring integration (Grafana pointed at the existing data sources)
- Automated GVM scan triage (Clawdia summarising the weekly scan results the same way she summarises nightly network discovery)
- Whatever the next hardware addition turns out to be, which will generate at least two posts about VRAM
The blog will document these as they happen. The methodology is in place. The deployment pipeline is automated. The writing is — demonstrated — possible.
The circle is complete. The loop begins again.
sequin.au is built with Astro 6 and deployed on Firebase Hosting. The source is in a private GitHub repository. The lab it documents runs in Queensland, Australia, on hardware that cost more than it should have and is worth every dollar.