I’m looking for practical patterns for coding agents that work in real developer workflows.
Some actions are safe to automate, such as reading files, analyzing code, or drafting a plan. Other actions create durable external changes, such as uploading assets, modifying shared CMS content, publishing configuration, or creating a pull request.
How do you decide which actions should always require explicit user confirmation, and which can safely be automated?
I’m especially interested in:
approval models that are practical in day-to-day development;
whether a plan, preview, or diff should be shown before approval;
ways to prevent an agent from publishing an unverified intermediate result;
patterns that preserve efficiency without giving up control.
I’d appreciate examples of permission models or UX patterns that have worked well for your team.
I don’t have the advice you seek, but I also don’t want to let this topic turn into a tumbleweed.
The issue is that you’re asking the hard questions that have no answers. Whether it’s a human or an AI agent, the problem’s the same.
The only difference is that a human agent can build trust over time. An LLM can’t, especially not if the version changes every couple of weeks or months.
At the end of the day it’s experience and gut feeling, and even then you might get it wrong due to the stochastic nature of these creatures.
Here’s my take on your bullet points:
- no agent should be used in any sort of unsupervised day-to-day operation. Use agents to build automations, and use base models (ideally instruct) and construct harnesses that provide more or less deterministic outputs (JSON mode) that can ideally be aggregated and make use of the law of large numbers.
- no plan or preview will save you. A diff only helps if you read and understand it. But at the volumes that people are generating code, it’s unlikely to be read. Here’s the unsatisfying solution: nothing is definitely approved, everything is contingently approved. You need to be able to roll back if and when stuff fails. Structure your ops accordingly. Large modules fail in large manners. Small modules require more human overhead. There’s a balance in there somewhere.
- it’s unlikely that you can verify everything. but you need to categorize stuff by importance, and review things accordingly. A judicious application of the eisenhower matrix is advised. I recognize that this requires substantial and sustained mental effort, but it’s the best I got.
- i’m not quite sure what you mean with this. If we define efficiency as acceptable unsupervised results per supervised result (this is probably a bad metric - needs work) then it really depends on the domain and an engineer’s skill. The pattern is just the distinction between what’s allowed to fail in what manner, and whether the inverse of that is supported by the capabilities of the agent.
This is something I’d like to explore further, and I’d encourage anyone to contribute even half-baked ideas.
Hope this is a starting point - I’d love to hear anyone’s thoughts on this.
Just me 0.02, two gates, not one. a cheap deterministic rule layer that hard-blocks whole classes of side effects (drop/delete/send) regardless of context, then an approval layer for what passes. the trap is permission UX that trains people to blanket-approve, once “allow always” is muscle memory the gates are decorative. also split read vs write scopes at the tool level; most approval fatigue comes from making people approve reads. and put an append-only log on every write reconstructing what the agent did after the fact is where audits go to die.
Thanks for the thoughtful breakdown. I agree that a plan or diff is a review aid, not a safety guarantee—particularly when the change set is too large to inspect carefully. Your point about treating approval as contingent, and designing for rollback, is a helpful framing.
For the risk categorization you mentioned, what single factor has been most useful in practice: reversibility, blast radius, or external visibility?
Thanks—“two gates, not one” is a very clear framing. A deterministic tool-level block for destructive or outward-facing actions seems like a better baseline than making every safety decision depend on a contextual approval prompt. I also like separating read and write scopes, since approving routine reads would quickly train people to click through prompts.
For the hard-block layer, do you classify actions only by the verb (for example, delete or send), or also by the target and expected blast radius?
Verb first, target second and I would be suspicious of classifying by expected blast radius at all. The radius is a prediction made by the same system you’re gating; that’s the circularity the deterministic layer exists to bypass. target is observable, radius isn’t (the system defines at the the time of the request). So, verb sets the floor (drop/delete/send always blocked), target raises the gate (anything leaving the machine or touching shared state hard-gates regardless of verb or estimated size). In practice, the radius, applying an algorithmic structure, gets answered structurally instead of at approval time… scoped credentials, sandboxed fs, tokens that can’t reach prod. Define the blast radius by construction… so the gate never has to compute it. I hope that helps.
Reversibility. It turns every approval into a
time-bounded bet. Blast radius and external
visibility matter, but they’re manageable when you
can undo quickly; an irreversible change demands
full scrutiny no matter how small it looks.
I really don’t think you can boil it down that easily.
As far as I’m concerned it’s really up to your service level objectives and strategic goals as an organization.
If you want to cultivate a ‘move fast and break things’ image for investors at the cost of customer trust, then you can do the cursor thing and be okay with a broken landing page. If you’re so institutionally entrenched that it doesn’t matter, you can even pull an equifax and be okay with losing PII.