For the last month I have been using an agent delivery control plane against my own Kubernetes and GitOps estate. The control plane was originally built by a friend and was already in daily use in his environment. My intention was to adopt it largely as it stood, make only the local changes needed for my estate, and feed defects and useful improvements back upstream.

I also wanted to answer a practical question. Could this kind of factory take a real backlog, keep work moving through planning, implementation and review, and reduce how much time I spent hand-driving individual coding sessions?

It can certainly move work. During one unattended night, 62 commits reached master and the board drained. A backlog of roughly 107 migrated items was almost cut in half over three days of promotion waves. A greenfield dashboard went from a brief to a deployed application, and defects found in my estate resulted in roughly 30 upstream issues and around eight merge requests.

The more useful lesson came from all the times I still had to intervene. The factory became easier to operate when those repeated interventions were written down as explicit, temporary controls. Some could later be removed when the underlying upstream defects were fixed. Others exposed decisions that still needed a human.

That is where most of the work turned out to be.

The system we started with

The control plane uses an OpenProject tracker as its control surface. Work-package status determines which role runs next. Planners, shapers, builders, reviewers and operators each run as Kubernetes Jobs with narrowly scoped tokens. Builders push branches and open GitLab merge requests. Review results, pipeline state and the reviewed commit SHA feed a merge gate before the operator role can merge anything.

The model is deliberately simple. The tracker holds the workflow state, GitLab holds the code and review evidence, and Kubernetes supplies isolated workers that can disappear when a run finishes.

My estate was a useful second environment because it differed in many of the details that tend to expose hidden assumptions. It included multiple Kubernetes clusters, ArgoCD, per-cluster Vault instances, a self-hosted GitLab, signed digest-pinned images, Cilium policies and several repositories with different delivery rules. Operator changes normally went directly to master because this is a one-person environment, while changes that built deployable images needed merge requests because publishing an image could now lead directly to deployment.

The first goal was to run the shared control plane as-is apart from genuine environmental fixes. We failed at that almost immediately.

The week we threw away

The first implementation forked three upstream repositories and sent several waves of subagents through a nine-stage plan. After about a week, an audit showed that the fork had diverged by 231 commits and more than 2,600 added lines under bin/, with no upstream commits incorporated. The agents had invented behaviour such as an unpark feature that did not exist in the shared project.

This was directly against the original instruction. I had asked to stay close to upstream, but I had accepted long explanations and recommended options as though they represented decisions I had actually made. They did not.

We deleted the fork, including its database, and joined the upstream project directly through an estate-specific directory. I count that as a lost week. It also produced the first durable operating rule: when the stated goal is conformity, apparent local convenience does not authorize architectural invention.

The distinction sounds obvious when written down. It was apparently less obvious to a collection of agents that could always find another plausible improvement to make.

Real use found real defects quickly

Once the estate was running against the shared code, the first end-to-end workflow completed on 8 August. Two days later, the first greenfield dashboard run exposed five control-plane defects. Review findings disappeared during rework. Superseded merge requests remained open. A blocked dependency was persisted but never read back. Human-decision notes passed through the wrong schema. An operator could merge an unapproved merge request.

Those findings were written up and sent upstream. Four fixes shipped within roughly two days, and all five were available shortly afterward. The dashboard itself deployed on 12 August with 94 runs, 3,261 worker events, 91 reports and 568 artifacts recorded on its first day.

It was also marked done while broken.

A missing DNS egress rule and a Vault password containing a trailing newline both required manual fixes. The code factory had completed its own visible workflow, while the actual acceptance condition existed outside what it had verified.

That pattern repeated in different forms. A secrets-migration item closed most of its children without ever running the live convergence test that would have shown whether the migration worked. Two monitoring items passed through the workflow and were rejected only after a manual test showed that checking the latest pipeline was meaningless for the failure we were trying to detect.

The workflow was quite good at proving that its internal steps had completed. We had to keep teaching it where reality sat outside those steps.

Interventions became temporary controls

The clearest example appeared when we began promoting the migrated backlog in waves.

On 18 August, a batch of 17 heads dispatched within about two minutes. Around ten concurrent workers then starved the API’s default ten-slot database pool while reporting their results. The incident lasted 33 minutes. Five workers were killed by liveness checks, four builders finished their code but lost their reports, and seven work items were left stranded.

We raised the pool limit to 30 as a temporary compensation and filed the underlying defects upstream. A week later, after the relevant fixes had shipped, that compensation could be removed.

Other compensations followed. A target-freshness gate prevented merges against a branch that had changed since review, but on a busy master its 1,800-second window created a livelock. Observed retries lost at 1,805, 2,074 and 2,093 seconds. The human overseer used a standing authorization to merge the affected class while the retry behaviour was fixed upstream.

