| name | gmux |
| description | Drive long-running terminal commands and AI coding agents through gmux sessions. Use when the user asks to run a command in the background, send input to a running session, wait for an agent's turn to finish, orchestrate multiple agents in parallel, or capture output from a tmux/screen-style session. |
gmux
A command run through gmux becomes a managed session the user can watch live
in a browser. The grammar is verb-first; running a command always uses the
explicit -- separator so gmux never guesses where its own flags end and
the command begins.
Primitives
gmux -- <cmd> [args]
gmux -d -- <cmd> [args]
gmux send <id> 'text' Enter
gmux send <id> C-c
gmux send --wait <id> 'text' Enter
gmux send --follow-up <id> 'text'
gmux send --steering <id> 'text'
gmux wait <id>
gmux wait <id> --for-text S
gmux tail <id> [-n N]
gmux tail --raw <id>
gmux ls [--json]
gmux kill <id>
ls IDs are 8-character prefixes; pass them directly to
send / wait / tail / kill. Tip: alias gm='gmux --' makes
gm pytest shorthand for gmux -- pytest.
Because gmux -- <cmd> propagates the child's exit code, it composes:
if gmux -- pytest -q; then ....
Sending input and keys
send types literal text; any trailing token that is a key name is sent as a
key. Enter is not implicit — add it to submit:
gmux send $id 'pytest -q' Enter
gmux send $id 'half a line'
gmux send $id C-c
gmux send $id Escape
echo "$body" | gmux send $id Enter
Key names follow tmux: Enter, Tab, Escape, Up/Down/Left/Right,
C-c, C-d, etc. For verbatim tmux compatibility there is also
gmux send-keys -t <id> <keys...> (with -l for literal text).
Everything after the id is verbatim — including dash-leading tokens, so
gmux send $id -v sends a literal -v with no -- guard needed. send's own
flags (--wait, --timeout, --follow-up, --steering) only work before
the id.
Prompting a busy agent: --follow-up vs --steering
When the target is an AI agent mid-turn, plain Enter vs the adapter's
queued-submit keystroke mean different things. Instead of memorizing
per-agent keybinds, use the mode flags — gmux appends the right submit
keystroke for the session's adapter (mutually exclusive; no trailing key
tokens; text only):
gmux send --follow-up $id 'then also update the changelog'
gmux send --steering $id 'stop — wrong branch, use main'
gmux send --wait --follow-up $id 'next task'
On an idle agent both are a plain submit. For agents whose Enter already
queues while busy (claude, codex) and for shells, both flags map to Enter.
Sequential orchestration
id=$(gmux -d -- pi "implement the feature")
gmux wait $id
gmux send --wait $id "$(cat review.txt)" Enter
gmux tail $id -n 100
Prefer gmux send --wait over gmux send … && gmux wait for "send a
prompt and wait for the reply": the two-command composition can observe the
previous turn's idle state and return before the agent has even started,
while --wait is race-free (the daemon arms the wait before delivering the
input and requires a fresh working→idle transition). --wait requires the
input to submit (a trailing Enter or a \r in piped stdin) and accepts
--timeout N; exit codes match gmux wait below.
Parallel orchestration
ids=()
for ticket in fa-48 fa-49 fa-52; do
ids+=( "$(gmux -d -- pi "Implement $ticket. Return when done.")" )
done
for id in "${ids[@]}"; do
gmux wait "$id" --timeout 600 || echo "$id failed: $?"
done
for id in "${ids[@]}"; do
echo "=== $id ==="
gmux tail "$id" -n 100
done
Waiting
gmux wait <id> blocks until the session goes idle — an agent finishing
its turn, a shell finishing its command and returning to a fresh prompt, or
a one-shot command's process exiting — optionally bounded by --timeout N.
Exit codes:
0 session reached idle (including a one-shot completing / a shell
exiting at its prompt)
2 session exited with its turn still open (crash mid-command/mid-turn)
3 --timeout elapsed
Every session is waitable. Shell sessions get per-command idle from OSC
133 prompt marks (fish emits them by default; bash/zsh need shell
integration): gmux send --wait <id> 'make build' Enter blocks until the
command finishes and the prompt returns. Sessions that never emit marks —
one-shot gmux -d -- <cmd> runs, or shells without integration — are one
lifetime-long turn: wait blocks until the process exits (gmux -d -- pnpm test; gmux wait $id waits for the test run). Careful: an interactive shell
without integration never exits on its own, so bound that wait with
--timeout or use an output condition below. Waits issued after the exit
answer the same as live ones.
To wait for specific output instead of idle, use --for-text <substr> or
--for-regex <pattern> (works for shell sessions too — no grep loop needed):
gmux wait $id --for-text 'listening on' --timeout 60
gmux wait $id --for-regex 'tests? passed: \d+' --timeout 120
Same exit codes (0 matched, 2 session exited first, 3 timeout). Matching
is line-wise against the rendered terminal output (ANSI stripped, same text
gmux tail --raw shows), including output that appeared before the wait
started, so the pattern must fit on one terminal line.
Reading a session's conversation
For agent sessions backed by a conversation file (pi), gmux tail prints the
conversation itself as markdown — ## User / ## Assistant messages with
compact [tool] … one-liners — instead of the TUI's terminal rendering.
-n counts messages there, not lines; thinking blocks and tool outputs are
omitted. This is the best way to read another agent's answer:
gmux send --wait $id 'summarize your findings' Enter
gmux tail $id -n 2
Shell sessions (and --raw) show terminal output instead.
Other agents have one-shot modes
Agents stay running by default. To make them exit after one prompt, use the
agent's print mode: pi -p, claude -p, codex exec:
gmux -- pi -p "summarize this PR"
Sessions on other machines
Sessions are local by default — bare IDs only ever match this host, so you
can't accidentally act on another machine. To address a peer session
explicitly, suffix the ID with @<peer> (see them with gmux ls --all):
gmux tail abc123@laptop
Reference