Unix Isn't for Agents

2026-03-0513:361816pwhite.org

The fundamental mismatch between how Unix thinks about processes and what AI agents actually need.

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.

Unix assumes interactive sessions are mortal. Agents need interactive sessions that are immortal.

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.

In BEAM, "interactive" doesn't mean "attached to a terminal." It means "accepting messages."

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.


Read the original article

Comments

  • By chrisshroba 2026-03-0516:52

    Processes by default get stdin and stdout. If you run a command interactively from your tty, the tty shows your stdout and collects stdin from you to pass to the process. But nothing about Unix prevents you from hooking something else up to stdin and stdout. As another commenter said, you could use sockets and have a completely generic input and output stream which an arbitrary tool could read and write to. Or you could spin up a websocket server that spawns the process and converts between websocket messages and stdin/stdout bytes. Or http requests and long polled responses. Or read input from a speech to text stream and push output into a text to speech stream.

    I feel like OP’s main gripe is that persistent interactive sessions should be supported without a third party tool like tmux or screen or zellij, but one of the main strengths of Unix is that it provides platform building blocks which can be composed to create whatever experience you’re looking for.

  • By xyzsparetimexyz 2026-03-0516:301 reply

    It's not X it's Y ass blog post

    • By advael 2026-03-0519:45

      This might be my new favorite hn comment. At the very least it captures the zeitgeist perfectly

  • By jauntywundrkind 2026-03-0517:27

    Coincidentally, I noticed yesterday that Deciduous (a tool, skill-set, & program for LLMs to look at git history & build decision graphs) opened a draft to switch to Elixer, from rust. https://github.com/notactuallytreyanastasio/deciduous/pull/1...

    OTP Supervision is listed as one of the primary reasons for this switch. I also noticed: 15,441 lines added / 109,254 lines removed !

    There's definitely a bunch of agent related thing out there they have various daemons they kick off. I feel like often this is over some kind of fancy protocol, where there is still a somewhat thick CLI client. I wanted to play around with making a very thin CLI (and with a prefork model in rust) and wrote a little sample repo for myself to explore the idea: it just passes the stdin/stdout/stderr directly to the daemon, for it process with. https://tangled.org/jauntywk.bsky.social/pfd

HackerNews