I let an agent rebuild my Kubernetes cluster. It took 20 minutes.

I wanted to learn GitOps on Kubernetes. Instead, I got a cluster that an agent destroyed and rebuilt in 20 minutes. The 20 minutes start at my prompt and stop when the new nodes were installed. I did most of it through a chat window.
My first cluster took me three hours. I had a pile of blog posts and install guides open in other tabs. The shared storage refused to cooperate, and Grafana was the final boss. At the end I had a working cluster, but no energy left to learn the thing I built it for.
So I gave the next round to Hermes, the agent that runs in my homelab. I talk to it through a Telegram plugin or the CLI chat. My bot is called IRIS. I used no skills and no special tuning: one agent, a chat, and three Proxmox hosts.
Root on my hypervisors
Before it could build anything, it needed access. On each Proxmox host, I created a Linux user iris, added an SSH key, and gave it this sudo rule:
iris ALL=(ALL) NOPASSWD: ALL
That is root without a password, on all three of my hosts. I knew the risk, and the agent only runs a command after I approve it. This was also the one step that the agent could not do itself. The build log that Hermes wrote afterwards flags it too: NOPASSWD: ALL is broad by design. A hardened setup needs a restricted sudo policy or a scoped API token.
It looked before it deleted
IRIS started with read-only commands: qm list, pct list, pvesm status, and a config dump for each VM. It found the four stopped Talos VMs of my hand-built cluster on pve-2. It also made a list of what it must not touch: Home Assistant, UniFi, AdGuard, and the media VM with its 650 GB data disk.
I approved the deletion scope. Then it ran qm destroy on exactly those four IDs.
The inventory also changed the plan. IRIS first wanted to put the worker next to the media VM on pve-3. It saw only about 1.1 GB of free RAM there, so it moved the worker to pve-1.
Where it got stuck
I use only static addresses, so the new Talos VMs got no IPv4 lease. There was nothing to connect to. IRIS used IPv6 link-local through the Proxmox bridge to ask the first VM for the name of its network interface:
talosctl --nodes 'fe80::<node-address>%25vmbr0' get links --insecure -o yaml
The answer was ens18, not eth0. The static network config needs that name.
The other problems were smaller. All of them are problems that you get in a real build:
| Layer | Problem | Fix |
|---|---|---|
| Kubernetes API | The planned endpoint did not answer. Also, the Talos API on port 50000 cannot use the same listener. | A small HAProxy LXC on port 6443 in front of the three control planes. Talos management connects directly to the nodes. |
| Git over SSH | Deploy keys failed. Port 22 was the normal OpenSSH of the container, not Gitea. | Enable the built-in SSH server of Gitea on port 2222. |
| Git user | The Gitea log said Invalid SSH username git - must use gitea for all git operations via ssh | Use ssh://gitea@<host>:2222/homelab/infrastructure.git |
I installed Gitea with a Proxmox helper script. Hermes helped me set up the repo structure. After I generated an API key, I let it do all the GitOps configuration. Flux is now the only GitOps controller. I had installed Argo CD during earlier experiments, and I removed it. Two controllers for the same job make no sense.
IRIS also made one decision on its own: it kept my media server out of Kubernetes. The log gives the reason. The cluster is a place to break things, and movie night must not depend on etcd quorum.
The train
The API key that I generated was read-only. Hermes needed write access, and only I can make that change in Gitea. I was on a train, and I could not reach my Gitea instance from there.
I asked IRIS how we could connect. It suggested Tailscale and built the node as a small, dedicated subnet-router LXC on pve-1. It did not put the node on the Proxmox host or inside Talos. The LXC has 1 vCPU, 256 MiB RAM and a 4 GiB disk. This is the effective configuration:
tailscale up \
--hostname=home-vpn-gateway \
--advertise-routes=192.168.2.0/24 \
--accept-dns=false \
--accept-routes=false \
--ssh=false
The gateway advertises one subnet. It is not an exit node, and it does not run Tailscale SSH. Then IRIS gave me instructions for the steps that only a human can do: create the Tailscale account, install the app, and approve the advertised route. I also set AdGuard as the DNS server for the tailnet.
The gateway is outside the cluster. So remote access to the LAN continues to work when the cluster is down.
Why I could judge it
Three hours against 20 minutes is not a fair comparison. The 20 minutes stop at the installed nodes, and my three hours contained more than that. The second run also had a known target, and my first attempt as a reference. I could read what IRIS built because I had built the first cluster by hand. I knew what shared storage must look like. I knew that three control plane VMs on one host are not three failure domains.
IRIS knew that too, to its credit. Its own list of lessons says: three VMs are not three physical failure domains. This is a good topology to learn with, but it is not physical-host HA. If you lose one VM, etcd keeps quorum. If you lose pve-2, you lose the full control plane.
It is also not perfect about its own history. Later, I asked how the cluster was built. Hermes first gave the wrong answer about who installed Flux. Then it corrected itself from the session record. The written build log settled the question. I check an agent's memory of its own work in the same way as anybody else's.
What I don't know yet
I know how I review one cluster in my own homelab. There, the worst result is a bad evening. I don't know what that review looks like when the environment belongs to someone else, or when there are thirty of them. That is what I want to find out next.
The build log that IRIS wrote is the source for the technical details in this post.
Gerelateerde Berichten
Restore access to Unifi OS Server
Locked out after a cross-instance backup restore? Here's how UniFi OS Server actually stores passwords — across MongoDB, PostgreSQL, and a file cache — and how to reset them when everything is inconsistent.
Why I Built a Shelly MCP Server (So I Could Migrate to Home Assistant)
I wanted a practical way to migrate Shelly settings into Home Assistant workflows through MCP. I found a Home Assistant MCP server, but no reliable Shelly MCP server, so I built one.
My Ultimate Self-Hosted AI Chat Stack
One Docker Compose stack to rule them all: private chat, local and cloud LLMs, image generation, voice input, web search, document research, and full observability — all on your own hardware.