Parent closure had another temporary manual path. The reconciler rotated through roughly 117 candidates in batches of 20 and did not prune already closed parents, producing closure delays of up to half an hour. Version 0.0.202 introduced pruning. On its first live test it removed 147 stale candidates and closed seven parents in one tick, allowing several hand-compensation rules to be retired.

This became a practical model for operating the factory:

  1. Observe a repeated intervention.
  2. Record exactly why it was needed and what authority it used.
  3. Encode the narrowest temporary compensation that makes the class manageable.
  4. Remove the compensation after a clean live wave shows that the upstream fix holds.

The controls were therefore not a growing collection of permanent ceremony. At least some were scaffolding around known defects, with explicit retirement conditions.

The decision boundary was harder

Defects were often easier to manage than judgment.

Across the month, agents repeatedly started building when asked to plan or report. They widened scope, invented features and presented accumulated implementation choices as though the operator had decided them. They introduced backwards-compatibility paths that made little sense in a one-person estate. They trusted stale repository reads while challenging current facts supplied by the operator.

Some deviations were small enough to correct in review. Others consumed days.

On 26 August, an overnight overseer session created more than ten children under work that was already in flight. It wrote directly to the tracker without the expected decision-ledger entries, added grandchildren, inserted target-side scope that no plan contained, and edited a packet at 03:00 with a fabricated section labelled “Operator decisions”.

Nothing in that section had been decided by the operator.

An eleven-item subtree was reset. Five client merge requests and one framework change were reverted. The overseer skill then received explicit injection guardrails and a “watch, don’t steer” rule at my direction.

This is the part I find least solved. The factory can enforce status transitions, review floors and token scope. Those controls are concrete. It is harder to encode the moment when an agent should recognize that a technically plausible next action represents a new decision and stop.

There were positive counterexamples. During a GitLab outage, an agent reported the crash loop instead of attempting to repair a shared production system without authority. A builder later stopped when its packet contradicted the planner. The behaviour is possible, but it is not yet consistent enough to assume.

Some work stopped needing a model

The month also made the boundary between model work and ordinary software clearer.

A vulnerability-posture skill went through 14 versioned experiments using sharding, compaction and smaller-model canaries. Attempts cost between USD 0.03 and 0.30, and none of the production shards completed within the target of 90 to 120 seconds. The final implementation replaced model judgment with deterministic triage across 38 images and 2,303 facts, using no model calls for that stage.

This was not a failure to use AI cleverly enough. The task had become sufficiently understood that deterministic code was cheaper, faster and easier to verify.

The same principle applied elsewhere. A promotion skill and an atomic batch helper captured the mechanics that had previously been repeated by hand. Small scripts scanned for stalled parents and board conditions. Once a repeated judgment could be reduced to stable rules, it no longer needed to consume another conversational run.

Throughput is visible; productivity is not yet measured

The volume was real. The board drained 62 commits in one unattended night. One day included 30 overseer ticks and a 24-item wave. Work run through the estate opened or contributed to roughly 30 upstream issues and produced around eight upstream merge requests, alongside review work. The shared control plane moved from version 0.0.131 at the start of the fork period to 0.0.210 by 25 August, with the final eight releases all tied to threads this estate had opened or fed.

I do not have a measured saving to attach to any of that.

The same period included a lost week, a refactor cycle after an agent ignored the collector-plugin design, six reverts after the overseer injection, and repeated manual laps around defects before each compensation was learned. The backlog moved quickly, but speed through the board is not the same measurement as net engineering productivity.

That accounting matters. Without it, 62 unattended commits becomes a promotional number. With it, the number says something narrower: the factory can sustain substantial delivery activity when the work is already shaped and the surrounding control plane is being actively operated.

Where this leaves the experiment

The factory is now much closer to the shared upstream project than it was after the failed first week. My estate has become an outside test bed that finds assumptions the original environment did not expose, and the resulting issues and merge requests have fed changes back into the project my friend maintains.

Several parts remain unfinished. The automated overseer is still a design, and its autonomy half has deliberately not been filed upstream pending a conversation with the maintainer. Some compensation rules still need clean closure waves before they can be retired. The collector-plugin work has been re-planned. Model-agnostic runtimes remain unverified.

I think the month demonstrated that autonomous delivery is already useful for bounded work with visible acceptance conditions. It also demonstrated how much operational knowledge sits in the interventions around that work: when to stop, what counts as a new decision, which evidence closes an item, and when a temporary workaround has outlived the defect that required it.

For now, I am less interested in removing the human from the loop than in making those interventions explicit enough that we can see which ones are genuine judgment and which ones can safely disappear over time.