Unix Isn't for Agents
Or: why tmux is a hack and BEAM might be the answer
I've been running Claude Code from a cloud VM lately. The workflow is: SSH in, start tmux, run Claude, work. When I disconnect, tmux keeps the session alive. When I reconnect, I reattach. It works.
But it's a hack. And the more I think about it, the more I realize the hack is papering over a fundamental mismatch between what AI agents need and what Unix provides.
Unix has two modes for processes: interactive and daemon.
Interactive means attached to a terminal. A human is present. When the terminal disconnects—when you close the laptop, lose the SSH connection, hang up the phone line (this is where SIGHUP comes from)—the process dies. This is the default. This is what Unix assumes you want.
Daemon means detached from any terminal. The process explicitly orphans itself: double fork, setsid(), close stdin/stdout/stderr. It runs in the background forever, logging to files, never interacting with anyone directly. Think web servers, databases, cron.
These two modes made sense for the world Unix was designed for. You're either a human typing commands, or you're a service running unattended. Interactive or automated. Present or absent.
Agents are neither.
An AI agent is:
Long-running—like a daemon. It might work on a task for hours. It needs to survive disconnection.
Interactive—like a terminal session. It's not just logging to a file. It's having a conversation. It needs input and produces output that a human (or another agent) will read and respond to.
Stateful—it maintains context. The conversation history, the working state, the plan it's executing. This state is the whole point.
Reconnectable—you should be able to disconnect, go for a walk, reconnect from your phone, and pick up exactly where you left off.
There's no Unix primitive for "persistent interactive process." The model assumes that if you want interaction, there's a human present, and humans eventually leave. When they leave, the session ends.
This isn't just convention. It's baked deep into the system.
The kernel tracks "controlling terminals." When you log in, your shell gets a controlling terminal. Processes you spawn inherit it. When the terminal goes away, the kernel sends SIGHUP to the session leader, which propagates to child processes. They die by default.
POSIX standardizes this. Sessions, process groups, controlling terminals, SIGHUP behavior—it's all in the spec. The assumption "interactive means ephemeral" is load-bearing infrastructure.
To make a daemon, you explicitly opt out: detach from the terminal, become a session leader with no controlling TTY, close the standard file descriptors. You're not just running in the background—you're abandoning the entire interactive paradigm.
There's no middle path. No "stay interactive but don't die when the terminal disconnects." The model doesn't have room for it.
tmux is a hack to create the missing primitive.
It's a daemon that pretends to be a terminal. Your shell thinks it's talking to a TTY, but it's actually talking to tmux, which buffers everything in memory. When you disconnect, tmux keeps running. When you reconnect, it replays the buffer and hands you back control.
This works. I use it every day. But it's a userspace workaround for a kernel-level assumption. You're running a program that fakes the existence of a persistent interactive session because the operating system doesn't believe such a thing should exist.
For AI agents, we're all running tmux. Or screen. Or nohup with tail -f. We're all working around the same missing primitive.
What would a system designed for agents look like?
Here's the interesting thing: it already exists. It's called BEAM.
BEAM is the Erlang virtual machine. It was designed in the 1980s for telephone switches—systems that needed to run forever, handle millions of concurrent connections, and never go down. The design constraints accidentally produced exactly what agents need.
In BEAM, processes are:
Lightweight—you can have millions of them. Each one costs about 2KB. They're not OS processes; they're VM constructs.
Isolated—each process has its own heap. No shared state. If one crashes, others are unaffected.
Addressable—every process has a PID. You can send it messages from anywhere. There's no concept of "attached to a terminal."
Persistent—processes run until they're done or they crash. There's no "session" that ends when someone disconnects. The process is the session.
Supervised—processes can be organized into supervision trees. If one dies, its supervisor can restart it. The state can be reconstructed.
This is the key inversion. Unix thinks interactivity requires a human present at a terminal. BEAM thinks interactivity is just message passing. You can send messages to a process from a terminal, from another process, from a web socket, from anywhere. The process doesn't care. It just receives messages and responds.
An "agent shell" built on BEAM might look like this:
Each agent is a process (a GenServer in Elixir terms). It has state—conversation history, current task, memory. It receives messages: user input, tool results, signals from other agents. It sends messages: output to display, requests to tools, coordination with other agents.
The agent process runs indefinitely. It doesn't care if you're connected. You "attach" to an agent by subscribing to its output and sending it your input. You "detach" by unsubscribing. The agent keeps running either way.
Phoenix LiveView—Elixir's real-time web framework—already does most of this for web UIs. You connect, you get a stateful server-side process that pushes updates to your browser. You disconnect, the process can keep running. You reconnect, you reattach to the same process.
The pieces exist. They just haven't been composed for agent use cases yet.
Why does this matter?
Because we're building the infrastructure for AI agents on a foundation that assumes agents shouldn't exist. Every time you SSH into a server and start tmux to run Claude Code, you're working around a fifty-year-old assumption about what "interactive" means.
The workarounds work. But they're friction. They're complexity. They're another thing to manage, another thing to break, another thing that makes agent usage feel like developer infrastructure instead of just... using a computer.
Someone is going to build the agent-native environment that treats persistent interactive execution as the default, not the exception. It might be built on BEAM. It might be something else. But it won't be built on the Unix interactive/daemon dichotomy, because that dichotomy doesn't have room for what agents actually are.
The computer science is already done. Erlang solved this in 1986. We just need to apply it to the agent problem—to build the shell that treats agents as first-class citizens instead of weird edge cases that need tmux to survive.