My assistant created the same task three days running. The fix has a name: idempotency.
A tiny automation bug taught the same lesson payment systems learned years ago: the question isn't whether it runs, it's what happens when it runs again.
I run a small automation that reconciles my inbox every morning. It reads the last week of mail in both directions, works out what's still waiting on a reply, and opens a task for anything that's genuinely open. Useful little thing. Then one week it created the exact same task three days running — same email, three near-identical tickets stacked on top of each other. Nothing broke. It just quietly made a mess I then had to clean up by hand.
Not broken. Just not idempotent.
The bug wasn't in what the routine did. It was in what it did the second time. Each morning it woke up, looked at that still-unanswered email, and reasoned — correctly, in isolation — "this needs a task." What it never asked was: did I already make one yesterday? There was no check for its own past work. Every run treated the world as a blank slate.
There's a precise word for what it was missing, borrowed from engineering: idempotency. An operation is idempotent if you can run it any number of times and the side effect happens exactly once. Create-a-task-for-this-email should have been idempotent. It wasn't, so running it three times created three tasks.
Payment systems solved this years ago
This isn't a new problem, and the people who worry about it most are the ones moving money. Stripe has a well-known engineering write-up on exactly this, and the opening premise is one every automation should start from: networks are unreliable. A request times out. The client isn't sure if it went through. So it retries — and now the server might be about to charge the same customer twice.
Their fix is the idempotency key: the client attaches a unique ID to the request, and the server remembers that ID. If a request with the same key shows up again, the server doesn't repeat the work — it returns the result of the first one. As their team puts it, an idempotent endpoint can "be called any number of times while guaranteeing that side effects only occur once." Retry all you like; the customer gets charged once.
The interesting question about any automation isn't "can it do the task." It's "what happens when it runs again."
The lesson for anyone wiring up AI routines
We're all building little agents and scheduled jobs now — inbox sweeps, report generators, things that fire every morning without us watching. And the failure mode is rarely the dramatic one. It's this quiet one: a routine that re-does work it already did, and hands you the duplicates to sort out. An agent that does slightly too much is often worse than one that does slightly too little, because the extra isn't value — it's noise you now have to filter.
My fix was the same shape as Stripe's, minus the payments. Before the routine creates a task, it now matches on a stable key — the email's thread ID — against the tasks that already exist. If there's already an open task for that thread, it updates it instead of adding a new one. The thread ID is my idempotency key. Run the job once or five times, one task exists.
Designing the routine like a system, not a trick
The reps show up in which question you ask first. A novice ships the happy path — the version where the job runs once, on a clean morning, and everything works. The happy path always works; that's why it's seductive. The discipline is to assume the thing will run again, overlap with itself, get interrupted halfway, and fire twice on the same input — and to make all of those safe. "Is this safe to run twice?" is a boring question that saves you from a hundred small messes.
It's the same instinct behind teaching my assistant to prep my week, where the hard part was making it stop starting over from scratch each run. It's why I don't fully trust an automation until I've watched how it behaves when it's wrong — the way the AI once told me nobody had replied when the reply was message 28. And it's the deeper reason a system only earns trust when the work moves without you standing over it. A routine you have to babysit for duplicates isn't saving you time. It's just moving the work to a different afternoon.
Idempotency is an ugly word for a simple, humane idea: build things that can repeat themselves without making a mess. Once you start asking "what happens on the second run?", you can't unsee all the places the answer is "something bad."
Sources & further reading
External
Stripe — Designing robust and predictable APIs with idempotency (why retries happen and how "exactly once" is guaranteed). Stripe API Reference — Idempotent requests (the idempotency-key mechanism in practice).
Related posts
I taught my assistant to prep my week. The hard part was making it stop starting over. Claude Cowork said nobody replied. The reply was message 28. The real test of a system is whether the work moves when you've left the desk.