Prompts¶
MCP prompts are reusable, parameterised text templates the server
ships to its clients. A client renders a prompt by calling
prompts/get; the rendered text is what the model sees.
libtmux-mcp’s prompts are short workflow recipes — the MCP-shaped
counterpart to the longer narrative recipes in Recipes.
Available prompts¶
run_and_waitExecute a shell command through run_command and inspect
its typed result.
diagnose_failing_paneGather pane context and produce a root-cause hypothesis without taking action.
build_dev_workspaceSet up a 3-pane editor / shell / logs layout shell-agnostically.
interrupt_gracefullySend SIGINT and verify the shell prompt returns, refusing to auto-escalate.
Tip
Most MCP clients render prompts via a slash-command UI
(/<server>:<prompt>). For tools-only clients that don’t expose
prompts, set LIBTMUX_MCP_PROMPTS_AS_TOOLS=1 in the server
environment to surface them as list_prompts / get_prompt
tools instead.
run_and_wait¶
Run a shell command in a tmux pane and wait for completion.
Use when the agent needs to execute a single shell command, wait for completion, and inspect exit status plus output.
Why use this instead of send_keys + capture_pane polling?
run_command sends the command, waits through a private
tmux signal, captures tail-preserved output, and returns a
RunCommandResult. That removes the manual
channel plumbing from the common authored-command workflow.
Arguments
Sample render (command="pytest", pane_id="%1"):
Run this shell command in tmux pane %1, wait until it
finishes, and inspect the typed result:
```python
result = run_command(
pane_id='%1',
command='pytest',
timeout=60.0,
max_lines=100,
)
```
Use `result.exit_status`, `result.timed_out`, and `result.output`
to decide what happened. Do NOT use a `send_keys` + `capture_pane`
retry loop for authored commands — `run_command` already performs
deterministic completion and returns tail-preserved output.
If the task needs persistent shell state or TUI keystrokes instead of
a one-shot shell command, use `send_keys` or `send_keys_batch`, then
observe later output with `capture_since`.
Single-line renders omit suppress_history, so MCP calls use the server’s
enabled-by-default setting. If command contains a carriage return or line
feed, the prompt instead renders suppress_history=False and warns that the
shell may record the multiline command. See History suppression for
the Bash, Zsh, and Fish behavior behind both cases.
For custom shell composition that falls outside run_command,
compose tmux wait-for -S <channel> yourself and call
wait_for_channel. Keep that as the low-level escape hatch,
not the default command-running recipe.
diagnose_failing_pane¶
Gather pane context and propose a root-cause hypothesis.
Use when something visibly went wrong in a pane and the agent needs to investigate before deciding what to fix. Produces a plan, not an action.
Why use this instead of just calling capture_pane? The recipe
prefers snapshot_pane readonly, which returns content + cursor
position + pane mode + scroll state in one call — saving a
follow-up get_pane_info round-trip. It also explicitly forbids
the agent from acting before it has a hypothesis, which prevents
“fix the symptom” anti-patterns. For repeated observation, it routes
follow-up reads through capture_since readonly cursors instead of full
pane captures.
Arguments
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
yes |
The pane to diagnose. |
Sample render (pane_id="%1"):
Something went wrong in tmux pane %1. Diagnose it:
1. Call `snapshot_pane(pane_id="%1")` to get content,
cursor position, pane mode, and scroll state in one call.
2. If the content looks truncated, re-call with `max_lines=None`.
3. If you need to watch the pane across more than one turn, call
`capture_since(pane_id="%1")`, keep the returned cursor,
and pass it to later `capture_since(cursor=...)` calls.
4. Identify the last command that ran (look at the prompt line and
the line above it) and the last non-empty output line.
5. Propose a root cause hypothesis and a minimal command to verify
it (do NOT execute anything yet — produce the plan first).
build_dev_workspace¶
Construct a simple 3-pane development session.
Use when the operator wants a fresh 3-pane workspace with editor on top, terminal bottom-left, and a logs pane bottom-right — the most common shape for active development.
Why use this instead of describing the layout in free form? The
recipe uses real parameter names that match the tools’ actual
signatures (session_name=, pane_id=, direction="below")
so an agent following it verbatim never hits a validation error. It
also explicitly avoids waiting for shell prompts after launching
vim / watch / tail -f — the kind of guidance that would
deadlock an agent following naïve “wait for the prompt between each
step” advice.
Arguments
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
yes |
Name for the new session. |
|
|
no |
Command to run in the logs pane. Defaults to an OS-neutral
|
Pass e.g. "tail -f /var/log/syslog" on Linux or
"log stream --level info" on macOS as the log_command to
override the OS-neutral default.
Sample render (session_name="dev"):
Set up a 3-pane development workspace named
'dev' with editor on top, a shell on the bottom-left, and
a logs tail on the bottom-right:
1. `create_session(session_name="dev")` — creates the
session with a single pane (pane A, the editor). Capture the
returned `active_pane_id` as `%A`.
2. `split_window(pane_id="%A", direction="below")` — splits off
the bottom half (pane B, the terminal). Capture the returned
`pane_id` as `%B`.
3. `split_window(pane_id="%B", direction="right")` — splits pane B
horizontally (pane C, the logs pane). Capture the returned
`pane_id` as `%C`.
4. Launch the editor and the log command via {tooliconl}`send-keys`:
`send_keys(pane_id="%A", keys="vim")` and
`send_keys(pane_id="%C", keys='watch -n 1 date')`. Leave pane B
at its fresh shell prompt — nothing needs to be sent there. No
pre-launch wait is required: tmux buffers keystrokes into the
pane's PTY whether or not the shell has finished drawing, so
`send_keys` immediately after `split_window` is safe and
shell-agnostic.
5. Optionally confirm each program drew its UI via
`wait_for_text(pane_id="%A", patterns=null, timeout=3.0)`
(and similarly for `%C`). Omitting `patterns` makes this a
"did anything new get printed?" check — it works whether the
pane shows a prompt glyph, a vim splash screen, or a log tail,
so no shell-specific regex is needed.
Use pane IDs (`%N`) for all subsequent targeting — they are stable
across layout changes; window renames are not.
interrupt_gracefully¶
Interrupt a running command and verify the prompt returned.
Use when the agent needs to stop a running command and confirm control returned to the shell — without escalating beyond SIGINT.
Why use this instead of just sending C-c? The recipe pairs the
interrupt with a wait_for_text readonly against a common shell prompt
glyph and an explicit instruction to stop and ask if the wait
times out. That prevents the most dangerous failure mode — an agent
auto-escalating to C-\\ (SIGQUIT, may core-dump) or kill
without operator consent — by drawing a clear escalation boundary.
Arguments
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
yes |
Target pane. |
Sample render (pane_id="%1"):
Interrupt whatever is running in pane %1 and
verify that control returns to the shell:
1. `get_pane_info(pane_id="%1")` — note `pane_current_command`.
That is the thing you are trying to change, and comparing it
before and after is the only reliable answer.
2. `send_keys(pane_id="%1", keys="C-c", literal=False,
enter=False)` — tmux interprets `C-c` as SIGINT.
3. `wait_for_text(pane_id="%1", patterns=["\$", "\#", "\%", ">"],
regex=True, timeout=5.0)` — waits for a common shell prompt glyph.
Adjust the patterns to match the user's shell theme.
Do NOT put `\^C` in `stop`: the terminal echoes `^C` whenever SIGINT
is DELIVERED, whether or not the process dies, so it marks the
success path as a failure. Measured on sh and bash — the process
exited and the wait still returned `outcome="stopped"`.
The `wait_for_channel` pattern doesn't apply here — `C-c` is a
signal, not a shell command, so there's no statement to compose
`tmux wait-for -S` into.
4. Re-read `get_pane_info(pane_id="%1")`. If
`pane_current_command` is back to a shell, the interrupt worked —
trust this over the wait result, which can time out on a prompt
whose glyph you did not predict.
5. Only if the command is UNCHANGED is the process ignoring SIGINT.
Stop and ask the caller how to proceed — do NOT escalate
automatically to `C-\` (SIGQUIT) or `kill`.
The shell-prompt regexes cover default bash / zsh — adjust for fish
(> ), zsh + oh-my-zsh (➜ ), or starship (❯ ). When the
patterns don’t match the user’s prompt theme the recipe times out
and surfaces the situation to the caller, which is the right
default for “I tried, can’t tell, what should I do?” workflows.