@@ -45,35 +45,32 @@ $ uvx --from 'libtmux' --prerelease allow python
4545_ Notes on the upcoming release will go here._
4646<!-- END PLACEHOLDER - ADD NEW CHANGELOG ENTRIES BELOW THIS LINE -->
4747
48- libtmux 0.57.0 broadens tmux support. It introduces
49- {class}` ~libtmux.Client ` as a first-class object, threads tmux's
50- native `` -f `` filter through the typed listing methods so callers can
51- push predicates into the tmux server, and adds typed access to many
52- more format tokens — all scope- and version-gated so they're safe on
53- every supported tmux version. Subcommand context now flows through
54- {exc}` ~libtmux.exc.LibTmuxException ` , making it easier for downstream
55- tools to dispatch on which tmux command produced an error.
48+ libtmux 0.57.0 broadens tmux support around attached clients, tmux-native
49+ filtering, and format-token fields. {class}` ~libtmux.Client ` gives callers a
50+ typed object for attached terminals, ` search_*() ` methods let tmux return only
51+ matching sessions, windows, and panes, and more tmux format tokens are exposed
52+ as typed attributes. {exc}` ~libtmux.exc.LibTmuxException ` now records which
53+ tmux subcommand failed, making command errors easier to handle downstream.
5654
5755### Breaking changes
5856
5957#### ` LibTmuxException ` string form gains a subcommand prefix (#672 )
6058
61- When {exc}` ~libtmux.exc.LibTmuxException ` is raised from one of the
62- typed command wrappers, `` str(exc) `` now begins with the originating
63- tmux subcommand name followed by `` ": " `` . For example, an error from
59+ When {exc}` ~libtmux.exc.LibTmuxException ` is raised from a libtmux method,
60+ `` str(exc) `` now begins with the originating tmux subcommand name followed
61+ by `` ": " `` . For example, an error from
6462{meth}` ~libtmux.Session.last_window ` used to render as ``"can't find
6563window"`` and now renders as `` "last-window: can't find window"``.
6664
67- `` exc.args[0] `` still carries the raw tmux output , and the new
65+ `` exc.args[0] `` still carries the original tmux error text , and the new
6866{attr}` ~libtmux.exc.LibTmuxException.subcommand ` attribute exposes
6967the tmux subcommand name as a separate field.
7068{func}` ~libtmux.common.raise_if_stderr ` is the shared helper that
7169populates both.
7270
73- The wrapped-stderr * type* changed: `` exc.args[0] `` is now `` str `` ,
71+ The error-payload * type* changed: `` exc.args[0] `` is now `` str `` ,
7472joined with `` "\n" `` when tmux emitted multiple stderr lines.
75- Previously it was `` list[str] `` — the raw `` proc.stderr `` was
76- passed through to :class:` Exception ` directly.
73+ Previously it was `` list[str] `` .
7774
7875This is a serialization-format change: code that pattern-matches on
7976`` str(exc) `` exactly, anchors a regex with `` ^ `` against the old
@@ -95,7 +92,7 @@ except LibTmuxException as exc:
9592 if exc.subcommand == " last-window" :
9693 ...
9794
98- # Or — match against the raw stderr without the prefix
95+ # Or — match against the original tmux error text without the prefix
9996try :
10097 session.last_window()
10198except LibTmuxException as exc:
@@ -110,20 +107,19 @@ Substring matches (``"can't find" in str(exc)``) and unanchored
110107
111108Previously, a tmux command failure under
112109{attr}` ~libtmux.Server.sessions ` , {attr}` ~libtmux.Server.clients ` , or
113- {meth}` ~libtmux.Server.search_sessions ` was swallowed by a bare
114- `` except Exception: pass `` , returning an empty
110+ {meth}` ~libtmux.Server.search_sessions ` could return an empty
115111{class}` ~libtmux._internal.query_list.QueryList ` indistinguishable
116112from "no sessions / no clients attached" or "filter matched nothing".
117- The wrappers now let {exc}` ~libtmux.exc.LibTmuxException ` propagate
118- via {func} ` ~libtmux.common.raise_if_stderr ` .
113+ Those accessors now let {exc}` ~libtmux.exc.LibTmuxException ` propagate
114+ for real tmux failures .
119115
120116Genuine empty results — a server with no attached clients, or a
121117filter that matched zero sessions — still return an empty
122- `` QueryList `` . `` "no server running" `` is also still treated as
123- an empty result, preserving the historic contract that a fresh
124- {class}` ~libtmux.Server ` can be safely introspected before its
125- daemon is up. Only real tmux errors (subprocess crash, malformed
126- output, version-incompatible flags) now surface.
118+ `` QueryList `` . A missing or not-yet-started tmux server is also still
119+ treated as an empty result, preserving the historic contract that a fresh
120+ {class}` ~libtmux.Server ` can be safely introspected before its daemon is
121+ up. Other tmux errors, such as socket permission failures or unsupported
122+ flags, now surface.
127123
128124``` python
129125# Before — silent on tmux failure
@@ -144,17 +140,15 @@ else:
144140
145141#### ` Client ` object and ` Server.clients ` accessor (#672 )
146142
147- New {class}` ~libtmux.Client ` dataclass and
148- {attr}` ~libtmux.Server.clients ` property bring typed-ORM ergonomics
149- to tmux's attached-client model. Reads like `` client.client_readonly ``
150- and `` client.client_session `` work directly on the client instead of
151- forcing callers down to {meth}` ~libtmux.Server.cmd ` .
143+ New {class}` ~libtmux.Client ` and {attr}` ~libtmux.Server.clients ` support tmux's
144+ attached-client model directly. Reads like `` client.client_readonly `` and
145+ `` client.client_session `` work on the client object without dropping down to
146+ {meth}` ~libtmux.Server.cmd ` .
152147
153- Note that `` client.session_id `` / `` client.window_id `` /
154- `` client.pane_id `` reflect the client's currently attached view at
155- hydration time — {meth}` ~libtmux.Client.refresh ` re-reads them after
156- the client switches focus. `` client.client_name `` is the client's
157- stable identifier.
148+ Note that `` client.session_id `` / `` client.window_id `` / `` client.pane_id ``
149+ reflect the client's attached view when the object was read —
150+ {meth}` ~libtmux.Client.refresh ` re-reads them after the client switches focus.
151+ `` client.client_name `` is the client's stable identifier.
158152
159153For typed access to the live attachment, use
160154{attr}` ~libtmux.Client.attached_session ` ,
@@ -170,11 +164,10 @@ Direct {meth}`~libtmux.Client.refresh` and
170164{meth}` ~libtmux.Client.from_client_name ` calls still surface missing
171165client lookup errors.
172166
173- {attr}` ~libtmux.Client.attached_pane ` is session-scope: it returns
174- the session's current window's active pane, not the client's
175- `` CLIENT_ACTIVEPANE `` focus. The two diverge once a client has used
176- `` select-pane -P `` to set its own active pane. See
177- {attr}` ~libtmux.Client.attached_pane ` for the resolution detail.
167+ {attr}` ~libtmux.Client.attached_pane ` follows the attached session's current
168+ window. That can differ from the per-client active pane set by
169+ `` select-pane -P `` ; see {attr}` ~libtmux.Client.attached_pane ` for the exact
170+ behavior.
178171
179172#### ` Server.display_message ` and ` Window.display_message ` (#672 )
180173
@@ -190,22 +183,20 @@ rather than dropping it silently. tmux uses stderr for both genuine
190183errors and informational messages on some versions, so the wrappers
191184warn rather than raise; callers that want to escalate can wrap the
192185call in :func:` warnings.catch_warnings ` with
193- `` filterwarnings("error") `` . See {doc}` MIGRATION ` for the escalation
186+ `` filterwarnings("error") `` . See {doc}` migration ` for the escalation
194187pattern.
195188
196- #### Native filter on typed listing methods (#672 )
189+ #### tmux-native filtering with ` search_*() ` (#672 )
197190
198191{meth}` ~libtmux.Server.search_panes ` ,
199192{meth}` ~libtmux.Server.search_windows ` ,
200193{meth}` ~libtmux.Server.search_sessions ` , and the Session/Window
201194analogues take a `` filter= `` kwarg routed to tmux's `` -f `` flag. tmux
202- evaluates the predicate and drops non-matching objects before any
203- Python instance is constructed.
195+ evaluates the expression and returns only matching objects.
204196
205- Caveat: tmux silently expands a malformed predicate to empty, which
206- the format engine treats as false — a typo looks identical to "no
207- matches". Verify predicate syntax against the FORMATS section of
208- `` tmux(1) `` .
197+ Caveat: tmux silently expands a malformed filter expression to empty, which
198+ it treats as false — a typo looks identical to "no matches". Verify filter
199+ syntax against the FORMATS section of `` tmux(1) `` .
209200
210201#### ` Pane.send_keys(cmd=None, …) ` flag-only invocation (#672 )
211202
@@ -217,10 +208,9 @@ key argument.
217208#### ` Server.list_buffers(format_string=, filter=) ` (#672 )
218209
219210{meth}` ~libtmux.Server.list_buffers ` gains `` format_string `` (`` -F `` )
220- and `` filter `` (`` -f `` ) kwargs. Callers can project a chosen template
221- (e.g. `` "#{buffer_name}" `` ) or push a buffer-name match expression
222- into tmux's format engine — same bad-filter caveat as the
223- `` search_* `` methods.
211+ and `` filter `` (`` -f `` ) kwargs. Callers can ask tmux to return selected
212+ fields (e.g. `` "#{buffer_name}" `` ) or only buffers matching an expression —
213+ same bad-filter caveat as the `` search_* `` methods.
224214
225215#### ` Server.run_shell(cwd=, show_stderr=) ` (#672 )
226216
@@ -237,31 +227,22 @@ returns bytes tmux has read from the pane but not yet committed to
237227the terminal — useful for diagnosing programs whose output stalls
238228mid-sequence.
239229
240- #### Scope-aware format-token retrieval (#672 )
230+ #### More format-token fields on tmux objects (#672 )
241231
242- The `` -F `` template libtmux sends to each `` list-* `` subcommand is now
243- scope- and version-aware. tmux's format engine cascades context
244- downward from client → session → current window → active pane, so a
245- `` Session `` row hydrates active-window and active-pane fields via that
246- cascade, and a `` Client `` row likewise hydrates the client's attached
247- session, window, and active pane. `` client_* `` tokens resolve only
248- under `` list-clients `` because tmux has no reverse cascade. Tokens
249- introduced after tmux 3.2a are gated through `` FIELD_VERSION `` so the
250- format string stays compatible with the project's minimum supported
251- tmux. Tokens the running tmux doesn't recognize stay `` None `` on the
252- typed surface — no crash, no warning.
232+ libtmux now asks each `` list-* `` subcommand for the format tokens that make
233+ sense for that object and tmux version. Tokens the running tmux does not
234+ support stay `` None `` instead of making the listing fail.
253235
254236{class}` ~libtmux.Pane ` , {class}` ~libtmux.Window ` ,
255- {class}` ~libtmux.Session ` , and {class}` ~libtmux.Client ` declare typed
256- dataclass fields for the scope-relevant tokens that ship in tmux 3.2a,
257- including pane state (`` pane_dead `` , `` pane_in_mode `` , `` pane_marked `` ,
258- `` pane_synchronized `` , `` pane_path `` , `` pane_pipe `` …), window state
259- (`` window_zoomed_flag `` , `` window_silence_flag `` , `` window_flags `` …),
260- session state (`` session_marked `` …), and the client view
261- (`` client_session `` , `` client_readonly `` , `` client_termtype `` …). Typed
262- fields for tokens tmux added in 3.4 / 3.5 / 3.6 and the forward-looking
263- set from tmux master will land in a follow-up shipment once those
264- releases can be validated end-to-end.
237+ {class}` ~libtmux.Session ` , and {class}` ~libtmux.Client ` expose more typed
238+ attributes for pane state (`` pane_dead `` , `` pane_in_mode `` , `` pane_marked `` ,
239+ `` pane_synchronized `` , `` pane_path `` , `` pane_pipe `` ), window state
240+ (`` window_zoomed_flag `` , `` window_silence_flag `` , `` window_flags `` ), session
241+ state (`` session_marked `` ), and client state (`` client_session `` ,
242+ `` client_readonly `` , `` client_termtype `` ). Some fields describe the active
243+ child object tmux reports with the row: for example, `` session.pane_id `` is
244+ the active pane in the session's current window, not a separate "session
245+ pane." See {ref}` format-tokens ` for details.
265246
266247### Fixes
267248
@@ -272,10 +253,9 @@ releases can be validated end-to-end.
272253### Documentation
273254
274255- New API page: {doc}` api/libtmux.client ` .
275- - {class}` ~libtmux.neo.Obj ` 's class docstring documents the
276- downward-cascade resolution target so readers know that, for
277- example, `` session.pane_id `` is the session's * current window's
278- active* pane — not "the session's pane" (#672 ).
256+ - New {ref}` format-tokens ` topic explains why some fields describe an active
257+ child object, such as `` session.pane_id `` reflecting the active pane in the
258+ session's current window (#672 ).
279259
280260## libtmux 0.56.0 (2026-05-10)
281261
0 commit comments