Burrow hands an AI coding agent real access to your production apps. If that makes you a little nervous, good. That instinct is exactly what guardrails are built around. A guardrail is a rule you set once about what is allowed to happen, checked before anything runs. This post is a tour of the three mechanisms that make handing over the keys safe.

The short versionA guardrail turns "please be careful" into a rule the system enforces. The agent proposes; your policy decides whether it runs, waits for you, or is refused.

Where the rule actually lives

Before the three dispositions, one thing worth being clear about: the agent is not trusted to police itself. The rules live in the piece of Burrow you install into your own cluster, the piece that holds your credentials. Every risky action the agent tries is checked there, before anything touches your cluster.

That matters because it means the guardrail is not a suggestion the agent can talk itself out of. The agent does not hold your cluster credentials at all. It sends a request to the part that does, and that part decides. If your policy says no, the agent never had the ability to do it in the first place. It only ever asked.

Three dispositions

Every risky action has a code: app.deploy, app.delete, app.run, dns.write, and the addon install action. For each code, in each environment, you pick one of three dispositions:

  • allow: the action runs.
  • confirm: the action holds and waits for your sign off.
  • deny: the action is refused, and nothing changes.

That is the whole model. There is no fourth secret mode, and the agent gets no back door around it. It runs the same commands you do, under the same policy.

The three cover the range of how you feel about a given action. Some things you are happy to let happen without a thought (allow). Some things you want to happen, but only with a human glancing at them first (confirm). Some things should simply never happen from an agent's hands (deny). You are not writing a program here. You are answering three way questions: fine, ask me, or never.

Set it once, per environment

Policy is per environment, so prod and staging can feel completely different. You lock prod down and leave staging loose:

burrow guard set app.delete deny --env prod
burrow guard set app.deploy confirm --env prod
burrow guard set app.delete allow --env staging

Now a delete against prod is simply off the table, a prod deploy pauses for your approval, and in staging the same actions just run because the blast radius is a throwaway environment.

This is the part that makes delegation practical instead of scary. Staging is where the agent should be able to move at full speed, breaking and fixing things with no human in the loop, because nothing there is precious. Prod is where you want the agent to still be useful but never unsupervised on the dangerous moves. Because policy is scoped to the environment, you do not have to choose one posture for both. You switch which environment you are pointed at with burrow env use, and the same commands land under whatever rules that environment carries.

What a denial looks like

When the agent reaches for something your policy refuses, it does not get halfway there and stop. The action never runs, and the reason is legible:

agent, on burrow
$burrow app delete api --env prod
# agent attempts a destructive action
✗ denied by guardrail: prod app.delete is set to deny
nothing changed · api still running

A held action reads the same way, except it pauses for you instead of refusing outright. You see which action, on which app, in which environment, waiting on your sign off. You approve, and only then does it run.

Notice that the result is structured, not just a wall of text. The agent gets back a clear signal: this was denied, here is the code, here is the environment, nothing changed. That legibility is deliberate, and it is what makes the confirm case work well, which is the next thing to look at.

How a held action actually flows

Deny is simple: the door is locked and stays locked. Confirm is the interesting one, because it is a pause, not a refusal, and the whole point is that the pause routes through you.

Here is the flow, step by step:

  1. The agent proposes. It tries an action that your policy has set to confirm, say a deploy to prod. It does this exactly the way it would try any action; it does not know in advance that this one will hold.
  2. Burrow holds it. Because the policy says confirm, the action does not run. Instead it comes back with a structured result that says, in effect, this is waiting for a human. Which action, which app, which environment.
  3. The agent surfaces it to you. It reads that structured result and tells you plainly: it wants to deploy to prod, and that needs your sign off.
  4. You decide. If you say yes, the agent retries the same action, this time marked as confirmed. If you say no, it stops there and nothing happens.
The line that keeps this honestThe agent must never confirm on its own behalf. A confirm can only be satisfied by a real human approving the specific action. The agent can ask; it cannot answer its own request.

That last rule is the load bearing one. If the agent could set the confirmed marker itself, confirm would collapse into allow and the whole distinction would be theater. So it cannot. The confirmation is something a person supplies, for one specific action, after seeing what it is. The agent's job is to propose clearly and then wait, not to nod its own proposals through.

For your own hands, the confirmed retry is a flag on the command (--confirm). The important thing is not the syntax; it is who is allowed to add it. That is always you.

