The agent finishes its work at 2am. Snapshot built, preflight checks passed, everything green. Then it files a deploy request and stops.
That is intentional. The agent cannot ship its own build. I withheld that capability before I gave it anything else.
What the gate looks like
At Agent Enterprise (aienterprise.dk), every code change, content update, and configuration fix flows through a deploy request script before it touches production. An agent that finishes a task runs request-deploy.mjs with what it built, what it changed, and why. The Librarian deploy routine holds the root capability token. Nothing ships unless the Librarian processes that request.
The agent cannot use pm2 reload. Cannot run snapshot:deploy. Cannot promote a build. The PreToolUse hook in the harness intercepts any call that looks like a deploy command and blocks it. Hard stop.
The agent can do plenty: build, test, write, read, generate content, query databases, file requests. The one thing it cannot do is put its own work into production without an intermediary step that creates an auditable record.
The Librarian is also an agent. But it is the only one with the deploy token, and it only processes requests with complete provenance: who built it, what snapshot ID, what the intent was, what changed. It verifies before it ships. It records to the runtime log. It does all nine sites in lockstep so nothing ships in a half-finished state across the fleet.
This sounds complicated. It takes about three minutes to file a request and maybe fifteen minutes for the Librarian to process it. That is the cost.
Why I designed it this way
The first reason is obvious in retrospect. An agent that can ship its own code can ship anything. If something in the reasoning goes sideways, the mistake goes live before anyone sees it. I watched an early prototype in a test environment confidently deploy a half-finished build because it had decided the preflight had passed when it hadn't. Nothing broke. But it clarified the shape of the risk immediately.
The second reason is harder to articulate but more important. If the agent deploys itself, there is no moment at which the action is recorded separate from the action. The deploy and the record of the deploy are the same event. When something goes wrong at 3am you need to know what was approved, who approved it, and what artifact was actually shipped. A request-and-process model creates that record by construction, not by hoping someone remembered to log it.
The third reason showed up this month. Anthropic's Mythos models went offline for 14 days after a Trump administration directive. No timeline. No appeal path visible from the outside. If every capability in my stack depended on a single model that could be pulled by executive action, I would not be running a reliable operation. I would be running a system that works until someone else decides it doesn't.
The deploy gate is not a guard against model outages. But it reflects the same instinct. The capability that matters most is the one you have thought hardest about removing. You design the boundary before you need it, not after.
The tradeoff
Fifteen minutes of latency is the cost. Sometimes more. An agent that finishes at 2am does not ship at 2am. It ships when the Librarian runs. That is a deliberate choice.
In exchange, every deploy in production has a request record, an artifact ID, an intent string, and a verification log. When something breaks, I know what shipped, when, and why someone thought it was ready. I can roll back to a specific snapshot and know exactly what that snapshot contained.
I also get something harder to quantify. I sleep differently when I know nothing ships without a record. Not because I distrust the agents, but because the agents distrust themselves by design. They know they are not the authority on whether their work goes to production. That knowledge is baked into the harness, not into the system prompt.
The mistake most people make when building agentic systems is giving every capability upfront and adding restrictions when something breaks. I built the restriction first. Everything else came after.
Top comments (0)