close

DEV Community

Batty
Batty

Posted on

How tmux Became the Runtime for AI Agent Teams

tmux was built in 2007 for one purpose: run multiple terminal sessions inside a single window. Almost two decades later, it's quietly become the best runtime for AI coding agent teams.

Not because anyone designed it for that. Because the properties that make a good terminal multiplexer — session isolation, persistence, real-time output, and remote attach — are exactly the properties you need to run multiple AI agents in parallel.

Why agents need a runtime at all

When you launch an AI coding agent like Claude Code or Codex, it runs as an interactive process. It reads stdin, writes stdout, and expects a terminal. Run one and it's simple. Run three on the same repo and you need answers to:

  • Where does each agent's output go?
  • How do you see what all of them are doing simultaneously?
  • What happens when you close your laptop?
  • How do you send a message to agent #2 without disrupting agent #1?

You need a runtime that manages these processes. The question is which one.

The alternatives I tried

Docker containers. Each agent in its own container. Full isolation, reproducible environments. But the overhead is massive — each container needs the full repo, its own git state, and a way to merge results back. SSH or volume mounts add latency. And you can't just glance at what an agent is doing — you need to docker exec into each one.

Background processes with log files. The simplest approach. agent1 > agent1.log & three times. But you lose interactivity — you can't send a message to an agent, and reading tail -f across three files is miserable. When something goes wrong, you're grepping logs instead of watching it happen.

A custom TUI. Build your own terminal UI with something like ratatui. Maximum control, but now you're maintaining a terminal emulator. Every agent's output needs to be captured, rendered, and scrollable. Keyboard handling, resize events, color parsing — all of it. Months of work for something tmux already does.

What tmux gives you for free

Each pane is a sandboxed terminal. An agent in pane 1 can't interfere with an agent in pane 2. They have separate stdin, separate stdout, separate scroll buffers. The isolation is at the OS level — they're different PTYs.

Real-time visibility. Split your terminal into panes and you're watching all agents simultaneously. No log files, no refresh buttons, no dashboards. Just terminals doing work, live, at the speed they're actually running.

Session persistence. tmux detach and everything keeps running. Close your laptop, fly to another city, SSH in, tmux attach — your agents are still working. This isn't a feature you build; it's how tmux has always worked.

Output capture. tmux capture-pane -p dumps the current visible content of any pane as text. This is how a supervisor can read what an agent is doing without interrupting it. Hash the output every few seconds — if the hash changes, the agent is active. If it doesn't, the agent might be idle.

Message injection. tmux send-keys pastes text into a pane's input buffer. This is how a supervisor delivers tasks and feedback to agents — by literally typing into their terminal, the same way a human would.

Why not tmux

Honest limitations:

tmux is a hard dependency. It doesn't run on Windows natively. WSL works but isn't well-tested. If your team is on Windows without WSL, tmux isn't an option.

No built-in networking. tmux manages local processes. If you want agents on different machines, you need SSH + tmux, which works but adds complexity.

Layout is manual. tmux doesn't know what your agents are doing. A supervisor needs to create panes, assign agents to them, and manage the layout. This is work tmux won't do for you.

Not designed for programmatic control. The tmux CLI works but it's string-based. Error handling is parsing exit codes and stdout. There's no structured API, no JSON output, no event stream. You're wrapping shell commands.

The practical architecture

Batty uses tmux as its runtime. The architecture:

  1. Create a tmux session with zone-based layout — architects, managers, and engineers each get their own column of panes, split hierarchically
  2. Launch agents in their panes. Each pane gets a custom @batty_role option so the daemon can identify which agent is where, even if panes get reordered
  3. Stream output via pipe-pane — every pane's output is continuously piped to a log file (cat >> agent.log), giving the daemon a persistent record without screen-scraping
  4. Detect state via capture-pane — the daemon reads the last 50 lines, classifies what it sees (agent prompt? spinner? context exhaustion?), and tracks a state machine: Active → Ready → Idle → PaneDead
  5. Deliver messages via send-keys in literal mode — text goes into the pane's input buffer with a 100ms delay before Enter, so the agent processes the input cleanly

That's ~1,600 lines of tmux wrapping. Each command completes in 1-5ms. At a 5-second poll interval, the overhead is invisible.

Operators get supervisor hotkeys too: Ctrl-b P pauses automation, Ctrl-b R resumes. tmux user variables store the state — the daemon polls it on each cycle.

The key insight: tmux is not the supervisor. tmux is the runtime the supervisor uses. It handles process isolation, output management, and session persistence. The supervisor handles task dispatch, test gating, and merge coordination.

The pattern applies beyond AI agents

Anything that involves running multiple interactive terminal processes in parallel benefits from tmux as a runtime:

  • Parallel test suites across different environments
  • Multi-service development (API + worker + frontend)
  • Long-running data pipelines that need monitoring
  • Any workflow where you want to detach and come back later

tmux wasn't built for AI agents. But the properties that made it good for terminal multiplexing in 2007 — process isolation, session persistence, real-time output, remote attach — are exactly what agent orchestration needs in 2026.

The best runtime turned out to be the one developers already have installed.

Try it: cargo install batty-cliGitHub | Demo

Top comments (0)