Skip to content

Releases: tmux-python/libtmux

v0.55.0 - compatibility features, more logging

08 Mar 01:00

Choose a tag to compare

What's Changed

via @tony in #636

Pane.set_title()

New Pane.set_title() method wraps select-pane -T and returns the pane
for method chaining. A Pane.title property aliases pane_title for
convenience:

pane.set_title("my-worker")
pane.pane_title  # 'my-worker'
pane.title       # 'my-worker'

The pane_title format variable is now included in libtmux's pane format
queries (it was previously excluded via an incorrect "removed in 3.1+" comment).

Configurable tmux binary path

Server now accepts a tmux_bin parameter to use an alternative binary
(e.g. wemux, byobu, or a custom build):

server = Server(socket_name="myserver", tmux_bin="/usr/local/bin/tmux-next")

The path is threaded through Server.cmd(), Server.raise_if_dead(),
fetch_objs(), all version-check functions (has_version,
has_gte_version, etc.), and hook scope guards in HooksMixin. Child
objects (Session, Window, Pane) inherit it automatically. Falls back to
shutil.which("tmux") when not set.

Pre-execution command logging

tmux_cmd now emits a structured DEBUG log record with
extra={"tmux_cmd": ...} before invoking the subprocess, using
shlex.join for POSIX-correct quoting. This complements the existing
post-execution stdout log and is a prerequisite for a future dry-run mode.

Bug fix: TmuxCommandNotFound raised for invalid tmux_bin path

Passing a non-existent binary path previously surfaced as a raw
FileNotFoundError from subprocess. Both tmux_cmd and
raise_if_dead now catch FileNotFoundError and raise
TmuxCommandNotFound consistently.

Full Changelog: v0.54.0...v0.55.

v0.54.0 - Revamped logging

07 Mar 16:08

Choose a tag to compare

Highlights

  • Structured lifecycle logging across Server, Session, Window, and Pane with filterable extra context
  • Bug fixes for rename_window(), Server.kill(), new_session(), and kill_window() error handling

What's new

