vmux
Appsvmux Daemon

Pane Commands

Create, split, launch, signal, close, and wait on panes inside a daemon-managed session.

Panes are the unit of work in vmux. Each pane owns one PTY and tracks one process lifecycle. The pane subcommands are designed for both interactive use ("split this window in half") and scripting ("launch this build, wait for exit, get the code").

CommandPurpose
vmux pane createCreate a new pane in an existing session/tab, optionally as a split of another pane.
vmux pane launchRun a specific argv inside a pane, with explicit cwd, env, and role.
vmux pane signalSend a Unix signal (SIGINT, SIGTERM, custom) to a pane's process.
vmux pane closeClose a pane and tear down its PTY, optionally --force (SIGKILL).
vmux wait-pane-exitBlock until a pane reaches a terminal runtime state, exit with the pane's exit code.

All pane commands work with pane UUIDs. You get those from vmux state, from the return value of vmux pane create, or by listing them with jq on the state JSON.

vmux pane create

vmux [global-flags] pane create
    [-s NAME-OR-UUID | --session NAME-OR-UUID]
    [--tab UUID]
    [--from PANE-UUID]
    [--axis horizontal|vertical]
    [--role shell|teammate|system|unknown]
    [--title STRING]

Create a new pane and print its UUID on stdout.

FlagDefaultEffect
-s, --session, --nameserver defaultSession to create the pane in. Accepts a name or a UUID.
--tab UUIDactive tab of the sessionTab to create the pane in.
--from PANE-UUIDnoneSplit this existing pane in half. Required when you want a split layout.
--axis horizontal|verticalinferredDirection of the split. Only meaningful with --from.
--role shell|teammate|system|unknownshellLogical role; surfaces in state and in GUI clients (e.g. teammate panes get a different chrome).
--title STRINGemptyDisplay title shown in chrome.

Without --from, the new pane is added to the session/tab as a fresh root or sibling. With --from, the targeted pane is split — the existing pane stays alive and the new pane gets the other half.

A freshly-created pane is in idleShell state: there is no process running yet. It does not have a shell unless you also call vmux pane launch.

# Add a pane to the active tab of "work"
NEW=$(vmux pane create -s work --role shell --title "build")

# Split an existing pane vertically (top/bottom)
SOURCE=$(vmux state -s work | jq -r '.tabs[0].activePaneID')
vmux pane create -s work --from "$SOURCE" --axis horizontal

Split axis convention: horizontal means the split line runs horizontally — i.e. one pane stacked on top of another. vertical means the split line is vertical — panes side by side.

vmux pane launch

vmux [global-flags] pane launch <PANE-UUID>
    [--cwd PATH]
    [--env KEY=VALUE]...
    [--title STRING]
    [--role shell|teammate|system|unknown]
    [--task-id ID] [--task-title STRING] [--agent-name STRING]
    [--replace]
    -- <argv...>

Run a process inside an existing pane. Everything after -- is the literal argv for the new process. The first positional argument before -- is the pane UUID.

FlagDefaultEffect
--cwd PATHinherited from daemonWorking directory of the new process.
--env KEY=VALUE (repeatable)inheritedAdd an environment variable. Repeat the flag to set more than one.
--title STRINGemptyPane title to show in chrome while this process runs.
--roleshellLogical role recorded with the launch.
--task-id, --task-title, --agent-namenoneOptional teammate metadata; surfaces in state.panes[].teammate. Source is recorded as vmux-cli.
--replacefalseIf a process is already running in this pane, terminate it before launching. Without this flag, launching into a busy pane fails.

Examples:

# Run "make test" with a project-local PATH and BUILD_ID
PANE=$(vmux pane create -s ci --role shell)
vmux pane launch "$PANE" \
  --cwd "$PWD" \
  --env "PATH=$PWD/bin:$PATH" \
  --env "BUILD_ID=$BUILD_ID" \
  --title "make test" \
  -- make test

