Cellaflow | The coordination and durability layer for AI agents

· Cellaflow

9 min read Original article ↗

⚡ MEASURED AGAINST FOUR Y COMBINATOR-BACKED AGENT CODEBASES

When multiple agents attempt the same action, Cellaflow coordinates execution so they don't independently repeat it. The result is recorded and reused across competing requests, retries, and recovery after a crash.

The coordination problem

It charges the card. Then the process dies, the retry starts clean, and it charges again. Or a second agent was already doing it. Or a third reached a different conclusion and acted on it. None of them is wrong, and none of them can see the others.

Nothing in the retry path holds a record of what the process already did outside the system. The four codebases below are what that looks like in code you can run, and the quickstart lets you cause it yourself.

That is a coordination problem, and Cellaflow solves it. Agents stay independent; the decision about who acts is taken once, in one place, in front of the action itself.

Four Y Combinator-backed agent codebases

We took four open-source agent products, all of them built by Y Combinator companies, pinned them at a commit, and killed the process mid-run. No simulations, no toy loops. This is what their own code does today.

Each one reproduces in about two minutes on a laptop. No API keys and no model spend, because the failure has nothing to do with the model.

Run the benchmarksCan't a lock fix this? Or Temporal?

Try it live, on a real engine

Start a few agents on the same order: price the cart, place the order, email the customer. Add more while it runs, or kill one mid-step. Each agent joins both sides. On the left it keeps its progress in memory, as most agents do today. On the right it runs on a live Cellaflow engine on AWS.

The right side runs against a real Cellaflow engine on AWS, through the same Python SDK you would install. Each agent there is its own process, and Kill sends it SIGKILL. Only the shop and the outbox are simulated, and the order step takes 5 seconds so you can act while it is in flight. The counts come from what the shop and the outbox recorded, not from what the agents report.

How Cellaflow works

Not a queue, not a workflow language, not a rewrite of how your agents think. A single point every agent passes through on its way to the outside world, which knows who is already acting, what has already been done, and what the answer was.

01

Admit one caller.

Fenced leases with monotonic tokens, so of ten agents reaching for the same action, exactly one proceeds. A hard lifetime ceiling means a holder that hangs without dying cannot block everyone behind it.

02

Record what it produced.

The result and the journal write commit to an append-only execution ledger in a single transaction, so the work survives the process that did it. This is the part a lock cannot copy. Once a result is committed, a restart replays it instead of running it again.

03

Hand it to whoever asks next.

A later caller deriving the same key does not run the body. It is handed what the first call returned, across processes, across machines, and across languages. A Python agent and a TypeScript agent converge on one action.

A durable log preserves completed work. Coordination decides which caller executes and which ones are handed the result instead. The ledger records which caller executed each step, under the coordination id the work was done for. Recording who else asked for that work, and was handed the result instead of running it, is shipping now: a deduplicated caller never executes, so it leaves no step of its own and has to be recorded separately.

The obvious objections

A lock, the checkpointer you are probably already running, a durable workflow engine, and the idempotency key your payment provider already takes. Each one handles part of this. Below is the part it does not.

Start with the lock, because it is what a good engineer reaches for first. We built that arm and measured it. It closes every concurrency case and neither crash case, because a lock answers who may act and has nowhere to record what they did.

A process hangs without dying. Everyone else keeps moving.

A Postgres advisory lock frees on connection death, so a worker wedged on a slow model call holds it forever. Cellaflow leases carry a hard lifetime ceiling that is independent of heartbeats, so a zombie holder is reclaimed and the queue behind it drains.

Two agents disagree about the arguments. Neither acts blind.

Duplicate work is the easy case. The hard case is two replicas that derived slightly different plans for the same step. Cellaflow sees they are aiming at the same position in the graph and refuses the second before the side effect, rather than serialising two different actions and calling that safe.

“Isn't that what my checkpointer does?”

It restores your state, and it does that correctly. In the crash test above, PostgresSaver got it right both times: one seat reserved, the finished node skipped on resume.

The duplicate came from the order of two writes. Your node calls the API, the card is charged, and the node has not returned yet, so no checkpoint exists. The process dies in that gap. Resume reads a history where the node never ran, which is true, and runs it again. Second charge.

