-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMIGRATION
More file actions
244 lines (179 loc) · 8.78 KB
/
Copy pathMIGRATION
File metadata and controls
244 lines (179 loc) · 8.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# Migration notes
Migration and deprecation notes for libtmux-mcp are here, see {ref}`history`
for the full release log.
```{admonition} Welcome on board! 👋
1. 📌 For safety, **always** pin the package version in your install
2. 📖 Check the migration notes _(You are here)_
3. 📣 If a deprecation interrupted you - past, present, or future - voice your opinion on the [tracker].
We want to make libtmux-mcp fun, reliable, and useful for users.
API changes can be painful.
If we can do something to draw the sting, we'll do it. We're taking a balanced approach. That's why these notes are here!
(Please pin the package. 🙏)
[tracker]: https://github.com/tmux-python/libtmux-mcp/discussions
```
## libtmux-mcp 0.1.0a21 (2026-08-30)
### `LIBTMUX_SAFETY` now crashes the server on load
`readonly`, `mutating` and `destructive` are gone. Tools belong to four
unordered toolsets named for what they do.
A server started with `LIBTMUX_SAFETY` still set raises while the module
loads, before it serves a request. Every value crashes, the former default
`mutating` included. Your MCP client reports a server that failed to start;
the message naming the replacement goes to the process's stderr, so read the
client's server log if the failure looks silent.
The variable is not ignored, and that is deliberate: one that silently
stopped working would leave you believing a surface was narrower than it is.
#### The new default names no environment variables
An unset {envvar}`LIBTMUX_TOOLSETS` selects `inspect,manage,execute` — the surface
`mutating` gave you. If you were on the old default, delete `LIBTMUX_SAFETY`
from your client config and put nothing in its place:
```json
{
"mcpServers": {
"tmux": {
"command": "uvx",
"args": ["libtmux-mcp"]
}
}
}
```
Name a variable only to move off that default.
#### Environment variables
| Before | After |
| --- | --- |
| `LIBTMUX_SAFETY=readonly` | `LIBTMUX_TOOLSETS=inspect` |
| `LIBTMUX_SAFETY=mutating` (the default) | nothing — the default is `inspect,manage,execute` |
| `LIBTMUX_SAFETY=destructive` | `LIBTMUX_TOOLSETS=inspect,manage,execute,teardown` |
Two variables are new. {envvar}`LIBTMUX_TOOLS` enables individual tools
regardless of toolset, and {envvar}`LIBTMUX_EXCLUDE_TOOLS` refuses them
regardless of every
enable above. An unknown name in any of the three fails startup the same way.
### Surfaces the tiers could not express
The tiers accumulated upward, so every surface was a prefix of the ladder.
The toolsets are a set, so this is now legal:
```console
$ LIBTMUX_TOOLSETS=inspect,teardown libtmux-mcp
```
An agent that can look and clean up, but not type.
### Tool names
| Before | After |
| --- | --- |
| `call_readonly_tools_batch` | {tooliconl}`call-read-tools-batch` |
| `call_mutating_tools_batch` | removed — call the tool directly |
| `call_destructive_tools_batch` | removed — call the tool directly |
A batch gives every nested call the wrapper's name, so a client rule keyed
on {tooliconl}`kill-session` never fires for a `kill_session` run inside one. That is
tolerable for reads and not for writes.
### Which toolset a tool is in
`inspect`
: Every `list_*`, `get_*`, `show_*`, `capture_*`, {toolref}`snapshot-pane`,
{toolref}`search-panes`, {toolref}`find-pane-by-position`,
{toolref}`display-message`, {toolref}`wait-for-text`,
{toolref}`call-read-tools-batch`.
`manage`
: `rename_*`, `select_*`, `resize_*`, {toolref}`move-window`,
{toolref}`swap-pane`, {toolref}`set-pane-title`, {toolref}`enter-copy-mode`,
{toolref}`exit-copy-mode`, {toolref}`wait-for-channel`,
{toolref}`signal-channel`, {toolref}`load-buffer`.
`execute`
: {toolref}`create-session`, {toolref}`create-window`,
{toolref}`split-window`, {toolref}`respawn-pane`, {toolref}`run-command`,
{toolref}`send-keys`, {toolref}`send-keys-batch`, {toolref}`paste-text`,
{toolref}`paste-buffer`, {toolref}`pipe-pane`, {toolref}`set-option`,
{toolref}`set-environment`.
`set_option` and `set_environment` are here rather than in `manage`
because tmux runs some stored values later: a `#(...)` job in a status
format runs when tmux draws it and repeats on the status interval, and
`default-command` decides what every future pane runs.
`teardown`
: {toolref}`kill-pane`, {toolref}`kill-window`, {toolref}`kill-session`,
{toolref}`kill-server`, {toolref}`clear-pane`, {toolref}`delete-buffer`.
### Documentation
The safety topic is now the {ref}`trust` page. The old URL redirects.
### MCP annotations
Every tool that requests a tmux operation now explicitly advertises
`readOnlyHint: false`,
`destructiveHint: true`, `idempotentHint: false`, and `openWorldHint: true`.
An existing tmux server can use aliases and hooks to replace or extend the
operation libtmux-mcp requests, so no stronger static promise holds for every
target. The optional prompt adapter tools render text without contacting tmux
and retain their narrower hints. Use the project-owned toolsets to distinguish
the direct operation libtmux-mcp requests.
## libtmux-mcp 0.1.0a19 (2026-07-25)
### `wait_for_text` takes `patterns`, and `wait_for_content_change` is gone
{tooliconl}`wait-for-text` accepted a single `pattern` string. It now takes `patterns`, a
list — or `null` to wait for any new output at all. The schema rejects the old
argument rather than silently ignoring it, so a call written against the old
signature fails loudly with `Remove or correct the unrecognized argument(s):
pattern`.
#### Before
```json
{"tool": "wait_for_text", "arguments": {"pane_id": "%1", "pattern": "ready"}}
```
#### After
```json
{"tool": "wait_for_text", "arguments": {"pane_id": "%1", "patterns": ["ready"]}}
```
`wait_for_content_change` and its `ContentChangeResult` are removed. Pass
`patterns: null` instead — it waits for any new output and additionally
excludes pre-existing scrollback and stale paint from the change predicate,
which the old tool did not.
```json
{"tool": "wait_for_text", "arguments": {"pane_id": "%1", "patterns": null}}
```
### Waits are capped by the server
{toolref}`wait-for-text`, {toolref}`wait-for-channel`, and
{toolref}`run-command` are all bounded by
{envvar}`LIBTMUX_MCP_WAIT_MAX_SECONDS` (30 seconds by default, clamped to `[1, 120]`).
An over-large `timeout` is **clamped, not rejected** — the call succeeds and
reports the value actually enforced, so read `effective_timeout` rather than
assuming your value was honoured. A wait that previously blocked for an hour
now returns at the ceiling.
Raise the ceiling with the environment variable if your workload needs it, or
call again — the command keeps running in the pane between calls.
### `WaitForTextResult` reports an `outcome`
The result's loose booleans are replaced by one `outcome` field taking
`matched`, `any_output`, `stopped`, `alternate_screen`, or `timeout`.
`risk_band_warned` is removed; the history-limit trim signal is delivered as an
MCP warning notification instead. Clients that cannot surface notifications
should compose `tmux wait-for -S` into the command and use
{tooliconl}`wait-for-channel`,
which does not read the pane at all.
### Self-bounded tools cannot be batched
{toolref}`run-command`, {toolref}`wait-for-text`, and
{toolref}`wait-for-channel` are rejected by the
batch wrappers per operation, because batching one multiplied the wait ceiling
by the operation count. Use {tooliconl}`send-keys-batch` for command sequences, or call
the tool directly.
## libtmux-mcp 0.1.0a6 (2026-05-09)
### Recommended registration slug: `libtmux` → `tmux`
Earlier docs and install widgets recommended registering the server as
`libtmux`. From 0.1.0a6 onward the recommended slug is `tmux`, matching
the value of `serverInfo.name` returned in the MCP handshake and the
`mcp__tmux__*` tool prefix that clients namespace tool calls under.
**Existing installations continue to work.** The slug is a per-install
user choice — your client looks up the server by whatever name you
registered. Migration is optional; it only matters if you want the new
`tmux` prefix on tool calls. Claude Code's `claude mcp remove <name>`
auto-detects the registration scope (verified against
`claude --version 2.1.138`), so the commands below work whether you
originally registered at `local`, `user`, or `project` scope.
#### Before
```console
$ claude mcp add libtmux -- uvx libtmux-mcp
```
→ tools surface as `mcp__libtmux__list_panes`, `mcp__libtmux__send_keys`, …
#### After
```console
$ claude mcp remove libtmux
```
```console
$ claude mcp add tmux -- uvx libtmux-mcp
```
→ tools surface as `mcp__tmux__list_panes`, `mcp__tmux__send_keys`, …
#### What's unchanged
- PyPI package name: `libtmux-mcp`
- Python module: `libtmux_mcp`
- GitHub repository: <https://github.com/tmux-python/libtmux-mcp>
- Existing `mcp__libtmux__*` references in CLAUDE.md / AGENTS.md
templates and agent histories continue to work if you keep the
`libtmux` slug.