Leviath
One file describes the agent. One binary runs ten thousand of them.
A model, a toolset and a context budget per stage, not per agent. One 28 MB Rust binary, nothing else to install.
10,000+agents in one process64 msfrom nothing to a running agent28 MBone binary, nothing elseHow these were measured ↓
Install
curl -fsSL https://leviath.dev/install.sh | shWhat goes wrong
Long agent runs fall apart in the same five places.
Long runs forget what you told them
Fifty tool calls in, the one constraint you opened with has been squeezed out by file dumps and stack traces.
Context regions →Grepping costs what planning costs
One model, one toolset and one prompt run the whole job, so the reasoning you pay a premium for is also the thing listing your files, and the only thing judging whether a fifth identical edit was progress.
Stages →A crash mid-run means starting over, or doing it twice
The process dies with hours of tool calls inside it, and nothing left on disk can tell you which of them already wrote a file, ran a migration, or pushed a branch.
Run journal →A handful of agents fills the machine
Every run brings its own process, its own memory, and its own copy of the runtime, so the box runs out long before the work does.
One shared world →You can interrupt the agent, but not its sub-agents
Three levels down, a worker hits a question only you can answer and guesses instead, because the only conversation on offer is with the agent on top.
Live steering →One file you write, and two things you never touch
The file is where you say what the agent does: its steps, which model each step gets, when it should hand you the keyboard, when it should stop and rethink, and how much it keeps in mind. The runtime reads that file as a graph, and it is the same graph you watch a real run move through in The Lair, or from your terminal with lev dash.
Leviath ships with 7 agents, so you never have to write one to start. The file below is one of them.
[stages.plan] ← Stagesmode = "interactive_points" ← Live steeringmodel = { models = [{ provider = "anthropic", model = "claude-sonnet-5" }] }available_tools = ["read_file", "ask_user_choice", "edit_document"]max_iterations = 20[stages.implement]model = { models = [{ provider = "anthropic", model = "claude-opus-5" }] }available_tools = ["write_file", "edit_file", "bash"]max_iterations = 50[stages.implement.transitions.reassess] ← Stagescondition = "stuck"stuck_after_iterations = 20stuck_after_minutes = 15stuck_after_same_file_edits = 5hint = "No forward progress - step back and reassess"[context.regions] ← Context regionstask = { kind = "pinned", budget = "2%" }plan = { kind = "pinned", budget = "5%" }conversation = { kind = "sliding_window", max_items = 40, budget = "20%" }
Real lines, trimmed for length.
becomes
agent-chosen when stuck automatic▤ parallel workers
All three are The Lair, which is part of this site rather than part of the binary: it runs in your browser and talks to the daemon on your own machine, so no run has to leave your computer to be watched.
The two you will not find in that file are the two nobody should have to set up: every agent lives inside one process, thousands at a time on one machine, and every step is written down as it happens, so a run that gets killed picks up instead of starting over.
Write your own →Measured
Ten thousand agents, and the runtime out of the way
These came off one machine, an Apple M3 Max with 16 cores, running a mixed fleet of the bundled agents against a mocked model that answers in a flat 1.5 seconds, from one 28 MB binary.
Memory is live memory rather than RSS, which is the smaller of the two figures: what the process still holds once the pages the kernel can reclaim come out of it. CPU is a share of the whole machine, so 100% would be all sixteen cores.
The mocked model is the point: a real one would bury what the runtime costs under its own latency. So this is the floor the runtime adds rather than a forecast for your workload, and with a real model the first wall you meet is your rate limit rather than your machine.
Peak memory, by how many agents were running
Agents spawnedInference pool held at 512 for every tier, so the only thing changing is the number of agents. The runtime is paid for once, so the cost per agent falls as you add them: 3.4 MB each at ten, 0.28 MB each at ten thousand. That top tier is where the ladder stops rather than where the machine did: 2.8 GB of 128 GB, with CPU peaking at 44%.
Runs in flight at the same moment
Agents spawnedSame fixed pool of 512. Agents in this fleet start sub-agents, so more runs happen than were spawned; how many overlap at one instant is a separate number, and at ten thousand it comes out lower.
From cold, with nothing warm anywhere
ScenarioStarting the daemon is measured inside each scenario rather than subtracted from it, so the 64 ms to begin a run already contains the 22 ms to boot one.
CPU while 1,000 agents were running
Inference pool widthAveraged across the span where runs were actually active, so idle time at either end cannot flatter it: under 6% of sixteen cores at every pool width.
Time for 1,000 agents to finish, by inference pool width
Same fleet, same machine, one setting changed.Agents spawned, inference pool held at 512
- 10
- 100
- 1k
- 10k
Memory over the whole run, and after it
Live memorySeconds since the tier started
Every tier climbs while there is work and drops back to nothing when the last run drains. A leak would be the line that never comes back.
CPU over the same runs
Share of the machineSeconds since the tier started
Ten thousand agents hold the machine at roughly 40% of sixteen cores for eleven minutes, and the smaller tiers barely mark the axis at all. Most of what is left is time spent waiting on a model.
Inference pool width, 1,000 agents spawned
- 128
- 256
- 512
- 1,024
A wider pool puts more of the work in flight
Live memorySeconds since the tier started
The same thousand agents, four pool widths. A wider pool runs more of them at once, so the memory is higher while it lasts and it lasts a lot less time: 128 stays under 400 MB across five minutes, 1,024 peaks past 1.2 GB and is finished in ninety seconds.
CPU across the sweep
Share of the machineSeconds since the tier started
Note the axis: this one tops out at 20% of the machine, not 100%. Read the area rather than the height: the total CPU spent falls at every step, from 14.5 machine-seconds at 128 to 2.9 at 1,024 for the same thousand agents, mostly because the wider pool is finished sooner.
All three repetitions are drawn in every chart, not an average of them, which is why each colour is three lines almost on top of each other. The bars above report the median of the three, so the tallest line here runs slightly above its bar.
For scale
The closest thing to a comparison
We do not benchmark other frameworks. Whatever baseline we wrote, somebody could fairly say we wrote it to lose, so here is a benchmark someone else ran. It measures a different thing to ours, and both sets of numbers have gaps worth knowing about before you put them side by side.
Somebody else measured these, on a workload that is not ours, with a memory metric that is not ours either. What that leaves is context, not a scoreboard.
| Framework | Language | Peak RSS | CPU | Cold start |
|---|---|---|---|---|
| AutoAgents | Rust | 1,046 MB | 29.2% | 4 ms |
| Rig | Rust | 1,019 MB | 24.3% | 4 ms |
| LangChain | Python | 5,706 MB | 64.0% | 62 ms |
| PydanticAI | Python | 4,875 MB | 53.9% | 56 ms |
| LlamaIndex | Python | 4,860 MB | 59.7% | 54 ms |
| GraphBit | JS/TS | 4,718 MB | 44.6% | 138 ms |
| LangGraph | Python | 5,570 MB | 39.7% | 63 ms |
- Different workloads. Theirs sends 50 requests, 10 at a time; the ladder here spawns up to 10,000 agents. Neither answer substitutes for the other.
- Theirs calls GPT-5.1 over the network, so a good share of what it times is the model. We mock the model at a fixed latency, which isolates the runtime but also means we publish nothing about real end-to-end speed.
- The memory columns are close relatives rather than the same measurement. Theirs is peak RSS; ours takes out the pages the kernel can reclaim, which makes it the smaller figure. Subtracting one from the other would not mean much.
- Cold start is the thinnest column on either side. The article reports that these frameworks "initialize" in that time without defining what it covers, and two of them land on the same 4 ms, so there is not much to compare against. Ours measures more (a separate daemon starting and answering a socket) and is correspondingly slower, which is a difference in scope rather than a result.
- Reproducibility cuts both ways. Theirs does not name its cloud instances or how many times it ran, so a rerun would be hard to line up. Ours names the machine and the binary and publishes every repetition, on exactly one machine.
The Claude Agent SDK and Codex are not here because we could not find published figures for them on this axis. What circulates traces back to posts with no method attached, and a gap seemed better than a citation like that. If you measure them yourself you will have better numbers than anyone currently quoting them, ours included.
7 agents out of the box
Every one is a file like the one above, already written. Pick one to see its shape.
coderFull coding workflow with an approved plan, an optional spike, and stuck detection.
agent-chosen when stuck automatic▤ parallel workers
lev run coder --task "add rate limiting to the API"Also in the box: a terminal dashboard (lev dash) · sub-agents and fan-out · sandboxing and taint tracking · MCP tool servers · REST + WebSocket API · OpenTelemetry tracing
Who builds this
Leviath is written by Gerald McAlister, and it is MIT licensed. One person, in the open, with the changelog as the record of it.
Bugs, security reports and questions all go to the issue tracker, which is the only place any of them gets answered in public. Open an issue