Rifty Notes
Glossary

Idempotency

Idempotency is the property whereby an operation produces the same end state whether it runs once or many times, so a safe retry cannot cause duplicate side effects. It is usually achieved by keying the operation on a stable identifier and deduplicating repeats, or by writing an absolute target state instead of a relative delta.

How it works

An idempotent operation is built so that applying it repeatedly leaves the system in the same state as applying it once. The property does not appear by accident; you design for it. Two mechanisms cover most cases:

  1. Idempotency keys. The caller attaches a stable, request-specific identifier. The server records which keys it has already processed and short-circuits repeats, returning the original result instead of acting again.
  2. Absolute writes. Instead of a relative mutation (add 1, append row), you express the operation as a target state (set count to 7, upsert row with id X). Replaying an absolute write is harmless because it re-asserts a state that is already true.

Reads are naturally idempotent. DELETE and PUT usually are. POST, appends, increments, and anything that emits an external effect — sending an email, charging a card, opening a ticket — are not, unless you wrap them in one of the mechanisms above. The cost is state: an idempotency ledger you must persist, key, and expire. If two concurrent calls share a key, you also need a lock or a compare-and-set so the second one waits rather than racing.

Why it matters in an agent harness

Agents retry constantly, and often for reasons the tool never sees. A tool call times out but actually succeeded. A reflection step decides the last action "didn't work" and re-issues it. A loop re-plans over a stale observation. A supervisor restarts a crashed worker mid-trajectory. In every case the same side-effecting call can fire twice.

Without idempotency, "the agent tried twice" becomes a double-charge, a duplicate deploy, two identical emails to a customer. With it, the second attempt collapses into a no-op and the incident never happens. This is what makes retries and durable execution safe to build on: a resumable workflow is only resumable because replaying its completed steps changes nothing.

Idempotency also shrinks blast radius. It lets you set aggressive retry and timeout policies without fearing amplification, and it lets a harness re-drive a job from its last checkpoint instead of reasoning about exactly which steps already ran. It is the property that turns an at-least-once delivery guarantee — the only kind most systems can actually offer — into effectively-once behavior.

Idempotency vs determinism

Operators conflate these, but they answer different questions. Determinism is about the output of a computation; idempotency is about the effect of applying it more than once.

DeterminismIdempotency
Question answeredSame inputs → same output?Repeat the operation → same end state?
Concerned withThe computationThe side effect
A non-deterministic LLM callFails determinismCan still be idempotent if keyed
A deterministic counter incrementPasses determinismFails idempotency (state drifts on replay)

The two are independent. An LLM tool call is non-deterministic yet can be made idempotent by caching the result under a request key, so a retry returns the first answer. A plain count += 1 is perfectly deterministic yet not idempotent, because each replay moves the state. You want determinism where you need reproducible reasoning and idempotency wherever a call touches the outside world.

The Rifty take

We treat idempotency as a precondition for autonomy, not a nice-to-have. An agent is only allowed to retry freely when its side-effecting tools are keyed and safe to replay; until then, every retry is a liability we'd rather not extend to the model. We accept the storage and bookkeeping cost of an idempotency ledger because it buys the thing we actually optimize for: an operation you can re-run without holding your breath. Reversibility undoes the wrong action; idempotency keeps the right action from compounding.

Implementation checks

  • Key on intent, not timing. Derive the idempotency key from the logical request (order id, target resource) so a genuine retry reuses it and a genuinely new action gets a fresh one.
  • Persist the ledger durably. An in-memory dedup table loses its guarantee on the exact restart where you need it most.
  • Handle concurrent duplicates. Two calls with the same key at once need a lock or compare-and-set, not just after-the-fact dedup.
  • Return the original result on replay. A duplicate call should get the first response, not a fresh error, so the caller can't distinguish a retry from a first try.
  • Set an explicit expiry. Decide how long a key is honored; too short reopens the duplicate window, too long grows the ledger unbounded.
  • Test the double-fire path. Assert that invoking each side-effecting tool twice with the same key produces one effect — most idempotency bugs hide until the second call.
  • Watch non-idempotent tools by default. Treat any unkeyed external write as at-least-once and gate it behind an approval or a guard until it's made replay-safe.

Frequently asked questions

What makes an operation idempotent?

An operation is idempotent when repeating it yields the same end state as running it once. You usually get this by attaching a stable idempotency key and deduplicating on it server-side, or by writing an absolute target state rather than applying a relative delta like an increment or append.

How is idempotency different from a retry?

A retry is the act of re-issuing a request after uncertainty; idempotency is the property that makes that retry safe. Without it, a retry can double-charge, double-send, or double-write. Retries are the reason you need idempotency, but they do not provide it — the operation's own design does.

Why does an agent harness need idempotency more than ordinary software?

Agents retry constantly — on timeouts, tool errors, reflection loops, and re-planning — and they act with real side effects. A non-idempotent tool call replayed by a confused loop can duplicate an irreversible action. Idempotency turns "the agent tried twice" from an incident into a harmless no-op.

Can every operation be made idempotent?

Not cleanly. Pure reads and absolute writes are naturally idempotent; relative mutations, appends, and external effects like sending email are not. You approximate idempotency for those with dedup keys, ledgers, or a check-then-act guard, but each adds durable state you must store, lock, and expire.

What is the relationship between idempotency and rollback?

They are complementary containment tools. Idempotency stops a repeated action from compounding; rollback reverses an action that should not have happened at all. Idempotency handles accidental duplication, rollback handles wrong decisions. A durable harness usually needs both, plus checkpoints to know which steps already ran.

Related glossary terms.

Idempotency