July 30, 2026 · StartupQuickstart

Propose-then-approve: trust patterns for agent writes

Agents that write to real data need a specific shape: draft, diff, human approval, enforced apply. How our own edit queue works, and why rubber-stamping 100 diffs a day turns the gate into theater.

Two people working on laptops at a shared table in a bright office

The first time an agent breaks something it shouldn’t, the postmortem tends to find the same thing: there was a human “in the loop,” but the human was approving a sentence instead of a change. Approval theater is easy to build. The real pattern, the one that lets agents write to production data without anyone losing sleep, has a specific shape, and every part of it earns its place.

The shape is propose-then-approve: the agent drafts a change, a human approves it, and the system applies it. Three roles, deliberately separated. The agent can propose anything but publish nothing. The human judges but doesn’t type. The system enforces the rules and performs the write. Most of what goes wrong in agent systems comes from collapsing two of these into one.

This isn’t our invention. OWASP’s guidance on excessive agency in LLM applications names the root causes as too much functionality, too many permissions, and too much autonomy, and recommends a human approving high-impact actions before they happen. Anthropic’s guide to building effective agents likewise describes agents pausing for human feedback at checkpoints. What follows is how to make that checkpoint real.

Approve the diff, not the description

An agent reporting “I updated the FAQ to reflect the new 3-month term” is grading its own homework. The description is what the agent believes it did; the diff is what will actually happen. A reviewer has to see the old value and the new value, side by side, for every field the draft touches. If your approval screen shows a prose summary next to an Approve button, you’ve built a politeness gate: the human is confirming the agent’s confidence instead of checking its work.

This has an upstream consequence people miss: the data has to be structured enough to diff. If a page is one blob of HTML, the diff is a wall of markup noise nobody reads. If it’s typed fields (headline, price, a list of FAQ items), the diff reads like a change log: this field, was this, becomes that. Diffability is a data-model decision, made long before any agent shows up.

The server decides what a draft may touch

Human review catches bad judgment. It shouldn’t be the only thing standing between a confused agent and a deleted pricing section. Server-side, every draft passes an allowlist keyed to the kind of request: a copy edit may change text fields and nothing else. Crucially, the classification comes from the actual base-versus-proposed diff, never from what the request claimed to be. A draft labeled “copy edit” that adds, removes, or reorders sections is rejected before a human ever sees it.

This is also your prompt-injection defense. Agents read untrusted text (customer emails, web pages, ticket threads), and untrusted text sometimes contains instructions. OWASP is candid that it is unclear whether fool-proof prevention exists, which is why the control has to live outside the model. An allowlist enforced in the server means a hostile sentence in a support email can, at worst, produce a strange text edit for a human to reject. It cannot make a copy edit delete a section, because no copy edit can.

Two more properties are non-negotiable. Apply must be idempotent. Approvals get double-clicked and requests get retried, and applying the same approved draft twice must produce exactly one change. Stripe’s API is the reference design here: an idempotency key lets a client safely retry a request without performing the same operation twice. And everything goes in an audit trail: who requested, what the agent drafted, who approved, when it published. When an agent does forty things a week, “what happened here” has to be a query, not a reconstruction.

A worked example: the managed-site edit queue

The platform our managed client sites run on is built around this pattern. An edit request arrives by email or the site’s request box and lands in a queue. An agent claims it and drafts a revision through the same structured content API a human editor uses; it never hand-edits markup. The server runs a structural diff gate and rejects any draft that exceeds what the request’s category allows. A human opens the review queue, reads a field-by-field diff (old text, new text), and approves or rejects. Approval writes an immutable, versioned revision and publishes it; the change is live minutes later and revertible forever. The agent holds no publish permission anywhere in the system. Approval is the only path to production, and rollback means an agent mistake costs minutes instead of a rebuild.

Approval fatigue, and the graduation path

Now the uncomfortable part: if a human rubber-stamps 100 diffs a day, the gate is theater. Decades of human-factors research on automation bias and complacency find that people over-trust automated suggestions, that experts are as susceptible as novices, and that training or instructions don’t prevent it. In our own queues, attention visibly thins as the day’s diff count climbs. The process keeps delivering the feeling of control after the substance is gone, which is how “human in the loop” ends up as a phrase in an incident report.

The fixes are structural, not motivational:

  • Batch. Twelve related copy tweaks across one page should be one review, not twelve.
  • Sample. For a trusted action type, review one draft in ten and audit the rest after the fact; keep full review for anything touching money or deleting data.
  • Graduate. Grant autonomy per action type, with budgets. After, say, 300 approved copy edits with a rejection rate under 2%, let copy edits under 50 changed words auto-apply, capped at 20 a day, every one still versioned, revertible, and reviewed weekly in a batch. A cap turns “what if it goes wrong” into “it can go wrong at most 20 small, reversible times.”

Graduation is per action type, never global. Copy edits can earn autonomy; “delete a section” never graduates, because its blast radius doesn’t shrink with a track record. Reversibility changes the math too: a versioned content write can graduate far sooner than an outbound email, which has no undo.

Where to skip all this: if your agent only reads, or writes to a scratch environment someone reviews wholesale, the ceremony costs more than it protects. Approval gates are for writes that are customer-visible or hard to reverse. A read-only research agent behind this much process is just slow.

This pattern is built into the platform our managed websites run on, and it’s the spine of every agent system we build for clients. If you’re planning an agent that writes to real data, start by listing its actions and asking which ones can be undone; that list is most of the design.

Sources

Want systems like this built for you?

We build and run data pipelines, websites, and AI automation for startups.