The Container Model and Its Costs
When Warp Factories, Factory.ai, Devin, or OpenHands spawn an agent for a task, they provision a container. The sequence is approximately:
- Pull or verify the container image (seconds to minutes first time; seconds on warm cache)
- Allocate a new network namespace and mount overlay filesystem (~2–5 seconds)
- Start the init process and runtime (~5–15 seconds)
- Initialise the agent process inside the container
- Begin work
Total cold-start: 15–60 seconds. Warm-cache start: 5–15 seconds.
Memory footprint per container: a minimal agent container (Alpine Linux + Node.js + agent runtime) occupies 200–600 MB RAM at minimum. A Python-based agent with ML dependencies easily exceeds 1–2 GB.
Running 50 simultaneous container-based agents requires 10–30 GB RAM and 750–2,500 seconds of aggregate boot time — before a single line of code is produced.
What a BEAM Process Actually Is
The BEAM VM (Erlang's Bogdan/Björn's Erlang Abstract Machine) does not use OS threads or OS processes as its concurrency primitive. It uses lightweight green processes — user-space threads managed entirely by the BEAM scheduler.
A BEAM process:
- Starts in ~2–5 microseconds
- Has an initial heap of 233 words (~1.8 KB) that grows incrementally
- Has its own garbage collector — no global GC pauses
- Communicates via message passing only — no shared mutable state
- Is scheduled preemptively using reduction counting — not OS scheduler yield points
- Is isolated — a crash in one process does not affect any other process
A BEAM VM running on an 8-core machine can sustain millions of concurrent processes without degradation. The scheduler maps BEAM processes to OS threads via a work-stealing scheduler — one OS thread per CPU core, processes distributed across them.
The Numbers Side by Side
| Metric | BEAM Process (Myelix Agents) | Docker Container (Competitors) |
|---|---|---|
| Startup time | ~3 microseconds | 5–60 seconds |
| Initial memory | ~2 KB | 200 MB – 2 GB |
| 50 agents RAM | ~100 KB heap overhead | 10–100 GB |
| 50 agents start time | <1 millisecond total | 250–3,000 seconds aggregate |
| Process isolation | Message-passing only (no shared state) | Linux namespace + cgroups |
| Crash propagation | None — OTP supervision catches and restarts | None — container boundary |
| Scheduler | Preemptive, per-CPU work-stealing | OS scheduler (no agent awareness) |
| Max practical concurrency | Millions of processes | Tens to hundreds (memory-bound) |
OTP Supervision: The Part Competitors Have No Answer To
BEAM processes alone are not enough. The critical differentiator is OTP supervision trees.
In Myelix Agents, every agent process is supervised. The supervision tree defines:
- Which processes depend on which other processes
- What to do when a process crashes — restart it, restart its siblings, or escalate
- Restart intensity limits — if a process crashes more than N times in M seconds, escalate to the parent supervisor
defmodule OrchestratorApi.AgentSupervisor do
use Supervisor
def start_link(session_id) do
Supervisor.start_link(__MODULE__, session_id,
name: via_tuple(session_id)
)
end
def init(session_id) do
children = [
{PlannerAgent, session_id},
{ToolOrchestrator, session_id},
{SatisfactionEvaluator, session_id},
{ContextManager, session_id}
]
# :one_for_one: if a child crashes, restart only that child
# max 5 restarts in 60 seconds before escalating
Supervisor.init(children,
strategy: :one_for_one,
max_restarts: 5,
max_seconds: 60
)
end
end
When the ToolOrchestrator crashes — due to a malformed tool response, a timeout, or an unexpected error — the supervisor restarts only that process. The PlannerAgent, ContextManager, and SatisfactionEvaluator continue running, their state intact. The session resumes from the last stable checkpoint.
Container orchestrators (Kubernetes) can do something analogous at the container level — but with 5–60 second restart latency and the full container boot overhead. OTP supervision restarts a process in microseconds.
Workspace Isolation Without Containers
One legitimate advantage of container-based agents is filesystem isolation. When a container-based agent modifies files, it is modifying the container's overlay filesystem — not the host. The changes are isolated by default.
Myelix Agents achieves the same result without containers, using Git Worktrees.
When an agent is spawned for a task, the system creates a new Git Worktree — a separate checked-out working copy of the repository linked to the same Git object store. Each worktree:
- Has its own working directory — file reads and writes are completely isolated
- Shares the same commit history and objects — no duplication of repository data
- Can be on a different branch — the agent works on its own ephemeral branch
- Is created in milliseconds, regardless of repository size
- Is cleaned up automatically when the agent task completes or is abandoned
Two agents working on the same repository in parallel cannot see each other's in-progress changes. They share only the committed history, not the working tree.
Scheduling: Reduction Counting vs OS Preemption
BEAM processes are scheduled using reduction counting. Every function call, pattern match, and message receive costs a fixed number of "reductions". When a process consumes its reduction budget (~2,000 reductions per timeslice), the BEAM scheduler suspends it and runs another process.
This has a critical property: no process can monopolise a CPU core. An agent doing heavy JSON parsing in a tool result is suspended after 2,000 reductions and the CPU is handed to the next waiting process. Latency for other agents is bounded.
OS thread-based agents (Node.js, Python asyncio) rely on cooperative multitasking — a process only yields when it explicitly awaits something. CPU-bound work between awaits blocks all other coroutines. BEAM's preemptive scheduling has no such vulnerability.
The Practical Consequence
The economic and performance implications are significant:
- A developer's MacBook Pro with 32 GB RAM can comfortably run 50 concurrent Myelix Agents sub-agents. The same machine can run 5–10 container-based agents before memory pressure degrades performance.
- A 10-agent session starting simultaneously takes <1ms on Myelix Agents. On a container platform, the slowest agent determines when the parallel work can begin — easily 30+ seconds.
- A crashed agent is restarted before the LLM response for another agent finishes streaming. On a container platform, a pod restart is measured in seconds and involves rescheduling, image pull verification, and init process startup.
This is not a marginal improvement. It is an architectural-tier difference. The BEAM was built to run telephone exchanges processing billions of concurrent calls with six-nines uptime. Autonomous software agents are, by comparison, a gentle workload.
Why Other Platforms Do Not Use the BEAM
The honest answer is ecosystem momentum. Python and Node.js have the richest LLM SDK ecosystems. Most agent frameworks were written by developers who think in those languages. The BEAM requires learning Elixir or Erlang — a real cost.
But that cost is the moat. The concurrency model, the fault-tolerance model, and the scheduling model of the BEAM cannot be retrofitted onto Python or Node.js. asyncio is cooperative, not preemptive. Python's GIL prevents true parallel execution within a process. Node.js is fundamentally single-threaded. Container orchestration addresses scale — it does not address the per-process overhead that makes the fundamental economics different.
The Myelix Agents runtime is built on the only VM designed for exactly this problem. That is not a marketing claim. It is the reason we chose Elixir.