Part 56: Conclusion and Roadmap
"The compiler does not sleep. The wiki does. So we make the wiki the compiler."
What we built
Fifty-five parts. Fifty-six counting this one. One typed, plugin-driven, six-stage-pipeline meta-orchestrator for local infrastructure, designed in public, built on the FrenchExDev toolbelt, consuming Ops.Dsl as its substrate, eating its own dog food, and shipping in three topologies that share the same compose contributors.
The recap, in one paragraph per Act:
Act I — The Problem & The Shape (parts 01–06): every developer who has ever wanted a homelab has rebuilt the same fragile pile of YAML, HCL, bash, and wiki pages. The drift is the disease. CLI-first is the cure, because CLI-first is testable-first. The CLI is thin; the lib is fat. The YAML the user edits is schema-validated against C# [Builder] types. Local overrides layer on top of a committed base via deep-merge. And there is no fictional demo project — the thing HomeLab stands up is the real GitLab + runners + box registry + NuGet feed + docs site that the FrenchExDev team uses to develop HomeLab itself.
Act II — The Lib Architecture (parts 07–14): the pipeline has six stages (Validate, Resolve, Plan, Generate, Apply, Verify) and one Result<T> discipline. SOLID and DRY are enforced by architecture tests, not folklore. The event bus is built on FrenchExDev.Net.Reactive. The plugin system is IHomeLabPlugin plus role-shaped contributors. The composition root is generated by the [Injectable] source generator. Ops.Dsl is the M3-backed substrate with eight sub-DSLs that HomeLab consumes. The test pyramid has four surfaces (architecture, unit, integration, CLI E2E) at four speeds, with a 60-second budget for the fast suite.
Act III — Talking to the Tools (parts 15–24): every external binary HomeLab depends on (Docker, Docker Compose, Podman, Podman Compose, Packer JSON, Packer HCL2, the Vagrantfile, the Vos data YAML, Traefik, GitLab) is wrapped by a typed source-generated client built on [BinaryWrapper]. Exit codes become Result<T>. Drifts in upstream CLI surfaces become compile errors.
Act IV — Building Docker / Podman Host VMs (parts 25–30): the Alpine base image, the Docker host overlay, the Podman host overlay, optional hardening, the Vagrant box registry, and the topology composition picker. By the end, homelab vos up boots VMs with the right OS, the right container engine, the right security posture, and the right place in the topology.
Act V — Speaking Compose & Traefik for DevLab (parts 31–35): the per-VM compose files generated by IComposeFileContributors, the contributor pattern that enforces no-conflicts at unit-test speed, the Traefik routing with shared middlewares and the GitLab /admin lockdown, the TLS init/install/trust trio, and the DNS hosts-vs-PiHole choice.
Act VI — Standing Up DevLab (parts 36–42): the bootstrap paradox solved by a 200-line bash script that runs once per machine; the eight-command DevLab bring-up sequence for both single-VM and multi-VM topologies; Postgres + MinIO with tuning computed from VM RAM and a six-bucket layout; GitLab in three flavors (single-VM, multi-VM, HA Reference Architecture without Kubernetes); and the four dogfood loops that close inside DevLab itself — the box registry, the NuGet feed, the docs site, and (Loop #5) this very blog.
Act VII — Operational Depth (parts 43–48): secrets store with five providers (file, age, sops, Vault, Bitwarden); observability stack with Ops.Observability declarations generating Prometheus / Grafana / Loki / Alertmanager configs automatically; backup framework with three providers (restic, pgbackrest, mc mirror) and a restore-test job that proves the dogfood loop; multi-host scheduling for N VMs across M physical machines; cost tracking with per-VM resource accounting; and GPU passthrough for the supported subset of hypervisors.
Act VIII — Day-2, Variants, Stress Tests (parts 49–52): ten day-2 verbs covering 80% of operational needs; the Podman variant with rootful and rootless modes; multi-instance side-by-side support with deterministic subnet allocation; and the clean teardown verb that respects multi-instance isolation.
Act IX — Writing Plugins (parts 53–54): an end-to-end Cloudflare DNS provider plugin in ~210 lines, and an Ops.HomeRouter sub-DSL plugin that adds four new MetaConcepts to the shared metamodel registry without forking HomeLab core.
Act X — What's Still Missing & What's Next (parts 55–56): the honest catalog of deferred items (ARM hosts, Windows containers, mTLS service mesh, federated multi-site, IaC drift detection, HA GitLab on K8s, multi-tenant RBAC, encrypted backup key rotation, cost-aware scheduling, web UI), and this conclusion.
The five-phase implementation plan
The plan comes from HomeLab/doc/PLAN.md and has not changed:
Phase 1: Foundation — IComposeFileContributor (the gap in DockerCompose.Bundle); Traefik.DockerCompose project. Parallel.
Phase 2: HomeLab core — GitLab.DockerCompose; the HomeLab lib (config, pipeline, schema generation); the HomeLab.Cli surface; unit tests for artifact generation, config builder, YAML round-trip, schema validation. Sequential within the phase.
Phase 3: Tool wrappers — FrenchExDev.Net.Git (BinaryWrapper); FrenchExDev.Net.EtcHosts (cross-platform hosts file); FrenchExDev.Net.Tls (ITlsCertificateProvider with native + mkcert providers). Parallel.
Phase 4: API clients + Registry — Vagrant.Registry, GitLab.Api.Bundle, PiHole.Api.Bundle. Parallel.
Phase 5: Full E2E — every CLI command runs end to end against a real VirtualBox + Docker + GitLab + runner setup, and the dogfood loop closes. The slow nightly test from Part 06 is the gate.
The phases are roughly the order in which the acts of this series should be implemented. Acts I–II are the design background; Act III is Phase 3; Act IV is Phase 1 + Phase 2 (the host overlays plus the contributor pattern); Acts V–VI are Phase 2 finishing; Acts VII–VIII are Phase 5 (the operational depth that completes the v1); and Act IX is what users do after v1 ships.
The 10-step pipeline as the spec
The pipeline that DevLab follows from homelab init to a fully working lab is:
0. homelab init ← bootstrap project
1. homelab packer init && homelab packer build ← build the box
2. homelab box add --local ← register the box
3. homelab vos init && homelab vos up ← boot the VMs
4. homelab dns add ... ← DNS entries
5. homelab tls init && tls install && tls trust ← cert + trust
6. homelab compose init && compose deploy ← service stacks
7. homelab gitlab configure ← GitLab post-install
8. homelab gitlab runner register ← runner registration
9. homelab verify ← health probes0. homelab init ← bootstrap project
1. homelab packer init && homelab packer build ← build the box
2. homelab box add --local ← register the box
3. homelab vos init && homelab vos up ← boot the VMs
4. homelab dns add ... ← DNS entries
5. homelab tls init && tls install && tls trust ← cert + trust
6. homelab compose init && compose deploy ← service stacks
7. homelab gitlab configure ← GitLab post-install
8. homelab gitlab runner register ← runner registration
9. homelab verify ← health probesTen steps. Eight verbs (some grouped). Same on every workstation. Same in CI. Same in single-VM, multi-VM, and HA topologies. The E2E test is exactly this sequence with assertions between each step.
This is the spec. If HomeLab ever stops being able to run these ten steps end to end, it has regressed past the line of being useful.
Where this fits in the larger ecosystem
This series is one piece of a larger story:
- Ops DSL Ecosystem — the substrate. Twenty-two sub-DSLs, three execution tiers, the M3 metamodel, the typed verbs of operations. HomeLab consumes the eight that matter for a local lab; the other fourteen apply to cloud, scale, compliance, and concerns HomeLab does not address.
- Typed Docker — the binary wrapper precedent. HomeLab's Docker, Podman, Packer, Vagrant, Git, mkcert wrappers all follow this pattern.
- GitLab Docker Compose — the typed compose service definition pattern that
GitLabComposeContributorbuilds on. - Wrapping Docker and Wrapping Traefik — the predecessor experiments that proved the binary-wrapper approach.
- Injectable DDD — the source generator that emits HomeLab's composition root.
- The Loop — the
dotnet quality-gate testdev-loop that HomeLab ships under. - This Website, Static — the static-site builder that produces this blog, which (in the dogfood loop) is hosted by DevLab.
- Feature Tracking — the
Requirementslibrary that traces HomeLab features from acceptance criteria to implementation to test.
If you have read this series and want to follow up, the natural next reads are the Ops DSL Ecosystem (for the substrate) and the Typed Docker series (for the binary wrapper deep dive).
The call to action
Three things you can do after reading this series:
1. Read HomeLab/doc/PLAN.md and start Phase 1
The spec is real. The phases are real. Phase 1 — IComposeFileContributor plus Traefik.DockerCompose — is the smallest possible step that produces a useful artifact. It can be implemented in a weekend by anyone who understands the contributor pattern.
2. Ship a plugin
Part 53 showed an afternoon-sized plugin (Cloudflare DNS). Pick a need your team has, write the plugin, publish to your own baget, and use it in your own DevLab. The plugin SDK exists. The pattern is documented. The architecture welcomes you.
3. Steal the patterns
Even if you never run HomeLab, the patterns in this series are reusable in any tool you build:
- The thin-CLI / fat-lib architecture
- The six-stage pipeline with
Result<T> - The contributor pattern with idempotent shared infrastructure
- The architecture tests that enforce SOLID at unit-test speed
- The typed binary wrapper via
[BinaryWrapper] - The
[Injectable]composition root - The event bus as a first-class observability surface
- The dogfood pivot — make the demo the real thing
These are not HomeLab-specific. They are patterns for building any non-trivial tool in C#. HomeLab is one application. There are many more.
A final thought on the dogfood loop
The thing I keep coming back to, after writing fifty-six parts, is the dogfood loop. The loop is not a technical decision. It is a commitment. It says: the tool I build is the tool I run. The bug I do not fix is the bug I have to live with. The feature I add is the feature I get to use. There is no audience. There is no demo. There is only the system, and the system is mine.
Every "build a homelab" series I have ever read fails the dogfood test. The author writes a thousand lines about a fictional project, ships the post, and never runs the homelab they described. The post is forgotten in six months. The blog gets a redesign and the tutorial breaks.
This series is different because DevLab is mine. I am writing this part inside the docs site that DevLab serves. I will commit it to the GitLab that DevLab hosts. The runner inside DevLab will rebuild the docs site. The new HTML will land in MinIO. Traefik will serve it. You will read it. None of those steps involve any system other than HomeLab. The series, by the very act of existing, proves itself.
That is the whole bet. Make the demo the real thing. Everything else in this series — the architecture, the SOLID rules, the event bus, the plugin system, the eight Ops.Dsl sub-DSLs, the four test surfaces, the topologies, the dogfood loops — all of it is in service of making the demo the real thing, and making the real thing reliable enough that you would actually trust it with your own work.
If you take one thing from this series, take that.
Cross-links
- Part 01: The Problem — where we started
- Part 06: The Dogfood Target — the central pivot
- Part 30: Topology Composition — single, multi, HA
- Part 37: Bringing DevLab Up — the eight commands
- Part 55: What's Still Missing — the honest catalog
- Ops DSL Ecosystem — the substrate
- Typed Docker — the wrapper precedent
- GitLab Docker Compose — the compose service precedent
- The Loop — the dev-loop that ships under
Thank you for reading. Now go build something.