I kept having the same problem with coding agents. I would ask one to run a build, test suite, or deployment, then lose track of what the command was doing inside the agent’s TUI. If the command ran for a long time, it might time out. If it failed, the useful part of the output was often buried in a large terminal dump.
Running the command inline was not much better. Every Nx status line, Playwright result, warning, and progress update went into the agent’s context. The agent usually needed one fact at the end: did it pass?
I started working around this with tmux. I would tell the agent to open a separate pane, run the command there, and check the pane when it finished. This gave me a terminal I could watch outside the agent’s interface. It also worked across different coding tools because agents are already good at running tmux commands and reading pane content.
The workaround was useful, but it was still a workaround. Agents would poll the pane every few seconds, recapture output they had already read, or miss the command’s real exit status. After using this pattern for a while, I asked an agent whether it should be a plugin or an MCP server.
That question became sidemux.
What sidemux does
sidemux is an MCP server that runs commands in real tmux panes. It works with Claude Code, Codex, OpenCode, and other clients that support stdio MCP servers.
The main loop uses three tools:
runstarts a command in a pane and waits for it to exit.waitblocks until a job exits, reaches a matching line, or becomes idle.readretrieves only the output the agent needs.
The waiting happens inside the local MCP server instead of the model’s tool loop. A command can run for minutes or hours without the agent spending turns asking if it has finished. When it exits, the agent gets the exit code and a short tail of the output.
If the command failed, the agent can ask for a filtered read:
read {since: "job", grep: "error|FAIL|AssertionError", context: 3}
If it is watching a dev server, since: "last-read" returns only lines written since the previous read. Full output is still stored in a per-job log file when a deeper investigation is needed.
The panes stay visible. They live in a dedicated tmux workspace, with headers showing what each pane is running. I can attach to the session or open the dashboard and watch the same command while the agent gets a compact result. That was one of my original requirements. I did not want efficiency to come at the cost of hiding the terminal from me.
The basic architecture is small:
coding agent
| stdio MCP
v
sidemux server
| tmux commands
v
live tmux panes
Terminal output is expensive context
Most terminal output has very little value after a command succeeds. It still takes up context, and the model has to carry that context through the rest of the session.
I added sidemux benchmark so I could measure this instead of relying on a feeling. It runs the same project command twice: once inline with full output captured, then once through sidemux over MCP.
On six build targets from one of my Nx monorepos, sidemux reduced terminal output entering context by 98.1% overall. The loudest Astro build dropped from an estimated 32,589 tokens to 132. Five Playwright suites showed a 98.9% reduction overall, with the largest dropping from 33,042 tokens to 90.
Those numbers depend on output volume. A quiet typecheck can cost slightly more through sidemux because the MCP response has its own small overhead. sidemux is most useful for verbose builds, test suites, dev servers, deployments, and jobs that run long enough to tempt an agent into polling.
Waiting is harder to put in a benchmark, but it was the original problem. During one real session, sidemux handled a 35-minute rewrite of 1,159 product descriptions, two 18-minute article passes, and an image job over 2,384 files. The agent spent zero turns polling those jobs. Each call returned when the work was done.
Finding the problems by using it
The first version proved the idea, then real work found all the ways it was wrong.
One job monitor reported completion immediately because the log contained the command the agent had typed. The completion string appeared in that command, so a grep found it before the process had done any work. Narrow panes wrapped long lines and broke file paths when the agent read them. A ten-minute timeout looked reasonable until I ran jobs that took half an hour. Pane listings from concurrent sessions leaked into each other and made it hard for an agent to tell which work belonged to it.
Each time, I brought the failed session back to the agent and asked what had gone wrong. We traced the behavior, filed an issue, wrote a failing test, and changed the design. The command-echo problem led to a strict exit marker containing the job id and numeric status. Wrapped captures now join lines and remove terminal escape codes. Timeouts now accept up to 24 hours. Pane ownership is scoped per agent session.
Two later failures were more subtle. A pattern wait could match old pane output when the caller only wanted lines written after the wait started. Another command returned to the shell prompt but remained marked as running because Nx had cleared the terminal and erased sidemux’s visible exit marker.
The fix for that second bug was to fall back to the raw pane log. tmux records the stream before the terminal clears its screen, so the exit marker is still there even when it is no longer visible in the pane.
This is where using AI to build the tool became more interesting than generating the first version. The agent was not working from an imagined set of edge cases. It had session logs, failed commands, and real tmux behavior to inspect. Every round started with evidence from the previous round.
The tool tested itself
I now run sidemux’s own lint, typecheck, test, and build gate through sidemux. During one maintenance session, three full gates produced about 103,000 characters of output. The agent ingested less than 1,000 tokens from them.
One of those gates failed. A targeted read returned 27 lines containing the test name, assertion difference, and source location instead of the full 39 KB Vitest log. The agent found an off-by-one error, fixed it, and reran the gate. The fail, diagnose, fix, and rerun loop used three tool calls.
I care about this beyond token savings. A command runner that tells an agent a failed test passed is dangerous. The agent will keep writing code on top of a broken state and do it confidently. sidemux refuses command environments where it cannot report an exit code reliably, and much of its test suite exists to make sure completion status is true.
Try it
The setup command detects common project scripts and adds instructions for the coding tools it finds:
npx sidemux init
You can then measure your own commands:
sidemux benchmark --command "pnpm test" --command "pnpm build"
sidemux requires Node 18 or newer and tmux 3.2 or newer. Source and setup documentation are available on GitHub. It is released under GPL-3.0.