· Engineering · 6 min read

Undo might be the most important AI feature nobody talks about

← All notes

While writing about WebMCP, I kept coming back to permissions. If websites start exposing proper tools to agents instead of making them squint at the DOM and guess which blue rectangle means "Book hotel", we obviously need some control over what those tools can do.

The obvious solution is confirmation. An agent wants to change your delivery address? Ask first. Cancel a booking? Definitely ask first. Update 14 products? Maybe ask first. It sounds sensible until you imagine actually using a product built like this. If every useful action needs approval, we've built a very clever system whose main job is asking me to click OK.

I'm starting to think we're putting too much weight on permission and not enough on recovery.

If I ask an agent to clean up a project board, I probably don't want twelve prompts while it moves tickets, changes labels and fixes priorities. I want to give it the task, inspect what it did afterwards and have a reliable way to put things back if its interpretation of "clean up" was slightly more enthusiastic than mine.

That sounds less exciting than AI permissions. It might also be more useful.

Not every action needs the same treatment

The useful distinction, I think, isn't simply between "allowed" and "needs permission". It's between actions based on what happens when they go wrong.

Changing a ticket label is easy to reverse. Deleting a document might also be easy if deletion really means moving it to a bin. Sending an email is different. You can send another email saying "please ignore that", but unfortunately email does not support git reset.

And transferring money is different again.

If I were designing an agent API today, I'd probably start by putting every action into one of three groups:

  1. Reversible. The system can restore the previous state reliably.
  2. Recoverable. It cannot literally undo the action, but there is a sensible recovery action.
  3. Final. Once this happens, the system cannot reliably take it back.

That classification immediately gives you something useful to build around. Reversible actions can usually run without stopping the user. Recoverable actions might need a little more care. Final actions are where confirmation starts earning its keep.

Instead of asking permission constantly, you ask when the agent is about to cross a boundary.

The action itself probably needs more information

This also changes how I think about exposing tools to an agent.

Take something boring like:

updateCustomerAddress(customerId, address)

The interesting bit isn't only the function name and its arguments. The product should also know what happened as a result of calling it. What was the old address? What is the new one? Which task caused the change? Can this specific change still be undone?

You don't necessarily need a complicated agent framework for this. A normal application could record something roughly like:

{
  action: "updateCustomerAddress",
  taskId: "task_123",
  before: {
    address: "12 Example Road"
  },
  after: {
    address: "18 Slightly Better Example Road"
  },
  reversible: true
}

The exact shape doesn't matter much. The important part is that "the agent updated something" becomes actual product state rather than a sentence buried somewhere in a chat log.

That gives you a proper history UI too. Instead of scrolling through a conversation trying to work out why a customer suddenly lives somewhere else, I could open the task and see exactly what changed.

More importantly, I could undo it.

An agent working through a project board while a visible action history records each change: changed label, moved ticket, updated priority, closed duplicate. The last entry has an Undo button, and pressing it hands the change back.

Undo the task, not 143 individual actions

Individual undo works until an agent starts doing larger jobs.

Suppose I ask one to reorganise 200 products, fix obvious naming problems and add missing descriptions. It changes 143 records. Technically, I could expose 143 undo buttons, but that feels like I've technically solved the problem while completely missing the point.

I'd rather treat the whole thing as one task.

Before the agent starts, create a checkpoint. Record every change against that task. When it finishes, give me something like:

143 products changed
81 categories updated
37 names edited
25 descriptions added
Review changes
Restore previous state

You don't necessarily need to copy half your database to make that work. Depending on the product, you might store previous values, use versioned records, soft delete things rather than really deleting them, or keep an event history you can replay backwards. There are plenty of fairly ordinary ways to build this.

A checkpoint taken before a task, followed by a chain of changes: move 38 products, rename 12 items, write descriptions, change categories. The end of the chain is a tangle of records, and a single arrow loops back to the checkpoint. Caption: restore the task, not 143 changes.

The interesting bit is making that recovery model part of the product rather than something engineers discover they need after an agent has helpfully modified 700 records.

Confirm the dangerous bit

This is the part I think we could use almost immediately.

Let the agent make reversible changes. Keep a clear history. Group related changes under the task that caused them. Create checkpoints before large operations. Then stop and ask when an action cannot safely be reversed.

An agent booking a holiday might search flights, compare dates, select seats and fill in passenger details without bothering me. Those are all temporary choices. The moment it reaches "Pay £842 and issue tickets", I want it to ask.

That permission means something because I haven't already approved seventeen harmless steps to get there.

There are some smaller rules I'd probably add too. Prefer soft deletion when agents can delete things. Make repeated calls safe where possible, so an agent retry doesn't create three orders because the first response timed out. Keep the original value when modifying important fields. Give task histories an actual place in the interface rather than hiding them inside an AI chat panel.

None of this is especially exotic. In fact, most of it is normal product engineering that becomes much more important once software starts taking several actions on somebody's behalf.

Maybe this is part of the agent interface too

WebMCP got me thinking about how websites might describe what they can do to an agent. Search these products. Add this item. Update this record. Book this room.

But I think describing capabilities is only half of it. We might also need to describe the consequences of those capabilities.

Can this action be undone? How long does undo remain available? Does it affect something outside the product? Should several actions belong to one checkpoint? Is this the point where the human needs to come back?

I don't know whether that eventually belongs in something like WebMCP, in application APIs, or simply in the architecture behind them. It might end up being a mixture of all three.

But if I were building agent actions into a product now, I wouldn't start with a confirmation modal in front of everything. I'd start by making as much as possible reversible, recording exactly what changed, and identifying the few places where reversal stops being reliable.

Then I'd put the confirmation dialog there.

At least when it interrupts me, it'll have a good reason.