This is the whole thing in one place: a segmented VMware lab behind a pfSense firewall, one identity provider enforcing MFA everywhere, a full metrics-and-logs monitoring stack, and encrypted off-site backups that have actually been restored. It runs on a single gaming PC and it’s built to be operated, not just stood up — so the point of this page isn’t the parts list, it’s how they fit and what happens when one breaks. Since then it has grown a second layer: it watches itself, with a SOC over its own logs and a digital twin that checks the network against what should be there, and it runs AI agents under controls that are enforced in code rather than asked for.
The Lab
Topology at a glance
The map is generated from the same data as the inventory below, so a box here is a component there. Hover for what it runs; click for the post.
The same lab as flows
Want the design underneath it — addressing, trust zones, the firewall policy matrix? See the network design →
How it's actually run
No pretending this is a datacentre. It's a virtual lab on one machine — so here's the real operating model, including what it doesn't do yet.
The machine it all runs on
No rack, no datacentre — every VM in the diagrams above lives on one desktop PC. Here's the hardware underneath, and how much of it the lab is actually given.
What the lab actually gets
Everything on the topology diagram sits inside that one slice. The rest of the box carries Windows and the pfSense VM — which is exactly why the lab is a nightly-shutdown environment and not an always-on one.
The AI plane
AI agents have real access to this lab, and one of them can change it, so the interesting question is not which models run here — it is what sits between them and anything that matters. Read it top down: every tier constrains the one beneath it.
Controls
What actually stops a bad change. Deterministic, not prompt instructions.
- Human approval bound to a SHA-256 of the exact plan — edit the plan, the approval is void
- Exclusive scope claims, so two agents cannot work the same service
- Intent recorded before a change; an unsettled one blocks any automatic retry
- Fail-closed redaction on every message stored, shown, or passed between agents
- A fail-closed leak gate on every pushed blog branch — a missing pattern is a refusal, not a clean scan
Orchestration
One request, three agents, a structured review rather than three opinions.
- Round 1 answered blind and committed before anyone sees anyone else
- Round 2 each reviewer sees the others' findings as labelled data
- Further rounds only when an agent asks for one
- A fourth model merges the panel and lists unsupported claims separately
Agents
Different powers on purpose — the one that builds cannot be the one that signs off.
- Claude Code — plans, and is the only agent permitted to change the lab
- Codex — implementation and test plans, review; prepares but never deploys
- Kimi — independent read-only audit, behind an integrity-checked launcher
- Kimi again, as the SOC analyst — same model, separate no-tools path, triages alerts and never remediates
- Claude Code again, for the blog — works from a redacted handoff in the repository, never the lab, and opens a pull request that I merge
Gateway
One endpoint for every model, with the spend limit enforced outside the caller.
- LiteLLM routes, authenticates and caps spend per virtual key
- Open WebUI for humans, behind single sign-on; the API takes keys, not logins
- Per-project keys scoped to specific models with their own budget
Observability
Every call recorded, so a claim about what an agent did can be checked.
- Langfuse traces every gateway call and every Claude Code session
- A hash-chained evidence ledger for agent tool calls, projected into the SIEM
- Tamper-evident, not tamper-proof — and the docs say so
How the three agents actually review one request: Three agents, one approval gate →
Every layer, every component
The lab as defence in depth — and every box below links to the post where I built it.
Boundary & network
A firewall VM is the only thing the rest of the lab talks to the world through — default-deny, private ranges blocked outbound, segmented into isolated zones.
Identity & access
One identity provider with MFA is the single login authority — for web dashboards and for the firewall's own admin login. Who you are and what you may do are decided in one place.
Compute & automation
One hardened Debian VM hosts the containers and the agent workflow. It runs the services above and the monitoring below, and it's locked down as its own audited surface.
Observability & detection
Metrics answer 'what's the number', logs answer 'what happened', and alerts reach out so nothing waits to be noticed. Dashboards, alerting, and a log SIEM on one stack.
Resilience & edge
The parts that decide whether the lab survives a bad day: encrypted off-site backups that have actually been restored, and a physical glance display that never crosses the isolation boundary.
From signal to phone
Both halves of monitoring feed one alert path: a number crossing a threshold, or a log line matching a pattern, ends up as the same buzz in my pocket — with an all-clear when it resolves.
Runs while the lab is up. The nightly shutdown is exactly why alert rules wait 10m before firing — so a morning boot isn't mistaken for an outage.
How the sources, the alert path and the dashboard fit together: see the SOC →
What changed
15 changes to what the lab is since July 2026, newest first. A tool that was retired stays in the post that covered it; this is where it left.
- 20 Oct 2026 retired The /detections/ catalogue and the /incidents/ log came off the blog. The rule counts still appear on /soc/ and here, but are now counted only off the live rule files on the lab host.
- 4 Oct 2026 added A second Claude Code instance owns the blog repository; the agent on the lab hands it redacted drafts. A fail-closed leak gate runs on every pushed branch between them. write-up →
- 28 Sep 2026 replaced systemd-timesyncd gave way to chrony on the lab VM, after the firewall was found advertising leap=3 for months. The root cause was a stopped Windows Time service on the hypervisor host. write-up →
- 10 Sep 2026 added The network digital twin: NetBox holds what should be listening, a bounded nmap scan holds what answers, and confirmed drift ships to Loki as the SOC's eighth source. Three detection rules came with it, taking the set to 53. write-up →
- 8 Sep 2026 added Kimi as a read-only SOC analyst: bounded, sanitised evidence in, a triage report out, called with no tools so it cannot act on what it finds. write-up →
- 6 Sep 2026 added The SOC: seven log sources centralised in Loki, detection rules on the Loki ruler, and one security dashboard over all of it. write-up →
- 25 Aug 2026 changed The council dashboard can now spend an existing approval and execute a plan. It still cannot approve one, and it holds no credential. write-up →
- 19 Aug 2026 added The Homelab Council: one request reviewed by Claude, Codex and Kimi in rounds, merged by a fourth model, behind a human approval bound to a hash of the plan. write-up →
- 18 Aug 2026 replaced Greenbone/OpenVAS was decommissioned for Grype + Trivy + nmap. It ate memory the VM did not have. Write-up date; the swap itself was earlier in August. write-up →
- 17 Aug 2026 added Kimi Code as a second, read-only auditor over the agents, behind a launcher that verifies its own policy files before it will start. write-up →
- 14 Aug 2026 added NetBox, as the lab's source of truth for devices, addresses and what each should be running. write-up →
- 7 Aug 2026 added The agent assurance plane: root-managed hooks around Claude Code, a hash-chained evidence ledger, and a reduced feed into the SIEM. Observe-only. write-up →
- 1 Aug 2026 added AdGuard Home as the DNS sinkhole for the host and the phone, bound to lab and tailnet addresses only. write-up →
- 29 Jul 2026 added The AI gateway: LiteLLM and Open WebUI, one endpoint for every model, single sign-on for people and keyed access for agents. write-up →
- 27 Jul 2026 added Langfuse, tracing every Claude Code session and every gateway call. write-up →