Lacunari

Writing

Lacunari vs. LangGraph, CrewAI, and AutoGen

The FAQ answer is two sentences: different problems, they compose. That's true, but it's also the kind of true that lets you avoid saying anything mechanical. Here is the actual distinction, with the parts of each system that make it real.

LangGraph, CrewAI and AutoGen are workflow engines for agents. They differ from each other in API shape and opinionatedness, but they solve the same category of problem: given a task, decide what steps happen, in what order, with what retries, and how results from parallel branches recombine. That category has a name, orchestration, and all three are good at it in ways Lacunari does not attempt to be.

Lacunari solves a different category. Given several independent agents that may be on different machines, different vendors, or not even running at the same time, make sure they never duplicate or overwrite each other's work, and make sure work started survives the process that started it. That category doesn't really have a settled name. "Coordination layer" is the closest fit, and it's deliberately a lower-level, less opinionated thing than a workflow engine.

What a graph engine actually gives you

Take LangGraph as the representative case, since its model is the most explicit. You define a graph: nodes are steps, edges are transitions, and the graph can branch, loop, and fan out to run several nodes concurrently before fanning back in to a join node that waits for all of them. State flows along the edges as a typed object every node can read and update. Retries are a property you attach to a node. The whole graph can checkpoint its state and resume from a specific point after a crash: deterministic replay of one run.

CrewAI and AutoGen wrap similar mechanics in a more agent-shaped API. Think "crews" of role-playing agents, or a "group chat" where a manager routes turns between participants. The underlying commitment is the same: one orchestrating process holds the state, decides what runs next, and owns the retry and recombination logic. That process is usually one language runtime and, in practice, one model vendor's SDK conventions baked into how tools get called.

This is exactly what you want when your problem is a graph: a research agent that must finish before a writer agent starts, three scoring functions that need to run in parallel and get compared, a retry policy for the step that calls a flaky API. None of that is what Lacunari does. There is no fan-out/fan-in here, no conditional branching, no deterministic replay of "what happened in this run." The README says this plainly under "what it is not."

What a durable shared queue gives you instead

Lacunari's unit is not a graph, it's a task row in Postgres. A task is claimed with a single atomic UPDATE, which means the claim is safe against two completely unrelated processes racing for it at once: different machines, different languages, different vendors. Nothing about the claim mechanism assumes the claimer is even the same kind of thing twice in a row. A Claude Code session can claim task #4, and a cron job running a Python script can claim task #5, and neither needs to know the other's runtime exists.

That is the property none of the three frameworks are built for, because none of them need it. Within one LangGraph process, there's no "another process might claim this node instead" problem, because there's one process running the graph. The problem only exists once you have multiple independent workers that don't share memory, don't share a process, and might not even be running at the same moment.

$ lac work --lanes backend & # laptop, Claude Code $ lac work --lanes research & # server, a GPT worker $ lac work --lanes ops & # cron job, no model at all

Kill any one of those mid-task and the lease expires, the keeper releases the claim, and a different worker, possibly a different vendor entirely, finishes it. There is no equivalent operation in a graph engine, because the graph engine's checkpointing resumes its own run in its own process. It was never designed to hand an in-flight step to an unrelated worker on a different machine.

The file-locking difference specifically

This is worth calling out on its own, because it's the concrete failure mode that motivates the whole project. When a graph engine fans out three nodes in parallel, the framework does not stop two of them from writing to the same file. That's not what fan-out means; it means "run these steps concurrently." If two of your nodes happen to both edit auth.py, nothing in LangGraph, CrewAI or AutoGen notices until you look at the diff. They manage control flow between steps, not writes to a shared filesystem outside the graph.

Lacunari's claim locks the files a task declared it will touch, and a second worker is refused before it starts, told which task and which agent holds the file, rather than discovering the collision at merge time. That's a narrower guarantee than a graph engine's retry and checkpoint machinery, but it's a guarantee about a different thing: not "did this step succeed," but "did two workers touch the same file at once."

When you'd want one, the other, or both

  • Just a graph engine. Your problem decomposes into steps with a real dependency order, inside one process, usually one vendor. A research-then-write pipeline. A scoring fan-out that must recombine. Retries matter more than cross-machine durability. Use LangGraph, CrewAI, or AutoGen: they are better at this than Lacunari will ever try to be.
  • Just Lacunari. You have several independent agents, possibly different vendors, possibly on different machines, possibly a human with psql, pulling from one backlog of mostly-independent tasks, and the failure you're trying to prevent is duplication and silent file collisions rather than step ordering.
  • Both, composed. A LangGraph pipeline is one task on the Lacunari board. It claims the task, runs its internal graph (fan-out, retries, checkpointing, all of it) and reports back done, refused, or blocked. Lacunari doesn't reach inside the graph, and the graph doesn't need to know a queue exists outside it. This is the same relationship Lacunari has with git: each does the part it's actually good at, and neither is trying to replace the other.

The shape of the actual boundary

If you want the one-sentence version to keep: a graph engine coordinates steps inside a run, and Lacunari coordinates workers across runs, processes, and machines. Confusing the two gets you either an orchestration framework straining to be a durable cross-machine queue (the checkpoint-and-resume story was never built for a different vendor's runtime to pick up the checkpoint) or a queue straining to express fan-out/fan-in and conditional branching it was deliberately built without. Pick based on which failure you're actually trying to prevent.


How Lacunari works →  ·  Why not just use git?  ·  More answers