The other half is concurrency. Checkpoints are keyed by thread_id. Two agents on the same order are two threads, and neither history mentions the other. Both resume correctly. Both charge. A checkpointer records what happened. It never decides who acts.

Use both. The checkpointer restores where your agent was. Cellaflow decides whether the call it was making should happen again.

“Can't a durable workflow engine do this?”

It can, and Temporal is not the wrong answer. It is a good durable execution engine and nothing here is a gap in it. The difference is where deduplication attaches.

Temporal's attaches to the invocation. Its own documented idempotency key is the workflow run id plus the activity id, which it describes as unique among workflow executions, and there is no deduplication of an activity across two of them. So two agents running their own workflows and reaching for one refund are, to Temporal, two unrelated activities.

You can still get there. Promote the refund to its own workflow with a deterministic id and have each agent start-or-attach. That works, and it is a workflow to own, deploy and version. Cellaflow attaches at the step inside the agent you already have, so the same thing is an argument on the call.

This is granularity, not capability. If your side effects already live behind service handlers, you may not need another layer at all.

“Doesn't Stripe already deduplicate this?”

For Stripe, when every caller sends the same key. That is a real answer and it covers the case this page opens with.

It stops covering it when two agents reason their way to slightly different arguments. Different arguments derive different keys, so the provider sees two unrelated requests and honours both. That is the case a key cannot see and a position claim can.

And most of what an agent actually calls takes no key at all: sending the email, firing the webhook, clicking the button, writing to your own internal API.

Where a provider does take one, use it. The idempotency key is opaque to the engine, so you can hand it Stripe's. These do not compete.

Crash a workflow after a tool returns. Resume it with the same session id and watch Cellaflow replay the recorded result instead of running the tool again.

One decorator. The side effect here is simulated: place_order writes a line to a local file rather than calling a real shop, so you can run this with no keys and no account. What the example demonstrates is the replay, which is the part that behaves the same whatever the tool does.

Prerequisites: Docker Python 3.9+ or Node 18+

Three minutes

“Won't Kubernetes just restart the pod?”

Yes, and that's what causes the second order. If nothing restarted, you'd have one order and a failed run. The duplicate exists because something retried, and Kubernetes is the retry.

Kubernetes restores the process. Your checkpointer restores the state. Neither restores any knowledge of what the process already did to the outside world.

Read the full guide

docs.cellaflow.com/quickstart

Use Cases

What changes when a second agent arrives, and what a crash costs when nothing recorded what already happened.

Multi-Agent Architectures Are Distributed Systems

Go from one agent to two and you are running a distributed system, whether you planned to or not. Stale reads, lost updates and double-executed tool calls arrive with the second agent.

Read Case Study

What a Lock Cannot Fix

Two replicas refunding the same ticket is a locking problem, and a lock solves it. A process that completes the refund and dies before recording it is not. We built the advisory-lock arm against two real codebases and measured which rows it reaches.

Read Case Study

Eighteen of Thirty Agents Chose the Same Branch Name

Anthropic gave thirty agents identical prompts and a shared repository. Eighteen independently created a branch with the same name. Convergence is the mechanism a coordination layer depends on, and the hazard it has to arbitrate.

Read Case Study

Charged Twice After a Crash

Kill a computer-use agent partway through a three-step checkout and the retry charges the card again. Both crash positions, every run, on the current release. Mutual exclusion was never the missing piece.

Read Case Study

Your numbers

One estimate, from one assumption: when a run dies partway through, the steps it already paid for get paid for again. Inconvo is the measured case, where nine of fifteen model calls were repeated and the answer cost 60% more.

1,000 runs

8 steps

$0.05

4%

Free to self-host

The engine is free to self-host, in production, under a license that restricts only reselling it as a hosted service. One docker run and one install. If it does not do what this page says, the fastest way to find out is to break it yourself.

Talk to the person who built it

Thirty minutes with the engineer who wrote the engine. Useful if you have an action you cannot let happen twice and want to know whether this belongs in front of it, or if you have read this page and think something on it is wrong.

  • Where Cellaflow sits in a LangGraph or custom agent loop
  • What it does not cover, including the crash window nothing closes
  • Whether a lock would be enough for your case