|
| 1 | +(prompts-overview)= |
| 2 | + |
| 3 | +# Prompts |
| 4 | + |
| 5 | +MCP prompts are reusable, parameterised text templates the server |
| 6 | +ships to its clients. A client renders a prompt by calling |
| 7 | +``prompts/get``; the rendered text is what the model sees. |
| 8 | +libtmux-mcp's prompts are short *workflow recipes* — the MCP-shaped |
| 9 | +counterpart to the longer narrative recipes in {doc}`/recipes`. |
| 10 | + |
| 11 | +Four prompts ship today: |
| 12 | + |
| 13 | +- {ref}`run-and-wait` — execute a shell command and block until it |
| 14 | + finishes, preserving exit status. |
| 15 | +- {ref}`diagnose-failing-pane` — gather pane context and produce a |
| 16 | + root-cause hypothesis without taking action. |
| 17 | +- {ref}`build-dev-workspace` — set up a 3-pane editor / shell / logs |
| 18 | + layout shell-agnostically. |
| 19 | +- {ref}`interrupt-gracefully` — send SIGINT and verify the shell |
| 20 | + prompt returns, refusing to auto-escalate. |
| 21 | + |
| 22 | +```{tip} |
| 23 | +Most MCP clients render prompts via a slash-command UI |
| 24 | +(``/<server>:<prompt>``). For tools-only clients that don't expose |
| 25 | +prompts, set ``LIBTMUX_MCP_PROMPTS_AS_TOOLS=1`` in the server |
| 26 | +environment to surface them as ``list_prompts`` / ``get_prompt`` |
| 27 | +tools instead. |
| 28 | +``` |
| 29 | + |
| 30 | +--- |
| 31 | + |
| 32 | +(run-and-wait)= |
| 33 | + |
| 34 | +## `run_and_wait` |
| 35 | + |
| 36 | +**Use when** the agent needs to execute a single shell command and |
| 37 | +must know whether it succeeded before deciding the next step. |
| 38 | + |
| 39 | +**Why use this instead of `send_keys` + `capture_pane` polling?** |
| 40 | +Each rendered call embeds a UUID-scoped ``tmux wait-for`` channel, |
| 41 | +so concurrent agents (or parallel prompt calls from one agent) can |
| 42 | +never cross-signal each other. The server side blocks until the |
| 43 | +channel is signalled — strictly cheaper in agent turns than a |
| 44 | +``capture_pane`` retry loop. |
| 45 | + |
| 46 | +**Parameters:** |
| 47 | + |
| 48 | +- ``command`` (str) — the shell command to run. |
| 49 | +- ``pane_id`` (str) — target pane (e.g. ``%1``). |
| 50 | +- ``timeout`` (float, default ``60.0``) — maximum seconds to wait. |
| 51 | + |
| 52 | +**Sample render** (``command="pytest"``, ``pane_id="%1"``): |
| 53 | + |
| 54 | +````text |
| 55 | +Run this shell command in tmux pane %1 and block |
| 56 | +until it finishes, preserving the command's exit status: |
| 57 | +
|
| 58 | +``` |
| 59 | +send_keys( |
| 60 | + pane_id='%1', |
| 61 | + keys='pytest; __mcp_status=$?; tmux wait-for -S libtmux_mcp_wait_<uuid>; exit $__mcp_status', |
| 62 | +) |
| 63 | +wait_for_channel(channel='libtmux_mcp_wait_<uuid>', timeout=60.0) |
| 64 | +capture_pane(pane_id='%1', max_lines=100) |
| 65 | +``` |
| 66 | +
|
| 67 | +After the channel signals, read the last ~100 lines to verify the |
| 68 | +command's behaviour. Do NOT use a ``capture_pane`` retry loop — |
| 69 | +``wait_for_channel`` is strictly cheaper in agent turns. |
| 70 | +```` |
| 71 | + |
| 72 | +The ``__mcp_status=$?`` capture and ``exit $__mcp_status`` mean the |
| 73 | +agent observes the command's real exit code via shell-conventional |
| 74 | +``$?`` — even though the wait-for signal fires regardless of |
| 75 | +success or failure. |
| 76 | + |
| 77 | +--- |
| 78 | + |
| 79 | +(diagnose-failing-pane)= |
| 80 | + |
| 81 | +## `diagnose_failing_pane` |
| 82 | + |
| 83 | +**Use when** something visibly went wrong in a pane and the agent |
| 84 | +needs to investigate before deciding what to fix. Produces a plan, |
| 85 | +not an action. |
| 86 | + |
| 87 | +**Why use this instead of just calling `capture_pane`?** The recipe |
| 88 | +prefers {tool}`snapshot-pane`, which returns content + cursor |
| 89 | +position + pane mode + scroll state in one call — saving a |
| 90 | +follow-up ``get_pane_info`` round-trip. It also explicitly forbids |
| 91 | +the agent from acting before it has a hypothesis, which prevents |
| 92 | +"fix the symptom" anti-patterns. |
| 93 | + |
| 94 | +**Parameters:** |
| 95 | + |
| 96 | +- ``pane_id`` (str) — the pane to diagnose. |
| 97 | + |
| 98 | +**Sample render** (``pane_id="%1"``): |
| 99 | + |
| 100 | +```text |
| 101 | +Something went wrong in tmux pane %1. Diagnose it: |
| 102 | +
|
| 103 | +1. Call ``snapshot_pane(pane_id="%1")`` to get content, |
| 104 | + cursor position, pane mode, and scroll state in one call. |
| 105 | +2. If the content looks truncated, re-call with ``max_lines=None``. |
| 106 | +3. Identify the last command that ran (look at the prompt line and |
| 107 | + the line above it) and the last non-empty output line. |
| 108 | +4. Propose a root cause hypothesis and a minimal command to verify |
| 109 | + it (do NOT execute anything yet — produce the plan first). |
| 110 | +``` |
| 111 | + |
| 112 | +--- |
| 113 | + |
| 114 | +(build-dev-workspace)= |
| 115 | + |
| 116 | +## `build_dev_workspace` |
| 117 | + |
| 118 | +**Use when** the operator wants a fresh 3-pane workspace with editor |
| 119 | +on top, terminal bottom-left, and a logs pane bottom-right — the |
| 120 | +most common shape for active development. |
| 121 | + |
| 122 | +**Why use this instead of describing the layout in free form?** The |
| 123 | +recipe uses real parameter names that match the tools' actual |
| 124 | +signatures (``session_name=``, ``pane_id=``, ``direction="below"``) |
| 125 | +so an agent following it verbatim never hits a validation error. It |
| 126 | +also explicitly avoids waiting for shell prompts after launching |
| 127 | +``vim`` / ``watch`` / ``tail -f`` — the kind of guidance that would |
| 128 | +deadlock an agent following naïve "wait for the prompt between each |
| 129 | +step" advice. |
| 130 | + |
| 131 | +**Parameters:** |
| 132 | + |
| 133 | +- ``session_name`` (str) — name for the new session. |
| 134 | +- ``log_command`` (str, default ``"watch -n 1 date"``) — command to |
| 135 | + run in the logs pane. Pass e.g. ``"tail -f /var/log/syslog"`` on |
| 136 | + Linux or ``"log stream --level info"`` on macOS to override the |
| 137 | + OS-neutral default. |
| 138 | + |
| 139 | +**Sample render** (``session_name="dev"``): |
| 140 | + |
| 141 | +````text |
| 142 | +Set up a 3-pane development workspace named |
| 143 | +'dev' with editor on top, a shell on the bottom-left, and |
| 144 | +a logs tail on the bottom-right: |
| 145 | +
|
| 146 | +1. ``create_session(session_name="dev")`` — creates the |
| 147 | + session with a single pane (pane A, the editor). Capture the |
| 148 | + returned ``active_pane_id`` as ``%A``. |
| 149 | +2. ``split_window(pane_id="%A", direction="below")`` — splits off |
| 150 | + the bottom half (pane B, the terminal). Capture the returned |
| 151 | + ``pane_id`` as ``%B``. |
| 152 | +3. ``split_window(pane_id="%B", direction="right")`` — splits pane B |
| 153 | + horizontally (pane C, the logs pane). Capture the returned |
| 154 | + ``pane_id`` as ``%C``. |
| 155 | +4. Launch the editor and the log command via ``send_keys``: |
| 156 | + ``send_keys(pane_id="%A", keys="vim")`` and |
| 157 | + ``send_keys(pane_id="%C", keys='watch -n 1 date')``. Leave pane B |
| 158 | + at its fresh shell prompt — nothing needs to be sent there. No |
| 159 | + pre-launch wait is required: tmux buffers keystrokes into the |
| 160 | + pane's PTY whether or not the shell has finished drawing, so |
| 161 | + ``send_keys`` immediately after ``split_window`` is safe and |
| 162 | + shell-agnostic. |
| 163 | +5. Optionally confirm each program drew its UI via |
| 164 | + ``wait_for_content_change(pane_id="%A", timeout=3.0)`` |
| 165 | + (and similarly for ``%C``). This is a "did the screen change?" |
| 166 | + check — it works whether the pane shows a prompt glyph, a vim |
| 167 | + splash screen, or a log tail, so no shell-specific regex is |
| 168 | + needed. |
| 169 | +
|
| 170 | +Use pane IDs (``%N``) for all subsequent targeting — they are stable |
| 171 | +across layout changes; window renames are not. |
| 172 | +```` |
| 173 | + |
| 174 | +--- |
| 175 | + |
| 176 | +(interrupt-gracefully)= |
| 177 | + |
| 178 | +## `interrupt_gracefully` |
| 179 | + |
| 180 | +**Use when** the agent needs to stop a running command and confirm |
| 181 | +control returned to the shell — without escalating beyond SIGINT. |
| 182 | + |
| 183 | +**Why use this instead of just sending `C-c`?** The recipe pairs the |
| 184 | +interrupt with a {tool}`wait-for-text` against a common shell prompt |
| 185 | +glyph and an explicit instruction to *stop and ask* if the wait |
| 186 | +times out. That prevents the most dangerous failure mode — an agent |
| 187 | +auto-escalating to ``C-\\`` (SIGQUIT, may core-dump) or ``kill`` |
| 188 | +without operator consent — by drawing a clear escalation boundary. |
| 189 | + |
| 190 | +**Parameters:** |
| 191 | + |
| 192 | +- ``pane_id`` (str) — target pane. |
| 193 | + |
| 194 | +**Sample render** (``pane_id="%1"``): |
| 195 | + |
| 196 | +````text |
| 197 | +Interrupt whatever is running in pane %1 and |
| 198 | +verify that control returns to the shell: |
| 199 | +
|
| 200 | +1. ``send_keys(pane_id="%1", keys="C-c", literal=False, |
| 201 | + enter=False)`` — tmux interprets ``C-c`` as SIGINT. |
| 202 | +2. ``wait_for_text(pane_id="%1", pattern="\$ |\# |\% ", |
| 203 | + regex=True, timeout=5.0)`` — waits for a common shell prompt |
| 204 | + glyph. Adjust the pattern to match the user's shell theme. |
| 205 | +3. If the wait times out the process is ignoring SIGINT. Stop and |
| 206 | + ask the caller how to proceed — do NOT escalate automatically |
| 207 | + to ``C-\`` (SIGQUIT) or ``kill``. |
| 208 | +```` |
| 209 | + |
| 210 | +The shell-prompt regex covers default bash / zsh — adjust for fish |
| 211 | +(``> ``), zsh + oh-my-zsh (``➜ ``), or starship (``❯ ``). When the |
| 212 | +pattern doesn't match the user's prompt theme the recipe times out |
| 213 | +and surfaces the situation to the caller, which is the right |
| 214 | +default for "I tried, can't tell, what should I do?" workflows. |
0 commit comments