mpmux-cli reference#
mpmux-cli is the command-line tool for mpmux. It does three jobs:
- Drive a running mpmux window (host control): open tabs and splits, type into panes, read their screen, show messages and dialogs.
- Talk to a session host (
mpmux-cli session …): list, create, and rename hosted sessions, send them input, pair with a remote host. - Pair devices (
mpmux-cli pair …) and manage hosts in a terminal interface (mpmux-cli tui).
This page explains the commands with examples. The exact options of every command are in Command-line help, generated from the binary.
- Connecting
- Output and errors
- Panes and tabs
- Typing and reading
- Messages and dialogs
- Clients, control, and events
- Clipboard and buffers
- Overlays: palette, pie menu, sidebars, extensions
- Agent runs
- Runtime and diagnostics
- Capture and playback
- Session host as a service
- Session host commands
- Pairing
- The session manager (tui)
- Recipes
Connecting#
To the mpmux window#
Every mpmux window listens on a host-control socket. mpmux sets
MPMUX_SOCKET_PATH in each of its panes, so commands run inside mpmux reach
their own window without options:
mpmux-cli status
From outside mpmux, mpmux-cli looks for, in this order:
--socket <path>or--host-control-tcp <host:port>MPMUX_SOCKET_PATHorMPMUX_HOST_CONTROL_TCP/run/user/<uid>/mpmux.sock(or the temp directory when there is no runtime directory)
mpmux-cli env prints the exports for the endpoint it would use, for
example to hand them to another shell:
eval "$(mpmux-cli env)"
To a session host#
mpmux-cli session … talks to mpmux-sessiond, not to the window. It looks
for:
--sessiond-socket <path>,--sessiond-tcp <host:port>, or--sessiond-iroh <target>/--sessiond-iroh-file <file>MPMUX_SESSIOND_SOCKET_PATH/run/user/<uid>/mpmux-sessiond.sock
A host with authentication on (all hosts reachable over the network) wants credentials:
| Who you are | Options | Environment |
|---|---|---|
| The host's owner, on the host | --sessiond-admin-token-file FILE |
MPMUX_SESSIOND_ADMIN_TOKEN_FILE |
| A paired device | --sessiond-device-id ID --sessiond-device-token-file FILE |
MPMUX_SESSIOND_DEVICE_ID, MPMUX_SESSIOND_DEVICE_TOKEN_FILE |
Without them you get auth-required: valid admin or device auth is required.
Output and errors#
Commands that change something print OK (split-pane prints the new pane
id). Commands that report something print their data as JSON. --json
prints the full response for every command, wrapped as
{"status": "ok", "data": …}, which is what scripts should read:
mpmux-cli list-panes | jq -r '.panes[] | select(.active) | .pane_id'
mpmux-cli --json list-panes | jq -r '.data.panes[] | select(.active) | .pane_id'
On failure, mpmux-cli prints Error: <code>: <message> to stderr and exits
with a non-zero status. Common codes:
| Code | Meaning |
|---|---|
failed to talk to socket … |
No mpmux listens there. Check MPMUX_SOCKET_PATH. |
host-control-access-denied |
Another client holds control; see Clients, control, and events. |
auth-required |
The session host wants an admin token or device credentials. |
workspace-not-current-owner |
Another device controls this session; take it over first. |
Panes and tabs#
mpmux-cli list-panes # every pane: id, size, cwd, title, active
mpmux-cli new-tab
pane=$(mpmux-cli split-pane --direction down) # prints the new pane id
mpmux-cli select-pane "$pane"
mpmux-cli resize-pane --pane-id "$pane" --direction up --amount 8
mpmux-cli window-action toggle-maximize # maximize the active pane, or restore
mpmux-cli kill-pane --pane-id "$pane" # without --pane-id: the active pane
mpmux-cli select-tab tab-1
Pane ids look like pane-3 and stay the same while the pane lives.
split-pane splits the active pane; select another pane first to split that
one. --direction is right (the default) or down.
list-panes example:
{
"active_pane_id": "pane-0",
"panes": [
{ "pane_id": "pane-0", "active": true, "focused": true, "cols": 116,
"rows": 39, "cwd": "/home/you/src", "title": "bash", "pid": 41237,
"terminal_running": true }
]
}
A pane whose program reported its status (OSC 7501) or progress (OSC 9;4)
also carries program_status:
"program_status": {
"records": [ { "state": "blocked", "kind": "permission", "app": "terraform",
"message": "Apply 3 to add, 1 to change?" } ],
"progress": { "state": "normal", "percent": 56 }
}
state is idle, working, blocked, done, or error; records with an
id come from programs that report several parts. progress.state is
normal, error, indeterminate, or paused.
list-windows, list-sessions, and list-clients list the other objects
the window knows about. has-session exits with 0 only when the window has
a running session, which is handy in scripts that wait for mpmux to start.
Typing and reading#
Send text#
mpmux-cli send-text --pane-id "$pane" $'cargo test\n'
The text goes to the program in the pane as if typed, including the newline
that presses Enter. Without --pane-id it goes to the active pane.
Send keys#
send-keys takes tmux-style items: key names, or text when the item is not a
key name.
mpmux-cli send-keys --pane-id "$pane" 'git status' Enter
mpmux-cli send-keys --pane-id "$pane" C-c # Ctrl+C
mpmux-cli send-keys --pane-id "$pane" Escape ':wq' Enter
mpmux-cli send-keys -l --pane-id "$pane" Enter # the word "Enter", literally
Key names (case does not matter): Enter/Return, Tab, Space,
BSpace/Backspace, Delete, Escape/Esc, Up, Down, Left,
Right, Home, End, PageUp, PageDown, F1–F12. Prefix C- for
Ctrl, M- for Alt, S- for Shift: C-a, M-x, S-Tab, C-M-Left.
send-key sends one logical key with explicit modifiers:
mpmux-cli send-key --ctrl c
mpmux-cli send-key --shift tab
Read the screen#
mpmux-cli capture-pane --pane-id "$pane" # the visible screen
mpmux-cli capture-pane --pane-id "$pane" --start-line -10 # its last 10 lines
capture-pane returns the visible viewport as text, one line per row, with
trailing spaces removed (--preserve-trailing-spaces keeps them).
--start-line and --end-line pick rows; negative numbers count from the
bottom. A fresh pane has its prompt at the top and empty rows below, so the
last rows can be empty: capture the whole screen and filter when you look
for output.
Scroll#
mpmux-cli scroll-viewport --pane-id "$pane" -20 # 20 rows back
mpmux-cli scroll-viewport --pane-id "$pane" 20 # 20 rows forward
mpmux-cli clear-history --pane-id "$pane"
mpmux-cli reset-terminal --pane-id "$pane" --clear # screen and scrollback
mpmux-cli reset-terminal --pane-id "$pane" # full reset (RIS)
Messages and dialogs#
mpmux-cli display-message 'Build finished'
mpmux-cli show-messages # the message history
mpmux-cli toggle-message-sidebar # show it as a sidebar
A message shows as a toast and lands in the message history.
mpmux-cli display-dialog 'Deploy?' 'All checks passed. Deploy to staging?' \
--primary-label Deploy --wait
display-dialog shows a modal dialog. With --wait the command blocks until
the dialog closes and prints how:
{ "title": "Deploy?", "outcome": "dismissed", "dismissed_by": "primary-button",
"primary_label": "Deploy", "message": "All checks passed. Deploy to staging?" }
dismissed_by tells what closed it: primary-button or enter (the person
confirmed), escape or close-button (the person declined), or
host-control (a script called dismiss-dialog).
dismiss-dialog closes the dialog from a script. Richer dialogs with fields
and buttons, and sidebars with lists, are described in the
host-control reference and the
extension architecture;
set-custom-dialog-field and invoke-custom-dialog-action drive them.
Clients, control, and events#
By default every mpmux-cli call is anonymous and may do anything. Scripts
that run for a while, or several scripts at once, should register as a
client:
id=build-bot
mpmux-cli --client-id $id attach --name "build bot" # role: controller
mpmux-cli --client-id $id acquire-control
# … commands with --client-id $id …
mpmux-cli --client-id $id release-control
mpmux-cli --client-id $id detach
Rules:
- Once any client has attached, commands that change the window
(
display-dialog,send-text,split-pane, …) need the control lease:Error: host-control-access-denied: command display-dialog requires acquire-control after explicit clients attach. Read-only commands (status,list-panes,capture-pane) keep working for everyone. --role observerattaches a client that only reads and listens.- The lease expires 30 seconds after the holder's last request.
Long-running controllers call
heartbeatmore often than that. transfer-control <client-id>hands the lease to another attached client;show-control-stateshows who holds it.
Wait for events instead of polling#
mpmux-cli --client-id $id subscribe dialog-state-changed
mpmux-cli --client-id $id wait-for-events # blocks until something happens
Events: control-owner-changed, ui-state-changed,
dialog-state-changed, custom-sidebar-state-changed. wait-for-events
returns all queued events at once (--max-events N limits them);
poll-events returns at once, also when the queue is empty. Do not loop
poll-events with sleep; call wait-for-events in a loop instead.
Example event:
{ "client_id": "build-bot", "events": [ {
"kind": "dialog-state-changed", "event_id": 15,
"dialog": { "open": true, "title": "Hi", "message": "event test", "primary_label": "OK" },
"controller_owner": "build-bot" } ],
"pending_event_count": 0 }
Clipboard and buffers#
mpmux keeps a buffer of its own, next to the system clipboard (tmux users know this as the paste buffer).
mpmux-cli copy-to-clipboard 'some text' # system clipboard and buffer
mpmux-cli set-buffer 'text' # buffer only
mpmux-cli show-buffer
mpmux-cli load-buffer notes.txt
mpmux-cli save-buffer out.txt
mpmux-cli paste-buffer # type the buffer into the active pane
mpmux-cli delete-buffer
mpmux-cli list-buffers
Media in the Viewer#
media shows images, tables, documents, pages and Wasm canvas guests in
the Viewer, a panel beside the terminal (guide chapter 7,
chapter 11).
mpmux-cli media show chart.png # prints ▣ chart.png · mpmux-media://chart.png
mpmux-cli media show results.csv --title "Test results"
mpmux-cli media show ./scene/ # index.html with the folder's other files
mpmux-cli media show README.md # with the files it links to
mpmux-cli media show https://example.org # a web link: the page itself
mpmux-cli media show life.wasm # a canvas guest
some-report | mpmux-cli media show - --type text/markdown --id report
mpmux-cli media list
mpmux-cli media console # what the shown page logged
mpmux-cli media close chart.png
mpmux-cli media clear
mpmux-cli media demo # sample objects to try
- The id is the file name unless
--idnames one; showing an id again replaces the object in place, so a script can redraw its chart.--backgroundadds it without switching the Viewer to it. - In an mpmux terminal
showdraws a PNG as a thumbnail above the link (--thumbnail auto|always|never,--thumbnail-rows). Clicking the link or the thumbnail opens the object again. - A Markdown or HTML file brings the files it links to by relative path
(in its folder or below, and what linked documents link to): following
such a link in the Viewer opens the file in the document's place.
shownames the links it cannot carry on standard error. console [ID] [--clear] [--wait 5] [--settle 1]prints a page's console: itsconsole.loglines and errors, with the file and line. The page runs only while the Viewer shows it, soconsoleshows it first, waits for it to load and then a little longer for what its scripts log. It needs the desktop web engine or the Android WebView.- Limits: 8 MB an object (640 KB from standard input, or over TCP); a page or document carries at most 64 files and 24 MB together.
- In a hosted session the session host keeps the objects, so they reach whichever device attaches, and outlive an app restart.
Agent integrations#
mpmux comes with integrations for coding agents: for Claude Code the
/todos-sidebar command, the media skill, the run monitor and prompt marks;
for Pi the todos tool and sidebar, the host-control and run-monitor
extensions and the skills. The packages carry them in
/usr/share/mpmux/agents (the macOS app in Contents/Resources/agents).
mpmux-cli agents install # into Claude Code and Pi, where found
mpmux-cli agents install claude --with run-monitor --with prompt-marks
mpmux-cli agents install --dry-run # print the commands only
mpmux-cli agents status # what is installed, Node, old copies
mpmux-cli agents uninstall pi
mpmux-cli todos-sidebar --detach # the todos sidebar for any agent
installregisters them with each harness (claude plugin marketplace addandclaude plugin install,pi install), which loads them in place from mpmux's folder: updating mpmux updates them. Run it again any time.- Claude Code's run monitor (
--with run-monitor) adds hooks that run on every tool call; prompt marks (--with prompt-marks) need Claude Code's inline TUI ("tui": "default"). statusandinstalllist copies set up by hand from an mpmux checkout before (links in~/.claudeand~/.pi/agent, run-monitor hooks insettings.json): remove them, or the agent loads both.todos-sidebarneeds Node 22.18 or newer.MPMUX_AGENTS_DIRpoints both commands at another folder (a source checkout:scripts/stage-mpmux-agents.sh DIR).
Overlays: palette, pie menu, sidebars, extensions#
These commands let scripts and tests drive the interface the way a person would.
mpmux-cli open-command-palette
mpmux-cli set-command-palette-query split
mpmux-cli move-command-palette-selection 1
mpmux-cli confirm-command-palette-selection
mpmux-cli dismiss-command-palette
mpmux-cli pie-menu list # menus and their items
mpmux-cli pie-menu open # the root menu
mpmux-cli activate-pie-menu-direction up # or a clock hour (1.5h) or degrees (45)
mpmux-cli pie-menu active
mpmux-cli move-picker-selection -1
mpmux-cli confirm-picker-selection
mpmux-cli dismiss-overlay
mpmux-cli set-custom-sidebar-filter build
mpmux-cli move-custom-sidebar-selection 1
mpmux-cli invoke-custom-sidebar-selection
mpmux-cli set-custom-sidebar-filter build --sidebar-id pi-todos-sidebar # one of several
mpmux-cli set-dock-split run-monitor # show that sidebar below the dock's panel
mpmux-cli set-dock-split # join the halves again
mpmux-cli clear-custom-sidebar --sidebar-id run-monitor
mpmux-cli set-message-sidebar-width 420
mpmux-cli set-message-sidebar-position bottom # left, right, top, bottom; saved
mpmux-cli extension list
mpmux-cli extension open <extension-id>
mpmux-cli show-ui-state # what is open right now, as JSON
Agent runs#
mpmux-cli run-monitor shows an agent's run in the custom sidebar: a
summary (state, steps done, what happens now, time, a progress bar), the plan
as a checklist, and Pause/Resume and Stop buttons. Approvals open a dialog.
Agents call it from their pane; the instructions for agents are the skill in
contrib/skills/mpmux-run-monitor/SKILL.md.
mpmux-cli run-monitor start "Fix the flaky test" --agent Codex
mpmux-cli run-monitor plan "Read the test" "Fix the race" "Push a branch"
mpmux-cli run-monitor step 2 running --detail "cargo test voice" --progress 40
mpmux-cli run-monitor note "Waiting for CI"
mpmux-cli run-monitor ask "Push to origin?" --detail '`git push origin fix`'
echo $? # 0 approved, 1 denied, 2 dismissed; the JSON line has the note
mpmux-cli run-monitor check # {"paused":false,"stop_requested":false}
mpmux-cli run-monitor finish "Fixed; branch pushed"
mpmux-cli run-monitor clear
| Command | What it does |
|---|---|
start TITLE [--agent NAME] |
A new run (replaces the old one); also starts a watcher for the buttons, which ends with the run. |
plan STEP... |
The plan; steps that keep their title keep their status. |
step N\|TITLE STATUS [--detail] [--progress] |
pending running waiting done failed skipped. |
note TEXT |
The summary's "Now" line. |
ask TITLE [--detail LINE]... [--warning] [--timeout SECS] |
Approval dialog; blocks until answered. |
check |
Whether the person pressed Pause or Stop. |
finish [SUMMARY] [--failed] |
Ends the run; the sidebar stays. |
clear |
Removes the sidebar and the run. |
hook [--agent NAME] [--agent-reports-plan] [--approve TEXT]... [--approve-all-bash] |
Agent hooks: Claude Code's (contrib/claude/README.md), and Pi's through its extension (contrib/pi/README.md). |
The run is kept per mpmux socket (or host-control TCP endpoint), so the commands work from separate processes and from hosted sessions; through the session host relay the waits poll instead of blocking.
Runtime and diagnostics#
mpmux-cli status # app, pid, focus, protocol version, counters
mpmux-cli metadata # stable facts: version, capabilities
mpmux-cli version # versions of all mpmux tools here, installed and running
mpmux-cli show-options # the settings in effect
mpmux-cli show-window-options
mpmux-cli show-hooks
mpmux-cli show-prompt-history
mpmux-cli show-environment # an allow-listed environment snapshot
mpmux-cli reload-config # re-read config.toml
mpmux-cli set-verbose-level 2 # more log output, without a restart
mpmux-cli cleanup-processes # end shells left over from crashed runs (--deep: their children too)
Capture and playback#
For screenshots, videos, tests, and bug reports:
mpmux-cli capture-ui shot.png # the whole window
mpmux-cli capture-ui --surface pane --pane-id pane-1 pane.png
mpmux-cli capture-ui --format video --fps 30 --frames 90 clip.mkv
mpmux-cli run-playback <name> # a built-in input scenario
mpmux-cli select-cells … # set a selection
capture-ui also works from a pane of a hosted session, whose window may be
on a phone or tablet: the image comes back through the session host and is
saved on this machine (scaled down if it is very large; video is not
available that way).
set-app-time-override and clear-app-time-override drive the app clock
for frame-exact recordings. start-terminal-segment-recording,
finish-terminal-segment-recording, and the *-terminal-replay-* commands
record terminal output and step through it frame by frame; see
UI capture and video and
sync point capture and replay.
show-hot-reload-bridge and sync-hot-reload-bridge are for developing the
interface with Makepad's --hot mode.
Session host as a service#
mpmux-cli service runs mpmux-sessiond as a user service, so the host
starts at login and keeps its shells when no window is open: a systemd user
unit on Linux, a launchd LaunchAgent on macOS.
mpmux-cli service install # this machine only
mpmux-cli service install --remote # also paired devices, over Iroh
mpmux-cli service status
mpmux-cli service uninstall # its shells end; pairings stay
| Option | Effect |
|---|---|
--remote |
device auth and an Iroh listener; creates the admin token ~/.config/mpmux/sessiond-admin-token that mpmux-cli pair uses |
--relay-url URL |
the Iroh relay (default https://relay.mightypainting.dev) |
--relay-only |
never connect devices directly, always through the relay |
--sessiond PATH |
the mpmux-sessiond to run (default: next to mpmux-cli, else from PATH) |
--restart |
apply changed options to a running service; this ends its shells |
--dry-run |
print the service file and the commands, change nothing |
The service file is ~/.config/systemd/user/mpmux-sessiond.service or
~/Library/LaunchAgents/dev.mightypainting.mpmux-sessiond.plist. install
refuses to replace a service file it did not write, and refuses to start
while another session host holds the socket. On Linux, sudo loginctl
enable-linger "$USER" keeps the service running after you log out.
Chapter 8 shows the whole remote setup.
Session host commands#
mpmux-cli session works with mpmux-sessiond directly. On the host, as its
owner:
export MPMUX_SESSIOND_ADMIN_TOKEN_FILE=~/.config/mpmux/auth/admin.token # when auth is on
mpmux-cli session status
mpmux-cli session list
mpmux-cli session create --label build
mpmux-cli session rename session-3 'build logs'
mpmux-cli session send-text session-3 $'make -j8\n'
mpmux-cli session send-key session-3 c --ctrl
mpmux-cli session snapshot session-3 --json # screen contents and state
mpmux-cli session resize session-3 120 40
Sessions keep running without a window. snapshot is the way to read their
screen from a script; send-text and send-key type into them.
Ownership: one device controls a session's workspace at a time.
mpmux-cli session takeover-status <workspace-id>
mpmux-cli session takeover <workspace-id> \
--expected-ownership-revision 4 --expected-membership-revision 2
takeover succeeds only if the revisions still match what
takeover-status reported, so two devices cannot take over at the same
time by accident.
attach and detach mark a session as attached by a client name; the
window does this itself, scripts rarely need it.
From another machine#
With credentials from pairing (next section), the same commands work over Iroh:
D=~/.config/mpmux/auth/build-server-device
mpmux-cli session --sessiond-iroh-file "$D/endpoint.target" \
--sessiond-device-id "$(cat "$D/device.id")" \
--sessiond-device-token-file "$D/device.token" list
Pairing#
Pairing gives a device its own credentials for a host. Run these on the host;
they need the admin token: the one of the active profile in
~/.config/mpmux/profiles.toml, else ~/.config/mpmux/sessiond-admin-token
(which mpmux-cli service install --remote creates).
The host's session host must run with device auth, which service install
--remote sets up. A plain service install or the service the Linux packages
ship cannot pair; pair then fails with auth-unavailable, and
mpmux-cli service install --remote --restart fixes it (the restart ends the
host's shells). After a plain service install, mpmux-cli service status
shows remote: off.
| Command | Gives you | Valid |
|---|---|---|
mpmux-cli pair url --device-label laptop |
an mpmux://sessiond-pair?… link, copied to the clipboard when possible (--no-copy skips that) |
10 minutes, once |
mpmux-cli pair qr-code --device-label tablet --output pair.png |
the same link as a QR code PNG; without --output it draws the code in a terminal that shows images (mpmux, kitty), otherwise it saves a PNG and prints its path |
10 minutes, once |
mpmux-cli pair short-code --device-label phone |
a short code to type on the device (through the rendezvous service) | 5 minutes, once |
--ttl-seconds changes the lifetime. --output and --code-output-file
refuse to overwrite existing files, so an invite never lands in a file you
did not mean.
On the device, the desktop app pairs from the clipboard (Session Management → Pair Iroh Invite), the phone app scans the QR code. Without a window:
mpmux-cli session --sessiond-iroh-file invite.txt pair \
--device-label ci-runner --host-label build-server
This saves endpoint.target, device.id, device.token, and host.label
in ~/.config/mpmux/auth/<host-label>-device/ (--save-dir picks another
directory, --no-save keeps nothing). Chapter 8
explains the whole flow and what each secret allows.
mpmux-cli session create-qr-code makes a short-code offer through a relay
of your choice (--relay, --relay-iroh-target) and saves it as a QR code;
the hidden command mpmux-cli short-code-relay runs such a relay
(relay server).
Treat links, codes, and token files like passwords: they do not belong in chats, tickets, logs, or screenshots.
The session manager (tui)#
mpmux-cli tui
A terminal interface for the hosts in ~/.config/mpmux/profiles.toml and
the hosts you paired with. It shows each host's state, its sessions, and its
paired devices; it creates sessions and invites, renames and closes
sessions, and walks through setting up a phone.
| Key | Action |
|---|---|
| ↑ ↓ or j k | Move through the actions, or the tree after v |
| Enter | Run the action; in the tree, attach to or create a session |
| v | Switch between the actions and the hosts and sessions tree |
| R | Rename the selected session |
| x | Close the selected session |
| c | Create a session |
| i | Create a pairing invite and show its QR code |
| n / e / y | New invite in place of the latest / expire it / copy its link |
| o / p | Offer or accept a short code |
| m | The action menu |
| r | Refresh |
| 1–4, Tab | Home, Logs, Advanced, Help |
| ? | Help |
| q, Esc | Quit |
profiles.toml names the hosts:
active = "server"
[profiles.server]
kind = "local" # or "container"
display-name = "Server"
network-mode = "iroh-relay" # local, iroh-relay, direct-lan, externally-secured-lan, adb-fallback
sessiond-socket = "/run/user/1000/mpmux-sessiond.sock"
[profiles.server.iroh]
relay-url = "https://relay.mightypainting.dev"
sessiond-key = "/home/you/.config/mpmux/iroh/sessiond.key"
allow-direct = true
[profiles.server.auth]
mode = "device-token"
auth-store = "/home/you/.config/mpmux/auth/auth-store.json"
admin-token-file = "/home/you/.config/mpmux/auth/admin.token"
Recipes#
Run tests in a side pane and wait for the result#
pane=$(mpmux-cli split-pane --direction down)
mpmux-cli send-text --pane-id "$pane" $'cargo test; echo "exit=$?"\n'
until mpmux-cli capture-pane --pane-id "$pane" | grep -q '^exit='; do sleep 2; done
mpmux-cli capture-pane --pane-id "$pane" | grep '^exit='
(Reading a screen has no event, so this recipe polls; keep the interval generous.)
A layout for a project#
#!/bin/sh
# Editor on the left, tests and a shell on the right.
cd ~/src/project
right=$(mpmux-cli split-pane --direction right)
mpmux-cli send-text --pane-id "$right" $'cargo watch -x test\n'
mpmux-cli select-pane "$right"
below=$(mpmux-cli split-pane --direction down)
mpmux-cli select-pane pane-0
mpmux-cli send-text $'nvim .\n'
Ask before something irreversible#
by=$(mpmux-cli --json display-dialog 'Publish?' "Publish $version now?" \
--primary-label Publish --wait | jq -r .data.dismissed_by)
case $by in primary-button|enter) ;; *) echo "not confirmed ($by)"; exit 1 ;; esac
Tell the person when a long job ends#
make release && mpmux-cli display-message 'Release build done' \
|| mpmux-cli display-message 'Release build FAILED'
printf '\a' # the bell marks this pane in the overview