Approvals that respect your time

Guardrails only work if you actually leave them on, and people turn off anything that nags. So we built sign off gates to be the opposite of a nag: they gate the handful of actions that are genuinely risky, and they get out of the way for everything else.

A normal deploy that stays inside its declared limits never asks for approval. It just ships. The gate is for the actions that can ruin your afternoon: deleting an app, rolling back prod, exposing something to the public internet, changing DNS, adding or removing an addon. Those pause and wait for your sign off. Routine work does not.

The short list of things that actually gate

It helps to be concrete about which actions are gated, because the list is deliberately short. These are the operations that can ruin an afternoon, and each one is a named guardrail you can set to allow, confirm, or deny:

  • app.deploy: shipping a new image. Usually left on allow, but you can require a sign off in prod if you want a human eye on every release there.
  • app.delete: removing an app. The classic "wait, which cluster am I on" mistake, gated so it cannot happen in one distracted keystroke.
  • app.autoscale: turning automatic scaling on or off for an app.
  • app.run: running a one off command against an app, the kind of thing you reach for during an incident.
  • dns.write and dns.delete: changing or removing a DNS record, which is the sort of change whose blast radius reaches past the one app.
  • addon.install: bringing a new addon, like a database, into the cluster.

That is the whole surface. Everything not on that list never pauses for anything. The gates exist for the handful of moves where a moment of "are you sure" is worth it, and nowhere else. A routine deploy that stays inside its declared limits is not on the list, so it just ships.

Confirm, deny, and the difference that matters

Every guardrail has three settings, and the middle one is where the design lives:

  • allow lets the action run with no interruption at all.
  • confirm holds the action and waits for an explicit sign off before it proceeds.
  • deny refuses the action outright. Not "ask a human," but "no, not here."

deny is for the things you never want to happen in a given place: delete an app in prod, full stop. confirm is for the things that are fine to do but should never happen by accident. The distinction keeps prompts meaningful. If everything asked for confirmation, you would learn to slap yes on all of it, and the gate would be theater. By reserving confirm for the genuinely risky handful and reaching for deny when the answer is simply no, the confirm prompts stay rare enough that you actually read them.

burrow guard set app.delete   deny    --env prod     # never here
burrow guard set app.deploy   confirm --env prod     # fine, but I want to see it
burrow guard set app.deploy   allow   --env staging  # just go

You can see the current dispositions at any time with burrow guard, so "what will pause and what will not" is never a mystery you have to reconstruct in your head.

The retry with confirm flow

When an action is held, nothing happens silently and nothing is auto approved. The result tells you exactly what is waiting: which action, on which app, in which environment. You look at it, and if you are happy, you rerun the same command with --confirm to release it.

$ burrow app delete cache --env prod
held: app.delete on "cache" in prod is set to confirm. re-run with --confirm to proceed.

$ burrow app delete cache --env prod --confirm
deleted.

That two step is the whole approval experience for a human at the terminal, and it is deliberately boring. The first run shows you the decision. The second run is you making it. There is no separate approvals inbox to go find, no modal stacked on a modal, just the same command with one honest flag that means "yes, I read that, do it."

The flow matters most when the request did not come from you. When your AI coding agent hits a gated action, it cannot confirm on its own. It gets the same held result, surfaces it to you, and waits. Approval is a thing a human does, on purpose, out loud. The agent proposes; you approve; only then does the retry with confirm go through. It never self approves, because the setting that would let it is one it does not have.

Every sign off is on the record

Because approvals are real decisions, Burrow writes them down. Every guarded operation, held or allowed, human or agent, lands in the audit log. So "who approved deleting that app, and when" is one command away rather than a memory you hope someone has.

burrow audit                # the record: what was gated, who confirmed, when

That record is part of what makes it comfortable to leave the gates set to confirm rather than deny. You are not just trusting that the right thing happened. You can go read that it did.

What stays out of the way

The other half of a good gate is everything it does not touch. Most of what you do in a day is not on the risky list, and none of it pauses. You deploy an image, you check status, you read logs, you scale up because traffic climbed, you set a config value, you run the app's list of releases. All of that flows without a single prompt, because none of it is the kind of move that ruins an afternoon.

burrow app deploy  web --image ghcr.io/acme/web:2.3.1   # ships, no prompt
burrow app scale   web 4                                 # scales, no prompt
burrow app logs    web --tail 100                        # reads, no prompt
burrow app config set web LOG_LEVEL=debug                # sets, no prompt