# Launch an agent-style teammate pane
vmux pane launch "$PANE" \
  --role teammate \
  --task-id agt-77 --task-title "fix flaky tests" --agent-name "claude-code" \
  -- claude-code --task agt-77

If the launch fails (binary not found, permission denied, etc.) the command writes vmux: <reason> to stderr and exits 1.

vmux pane signal

vmux [global-flags] pane signal <PANE-UUID> <SIGNAL>

Send a Unix signal to the pane's running process.

<SIGNAL> is one of:

  • A numeric signal number (e.g. 9).
  • A symbolic name with or without prefix: INT or SIGINT, TERM or SIGTERM. Recognized: HUP, INT, QUIT, TERM, KILL, USR1, USR2.
# Polite stop
vmux pane signal "$PANE" TERM

# Hard stop
vmux pane signal "$PANE" KILL

# By number
vmux pane signal "$PANE" 2

Exit 0 on success, 1 on failure with a stderr message.

vmux pane close

vmux [global-flags] pane close <PANE-UUID> [--force]

Close a pane. The pane's PTY is torn down and the pane is removed from its tab.

FlagEffect
--forceSend SIGKILL to the pane's process group instead of letting it exit cleanly.

Without --force, the daemon sends SIGHUP to the foreground job and waits for the shell to exit. With --force, the pane is gone immediately regardless of what the process is doing.

If the pane was the last one in its tab, the tab is also removed. If the tab was the last one in the session, the session ends and all attached clients receive sessionEnded.

# Polite close — for an interactive shell, this usually triggers exit
vmux pane close "$PANE"

# Last resort
vmux pane close "$PANE" --force

vmux wait-pane-exit

vmux [global-flags] wait-pane-exit <PANE-UUID> [--timeout SECONDS]

Block until the pane's runtime state becomes exited or failed. Used for scripting, where pane launch kicks off a job and the script needs the result.

FlagDefaultEffect
--timeout SECONDS30Maximum seconds to wait. Must be a number. On timeout the command exits 1 with vmux: waitForPaneExit timed out.

On exit:

  • exited <code> is printed to stdout.
  • The command exits with the pane's exit code.

On failure:

  • vmux: <message> is written to stderr.
  • The command exits 1.
PANE=$(vmux pane create -s ci --role shell)
vmux pane launch "$PANE" --cwd "$PWD" -- ./run-suite.sh

if vmux wait-pane-exit "$PANE" --timeout 600; then
  echo "suite passed"
else
  echo "suite failed (exit=$?)"
fi

The wait command holds an open observation connection to the daemon and consumes both push events (processExited, processFailed) and polled paneState snapshots. It does not poll busily — it sleeps inside poll(2) until the daemon sends data or the deadline is reached.

Listing panes

There is no dedicated vmux pane ls. Use vmux state and jq:

# Every pane UUID in the work session
vmux state -s work | jq -r '.tabs[].panes[].paneID'

# Pane UUID, role, and runtime state
vmux state -s work | jq -r '
  .tabs[].panes[] | "\(.paneID)  \(.role)  \(.runtimeState.kind)"
'

# Just running teammate panes
vmux state | jq -r '
  .tabs[].panes[]
  | select(.role == "teammate" and .runtimeState.kind == "running")
  | .paneID
'

Putting it together

A complete "spin up a build, wait for it, capture exit" script:

#!/usr/bin/env bash
set -euo pipefail

SESSION=ci-build
vmux session create -s "$SESSION" >/dev/null || true
PANE=$(vmux pane create -s "$SESSION" --role shell --title "make all")
vmux pane launch "$PANE" --cwd "$PWD" -- make all

if vmux wait-pane-exit "$PANE" --timeout 1800; then
  echo "build ok"
else
  rc=$?
  vmux pane close "$PANE" --force || true
  exit "$rc"
fi
vmux pane close "$PANE"

You can also vmux attach -s ci-build from another terminal at any time to watch the build live. When the wait finishes and pane close runs, the attached client will see the session end and exit cleanly.

See also