A tmux wrapper for managing long-running commands, built for the case where both an AI agent and a developer need to observe and control the same processes.
Dev servers, watchers, and builds need to persist across many short-lived agent
turns. Plain tmux works, but it leaves friction on both sides: session names are
arbitrary and easy to forget, there's no project scoping (one list shows
everything), and a crashed process just disappears. An agent can't reliably find
"the dev server for this project" without bespoke plumbing.
omux removes that friction with one idea: the command is the session name.
Sessions are deterministic and project-scoped, so omux run 'bun run dev' is
safe to call repeatedly — it no-ops if the process is already running, respawns
it if it died, and an agent never has to track any state to find it again.
bun install bun link
Requires: tmux
omux run 'bun run dev' # Start command in tmux (idempotent) omux run -k 'bun run dev' # Kill first, then start fresh omux run -a 'bun run dev' # Start and attach (read-only) omux run -k -a 'bun run dev' # Restart and attach omux list # List sessions for this project omux list --global # List all sessions globally omux read 'bun run dev' # Read last 50 lines of output omux read 'bun run dev' -n 100 # Read last 100 lines omux attach 'bun run dev' # Attach to session (read-only) omux logs 'bun run dev' # List log files omux send 'bun run dev' 'r' # Send input to session omux kill 'bun run dev' # Kill a session omux killall # Kill all project sessions omux killall --global # Kill all sessions globally
Commands must be quoted - this avoids issues with paths, pipes, and special characters.
Sessions are named omux-{project}-{command-slug}:
{project}= current directory name (dots/colons become underscores){command-slug}= command with spaces as dashes (dots/colons become underscores)
omux run 'bun run dev' → omux-myapp-bun-run-dev
Because the name is derived from the command, running the same command twice is idempotent - there's nothing to look up and no way to accidentally start a duplicate.
Every run also pipes the pane's output to a log file (ANSI escape codes
stripped on the way in, so logs are clean text). omux logs lists them.
- Isolated - uses a dedicated tmux socket (
-L omux), so omux sessions never collide with your normal tmux - Idempotent -
runis safe to call repeatedly; respawns dead processes, no-ops live ones - Visible failures - dead processes remain visible with exit status (via
remain-on-exit) - Command = session name - predictable, no manual naming
- Project-scoped -
listandkillallonly touch sessions for the current directory;--globaloverrides
When a process exits, the pane stays around showing the exit status:
Pane is dead (status 1, Thu Jan 22 17:54:07 2026)
Pane is dead (signal segv, Thu Jan 22 17:58:44 2026)
Running omux run again respawns the process. Use omux kill to clean up dead sessions.
~/.cache/omux/tmux.conf- generated tmux config (setsremain-on-exit onand apane-diedlog hook)~/.local/share/omux/logs/{project}/- per-session log files- Socket:
tmux -L omux- isolated from your normal tmux server
These paths and the socket name can be overridden with environment variables:
| Variable | Default | Purpose |
|---|---|---|
OMUX_SOCKET |
omux |
tmux socket name (-L) |
OMUX_CACHE_DIR |
~/.cache/omux |
location of the generated tmux.conf |
OMUX_LOG_DIR |
~/.local/share/omux/logs |
per-session log output |
OMUX_CWD |
current directory | project root used for naming and scoping |
- Auto-restart or process supervision