Elixir and the BEAM for AI systems

What Elixir Gives a Coding Harness for Free

José Valim's case for Elixir as a coding-agent harness holds up on the runtime. The tax is the ecosystem around it — sandboxing, plugins, and SDKs.

TL;DR: José Valim posted that people are sleeping on Elixir as the substrate for a coding harness — the client you actually drive an AI agent through, not the backend that runs a fleet of them. He’s right about the runtime: hot-code reload, the actor model, and built-in distribution really do turn three hard harness problems into defaults instead of designs. He’s quieter about the tax: the sandbox boundary still has to be built by hand, the plugin ecosystem lives in TypeScript, and the model SDKs land in Python first. The runtime argument wins. The ecosystem argument is the bill that comes due every week you maintain the thing.

The claim, and why it’s not just BEAM boosterism again

I’ve made the general case before that the BEAM is the runtime AI agents want — that post was about running fleets of agents in production: supervision trees restarting crashed workers, process isolation containing failures, per-agent processes cheap enough to spawn thousands of. Valim’s tweet is a narrower and more interesting claim. It’s not about the thing agents run on; it’s about the tool a developer runs through — the Claude Code / OpenCode / Pi class of coding harness that reads a repo, edits files, and executes tools in a loop while a human watches.

He named three specific mechanics, not a general vibe:

People are sleeping on Elixir for a coding harness:

  • Hot-code swapping allows you to build an extensible plugin system similar to Pi, which reloads live without dropping state

  • Designing a client-server architecture, similar to OpenCode, is basically a byproduct of the actor model (plus you get both IO/CPU concurrency)

  • The built-in distribution means you can easily isolate the brains (model + session) from the hands (sandbox + tools). For example, you can [run] the agentic session on your machine which coordinates agents executing inside Docker or a remote node. Or even have one agent session coordinate multiple nodes (this is basically how Livebook works anyway)

Those can definitely be built from scratch in other languages, but in Elixir the building blocks are basically part of the runtime.

Each one is a real, specific harness problem, and that closing line is the actual claim. Not that Elixir can do these things — that you don’t build them.

Valim isn’t a neutral narrator here, and it’s fair to say so without treating it as a knock: he and Dashbit build Tidewave, an Elixir/Phoenix-native agent-tooling product, so he has real hands-on evidence for what the runtime buys. The disclosure runs the other way too, so take it as the preface to everything below: I ship this site on Phoenix, and I recommend Elixir to clients because it’s the right default for most of what gets built today. None of that is in tension with the costs I’m about to name. A language worth recommending is one whose limits you can state out loud.

Hot-reload solves the one thing every other harness fakes

A coding harness’s state is the conversation: the message history, the open-file context, the tool-call log the model is reasoning over. Every plugin system built on Node or Python has to solve the same problem when a plugin changes — reload the process and lose that state, or bolt on serialization so the session survives the restart. Most don’t bother; you restart the harness to pick up a new tool definition, and the in-flight session is gone.

Elixir sidesteps this because code reloading was never a hack bolted onto the language — it’s how the BEAM ships production upgrades without dropping connections, a capability that predates the AI harness use case by decades. A GenServer holding a coding session’s state doesn’t need to die to pick up a new module version; the process stays alive, the state stays in memory, and the code executing against it changes underneath it. For a plugin system, that’s the difference between “install a tool, keep working” and “install a tool, lose your context.”

Client/server and concurrency are what you get, not what you design

OpenCode’s shape — a headless server plus swappable clients (TUI, editor extension, web UI) — is an architecture other stacks have to deliberately design: pick a wire protocol, decide what state lives server-side versus client-side, build the reconnection logic. In Elixir it’s closer to the default shape of a GenServer plus however many client processes talk to it. You’re not inventing a client/server split so much as declining to collapse the one the actor model hands you.

The concurrency half of the claim is worth separating from the buzzword. A harness session is doing at least three things simultaneously: streaming tokens from the model (IO-bound), watching the filesystem for changes the agent should notice (IO-bound), and running the build or test suite the agent just triggered (CPU-bound). The BEAM’s scheduler handles both classes on the same set of lightweight processes without the harness author reaching for a thread pool and a separate async-IO runtime and gluing the two together, which is closer to normal in Python and Node harnesses today.

