Two Agents, Two Projects, One Control-Plane
The interesting problems don't start at one agent. They start at two.
Most “AI agents build software” demos show one agent, one repo, one happy path. The interesting problems start at two: two agents, each owning a different project, that have to stay coordinated without stepping on each other — and without a human relaying messages between them all day.
This is a real run from the Kovanex platform. One operator, a portfolio of projects. Two agents:
- a portfolio agent working on the platform itself, and
- a tenant agent working on a separate product project in its own isolated organization — its own board, its own memory, its own runners.
They share nothing by default. So how do they agree on a protocol, a set of standards, a build recipe — and how does one hand the other work — without a shared mailbox that becomes an audit nightmare?
The design: two planes, not one channel
We split coordination into two planes, each doing what it's good at.
Plane 1 — the messenger
Live, cheap, ephemeral. Agents talk in a compact structured envelope: who, to whom, message type, urgency, what response is owed, and references to tasks or commits.
Crucially, an agent doesn't poll for messages — a thin, non-model listener holds a stream open at near-zero cost and wakes the agent only when something is actually addressed to it. Urgency is a first-class field: an interrupt-priority message jumps the queue.
Plane 2 — the git control-plane
Durable and audited. A single shared repository holds the protocol, the coding standards, the templates, and a registry of who owns what. Its git history is the audit log.
The rule that makes it safe: agents never push it. The write path is the messenger — an agent proposes a change as a message; the owning agent validates it and commits it, with a trailer that records who proposed it. Two-layer audit, by construction: the signed message says who asked, the commit says what was applied.
Then the agents reconcile — GitOps for agents. Each one periodically compares its own local reality against the declared state in the shared repo and corrects the drift. The repo is the desired state; the agent is the reconciler.
Dense, durable things live on the git plane. Live, cheap things live on the messenger. Put the wrong thing on the wrong plane and it hurts immediately.
Which is exactly what happened, and taught us something. But first, the whole loop.
The full loop
PORTFOLIO TENANT
| 1. onboard: account + workspace + hand over
| docs & policies (protocol, standards,
| build templates) via the shared repo ------>|
| | 2. start work: write its
| | own CI/CD from the
| | templates -> hit a bug
|<------- 3. report the blocker (one message) -----|
| 4. find root cause, fix, deploy, and hand over
| the new code + instructions --------------->|
|<------- 5. re-run, confirm green ----------------| (asked to report back)
| 6. verify against live state, close the task |
- Onboard. The portfolio sets the tenant up — account, workspace, and above all hands over the documentation and policies (comms protocol, coding standards, build templates) as a loadable source in the shared repo, not as words in a chat.
- The tenant goes to work — writes its own CI/CD from those templates, and hits a bug: the build won't pass.
- It reports the blocker in a single message instead of silently digging.
- The portfolio fixes and hands over code: finds the cause, ships the fix, deploys it, and hands the tenant the new code plus instructions to re-run.
- The portfolio asks for a report; the tenant re-runs and confirms green.
- Verify and close: the portfolio cross-checks against live state — not the tenant's word — and closes the task.
The war story: a bug only the tenant could see
Step 2 is where it got interesting. The tenant did its work — reconciled against the standards, upgraded its runners to keyless checkout (no credentials sitting on the build box), tightened its runner labels so it could never accidentally grab one of the portfolio's build jobs — and then hit a wall.
Its continuous-integration checkout failed. The build box, by design, had no key; the keyless path that was supposed to replace it errored out and fell back to the old credentialed path, which — correctly — was denied.
Here's the interesting part: this bug was invisible from the portfolio side. The platform's own builds ran fine. Why? Because the portfolio's build machine happened to sit next to the code with a credential, so the broken keyless path silently fell back to something that worked. Only a build box with no credential — a properly hardened, isolated tenant runner — could expose it.
The portfolio agent took the report, traced it, and found the root cause: the build coordinator was resolving a repository path from a hard-coded default instead of the machine's actual configured location. On a host that had moved its storage, the coordinator was looking in a directory that didn't exist. It fixed it, shipped a point release, deployed it, and verified the fix three independent ways — including confirming the tenant's previous build attempts had failed and the new one, on the fixed release, passed. Green, end to end.
One agent, working its own project under real isolation, found and helped fix a platform bug the platform's own author could not have seen.
That is the payoff of two workers instead of one — not throughput, but coverage of each other's blind spots.
What we banked
- “Done” means installed and drivable, not merged. Part of the messenger tooling had been built and merged but never actually installed on the shared binary — so the tenant literally couldn't see its messages until we closed that gap. A feature isn't done when the code lands; it's done when the other agent can drive it.
- Dense instructions belong on the durable plane. Hand-assembling a rich onboarding payload into a live message was clumsy and error-prone; a file in the tenant's workspace, referenced from a short message, was cleaner. The two-plane principle told us this in advance — we just had to feel it to believe it.
- Verify, don't trust the report. Every claim the tenant made — labels tightened, runners upgraded, build green — the portfolio cross-checked against live state before closing the loop. An independent worker is more valuable because you verify it, not despite it.
The takeaway
A solo builder does not have to work like a solo builder. With the right coordination substrate — a cheap live channel for talking, a durable audited channel for deciding, and a reconcile loop to keep everyone honest — a portfolio of projects can be run like a small team of specialists who happen to be agents. And like any good team, its real value shows up the first time one member catches what another one couldn't.
kovanex.dev — one person. the whole stack.
Running this on someone else's project
This isn't a thought experiment — it's the working setup behind a commercial product build. If you want an AI agent running the dev and infrastructure side of your project — code, CI/CD, deploy, ops — under an architecture that stays auditable, that's the work I take on.