# Rui / रुई: a hundred agents in 7.4 MB

> 100 waiting agents take 210–517 MB in other harnesses and 7.4 MB in Rui. Where the memory goes, and how one process avoids it.

Published 2026-10-24.

I believe most agents will soon be started by other agents. A few years (okay weeks) ago, OpenAI [pointed about 10,000 agents](https://openai.com/index/navier-stokes-solution/) at the Navier–Stokes Millennium Prize problem and succeeded. I expect runs like that to become routine, with models trained to work alongside hundreds, if not thousands, of other agents.

That makes memory a scarce resource on a machine running agents. Most of the time an agent is just waiting for the model, so what matters is what a waiting agent costs. Today that cost is high: 100 waiting agents take 276 MB in pi and 210 MB in Codex app-server, and Jarred Sumner's [Bun AOT build](https://x.com/jarredsumner/status/2113933905300742383) of Claude Code takes 267 MB with 67 active subagents. At the rate pi and Codex app-server add per agent, 10,000 would need about 12 GB and 18 GB.

In [Rui](https://github.com/DivyanshGolyan/rui), my agent harness, the same 100 waiting agents cost 7.4 MB, and 10,000 would need about 200 MB.

<figure>
	Figure: Memory with 100 waiting agents, log scale: Rui 7.4 MB, Codex app-server 210 MB, pi 276 MB, fx 476 MB, OpenCode 517 MB.
	<figcaption>Rui holds 100 waiting agents in 7.4 MB. The next lightest harness needs 210 MB, about 28 times as much.</figcaption>
</figure>

## A swarm pays for memory in three ways

In my testing, about 85% of each turn went to waiting on the model.

<details class="figure-data">
	<summary>Where each turn's time went</summary>

| Stage | Share | Per call |
| --- | ---: | --- |
| Model: network and generation | 84.7% | median 1.76 s per model call |
| Bash running | 4.7% | median 66 ms per session |
| Rui polling: waiting for dispatch | 4.3% | 105 ms per model call |
| Rui polling: Bash exit to cleanup | 3.0% | about 125 ms per Bash call |
| Rui polling: completion pickup | 1.1% | 26 ms per model call |
| Rui polling: admission to first request | 1.1% | about 70 ms per session |
| Rui’s own work | about 1% | 10–20 ms per model call |

15 sessions, 42 model calls, 27 Bash calls, 101.9 s in total.

</details>

So an agent mostly holds a conversation open while the model thinks. A swarm then costs the harness's starting memory, plus what each waiting agent adds times the number of agents.

The first is keeping each agent's state in memory while it waits. Harnesses that run every agent in one process, like Codex app-server and pi, add about 1.8 MB and 1.2 MB for each one.

The second is giving every agent its own process. Each process brings its own copy of everything: a heap, threads, a connection to the model. fx does this, at about 4.8 MB per agent. Many harnesses do, because they were built for one person driving one agent in a terminal.

The third is loading a heavy runtime before any agent starts. OpenCode's server takes 300 MB before its first agent.

Rui avoids all three. Here is how the five harnesses compare as agents are added.

<figure>
	Figure: Memory at 0, 1, 10 and 100 waiting agents, log scale: Rui 5.8 MB, 6.7 MB, 6.8 MB, 7.4 MB; Codex app-server 16.7 MB, 25.9 MB, 48.9 MB, 210 MB; pi 125 MB, 146 MB, 166 MB, 276 MB; fx 2 MB, 4.4 MB, 47.8 MB, 476 MB; OpenCode 300 MB, 393 MB, 439 MB, 517 MB. A shaded band marks 0 to just past 1 agent, where fx uses less memory than Rui.
	<figcaption>Where a line starts is what a harness costs before any agent. How steeply it climbs is what each agent adds. Rui starts at 5.8 MB and barely climbs.</figcaption>
	<details class="figure-data">
		<summary>Numbers</summary>

| Harness | 0 agents | 1 | 10 | 100 | Added per agent |
| --- | ---: | ---: | ---: | ---: | ---: |
| Rui | 5.8 MB | 6.7 MB | 6.8 MB | 7.4 MB | 7.5 KB |
| Codex app-server | 16.7 MB | 25.9 MB | 48.9 MB | 210.4 MB | 1,795 KB |
| pi | 125.3 MB | 145.5 MB | 165.7 MB | 275.7 MB | 1,222 KB |
| fx | 2.0 MB | 4.4 MB | 47.8 MB | 475.9 MB | 4,757 KB |
| OpenCode | 300.3 MB | 392.5 MB | 438.7 MB | 516.7 MB | 866 KB |

Physical footprint, median of 3 runs. Added per agent is the growth from 10 to 100 agents, divided by 90. Rui and pi were measured in a later session than the others. Rui's per-agent figure is within the method's noise: the same build measured 0.2 KB in the earlier session.

	</details>
</figure>

## One process runs every agent's loop

Simplified, an agent is a loop which sends user inputs to an API and gets back outputs, which it shows the user or acts on in the environment. The loop goes on until something interrupts it: the environment, the user, or the model itself. This loop needs little memory. What it needs is the network stack, the storage stack, and small bits of information for coordination.

This is the same loop across every agent, so you don't need a separate process for each one. One process can run the loop for all of them: it stores the state and runs the network stack.

In Rui that process is the Host. Rui is a compiled Zig program, so there is no runtime to load first, and the Host starts at 5.8 MB. It loads its network stack and SQLite once. Every agent's request goes over one shared connection, and one event loop watches all of them, so no agent needs its own thread.

A waiting agent's request is one stream on the shared connection, and everything else about it is rows in SQLite, so memory doesn't grow with conversation length.

<figure>
	Figure: Left: 100 agents as 100 separate processes, each with its own heap, threads and connection (fx: 700 threads). Right: one Host process with one heap and one connection, holding 100 agents as rows (Rui: 6 threads).
	<figcaption>A process per agent pays for a heap, threads and a connection 100 times. One Host pays once.</figcaption>
</figure>

So a turn should cost almost nothing. Follow one agent, swarm/42, through one.

## One turn costs a few KB

- **Send.** You send swarm/42 a message. Rui saves it to SQLite first, so it survives a crash.
- **Admit.** If one of the 100 slots is free, swarm/42 takes it. If not, it stays a row and waits.
- **Request.** Rui builds the request from the saved conversation and sends it over the shared connection. This is the only step that costs memory.
- **Wait.** The model thinks. This is most of the turn, and nothing runs for swarm/42 while it waits.
- **Answer.** The answer streams in through a small fixed buffer and goes straight to SQLite.
- **Bash.** If the model asks to run a command, Rui starts it as a separate process. That memory belongs to the command and is freed when it exits.
- **Release.** The result is saved and the slot is freed. swarm/42 is just rows again until its next message.

The few KB the Request step adds are mostly curl, the library Rui uses to talk HTTP. Everything else was set aside once, when the Host started.

## What one process costs you

Running every agent in a single process has a cost too: one shared limit, and one point of failure.

The limit is the number of slots. Say you start Rui with the default 100 slots. A slot holds one piece of running work, either a model call or a Bash command, so up to 100 agents can be working at once. Agent 101 waits as a row until a slot frees up. It has no request built and costs no memory while it waits. (Past the point where the provider rate-limits you, more slots only buy more retries.)

If the Host crashes, every agent stops with it. No saved work is lost, because the Host saves every message and result in SQLite before it acts on them. Start the Host again and the work is still there.

## Start a swarm

Rui runs on Apple Silicon Macs and x86-64 Linux, and works with OpenAI's Codex models today, so you need a ChatGPT account. [Install Rui](https://github.com/DivyanshGolyan/rui#install), sign in and pick a model:

```sh
curl -fsSL https://github.com/DivyanshGolyan/rui/releases/latest/download/install.sh | sh

rui auth login codex
rui defaults configure --model gpt-6.1-sol
```

Then run `rui` in your project and ask for a swarm:

```text
Split this repo into areas, start one agent per area to look for bugs, and give me one list of what they find.
```

Those agents will spend most of their time waiting. In Rui, a hundred of them wait in 7.4 MB.

## How I measured

_Everything ran on one MacBook Pro (M1 Pro, 16 GB). Rui measured between 6.4 and 7.4 MB at 100 agents across two sessions. Each harness talked to a fake model that accepts every request and never answers, so every agent stays waiting on the model with its request open. Rui talked to it over TLS and HTTP/2, the others over plain HTTP, which costs Rui a little extra. Rui's requests carried one tool, Bash, and the others carried 4 to 15, so part of their memory pays for features Rui doesn't have. The others were Codex app-server 0.164.0, pi 1.4.0, fx 0.0.14 and OpenCode 1.19.4. I count the physical footprint, the memory macOS charges to each process, summed over every process a harness starts. I don't use RSS, because it counts shared program code once per process and inflates any harness that runs a process per agent. For 10,000 agents, Rui needs 10,000 slots: an idle Host started with 10,000 slots takes about 100 MB, or about 10 KB per slot, before each agent adds its 7.5 KB. The turn timings come from 15 live sessions on gpt-6-luna, run one at a time, each a small task that calls Bash._
