Rolling Back AI Agent Actions: What Can Be Undone
Rolling back AI agent actions: which can be undone, which can only be compensated, and how holds, idempotency keys and decision records make recovery work.
Rolling back AI agent actions: which can be undone, which can only be compensated, and how holds, idempotency keys and decision records make recovery work.
TL;DR: Rolling back AI agent actions isn’t like rolling back a database transaction, because the agent’s actions commit in other systems. You can discard its internal state, compensate actions that have an opposite (release a reservation, revert a setting), and only mitigate actions that already left your hands (an email delivered, a payment settled). The work is done before the agent acts: hold instead of spend, make every call idempotent, and record each decision so you know exactly what to reverse.
A prompt change shipped at two o’clock. By three, someone noticed the support agent had been approving refunds it should have escalated. You reverted the prompt in a minute. Then came the real question: what did the agent do in that hour, and how much of it can be taken back?
In a database transaction that hasn’t committed, that question has a one-word answer: ROLLBACK. Other transactions can’t see its changes until it commits, so aborting discards them. Agents don’t work that way. Each tool call commits somewhere else, in a payment processor, an email provider, a CRM, a ticketing system, the moment it runs. There is no transaction around the agent’s run to abort.
So “rolling back” an agent is really three different operations, and which one you get depends on decisions you made before the agent ever ran.
Rolling back AI agent actions means reversing the effects of what an agent did. Only some effects can be reversed. Internal state can be discarded. External effects with a defined opposite, such as a reservation or a hold, can be compensated. Effects that already reached people or money, such as a sent email or a settled payment, can only be followed by a correcting action.
The useful question isn’t “can we undo this?” after the fact. It’s “which of these three kinds is each action?” before the agent is allowed to take it.
A refund is not an undo. It’s a second payment in the opposite direction, with its own fees, timing and failure modes. An apology email is not an undo either. The customer read the first one.
| Kind of action | Examples | What “undo” means |
|---|---|---|
| Internal | Agent memory, plans, drafts, scratch files, checkpoints | Discard or rewind it; nobody else saw it |
| Reversible external | A hold on funds, a reserved slot, a ticket status, a feature flag, a pending order | Run a compensating action with the opposite effect |
| Irreversible external | An email or SMS delivered, a payment settled, a trade executed, data shared with a third party | Nothing undoes it; you can only follow it with a correction, such as a refund or an apology |
Recovery starts by stopping new effects, in this order:
Pause the agent. Revert the bad version or switch the agent off, so no new decisions run.
Stop the executor. If pivots run through a separate executor, as in the pending-action pattern below, stop it too. Nothing that is held or pending becomes final while you investigate.
Zero the limits. Set the agent’s per-agent limits to zero. A run already in flight, or a retry queued before the pause, can’t place new holds.
Then work out what happened. Each step is cheap to reverse, and each one shrinks the set of effects you’ll have to compensate.
Agent frameworks offer checkpoints and “time travel,” and it’s tempting to treat them as rollback. They aren’t.
LangGraph’s time travel docs describe replaying or forking a run from a prior checkpoint. “Nodes before the checkpoint are not re-executed (results are already saved). Nodes after the checkpoint re-execute, including any LLM calls, API requests, and interrupts (which may produce different results).”
That’s the right tool for debugging and for exploring an alternative path. But read the second sentence carefully. Rewinding restores the agent’s state to an earlier point; it does nothing to the refunds the agent issued after that point. And replaying from there re-executes the API requests, so without protection a replay can issue them a second time.
Agent state is internal. Rewinding it is cheap and safe. The world outside is not part of the checkpoint.
“Rollback” also means reverting the agent: the prompt, model, tool set and rules that produced the bad hour. That’s common. A Sinch survey of 2,527 senior decision makers, released in May 2026, found that 74% of enterprises “have already rolled back or shut down an AI customer communications agent after deployment due to a governance failure.”
Reverting behavior is the easy half if the agent ships as one versioned bundle (prompt, model, tool manifest and rules) so that one switch restores the previous version. Record that version on every action; it’s the policy_version column in the table below, and it’s how you find the hour’s actions later.
Ship new versions to a slice of traffic first. Google’s SRE workbook defines canarying as “a partial and time-limited deployment of a change in a service and its evaluation” (Canarying Releases). A canary bounds how many actions a bad version can take before you notice.
Reverting the bundle stops new damage. It does nothing about actions already taken, and the rest of this page is about those.
For actions that have an opposite, the established answer is the saga. Hector Garcia-Molina and Kenneth Salem introduced it in Sagas (ACM, 1987) for long-lived transactions. A saga is a sequence of smaller transactions, and the system guarantees “that either all the transactions in a saga are successfully completed or compensating transactions are run to amend a partial execution.”
The paper is precise about what compensation means: “The compensating transaction undoes, from a semantic point of view, any of the actions performed by Ti, but does not necessarily return the database to the state that existed when the execution of Ti began.” In the paper’s airline example, cancelling a seat reservation subtracts one from the reservation count; it can’t simply restore the old count, because other transactions may have changed it in between.
Microsoft’s Saga pattern guide adds vocabulary that maps cleanly onto agent tools. Compensable transactions “can be undone or compensated for by other transactions with the opposite effect.” Pivot transactions “serve as the point of no return in the saga.” Retryable transactions follow the pivot; they “are idempotent and help ensure that the saga can reach its final state.”
For an agent, that suggests a rule for ordering tool calls: do every compensable step first, put the one irreversible step (the pivot) as late as possible, and make everything after it retryable. If anything fails before the pivot, compensate in reverse order. More on the pattern itself in the saga pattern entry.
Compensations can fail too. Make each one idempotent and retry it until it succeeds, or route it to a human.
The best way to make an action reversible is to split it into a reversible part and an irreversible part, and let the agent do only the first.
Card payments work this way already. Stripe’s docs on placing a hold on a payment method say “Authorizing a payment guarantees the amount by holding it on the customer’s payment method,” and capture is a separate step. If the authorization expires before capture, “the funds are released and the payment status changes to canceled.”
The same shape works for state you own:
Budget holds. The agent reserves 400 against a team’s budget. Spending happens only when the hold is converted, by a later check or a person.
Inventory and slot holds. The agent reserves a unit or a calendar slot with an expiry. If nothing confirms it, the hold lapses.
Pending actions. The agent writes “refund 120 to order 5531, pending” instead of calling the refund API. A separate executor, with its own checks, performs the pivot.
A hold is the agent’s decision made concrete without being final. If the decision turns out to be wrong, you release the hold. Nothing left your systems.
Rollback gets much harder when you don’t know how many times an action ran. Agents retry tool calls, harnesses replay steps after crashes, and recovery scripts re-run. Every external call with a side effect needs an idempotency key.
Stripe’s idempotent requests docs describe the contract: with an idempotency key, “if a connection error occurs, you can safely repeat the request without risk of creating a second object or performing the update twice.” Derive the key from the decision, not the attempt: decision_id + action, so that a replay of the same decision maps to the same effect. Keys don’t last forever: for its v1 API, Stripe says keys can be removed once they’re at least 24 hours old, and a key reused after the original is pruned creates a new request. A replay that runs later than that needs its own check, such as a lookup of the decision record.
Idempotency doesn’t reverse anything. It makes the set of effects you have to reverse finite and knowable.
Back to the bad prompt. To recover, you need to answer, quickly and completely: which actions did the agent take between 14:00 and 15:01 under prompt version 41, what did each one change, and what is each one’s compensation status?
If the answer lives in log lines spread across five services, recovery takes a day and misses things. If every action is a row, it’s a query.
CREATE TABLE agent_actions (
decision_id uuid PRIMARY KEY,
agent_id text NOT NULL,
policy_version text NOT NULL, -- prompt, model and rules version
decided_at timestamptz NOT NULL,
action text NOT NULL, -- 'hold_budget', 'refund', 'send_email'
kind text NOT NULL, -- 'internal' | 'compensable' | 'irreversible'
external_ref text, -- refund ID, message ID, hold ID
inputs jsonb NOT NULL, -- what the agent read
status text NOT NULL -- 'held' | 'committed' | 'compensated'
);
-- What does the bad deploy need undone?
SELECT kind, status, count(*)
FROM agent_actions
WHERE policy_version = 'v41'
AND decided_at >= '2026-10-12 14:00' AND decided_at < '2026-10-12 15:01'
GROUP BY kind, status;
An illustrative result, with constructed numbers: 23 refund holds still held (release them), 9 refunds committed (review each, and claw back only where policy allows), 5 customer emails irreversible (send a correction). Without the record, you’d know only that “some refunds went out.” The decision ledger entry covers this kind of record in more depth.
Recording the action and placing the hold should happen together. If the hold is written and the record isn’t, you have an effect nobody knows to release. If the record is written and the hold isn’t, recovery will try to release something that doesn’t exist.
Tacnode cannot undo an external effect. A payment that settled, an email that was delivered or a trade that executed is final in the system where it happened, and no store downstream changes that.
What Tacnode can hold is the reversible part. In the Tacnode Context Lake™, holds, per-agent limits, pending actions and the decision records for every agent action can live as the system of record (the decision context the agents read and write). That gives you three properties that matter for rollback:
The hold and its record commit together. Placing a budget hold, checking it against the limit, and writing the decision record run in one ACID transaction. Two agents can’t both fit into the same remaining budget, and there’s never a hold without a record.
Compensation is a transactional write. Releasing a hold and marking the decision compensated happen together, and an idempotent release can be retried safely.
The record is queryable. “Everything under policy v41 in this window, by kind and status” is a SQL query over the same store the agents write to, so the answer includes actions taken a moment ago.
Each decision written back is also context for the next one: an agent checking a budget sees every committed hold placed by every other agent, not a copy refreshed some time ago. Payments, emails and orders in the systems you run stay there; Tacnode doesn’t enforce anything inside a ledger it doesn’t hold.

Former Couchbase and IBM. Two decades helping enterprises adopt new database paradigms.
Fresh Context Newsletter
The argument behind the posts — what breaks when AI acts on stale data, from the team building the Context Lake. About twice a month.
Book a demo and discover how Tacnode can power your AI-native applications.
Book a Demo