Can you actually isolate the brains from the hands?

Yes — and this is the part of Valim’s argument that’s least hypothetical, because Livebook already ships it. Livebook’s attached-node runtime lets a notebook process on your machine connect to and evaluate code on a completely separate Elixir node — the same primitive Valim is describing for a coding agent, just applied to REPL cells instead of tool calls. A minimal version of “session here, execution there” is genuinely a few lines:

Node.connect(:"sandbox@10.0.0.4")
Node.spawn(:"sandbox@10.0.0.4", Tool, :run, [cmd])

The session process, model context, and conversation history stay on your laptop; the Tool.run/1 call executes wherever sandbox@10.0.0.4 happens to be — a Docker container, a remote node, a machine that isn’t yours at all. One session coordinating several such nodes is the same primitive applied twice.

Where’s the tax?

The tax is everywhere the runtime’s elegance stops and the ecosystem around it starts.

The distribution primitive gets you coordination, not a sandbox. Valim names Docker himself — “agents executing inside Docker or a remote node” — and that passing mention is carrying the entire weight of the cost. Node.connect/1 and Node.spawn/3 move code execution to another machine; they say nothing about what that code is allowed to do once it’s there. A BEAM process is cheap and isolated for failure — a crash doesn’t take down its siblings — but that isolation was never designed against a hostile payload. A rogue tool call is a System.cmd, a NIF, or an open port, and none of those respect a process boundary. So the sandbox is still yours to build, out of Docker or a microVM or OS-level controls, and it’s a different discipline from the coordination layer sitting above it. For scale: even the far narrower problem of keeping parallel agents from colliding on ports, databases, and asset watchers took a whole post of Phoenix-specific plumbing, and none of that plumbing was a security boundary. Coordination is the easy 80%. The boundary is the 20% that actually protects you.

Plugin authors live in TypeScript, not Elixir. A hot-reloadable plugin system is only as valuable as the population willing to write plugins for it, and the people writing coding-agent extensions today write JS/TS almost universally — it’s the ecosystem every major harness (VS Code, Claude Code, Cursor) already targets. An Elixir harness either accepts a much smaller plugin pool, or embeds a JS runtime to host third-party plugins — at which point you’ve given back a chunk of the hot-reload story you built the system to get, because now two runtimes need to agree on what “reload without dropping state” means.

Model-provider SDKs land in Python and TypeScript first. I’ve made the general version of this point — the model layer was never the BEAM’s — but the harness version is narrower and bites more often, because it isn’t about local inference, it’s about protocol churn. Structured-output formats, new tool-call shapes, streaming-protocol changes — these ship against the two languages providers actually maintain official SDKs for. An Elixir harness maintainer is frequently doing the HTTP-level translation work a Python maintainer gets for free from pip install. I’ve written about building the agent loop itself in about fifty lines of Elixir, and the loop genuinely is that small — it’s the provider integration surface around the loop, not the loop, that recurs as a maintenance cost every time a provider ships a new feature.

So who should actually take the trade?

Distribution moves the execution. It doesn’t decide what the execution is allowed to do.

If you’re already running production Elixir — an Oban-backed job runtime, a Phoenix app, the stack you’d pick for an AI startup backend anyway — building an internal coding harness on the same stack is a genuinely good trade. You inherit hot-reload, distribution, and the concurrency model for the coordination layer, you’re not selling a plugin ecosystem to strangers, and you can lean on patterns like the durable Oban-based agent runtime for the parts that need to survive a restart. Your team already pays the Elixir-hiring and Elixir-SDK tax for everything else you ship; the harness doesn’t add a new cost, it just uses the one you already carry.

If you’re building a general-purpose harness for the whole market — competing with Claude Code, Cursor, or OpenCode for developers who’ve never touched Elixir — the ecosystem tax compounds against you on every axis that matters for adoption: who can write a plugin, who can read the source and contribute, how fast you track provider API changes. The runtime elegance doesn’t show up in the sales pitch; the plugin count and the time-to-support-the-newest-model do. That’s not an argument against Elixir — it’s an argument for knowing which of the two harnesses you’re actually building before you pick the stack.

If you’re weighing that call for a team already on Elixir — internal harness versus buying one, and where the sandbox boundary actually has to sit — that’s the kind of decision I work through with founders as a fractional CTO.