Skip to content

Commit abcd184

Browse files
authored
docs(tools): split area pages into per-tool pages by tmux scope (#26)
why: The 7 area pages under `docs/tools/` packed 47 tools into long documents organized by safety tier (Inspect/Act/Destroy). Every `{tool}`…`` reference in prose pointed into section anchors on those pages, and agents navigating the site had to scroll an area page to find a single tool's shape. Per-tool pages align with the Server > Session > Window > Pane hierarchy agents already reason about, give every tool a canonical citable URL, and let the sidebar scope itself to the area the reader is currently in. what: - **47 per-tool pages** organized under six tmux-scope directories: `docs/tools/{server,session,window,pane,buffer,hook}/`. Each page carries the existing `{fastmcp-tool}` directive, its "Use when / Avoid when / Side effects / Example" prose, and the matching `{fastmcp-tool-input}` directive — extracted verbatim from the old area pages, no rewrites. - **Six area `index.md` pages** with `grid-item-card` summaries + hidden `{toctree}` so the left sidebar populates per area. The top-level `tools/index.md` keeps its "Which tool do I want?" decision tree and gains a new scope-grouped toctree. - **`docs/conf.py` `fastmcp_area_map`** remapped from flat area basenames (`"pane_tools": "panes"`) to scope-index paths (`"pane_tools": "pane/index"`). `option_tools` / `env_tools` now route to `server/`; `wait_for_tools` routes to `pane/`. - **`sphinxext-rediraffe` redirects.** Seven entries in `docs/redirects.txt` map every deleted area page to its new scope index — `tools/panes → tools/pane/index`, `tools/sessions → tools/server/index`, `tools/windows → tools/window/index`, `tools/buffers → tools/buffer/index`, `tools/hooks → tools/hook/index`, `tools/options → tools/server/index`, `tools/waits → tools/pane/index`. Rediraffe's check-diff builder confirms each old URL still resolves. - **Three area-level intros restored** to the corresponding scope `index.md` after code-review caught content the mechanical split dropped: `buffer/index.md` now documents UUID-namespacing and the deliberate absence of a `list_buffers` tool (OS- clipboard leak prevention); `hook/index.md` explains the "Why no `set_hook`?" design decision (FastMCP lifespan teardown bypassed on `kill -9` / OOM, leak risk for persistent user servers); `pane/wait-for-channel.md` restores the `send_keys → wait_for_channel` composition pattern and the `; status=$?; tmux wait-for -S NAME; exit $status` load-bearing safety contract for edge-triggered waits. - **One stale relative link fixed.** `pane/search-panes.md` now points at `../../../CHANGES` (three directories up from the new nesting) instead of the old `../../CHANGES`. Supersedes the earlier, stale `docs-overhaul-april-early-2026` branch (PR #12, closed unmerged) — re-derived from current main rather than rebased. Uses gp-sphinx's upstream `sphinx-autodoc-fastmcp` directives, not the local autodoc the earlier branch proposed.
2 parents bd0ad2f + ca17bbc commit abcd184

63 files changed

Lines changed: 2247 additions & 1893 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/conf.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,15 @@
8080
"libtmux_mcp.tools.hook_tools",
8181
]
8282
conf["fastmcp_area_map"] = {
83-
"server_tools": "sessions",
84-
"session_tools": "sessions",
85-
"window_tools": "windows",
86-
"pane_tools": "panes",
87-
"option_tools": "options",
88-
"env_tools": "options",
89-
"buffer_tools": "buffers",
90-
"wait_for_tools": "waits",
91-
"hook_tools": "hooks",
83+
"server_tools": "server/index",
84+
"session_tools": "session/index",
85+
"window_tools": "window/index",
86+
"pane_tools": "pane/index",
87+
"option_tools": "server/index",
88+
"env_tools": "server/index",
89+
"buffer_tools": "buffer/index",
90+
"wait_for_tools": "pane/index",
91+
"hook_tools": "hook/index",
9292
}
9393
conf["fastmcp_server_module"] = "libtmux_mcp.server:mcp"
9494
conf["fastmcp_model_module"] = "libtmux_mcp.models"

docs/redirects.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@
1515
"concepts" "topics/concepts"
1616
"safety" "topics/safety"
1717
"guides/troubleshooting" "topics/troubleshooting"
18+
"tools/panes" "tools/pane/index"
19+
"tools/sessions" "tools/server/index"
20+
"tools/windows" "tools/window/index"
21+
"tools/buffers" "tools/buffer/index"
22+
"tools/hooks" "tools/hook/index"
23+
"tools/options" "tools/server/index"
24+
"tools/waits" "tools/pane/index"

docs/tools/buffer/delete-buffer.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Delete buffer
2+
3+
```{fastmcp-tool} buffer_tools.delete_buffer
4+
```
5+
6+
**Use when** you're done with a buffer and want to free server-side
7+
state. Always call this when the buffer's purpose is complete —
8+
tmux servers outlive the MCP process, so leaked buffers persist
9+
across MCP restarts.
10+
11+
**Side effects:** Removes the named buffer from the tmux server.
12+
Subsequent {tooliconl}`paste-buffer` calls against the deleted name
13+
return `ToolError`.
14+
15+
```{fastmcp-tool-input} buffer_tools.delete_buffer
16+
```

docs/tools/buffer/index.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Buffer tools
2+
3+
tmux paste buffers are a server-global namespace shared by every client on the same socket. The buffer tools in libtmux-mcp expose a narrow, agent-namespaced subset: every allocation gets a UUID-scoped name like `libtmux_mcp_<32-hex>_<logical>`, so concurrent agents (or parallel tool calls from one agent) cannot collide on each other's payloads.
4+
5+
There is **no** `list_buffers` tool. The user's OS clipboard often syncs into tmux paste buffers, so a generic enumeration would leak passwords, tokens, and other private content the agent has no business reading. Callers track the buffers they own via the {tool}`load-buffer` returns.
6+
7+
::::{grid} 1 2 2 3
8+
:gutter: 2 2 3 3
9+
10+
:::{grid-item-card} load_buffer
11+
:link: load-buffer
12+
:link-type: ref
13+
Stage content into a new tmux paste buffer.
14+
:::
15+
16+
:::{grid-item-card} paste_buffer
17+
:link: paste-buffer
18+
:link-type: ref
19+
Push a staged buffer into a pane.
20+
:::
21+
22+
:::{grid-item-card} show_buffer
23+
:link: show-buffer
24+
:link-type: ref
25+
Read a staged buffer's contents back.
26+
:::
27+
28+
:::{grid-item-card} delete_buffer
29+
:link: delete-buffer
30+
:link-type: ref
31+
Free the server-side state of a staged buffer.
32+
:::
33+
34+
::::
35+
36+
```{toctree}
37+
:hidden:
38+
:maxdepth: 1
39+
40+
load-buffer
41+
paste-buffer
42+
show-buffer
43+
delete-buffer
44+
```

docs/tools/buffer/load-buffer.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Load buffer
2+
3+
```{fastmcp-tool} buffer_tools.load_buffer
4+
```
5+
6+
**Use when** you need to stage multi-line text for paste — sending a
7+
shell script, prepared input for an interactive prompt, or content
8+
that's too long for a clean {tooliconl}`send-keys` invocation.
9+
10+
**Avoid when** the text is a single command line that {tooliconl}`send-keys`
11+
can deliver directly. `load_buffer` allocates server-side state that
12+
must be cleaned up via {tooliconl}`delete-buffer`.
13+
14+
**Side effects:** Allocates a tmux paste buffer. Use the returned
15+
`buffer_name` for follow-up calls. The `content` argument is redacted
16+
in audit logs.
17+
18+
**Example:**
19+
20+
```json
21+
{
22+
"tool": "load_buffer",
23+
"arguments": {
24+
"content": "for i in 1 2 3; do\n echo line $i\ndone\n",
25+
"logical_name": "loop"
26+
}
27+
}
28+
```
29+
30+
Response:
31+
32+
```json
33+
{
34+
"buffer_name": "libtmux_mcp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6_loop",
35+
"logical_name": "loop"
36+
}
37+
```
38+
39+
```{fastmcp-tool-input} buffer_tools.load_buffer
40+
```
41+
42+
---
43+
44+
## Paste

docs/tools/buffer/paste-buffer.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Paste buffer
2+
3+
```{fastmcp-tool} buffer_tools.paste_buffer
4+
```
5+
6+
**Use when** you've staged content via {tooliconl}`load-buffer` and
7+
need to push it into a target pane. Use bracketed paste mode
8+
(default `bracket=true`) for terminals that handle it; the wrapping
9+
escape sequences signal "this is pasted text, not typed input".
10+
11+
**Avoid when** the buffer name doesn't match the MCP namespace —
12+
`paste_buffer` refuses non-`libtmux_mcp_*` names so it cannot be
13+
turned into an arbitrary-buffer paster.
14+
15+
**Side effects:** Pastes content into the target pane (the pane's
16+
shell receives the bytes as input). Open-world: the resulting shell
17+
behavior is whatever the pasted bytes invoke.
18+
19+
```{fastmcp-tool-input} buffer_tools.paste_buffer
20+
```
21+
22+
---
23+
24+
## Inspect

docs/tools/buffer/show-buffer.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Show buffer
2+
3+
```{fastmcp-tool} buffer_tools.show_buffer
4+
```
5+
6+
**Use when** you need to confirm what was staged before pasting, or
7+
to read back a buffer between modifications. Restricted to
8+
MCP-namespaced buffers — non-agent buffers are rejected.
9+
10+
**Side effects:** None. Readonly.
11+
12+
```{fastmcp-tool-input} buffer_tools.show_buffer
13+
```
14+
15+
---
16+
17+
## Clean up

docs/tools/buffers.md

Lines changed: 0 additions & 111 deletions
This file was deleted.

docs/tools/hook/index.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Hook tools
2+
3+
tmux hooks let you attach commands to lifecycle events — `pane-exited`, `session-renamed`, `command-error`, and so on. libtmux-mcp exposes **read-only** hook introspection so agents can audit what hooks the human user has configured before running automation that might trigger them.
4+
5+
## Why no `set_hook`?
6+
7+
Write-hooks are deliberately not exposed. tmux servers outlive the MCP process, and FastMCP's `lifespan` teardown runs only on graceful SIGTERM/SIGINT — it's bypassed on `kill -9`, OOM-kill, and C-extension-fault crashes. Any cleanup registry in Python could be silently bypassed, leaking agent-installed shell hooks into the user's persistent tmux server where they would fire forever. Three plausible future paths exist (a tmux-side `client-detached` meta-hook for self-cleanup, requiring `LIBTMUX_SAFETY=destructive`, or exposing one-shot `run_hook` only); none is in scope.
8+
9+
Until one of those paths is implemented, the surface here is visibility only.
10+
11+
## Inspect
12+
13+
::::{grid} 1 2 2 3
14+
:gutter: 2 2 3 3
15+
16+
:::{grid-item-card} show_hooks
17+
:link: show-hooks
18+
:link-type: ref
19+
Enumerate bindings at a scope.
20+
:::
21+
22+
:::{grid-item-card} show_hook
23+
:link: show-hook
24+
:link-type: ref
25+
Inspect a single binding.
26+
:::
27+
28+
::::
29+
30+
```{toctree}
31+
:hidden:
32+
:maxdepth: 1
33+
34+
show-hooks
35+
show-hook
36+
```

docs/tools/hook/show-hook.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Show hook
2+
3+
```{fastmcp-tool} hook_tools.show_hook
4+
```
5+
6+
**Use when** you know which hook you want to inspect by name. Returns
7+
empty when the hook is unset; raises `ToolError` for unknown hook
8+
names (typos, wrong scope) so input mistakes don't masquerade as
9+
"nothing configured".
10+
11+
**Side effects:** None. Readonly.
12+
13+
```{fastmcp-tool-input} hook_tools.show_hook
14+
```

0 commit comments

Comments
 (0)