Structured lifecycle logging (#637)

All lifecycle operations (create, kill, rename, split) now emit INFO-level log records with structured extra context. Every log call includes scalar keys for filtering in log aggregators and test assertions via caplog.records:

Key Type Context
tmux_subcommand str tmux subcommand (e.g. new-session)
tmux_target str tmux target specifier
tmux_session str session name
tmux_window str window name or index
tmux_pane str pane identifier

Logging hygiene improvements:

  • NullHandler added to library __init__.py per Python logging best practices
  • DEBUG-level structured logs for tmux_cmd execution with isEnabledFor guards and heavy keys (tmux_stdout, tmux_stderr, tmux_stdout_len, tmux_stderr_len)
  • Lazy formatting: replaced f-string log formatting with %s throughout
  • Diagnostics: replaced traceback.print_stack() with logger.debug(exc_info=True)
  • Options warnings: replaced logger.exception() with logger.warning() and tmux_option_key structured context for recoverable parse failures
  • Cleanup: removed unused logger definitions from modules that don't log

Bug fixes

Window.rename_window() now raises on failure (#637)

Previously rename_window() caught all exceptions and logged them, masking tmux errors. It now propagates the error, consistent with all other command methods.

Server.kill() captures stderr (#637)

Server.kill() previously discarded the tmux return value. It now checks stderr, raises on unexpected errors, and silently returns for expected conditions ("no server running", "error connecting to").

Server.new_session() checks kill-session stderr (#637)

When kill_session=True and the existing session kill fails, new_session() now raises LibTmuxException with the stderr instead of proceeding silently.

Session.kill_window() target formatting fix (#637)

Fixed self.window_name (wrong attribute) to self.session_name when formatting tmux targets for integer target_window values. Also widened the type signature from str | None to str | int | None to match the existing isinstance(target_window, int) branch.


Installation

pip:

$ pip install libtmux==0.54.0

uv:

$ uv add libtmux==0.54.0

What's Changed

  • Add structured logging with lifecycle events and test coverage by @tony in #637

Full Changelog: v0.53.1...v0.54.0

v0.53.1 - Bug fix for new sessions

19 Feb 00:48

Choose a tag to compare

What's Changed

Bug fixes

  • Fix race condition in new_session() by avoiding list-sessions query by @neubig in #625

Development

  • build: Migrate from Makefile to justfile by @tony in #617

New Contributors

Full Changelog: v0.53.0...v0.53.1

v0.53.0 - Bug fixes

14 Dec 12:14

Choose a tag to compare

A focused maintenance release that fixes a critical bug in Session.attach() that caused tracebacks when users killed sessions while attached via tmuxp load.

Highlights

  • Fixed: Session.attach() no longer raises TmuxObjectDoesNotExist when a user kills the session during attachment
  • Breaking: Session.attach() no longer calls refresh() after returning (semantically incorrect for interactive commands)

Bug Fixes

Session.attach() no longer fails if session killed during attachment (#616)

Fixed an issue where Session.attach() would raise TmuxObjectDoesNotExist when a user:

  1. Attaches to a tmux session via tmuxp load
  2. Works in the session
  3. Kills the session (e.g., closes all windows) before detaching
  4. Detaches from tmux

User Experience (Before Fix)

After running tmuxp load, users would see this traceback printed to their terminal after detaching:

Traceback (most recent call last):
  File "~/.local/bin/tmuxp", line 7, in <module>
    sys.exit(cli.cli())
  ...
  File ".../libtmux/session.py", line 332, in attach
    self.refresh()
  File ".../libtmux/neo.py", line 167, in _refresh
    obj = fetch_obj(...)
  File ".../libtmux/neo.py", line 242, in fetch_obj
    raise exc.TmuxObjectDoesNotExist(...)
libtmux.exc.TmuxObjectDoesNotExist: Could not find object

Root Cause

Session.attach() called self.refresh() after the attach-session command returned. Since attach-session is a blocking interactive command, the session state can change arbitrarily during attachment—including being killed entirely.

Technical Details

The refresh() call was semantically incorrect for interactive commands:

  • attach-session blocks until user detaches
  • Session state can change during attachment (user may kill session, rename it, etc.)
  • Refreshing the object after such a command makes no sense—the state could be anything

The fix: Remove the self.refresh() call from Session.attach() (2 lines removed).


Breaking Changes

Session.attach() no longer calls refresh() (#616)

Session.attach() previously called Session.refresh() after the attach-session command returned. This was semantically incorrect since attach-session is a blocking interactive command where session state can change arbitrarily during attachment.

This was never strictly defined behavior as libtmux abstracts tmux internals away. Code that relied on the session object being refreshed after attach() should explicitly call session.refresh() if needed.

Migration

# If you relied on the implicit refresh (unlikely):
session.attach()
session.refresh()  # Now explicit if you need it

Timeline

Date Event
Feb 2024 Session.attach() added with refresh() call (9a5147a)
Nov 2025 tmuxp switched from attach_session() to attach() (fdafdd2b)
Dec 2025 Users started experiencing the bug
Dec 2025 v0.53.0 released with fix

Installation

pip:

pip install libtmux==0.53.0

uv:

uv add libtmux==0.53.0

pipx (for tmuxp users):

pipx upgrade tmuxp

What's Changed

  • fix(Session.attach()): Remove refresh() call that fails after session killed by @tony in #616

Full Changelog: v0.52.1...v0.53.0

v0.52.1 - Trusted Publisher for PyPI builds

07 Dec 21:42

Choose a tag to compare

Development

  • ci(release): Migrate to PyPI Trusted Publisher by @tony in #615

Full Changelog: v0.52.0...v0.52.1

v0.52.0 - `send_keys()` updates

07 Dec 20:49

Choose a tag to compare

libtmux 0.52.0

capture_pane() enhancements

The Pane.capture_pane() method now supports 5 new parameters exposing additional tmux capture-pane flags:

Parameter tmux Flag Description
escape_sequences -e Include ANSI escape sequences (colors, attributes)
escape_non_printable -C Escape non-printable chars as octal \xxx
join_wrapped -J Join wrapped lines back together
preserve_trailing -N Preserve trailing spaces at line ends
trim_trailing -T Trim trailing empty positions (tmux 3.4+)

Examples

Capturing colored output:

# Capture with ANSI escape sequences preserved
pane.send_keys('printf "\\033[31mRED\\033[0m"', enter=True)
output = pane.capture_pane(escape_sequences=True)
# Output contains: '\x1b[31mRED\x1b[0m'

Joining wrapped lines:

# Long lines that wrap are joined back together
output = pane.capture_pane(join_wrapped=True)

Version compatibility

The trim_trailing parameter requires tmux 3.4+. If used with an older version, a warning is issued and the flag is ignored. All other parameters work with libtmux's minimum supported version (tmux 3.2a).

What's Changed

Full Changelog: v0.51.0...v0.52.0

v0.51.0 (Breaking API deprecations)

06 Dec 21:16

Choose a tag to compare

Breaking Changes

Deprecate legacy APIs

Legacy API methods (deprecated in v0.16–v0.33) now raise DeprecatedError (hard error) instead of emitting DeprecationWarning.

See the migration guide for full context and examples.

  • Deprecate legacy APIs (raise DeprecatedError) by @tony in #611

Method Renamings

Deprecated Replacement Class Deprecated Since
kill_server() kill() Server 0.30.0
attach_session() attach() Session 0.30.0
kill_session() kill() Session 0.30.0
select_window() select() Window 0.30.0
kill_window() kill() Window 0.30.0
split_window() split() Window 0.33.0
select_pane() select() Pane 0.30.0
resize_pane() resize() Pane 0.28.0
split_window() split() Pane 0.33.0

Property Renamings

Deprecated Replacement Class Deprecated Since
attached_window active_window Session 0.31.0
attached_pane active_pane Session 0.31.0
attached_pane active_pane Window 0.31.0

Query/Filter API Changes

Deprecated Replacement Class Deprecated Since
list_sessions() / _list_sessions() sessions property Server 0.17.0
list_windows() / _list_windows() windows property Session 0.17.0
list_panes() / _list_panes() panes property Window 0.17.0
where({...}) .filter(**kwargs) on sessions/windows/panes All 0.17.0
find_where({...}) .get(default=None, **kwargs) on sessions/windows/panes All 0.17.0
get_by_id(id) .get(session_id/window_id/pane_id=..., default=None) All 0.16.0
children property sessions/windows/panes All 0.17.0

Attribute Access Changes

Deprecated Replacement Deprecated Since
obj['key'] obj.key 0.17.0
obj.get('key') obj.key 0.17.0
obj.get('key', None) getattr(obj, 'key', None) 0.17.0

Still Soft Deprecations (DeprecationWarning)

The following deprecations from v0.50.0 continue to emit DeprecationWarning only:

Deprecated Replacement Class
set_window_option() set_option() Window
show_window_option() show_option() Window
show_window_options() show_options() Window
g parameter global_ parameter Options & hooks methods

Migration Example

Before (deprecated, now raises DeprecatedError):

# Old method names
server.kill_server()
session.attach_session()
window.split_window()
pane.resize_pane()

# Old query API
server.list_sessions()
session.find_where({'window_name': 'main'})

# Old dict-style access
window['window_name']

After:

# New method names
server.kill()
session.attach()
window.split()
pane.resize()

# New query API
server.sessions
session.windows.get(window_name='main', default=None)

# New attribute access
window.window_name

Links

Full Changelog: v0.50.1...v0.51.0

v0.50.1 - Maintenance release

06 Dec 17:15

Choose a tag to compare

Documentation

Full Changelog: v0.50.0...v0.50.1

v0.50.0 - options and hook management

30 Nov 21:42

Choose a tag to compare

libtmux 0.50 brings a major enhancement to option and hook management with a unified, typed API for managing tmux options and hooks across all object types.

Highlights

  • Unified Options API: New show_option(), show_options(), set_option(), and unset_option() methods available on Server, Session, Window, and Pane
  • Hook Management: Full programmatic control over tmux hooks with support for indexed hook arrays and bulk operations
  • SparseArray: New internal data structure for handling tmux's sparse indexed arrays (e.g., command-alias[0], command-alias[99])
  • tmux 3.2+ baseline: Removed support for tmux versions below 3.2a, enabling cleaner code and full hook/option feature support

Unified Options API

All tmux objects now share a consistent options interface:

import libtmux

server = libtmux.Server()
session = server.sessions[0]
window = session.windows[0]

# Get all options as a structured dict
session.show_options()
# {'activity-action': 'other', 'base-index': 0, ...}

# Get a single option value
session.show_option('base-index')
# 0

# Set an option
window.set_option('automatic-rename', True)

# Unset an option (revert to default)
window.unset_option('automatic-rename')

Hook Management

Programmatic control over tmux hooks:

session = server.sessions[0]

# Set a hook
session.set_hook('session-renamed', 'display-message "Renamed!"')

# Get hook value (returns SparseArray for indexed hooks)
session.show_hook('session-renamed')
# {0: 'display-message "Renamed!"'}

# Get all hooks
session.show_hooks()

# Remove a hook
session.unset_hook('session-renamed')

# Bulk operations for indexed hooks
session.set_hooks('session-renamed', {
    0: 'display-message "Hook 0"',
    1: 'display-message "Hook 1"',
    5: 'run-shell "echo hook 5"',
})

Breaking Changes

Deprecated Window methods

The following methods are deprecated and will be removed in a future release:

Deprecated Replacement
Window.set_window_option() Window.set_option()
Window.show_window_option() Window.show_option()
Window.show_window_options() Window.show_options()

Deprecated g parameter

The g parameter for global options is deprecated in favor of global_:

# Before (deprecated)
session.show_option('status', g=True)

# After (0.50.0+)
session.show_option('status', global_=True)

New Constants

  • OptionScope enum: Server, Session, Window, Pane
  • OPTION_SCOPE_FLAG_MAP: Maps scope to tmux flags (-s, -w, -p)
  • HOOK_SCOPE_FLAG_MAP: Maps scope to hook flags

Documentation

  • New topic guide: Options and Hooks
  • New topic guides: Automation patterns, Workspace setup, Pane interaction, QueryList filtering
  • Refreshed README with hero section, quickstart, and more examples

tmux Version Compatibility

Feature Minimum tmux
All options/hooks features 3.2+
Window/Pane hook scopes (-w, -p) 3.2+
client-active, window-resized hooks 3.3+
pane-title-changed hook 3.5+

What's Changed

  • Improved option management, add hook management by @tony in #516
  • Refresh README by @tony in #609

Full Changelog: v0.49.0...v0.50.0

v0.49.0 (drop tmux < 3.2)

29 Nov 23:30

Choose a tag to compare

What's Changed

Breaking: tmux <3.2 fully dropped

  • Drop support for tmux versions < 3.2 by @tony in #608

Full Changelog: v0.48.0...v0.49.0