Skip to content

Commit ba26d68

Browse files
committed
mcp(docs[tools/prompts]): document the four MCP recipe prompts
The four prompts shipped this branch (``run_and_wait``, ``diagnose_failing_pane``, ``build_dev_workspace``, ``interrupt_gracefully``) had zero docs coverage — no ``{fastmcp-prompt}`` autodoc directive (the sphinx-autodoc-fastmcp extension only ships ``{fastmcp-tool}``, ``{fastmcp-tool-input}``, ``{fastmcp-tool-summary}``; verified by reading the installed extension's ``__init__.py``), and ``docs/topics/prompting.md`` covers general agent-prompting heuristics rather than the project's MCP-registered prompts. Adds ``docs/tools/prompts.md`` — a hand-written page (since autodoc isn't available for prompts) with one section per recipe covering: when to use it, why it exists vs. the obvious alternative tool calls, parameters, and a sample render at one representative argument set. The samples use stable representative output (``<uuid>`` placeholder for the wait-for channel) so the page doesn't churn on every regeneration. Wires the new page into the docs toctree under "Use it" between ``tools/index`` and ``recipes`` (the latter is the longer narrative agent-reasoning page, conceptually distinct from these short MCP-protocol prompts). Adds a one-paragraph cross-reference from ``docs/tools/index.md``'s decision tree so readers discovering the tool surface find the prompts naturally.
1 parent bac1ae7 commit ba26d68

3 files changed

Lines changed: 222 additions & 0 deletions

File tree

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ clients
9393
:caption: Use it
9494
9595
tools/index
96+
tools/prompts
9697
recipes
9798
configuration
9899
```

docs/tools/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ All tools accept an optional `socket_name` parameter for multi-server support. I
5656
- tmux options → {tool}`show-option` / {tool}`set-option`
5757
- Environment vars → {tool}`show-environment` / {tool}`set-environment`
5858

59+
**Reaching for a workflow recipe?** The server also ships four
60+
short MCP prompts the client renders for the model — see
61+
{doc}`/tools/prompts`. They cover the most common patterns
62+
(run-and-wait, diagnose-failing-pane, build-dev-workspace,
63+
interrupt-gracefully) with embedded UUID-scoped wait channels and
64+
shell-agnostic guidance.
65+
5966
## Inspect
6067

6168
Read tmux state without changing anything.

docs/tools/prompts.md

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
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

Comments
 (0)