Even autoscaling, once you have turned it on, does its job quietly. Turning it on or off is the gated action, because that is the real decision. After that, the app scaling itself up and down under load is exactly the routine work you wanted, and it does not ask permission every time the traffic moves. The gate sits at the decision, not at every consequence of the decision.

burrow app autoscale web        # the on/off is gated; the scaling that follows is not

This is the line the whole design walks. A gate that fires on routine work is a gate you resent, and a resented gate gets turned off. By keeping the pauses to the short risky list and letting everything else run, the gates stay welcome, which is the only way they stay on.

A day where it actually matters

Picture a normal incident. Traffic is climbing, an app is struggling, and you are moving fast. Here is where the gates are and are not, in the order you would hit them:

burrow app scale api 6                 # no prompt, just scales
burrow app logs  api --tail 200        # no prompt, just reads
burrow app run   api -- ./repair.sh    # HELD: app.run is confirm in prod

The scale and the log read never slow you down, which is exactly what you want mid incident. But the one off repair command pauses, because running arbitrary commands against prod is on the risky list. You read the held message, decide it is the right move, and release it:

burrow app run api -- ./repair.sh --confirm

One deliberate pause, at the one moment a pause is worth it, and nothing else in the sequence got in your way. Afterward, burrow audit shows the whole run: the scale, the log read, the held command, and your sign off on it. When the incident review happens, the timeline is already written.

Lock down prod, stay loose in staging

Policy is set per environment, so you choose the temperature that fits each one. Lock prod down: hold risky actions for your confirmation, deny the ones you never want, and sleep fine. Leave staging permissive: let the same actions just run, because the blast radius is a throwaway environment and speed is the point.

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

The same deploy flow works everywhere. What changes is how much friction each environment earns. You are not choosing between "safe" and "fast" as one global setting for your whole world. You are saying prod is where you slow down and staging is where you do not, which is what you already believe anyway.

The per environment split is also what keeps the confirm prompts from wearing out their welcome. You get the pause where it counts, in the one place a mistake is expensive, and you get out of your own way everywhere else. If staging asked for a sign off on every delete, you would stop reading the prompts within a day. It does not, so the prod prompt still means something when it appears.

Tuning the gates over time

You do not have to get the policy perfect on day one, and you should not try to. The comfortable path is to start a little strict in prod, live with it for a week, and loosen the gates that turn out to fire on genuinely routine work. Because setting policy is itself just a command, adjusting it is a thirty second edit, not a support ticket.

burrow guard set app.deploy confirm --env prod    # start cautious: eyes on every prod ship
# a week later, deploys have all been fine and the prompt is just noise
burrow guard set app.deploy allow   --env prod    # relax it, keep the riskier gates

The reverse works too. If something scary happens once, tightening the gate that would have caught it is a single line, and it applies from the next action onward. The policy is a living thing you shape to how you actually work, not a wizard you fill out once and forget. And every change to it is legible: run burrow guard and the current picture is right there, no hidden defaults, no setting buried three screens deep that quietly overrides what you thought you chose.

This is what makes "guardrails you keep on" realistic rather than aspirational. A policy you can read and adjust in seconds is a policy you actually maintain. A policy locked behind a console you avoid is a policy you eventually route around. Keeping the whole thing in plain commands means the gates stay tuned to reality, and a gate tuned to reality is one you never resent enough to disable.

Questions this usually raises

Does a normal deploy get held? No, unless you set app.deploy to confirm in that environment. Out of the way is the default for routine work. The gate is for the risky handful, not for shipping.

What if I want zero friction in a scratch environment? Set the guardrails you care about to allow in that environment and they will never pause. The temperature is yours to pick per environment, and nothing forces the same setting everywhere.

Can my agent quietly approve its own risky action? No. Confirming is a capability the agent does not have. It can propose and it can retry with confirm only after you have said yes, and the whole exchange is on the record in burrow audit.

How do I know what will pause before I run it? burrow guard shows the current disposition for every guardrail in every environment. There is no hidden policy; what you see there is what will happen.

What is the difference between confirm and deny again? Confirm holds the action and waits for your sign off, so you can still do it, you just have to mean it. Deny refuses it outright in that environment, so it cannot happen there at all. Reach for confirm when the answer is "yes, but carefully" and deny when the answer is simply "not here."

That is the whole idea: guardrails you keep on, because they only ever stop you when stopping is the right call.