To make that concrete, picture a normal exchange. You ask the agent to ship the latest build to prod. It runs the deploy, which your policy has set to confirm. It comes back to you not with "done" but with something closer to "this needs your sign off: deploy website to prod." You look, you agree, you tell it to go ahead. It runs the same deploy again, this time confirmed, and it goes through. From your seat it felt like one short conversation. Underneath, the pause was real and the approval was genuinely yours. If you had said no, the second run never would have happened.

Everything is written down

Set once and enforce is only half of trust. The other half is being able to look back and see what actually happened. Every guarded action is recorded, whether it was allowed, held and then confirmed, or denied. Nothing that touches the guardrails does so silently.

burrow audit

You get a running record of what was attempted, by which path, in which environment, and how the policy responded. A denied delete shows up there just as plainly as an approved deploy. That means "the agent tried to do X and was refused" is not something you have to take on faith or reconstruct from memory. It is written down, in order, for you to read.

Why the denials are logged tooA denial is a signal, not a non event. Seeing that the agent repeatedly reached for something you have locked off tells you something worth knowing, either about the task you gave it or about a rule that is in the wrong place.

The actions you can guard

The codes are deliberately coarse. They map to the moves that can actually cost you something, not to every command:

  • app.deploy ships a new version. Set it to confirm in prod if you want a human to glance at every release.
  • app.delete removes an app. The classic deny in prod, allow in staging split.
  • app.run runs a one off command against your app, like a task or a script. Useful, and worth gating where the blast radius is real.
  • app.autoscale turns autoscaling on or off. Autoscaling is shipped, and changing that behavior in prod is the kind of thing you may want to hold.
  • dns.write and dns.delete change or remove DNS records, which is how the outside world finds your app. Getting these wrong is quietly disruptive, so they get their own gates.
  • the addon install action brings new pieces into your cluster. Installing something new is exactly the kind of move worth a human nod.

You do not have to set all of them. Anything you leave alone runs under its default, and you tighten the ones that matter to you.

The coarseness is a feature, not a shortcut we have not finished. A guardrail you can hold in your head is a guardrail you will actually set correctly. If the model asked you to write fine grained rules about which app, which flag, which time of day, most people would either skip it or get it subtly wrong, and a subtly wrong guardrail is worse than an obvious one because you trust it more than you should. Three dispositions over a short list of coarse actions, scoped per environment, is small enough to reason about and still catches the moves that actually hurt.

Warm rollbacks, the safety net under it all

Guardrails stop the obvious mistakes. Warm rollbacks handle the ones that slip through anyway. Every deploy keeps the previous revision warm, so if a change looks fine and then misbehaves under real traffic, going back is one command and a moment, no rebuild and no cold start.

An honest limitGuardrails gate the risky actions; they do not gate an ordinary deploy, and they cannot catch a bug that is inside your code. That is what warm rollback is for. The two work together: stop what you can, recover fast from what you cannot.

We keep the deep version of how warm rollback works, the timing and the edges, in its own engineering post. Here it is the third leg of the stool: deny the impossible, confirm the sensitive, and keep a fast way back under everything else.

A few questions

Can the agent turn off a guardrail? No. Setting policy is done through the human CLI that holds your credentials. The agent runs under the policy; it does not get to rewrite it. It holds no cluster credentials to do so with.

Does confirm mean the agent sits and waits forever? It waits for your answer. If you never answer, nothing happens, which is the safe outcome. A held action that is never confirmed simply never ran.

What if I want prod fully hands off for some low risk action? Set that code to allow in prod. Per environment policy is exactly for drawing that line where you want it, action by action.

Can I see what the agent tried without approving anything? Yes. That is what the audit record is for. Attempts, approvals, and denials are all there to read after the fact.

Do I have to trust the agent to be careful? No, and that is the whole idea. Guardrails do not depend on the agent being cautious or well behaved. They are checked before the action runs, by the part of Burrow that actually holds your credentials, so a careless or confused agent runs into the same wall a careful one would. You are trusting the policy you wrote, not the agent's judgment.

Handing over the keys, safely

Put together, these are the three moves that let you actually delegate: deny the actions you never want, confirm the ones you want to sign off on, and keep a warm previous revision under everything so a bad call is cheap to undo. The agent moves fast inside those rails. You keep the parts that matter: what is off limits, what needs your nod, and a fast way back.