# Changelog

For instructions on installing the development version of libtmux, refer to
[development releases](https://libtmux.git-pull.com/quickstart.html#developmental-releases).

[pip](https://pip.pypa.io/en/stable/):

```console
$ pip install --user --upgrade --pre libtmux
```

[pipx](https://pypa.github.io/pipx/docs/):

```console
$ pipx install \
    --suffix=@next \
    --pip-args '\--pre' \
    --force \
    'libtmux'
```

Run the suffixed executable as:

```console
$ libtmux@next [command]
```

[uv](https://docs.astral.sh/uv/):

```console
$ uv add libtmux --prerelease allow
```

[uvx](https://docs.astral.sh/uv/guides/tools/):

```console
$ uvx --from 'libtmux' --prerelease allow python
```

## libtmux 0.63.x (Yet to be released)

<!-- To maintainers and contributors: Please add notes for the forthcoming version below -->

<!-- KEEP THIS PLACEHOLDER - DO NOT REMOVE OR MODIFY THIS LINE -->
_Notes on the upcoming release will go here._
<!-- END PLACEHOLDER - ADD NEW CHANGELOG ENTRIES BELOW THIS LINE -->

## libtmux 0.62.0 (2026-07-12)

libtmux 0.62.0 teaches libtmux objects to locate themselves and to resolve
shared windows the way tmux does. Code running *inside* tmux can now find its
own pane, window, session, and server with
{meth}`Pane.from_env() <libtmux.Pane.from_env>` and its siblings, and a window
reports every session that holds it through
{attr}`~libtmux.Window.linked_sessions`. Point lookups now resolve a linked
window to the session and index tmux itself would act on rather than an
arbitrary one. The release also folds {exc}`~libtmux.exc.ObjectDoesNotExist`
and {exc}`~libtmux.exc.MultipleObjectsReturned` into the
{exc}`~libtmux.exc.LibTmuxException` hierarchy — a breaking change for
exception handlers, detailed below. See {ref}`self-location` and
{ref}`winlinks` for the full story.

### Breaking changes

#### Query errors join the libtmux exception hierarchy (#718)

{exc}`~libtmux.exc.ObjectDoesNotExist` and
{exc}`~libtmux.exc.MultipleObjectsReturned` now subclass
{exc}`~libtmux.exc.LibTmuxException`. Because
{exc}`~libtmux.exc.TmuxObjectDoesNotExist` inherits from
{exc}`~libtmux.exc.ObjectDoesNotExist`, it now falls under
{exc}`~libtmux.exc.LibTmuxException` as well. Previously, a lookup-specific
handler could follow the common libtmux handler:

```python
from libtmux import exc

try:
    pane = server.panes.get(pane_id="%0")
except exc.LibTmuxException:
    pane = None
except exc.ObjectDoesNotExist:
    pane = None
```

Put the more specific handler first:

```python
from libtmux import exc

try:
    pane = server.panes.get(pane_id="%0")
except exc.ObjectDoesNotExist:
    pane = None
except exc.LibTmuxException:
    pane = None
```

Blanket retry policies for {exc}`~libtmux.exc.LibTmuxException` should exclude
{exc}`~libtmux.exc.ObjectDoesNotExist` and
{exc}`~libtmux.exc.MultipleObjectsReturned`: they report deterministic missing
or ambiguous lookups, not transient tmux failures.

### What's new

#### Find where you are running (#714)

Code running *inside* tmux — a script in a split, a hook, a test harness, an
agent — can now ask libtmux where it is.
{meth}`Pane.from_env() <libtmux.Pane.from_env>` returns the pane the calling
process is running in, and {meth}`Server.from_env() <libtmux.Server.from_env>`,
{meth}`Session.from_env() <libtmux.Session.from_env>` and
{meth}`Window.from_env() <libtmux.Window.from_env>` do the same for the rest of
the hierarchy. Each takes an optional environment mapping, so code that locates
itself stays testable outside a pane.

The answer stays true as tmux moves things around: it survives a `move-window`,
and for a window linked into several sessions it names the session tmux itself
would act on. Outside tmux, or with an environment that does not parse, the
family raises {exc}`~libtmux.exc.NotInsideTmux` rather than guessing.

See {ref}`self-location` for the whole story — why the session id tmux exports
goes stale, the window that *contains* you versus the one in front of you, and
how to test code that locates itself.

#### Ask a window which sessions hold it (#718)

{attr}`~libtmux.Window.linked_sessions` lists every
{class}`~libtmux.Session` from which a window is reachable. A typical window
returns one session; a linked or grouped window can return several, with each
session appearing once even when it holds the same window at multiple indexes.

Use {attr}`~libtmux.Window.linked_sessions` when you need every holder.
{attr}`~libtmux.Window.session` follows the `session_id` recorded on that
{class}`~libtmux.Window` instance; use
{meth}`~libtmux.Window.from_window_id` when you need tmux to resolve a window id
afresh.
See {ref}`winlinks` for the relationship between sessions, indexes, and shared
windows.

### Fixes

#### Linked windows resolve to the session tmux would use (#713)

A window can be linked into several sessions at once, and libtmux used to pick
one of them by accident — whichever sorted last by name. So
{meth}`Window.from_window_id() <libtmux.Window.from_window_id>`,
{meth}`Pane.from_pane_id() <libtmux.Pane.from_pane_id>`,
{meth}`Window.refresh() <libtmux.Window.refresh>` and
{meth}`Pane.refresh() <libtmux.Pane.refresh>` could change their answer when you
renamed a session.

libtmux now lets tmux resolve the object, so a window reports the session tmux
itself would act on. For a window in a single session — the ordinary case —
nothing changes. For a linked or grouped window, note that tmux picks by
*activity*: the session a window reports can change as focus moves between the
sessions holding it, where before it was stable but arbitrary. The lookups also
got cheaper: they list one window's panes or one session's windows instead of
scanning the whole server.

#### A window linked twice now reports tmux's index (#718)

tmux lets one session link the same window at multiple indexes.
{meth}`Window.from_window_id() <libtmux.Window.from_window_id>` and
{meth}`Window.refresh() <libtmux.Window.refresh>` now give
{attr}`Window.window_index <libtmux.Window.window_index>` the index tmux would
choose: the current link when that window is current, otherwise the
lowest-indexed link. Windows held at one index are unaffected.

#### Missing and ambiguous lookups explain what happened (#718)

{meth}`QueryList.get() <libtmux._internal.query_list.QueryList.get>` now names
both the lookup and its missing or ambiguous outcome. A missing
`pane_id="%99"` raises {exc}`~libtmux.exc.ObjectDoesNotExist` with
`No objects found: pane_id='%99'`; two matches for `pane_id="%0"` raise
{exc}`~libtmux.exc.MultipleObjectsReturned` with
`Multiple objects returned (2): pane_id='%0'`.

### Documentation

#### Understand winlinks in server-wide listings (#718)

{ref}`winlinks` explains that
{attr}`Server.windows <libtmux.Server.windows>` and
{attr}`Server.panes <libtmux.Server.panes>` enumerate {term}`winlinks <winlink>`
— the session, index, and window relationships tmux stores — rather than
deduplicating windows. A shared window can therefore appear once for each path
by which a session reaches it.

Read those rows when you need their session and index context. For a unique
lookup by id, use {meth}`Pane.from_pane_id() <libtmux.Pane.from_pane_id>` or
{meth}`Window.from_window_id() <libtmux.Window.from_window_id>`; use
{attr}`~libtmux.Window.linked_sessions` when you need every holding session.

## libtmux 0.61.0 (2026-07-04)

libtmux 0.61.0 hardens support for the tmux 3.7 patch line. It fixes
{meth}`~libtmux.Pane.break_pane` naming broken-out windows `libtmux`
instead of tmux's own default on tmux 3.7a/3.7b, and adds
{func}`~libtmux.common.get_version_str` for the raw tmux version string
with its point-release suffix intact. The test suite now also passes
against tmux 3.7a and 3.7b.

### What's new

#### New helper: `get_version_str()` (#699)

{func}`libtmux.common.get_version_str` returns the running tmux version
verbatim, keeping the point-release suffix (`"3.7a"`) that
{func}`~libtmux.common.get_version` strips for numeric comparison. Reach
for it to distinguish patch releases whose behavior differs -- for
example telling tmux `3.7` from `3.7a`.

### Fixes

#### `break_pane()` keeps tmux's default window name on 3.7a/3.7b (#699)

On tmux 3.7a/3.7b, breaking a pane into a new window without an explicit
`window_name` left it named `libtmux` instead of tmux's own default
(typically the running command). {meth}`~libtmux.Pane.break_pane` now
keeps that natural name; passing `window_name` is unaffected.

### Development

#### tmux 3.7a/3.7b test compatibility (#698)

libtmux's test suite now passes against tmux 3.7a and 3.7b, which CI also
exercises. A window-name test had assumed the `:`/`.` rejection tmux
introduced in 3.7, but tmux reverted it in 3.7a as "overly pernickety" — so
the test now checks these names are accepted.

## libtmux 0.60.0 (2026-06-28)

libtmux 0.60.0 completes tmux 3.7 feature parity. Building on the 3.7
compatibility shipped in 0.59.0, it adds first-class floating panes via
{meth}`~libtmux.Pane.new_pane` and {meth}`~libtmux.Window.new_pane`,
types tmux 3.7's new server, session, window, and pane options, exposes
the new pane format variables on {class}`~libtmux.Pane`, and wraps tmux
3.7's new command flags. Every 3.7-only surface is version-gated, so
tmux 3.2a-3.6 keep working unchanged. See {ref}`floating-panes` for a
guide.

### What's new

#### Typed tmux 3.7 options (#694)

The option dataclasses now type tmux 3.7's new options. On the server,
`get-clipboard`; on the session, `focus-follows-mouse`,
`message-format` and `prompt-command-cursor-style`; and on the window,
the copy-mode line-number options, the tree-mode preview options and the
window-pane status formats (of these, `tree-mode-preview-format` is also
pane-scoped). The pane `remain-on-exit` option gained tmux 3.7's `key`
value, and `pane-active-border-style` / `pane-border-style` (widened to
pane scope in 3.7) now type on the pane too.

#### tmux 3.7 pane format variables (#694)

{class}`~libtmux.Pane` now exposes tmux 3.7's new pane format
variables: the floating-pane geometry and flags (`pane_floating_flag`,
`pane_x`, `pane_y`, `pane_z`, `pane_flags`, `pane_zoomed_flag`), the
OSC 9;4 progress report (`pane_pb_progress`, `pane_pb_state`),
`pane_pipe_pid`, and the `bracket_paste_flag` and
`synchronized_output_flag` screen-mode flags. Each is version-gated, so
the format template stays clean on tmux 3.2a–3.6.

#### tmux 3.7 command flags (#694)

New tmux 3.7 flags are exposed on existing wrappers:
{meth}`~libtmux.Pane.capture_pane` gains `hyperlinks` (`-H`, hyperlink
targets only),
`line_numbers` (`-L`) and `line_flags` (`-F`);
{meth}`~libtmux.Window.split` / {meth}`~libtmux.Pane.split` gain `empty`
(`-E`, an empty pane) plus `style`/`active_border_style`/
`inactive_border_style` (`-s`/`-S`/`-R`), `message` (`-m`) and `keep`
(`-k`, remain-on-exit); {meth}`~libtmux.Session.kill` gains `group`
(`-g`, kill the session group); and {meth}`~libtmux.Pane.paste_buffer`
gains `no_vis` (`-S`, paste raw bytes). On the server,
{meth}`~libtmux.Server.command_prompt` gains `no_freeze` (`-C`, don't
freeze panes), {meth}`~libtmux.Server.list_keys` gains `format_`
(`-F`, custom output format), {meth}`~libtmux.Server.run_shell`
accepts trailing `args` expanded as `#{1}`/`#{2}`, and
{meth}`~libtmux.Server.refresh_client` gains `request_clipboard`
(`-l`, request the terminal clipboard). Each warns and is ignored on
tmux < 3.7.

#### Floating panes (`new-pane`) (#694)

tmux 3.7's flagship feature, floating panes, is now reachable through
{meth}`Window.new_pane() <libtmux.Window.new_pane>` and
{meth}`Pane.new_pane() <libtmux.Pane.new_pane>`. A
floating pane sits above the tiled layout like a popup but behaves like
a real pane. Pass `width`/`height` to size it and `x`/`y` to position
it, alongside the usual `shell`, `start_directory`, `environment`,
`zoom` and `empty`, plus `style`, `active_border_style`,
`inactive_border_style`, `message` and `keep` (remain-on-exit). The
returned {class}`~libtmux.Pane` reports
`pane_floating_flag == "1"`. Requires tmux 3.7+. See {ref}`floating-panes`
for a guide.

## libtmux 0.59.0 (2026-06-27)

libtmux 0.59.0 adds support for tmux 3.7. tmux 3.7 shipped an upstream
regression that crashed the server on `break-pane`;
{meth}`~libtmux.Pane.break_pane` now works around it so breaking and
rejoining panes works again, and tmux 3.7 joins the tested version
matrix alongside 3.2a-3.6.

### Fixes

#### `break-pane` no longer crashes the tmux 3.7 server (#693)

tmux 3.7 shipped a regression where `break-pane` aborts the server with
a NULL-pointer dereference whenever a pane is broken out of a window
without an explicit name (fixed upstream after the 3.7 release).
{meth}`~libtmux.Pane.break_pane` now works around this on tmux 3.7 by
always supplying a name and applying the requested one afterwards, so
breaking a pane into a new window — and joining it back with
{meth}`~libtmux.Pane.join` — work again. Older and post-3.7 tmux are
unaffected.

## libtmux 0.58.1 (2026-06-16)

libtmux 0.58.1 restores compatibility with pytest 9.1. The bundled
pytest plugin no longer aborts at import time, so projects that rely on
libtmux's fixtures can move to the latest pytest without their test
suite failing before collection.

### Fixes

#### pytest 9.1 compatibility for the pytest plugin (#687)

libtmux's pytest plugin (see {ref}`pytest_plugin`) now imports cleanly
under pytest 9.1, which began rejecting marks applied to fixture
functions. Projects that use libtmux's fixtures can upgrade to pytest
9.1+ without the plugin aborting before test collection.

## libtmux 0.58.0 (2026-05-23)

libtmux 0.58.0 fixes subprocess output decoding on non-UTF-8 locales.
Both {class}`~libtmux.common.tmux_cmd` and
{class}`~libtmux._internal.control_mode.ControlMode` now enforce UTF-8
when reading tmux output, matching tmux's own encoding contract.

### Fixes

#### Subprocess encoding on non-UTF-8 locales (#679)

{class}`~libtmux.common.tmux_cmd` and {class}`~libtmux._internal.control_mode.ControlMode`
now pass `encoding="utf-8"` to `subprocess.Popen`, ensuring tmux output
is decoded correctly regardless of the system locale. Previously, on
non-UTF-8 locales, the {data}`~libtmux.formats.FORMAT_SEPARATOR` character
(U+241E) was corrupted during decoding, causing list accessors
({attr}`~libtmux.Server.sessions`, etc.) to return empty results.

## libtmux 0.57.1 (2026-05-18)

Restores the "lenient-by-default" behavior for
{attr}`~libtmux.Server.sessions` and {attr}`~libtmux.Server.clients` that
was changed in 0.57.0.

### Behavioral Changes

#### Lenient `Server.sessions` and `Server.clients` accessors

{attr}`~libtmux.Server.sessions` and {attr}`~libtmux.Server.clients` once
again return an empty {class}`~libtmux._internal.query_list.QueryList`
when tmux fails for any reason (permission errors, subprocess crashes,
etc.).

This reverts a change in 0.57.0 that made these accessors raise
{exc}`~libtmux.exc.LibTmuxException`. The restored behavior matches the
contract {attr}`~libtmux.Server.sessions` has followed since 0.17.0.

- **Upgrade path:** Code that added ``try/except LibTmuxException`` blocks around
  these accessors for 0.57.0 can now remove them.
- **Connectivity checks:** If you need to distinguish between "no results" and
  "tmux is unreachable", use the explicit {meth}`~libtmux.Server.is_alive` or
  {meth}`~libtmux.Server.raise_if_dead` methods.

#### Stricter `search_*` methods

The newer {meth}`~libtmux.Server.search_sessions`,
{meth}`~libtmux.Server.search_windows`, and
{meth}`~libtmux.Server.search_panes` continue to raise on tmux errors.
Since these methods take a caller-supplied filter, a tmux failure is
considered a meaningful error signal that should not be swallowed.

## libtmux 0.57.0 (2026-05-17)

libtmux 0.57.0 broadens tmux support around attached clients, tmux-native
filtering, and format-token fields. {class}`~libtmux.Client` gives callers a
typed object for attached terminals, `search_*()` methods let tmux return only
matching sessions, windows, and panes, and more tmux format tokens are exposed
as typed attributes. {exc}`~libtmux.exc.LibTmuxException` now records which
tmux subcommand failed, making command errors easier to handle downstream.

### Breaking changes

#### `LibTmuxException` string form gains a subcommand prefix (#672)

When {exc}`~libtmux.exc.LibTmuxException` is raised from a libtmux method,
``str(exc)`` now begins with the originating tmux subcommand name followed
by ``": "``. For example, an error from
{meth}`~libtmux.Session.last_window` used to render as ``"can't find
window"`` and now renders as ``"last-window: can't find window"``.

``exc.args[0]`` still carries the original tmux error text, and the new
{attr}`~libtmux.exc.LibTmuxException.subcommand` attribute exposes
the tmux subcommand name as a separate field.
{func}`~libtmux.common.raise_if_stderr` is the shared helper that
populates both.

The error-payload *type* changed: ``exc.args[0]`` is now ``str``,
joined with ``"\n"`` when tmux emitted multiple stderr lines.
Previously it was ``list[str]``.

This is a serialization-format change: code that pattern-matches on
``str(exc)`` exactly, anchors a regex with ``^`` against the old
shape, or indexes ``exc.args[0]`` element-by-element will no longer
match.

```python
# Before
try:
    session.last_window()
except LibTmuxException as exc:
    if str(exc) == "can't find window":
        ...

# After — dispatch on the typed attribute
try:
    session.last_window()
except LibTmuxException as exc:
    if exc.subcommand == "last-window":
        ...

# Or — match against the original tmux error text without the prefix
try:
    session.last_window()
except LibTmuxException as exc:
    if exc.args and exc.args[0] == "can't find window":
        ...
```

Substring matches (``"can't find" in str(exc)``) and unanchored
``re.search`` patterns continue to work unchanged.

#### `Server.sessions`, `Server.clients`, and `Server.search_sessions` raise on tmux errors (#672)

Previously, a tmux command failure under
{attr}`~libtmux.Server.sessions`, {attr}`~libtmux.Server.clients`, or
{meth}`~libtmux.Server.search_sessions` could return an empty
{class}`~libtmux._internal.query_list.QueryList` indistinguishable
from "no sessions / no clients attached" or "filter matched nothing".
Those accessors now let {exc}`~libtmux.exc.LibTmuxException` propagate
for real tmux failures.

Genuine empty results — a server with no attached clients, or a
filter that matched zero sessions — still return an empty
``QueryList``. A missing or not-yet-started tmux server is also still
treated as an empty result, preserving the historic contract that a fresh
{class}`~libtmux.Server` can be safely introspected before its daemon is
up. Other tmux errors, such as socket permission failures or unsupported
flags, now surface.

```python
# Before — silent on tmux failure
if not server.clients:
    log("no clients")  # also runs when tmux itself crashed

# After — distinguish the two cases
try:
    clients = server.clients
except LibTmuxException as exc:
    log(f"list-clients failed: {exc}")
else:
    if not clients:
        log("no clients")
```

### What's new

#### `Client` object and `Server.clients` accessor (#672)

New {class}`~libtmux.Client` and {attr}`~libtmux.Server.clients` support tmux's
attached-client model directly. Reads like ``client.client_readonly`` and
``client.client_session`` work on the client object without dropping down to
{meth}`~libtmux.Server.cmd`.

Note that ``client.session_id`` / ``client.window_id`` / ``client.pane_id``
reflect the client's attached view when the object was read —
{meth}`~libtmux.Client.refresh` re-reads them after the client switches focus.
``client.client_name`` is the client's stable identifier.

For typed access to the live attachment, use
{attr}`~libtmux.Client.attached_session`,
{attr}`~libtmux.Client.attached_window`, and
{attr}`~libtmux.Client.attached_pane`. Each property re-reads the
client from ``list-clients`` before resolving; if tmux no longer
reports that ``client_name``, such as after the client detaches, the
property returns ``None``. Otherwise, the returned
{class}`~libtmux.Session` / {class}`~libtmux.Window` /
{class}`~libtmux.Pane` reflects where the client is attached *now*,
not where it was when the {class}`~libtmux.Client` was constructed.
Direct {meth}`~libtmux.Client.refresh` and
{meth}`~libtmux.Client.from_client_name` calls still surface missing
client lookup errors.

{attr}`~libtmux.Client.attached_pane` follows the attached session's current
window. That can differ from the per-client active pane set by
``select-pane -P``; see {attr}`~libtmux.Client.attached_pane` for the exact
behavior.

#### `Server.display_message` and `Window.display_message` (#672)

{meth}`~libtmux.Server.display_message` and
{meth}`~libtmux.Window.display_message` join the existing
{meth}`~libtmux.Pane.display_message`. Server reads like
``#{version}`` and ``#{socket_path}`` work without a pane handle;
window reads (``#{window_zoomed_flag}``, ``#{window_active_clients_list}``)
auto-bind to the window's id.

All three wrappers surface tmux stderr via :func:`warnings.warn`
rather than dropping it silently. tmux uses stderr for both genuine
errors and informational messages on some versions, so the wrappers
warn rather than raise; callers that want to escalate can wrap the
call in :func:`warnings.catch_warnings` with
``filterwarnings("error")``. See {doc}`migration` for the escalation
pattern.

#### tmux-native filtering with `search_*()` (#672)

{meth}`~libtmux.Server.search_panes`,
{meth}`~libtmux.Server.search_windows`,
{meth}`~libtmux.Server.search_sessions`, and the Session/Window
analogues take a ``filter=`` kwarg routed to tmux's ``-f`` flag. tmux
evaluates the expression and returns only matching objects.

Caveat: tmux silently expands a malformed filter expression to empty, which
it treats as false — a typo looks identical to "no matches". Verify filter
syntax against the FORMATS section of ``tmux(1)``.

#### `Pane.send_keys(cmd=None, …)` flag-only invocation (#672)

{meth}`~libtmux.Pane.send_keys` accepts ``cmd=None`` together with
``reset=True`` or ``repeat=N`` to invoke tmux's flag-only
``send-keys -R`` / ``send-keys -N <n>`` form without any trailing
key argument.

#### `Server.list_buffers(format_string=, filter=)` (#672)

{meth}`~libtmux.Server.list_buffers` gains ``format_string`` (``-F``)
and ``filter`` (``-f``) kwargs. Callers can ask tmux to return selected
fields (e.g. ``"#{buffer_name}"``) or only buffers matching an expression —
same bad-filter caveat as the ``search_*`` methods.

#### `Server.run_shell(cwd=, show_stderr=)` (#672)

{meth}`~libtmux.Server.run_shell` gains ``cwd`` (``-c``) to set the
shell command's working directory and ``show_stderr`` (``-E``) to
merge the command's stderr into the captured output. Both kwargs are
version-gated; older tmux warns and ignores the flag instead of
erroring.

#### `Pane.capture_pane(pending=True)` (#672)

{meth}`~libtmux.Pane.capture_pane` gains a ``pending`` kwarg that
returns bytes tmux has read from the pane but not yet committed to
the terminal — useful for diagnosing programs whose output stalls
mid-sequence.

#### More format-token fields on tmux objects (#672)

libtmux now asks each ``list-*`` subcommand for the format tokens that make
sense for that object and tmux version. Tokens the running tmux does not
support stay ``None`` instead of making the listing fail.

{class}`~libtmux.Pane`, {class}`~libtmux.Window`,
{class}`~libtmux.Session`, and {class}`~libtmux.Client` expose more typed
attributes for pane state (``pane_dead``, ``pane_in_mode``, ``pane_marked``,
``pane_synchronized``, ``pane_path``, ``pane_pipe``), window state
(``window_zoomed_flag``, ``window_silence_flag``, ``window_flags``), session
state (``session_marked``), and client state (``client_session``,
``client_readonly``, ``client_termtype``). Some fields describe the active
child object tmux reports with the row: for example, ``session.pane_id`` is
the active pane in the session's current window, not a separate "session
pane." See {ref}`format-tokens` for details.

### Fixes

- {meth}`~libtmux.Pane.reset` now clears pane scrollback. In 0.56.0
  the history clear silently no-op'd, leaving the scrollback intact
  (#650).

### Documentation

- New API page: {doc}`api/libtmux.client`.
- New {ref}`format-tokens` topic explains why some fields describe an active
  child object, such as ``session.pane_id`` reflecting the active pane in the
  session's current window (#672).

## libtmux 0.56.0 (2026-05-10)

libtmux 0.56.0 is the tmux command-parity release. It adds more than
50 commands across {class}`~libtmux.Server`, {class}`~libtmux.Session`,
{class}`~libtmux.Window`, and {class}`~libtmux.Pane`, filling in many
commands that previously required raw {meth}`~libtmux.Server.cmd` calls.
It also adds attached-client test support so interactive tmux commands can be
covered in headless test suites.

### What's new

#### Interactive tmux commands are now scriptable (#653)

libtmux now exposes Python commands for tmux that normally depend on
an attached client: {meth}`~libtmux.Pane.display_popup`,
{meth}`~libtmux.Server.display_menu`,
{meth}`~libtmux.Server.command_prompt`,
{meth}`~libtmux.Server.confirm_before`,
{meth}`~libtmux.Session.detach_client`,
{meth}`~libtmux.Server.detach_client`,
{meth}`~libtmux.Server.detach_all_clients`,
{meth}`~libtmux.Pane.display_panes`,
{meth}`~libtmux.Pane.choose_buffer`,
{meth}`~libtmux.Pane.choose_client`, and
{meth}`~libtmux.Pane.choose_tree`.

The `detach-client` API is split by the same scopes tmux actually honors:
{meth}`~libtmux.Session.detach_client` maps to
`tmux detach-client -s <session_id>`,
{meth}`~libtmux.Server.detach_client` maps to
`tmux detach-client [-t <client>]`, and
{meth}`~libtmux.Server.detach_all_clients` maps to
`tmux detach-client -a [-t <keep>]`. This keeps each method to one tmux flag
group and one subprocess call.

#### tmux buffer I/O has first-class support (#653)

Named tmux buffers can now be used from libtmux without hand-built commands.
{meth}`~libtmux.Server.set_buffer`,
{meth}`~libtmux.Server.show_buffer`,
{meth}`~libtmux.Server.delete_buffer`,
{meth}`~libtmux.Server.save_buffer`,
{meth}`~libtmux.Server.load_buffer`,
{meth}`~libtmux.Server.list_buffers`, and
{meth}`~libtmux.Pane.paste_buffer` cover the common clipboard, capture, and
inter-process handoff workflows.

#### Server commands cover key bindings, clients, shell execution, and access (#653)

{class}`~libtmux.Server` gains support for key-binding inspection and mutation
({meth}`~libtmux.Server.bind_key`,
{meth}`~libtmux.Server.unbind_key`,
{meth}`~libtmux.Server.list_keys`,
{meth}`~libtmux.Server.list_commands`), shell/config execution
({meth}`~libtmux.Server.run_shell`,
{meth}`~libtmux.Server.if_shell`,
{meth}`~libtmux.Server.source_file`), and client/server control
({meth}`~libtmux.Server.list_clients`,
{meth}`~libtmux.Server.start_server`,
{meth}`~libtmux.Server.lock_server`,
{meth}`~libtmux.Server.lock_client`,
{meth}`~libtmux.Server.refresh_client`,
{meth}`~libtmux.Server.suspend_client`,
{meth}`~libtmux.Server.server_access`,
{meth}`~libtmux.Server.show_messages`,
{meth}`~libtmux.Server.show_prompt_history`,
{meth}`~libtmux.Server.clear_prompt_history`). {class}`~libtmux.Session`
also gains {meth}`~libtmux.Session.lock_session`, and
{class}`~libtmux.Pane` gains {meth}`~libtmux.Pane.send_prefix`.

#### Windows and panes can be rearranged through the object API (#653)

Window-level operations now include {meth}`~libtmux.Window.swap`,
{meth}`~libtmux.Window.link`, {meth}`~libtmux.Window.unlink`,
{meth}`~libtmux.Window.respawn`, {meth}`~libtmux.Window.last_pane`,
{meth}`~libtmux.Window.next_layout`,
{meth}`~libtmux.Window.previous_layout`, and
{meth}`~libtmux.Window.rotate`. Pane-level operations now include
{meth}`~libtmux.Pane.swap`, {meth}`~libtmux.Pane.join`,
{meth}`~libtmux.Pane.break_pane`, {meth}`~libtmux.Pane.move`,
{meth}`~libtmux.Pane.pipe`, {meth}`~libtmux.Pane.clear_history`,
{meth}`~libtmux.Pane.respawn`, {meth}`~libtmux.Pane.copy_mode`,
{meth}`~libtmux.Pane.clock_mode`,
{meth}`~libtmux.Pane.customize_mode`, and
{meth}`~libtmux.Pane.find_window`.

Navigation helpers fill in the surrounding topology:
{meth}`~libtmux.Server.wait_for`,
{meth}`~libtmux.Session.last_window`,
{meth}`~libtmux.Session.next_window`, and
{meth}`~libtmux.Session.previous_window`.

#### Improvements (#653)

Several established methods now surface tmux flags that were previously only
available by dropping to raw commands. Highlights include
{meth}`~libtmux.Pane.send_keys` (`literal`, `hex_keys`, `key_name`,
`expand_formats`, `target_client`), {meth}`~libtmux.Pane.split`
(`percentage`), {meth}`~libtmux.Pane.capture_pane`
(`alternate_screen`, `quiet`, buffer output), and
{meth}`~libtmux.Pane.display_message` (formatting, delay, notify, verbose, and
style/update controls).

Window/session/server additions include extra flags on
{meth}`~libtmux.Window.move_window`,
{meth}`~libtmux.Window.select_layout`,
{meth}`~libtmux.Server.new_session`,
{meth}`~libtmux.Session.new_window`,
{meth}`~libtmux.Server.set_environment`, and
{meth}`~libtmux.Server.show_options`.

#### Attached-client tests are available through `control_mode` (#653)

The {fixture}`control_mode` fixture starts a real `tmux -C` client attached to
the test session. Downstream test suites can exercise commands such as
{meth}`~libtmux.Pane.display_popup`,
{meth}`~libtmux.Session.detach_client`,
{meth}`~libtmux.Server.command_prompt`, and
{meth}`~libtmux.Server.confirm_before` without requiring an interactive TTY.
The fixture is exported by {mod}`libtmux.pytest_plugin`.

### Fixes

#### `Window.move_window()` refreshes moved windows (#653)

{meth}`~libtmux.Window.move_window` now refreshes the moved
{class}`~libtmux.Window` after tmux completes the move. Code that reads
attributes after a relative or cross-session move no longer needs a manual
{meth}`~libtmux.Window.refresh` call to avoid stale state.

### Documentation

#### gp-sphinx docs stack moves to the Vite-backed theme path (#666)

The documentation stack now uses `gp-furo-theme`, a Tailwind v4 respin of Furo,
with `sphinx-vite-builder` owning theme asset builds. This picks up the shared
gp-sphinx documentation surface used by sibling projects.

### Tests

#### "No server" tests no longer depend on hardcoded sockets (#665)

`test_no_server_*` and `test_raise_if_dead_no_server_raises` now use the
{fixture}`server` fixture for unique socket names and finalizer cleanup. The
tests no longer fail just because a stale tmux daemon survived at one of the
old hardcoded socket paths. Fixes #664.

### Development

#### tmux 3.7 is within the known-version range (#653)

{data}`~libtmux.common.TMUX_MAX_VERSION` is now `"3.7"`, enabling support and
tests for version-gated tmux 3.7 flags such as
{meth}`~libtmux.Server.command_prompt` `bspace_exit` and
{meth}`~libtmux.Server.show_messages` `terminals` / `jobs`. Installations on
tmux 3.6 and earlier keep their existing behavior.

## libtmux 0.55.1 (2026-04-19)

libtmux 0.55.1 is a documentation and test-isolation release. It makes the
pytest plugin's server cleanup more robust, documents fixtures as first-class
API objects, and brings the docs site onto the shared gp-sphinx visual stack.

### What's new

#### pytest fixtures have generated API reference pages (#656)

The docs now render pytest fixtures with autodoc-style directives for
individual fixtures, bulk fixture listings, and a fixture index. Fixture pages
show scope, kind, factory metadata, dependencies, generated usage examples, and
responsive badge styling through the gp-sphinx fixture extension.

### Fixes

#### pytest plugin server cleanup removes stale socket files (#661)

The {fixture}`server` and {fixture}`TestServer` finalizers now unlink tmux
socket files under `/tmp/tmux-<uid>/` after killing the server. This prevents
long-lived development machines from accumulating stale `libtmux_test*`
sockets that can break later test runs. Fixes #660.

#### `session_params` fixture docs report the right return type (#656)

The {fixture}`session_params` fixture docstring now describes the value pytest
actually injects.

### Documentation

#### API docs adopt the gp-sphinx presentation stack (#658, #659)

API pages pick up gp-sphinx card layouts, badges, MyST-aware cross references,
argparse-label fixes, IBM Plex typography, and the 0.0.1a8 docs-stack bump.

### Development

#### `types-docutils` is available for type checking (#656)

The dev dependency set now includes `types-docutils`, keeping the fixture-docs
extension visible to mypy.

## libtmux 0.55.0 (2026-03-07)

libtmux 0.55.0 improves pane naming, custom tmux binary support, and command
diagnostics. The release is useful for projects that run against alternate tmux
builds or need clearer subprocess logging.

### What's new

#### Pane titles can be set and read through short aliases (#636)

{meth}`~libtmux.Pane.set_title` wraps `select-pane -T`, and
{attr}`~libtmux.Pane.title` is a short alias for
{attr}`~libtmux.Pane.pane_title`.

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

The `pane_title` tmux format variable is now included in libtmux format
queries.

#### `Server` can use an explicit tmux binary (#636)

{class}`~libtmux.Server` accepts `tmux_bin` for alternate binaries such as
wemux, byobu, or locally built tmux checkouts.

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

The binary path flows through {meth}`~libtmux.Server.cmd`,
{meth}`~libtmux.Server.raise_if_dead`, {func}`~libtmux.neo.fetch_objs`,
version checks such as {func}`~libtmux.common.has_version` and
{func}`~libtmux.common.has_gte_version`, and option/hook scope guards. Child
objects inherit it automatically. When `tmux_bin` is omitted, command execution
falls back to `shutil.which("tmux")`.

#### tmux commands log before execution (#636)

{func}`~libtmux.common.tmux_cmd` logs the full command line at `DEBUG` before
running it, complementing the existing post-execution output logging and giving
operators a better diagnostic trail.

### Fixes

#### Invalid `tmux_bin` paths raise `TmuxCommandNotFound` (#636)

Passing a missing binary path now raises
{exc}`~libtmux.exc.TmuxCommandNotFound` consistently in both
{func}`~libtmux.common.tmux_cmd` and
{meth}`~libtmux.Server.raise_if_dead`, instead of leaking a raw
`FileNotFoundError`.

## libtmux 0.54.0 (2026-03-07)

libtmux 0.54.0 adds structured lifecycle logging and tightens failure handling
for important object operations. Applications can now filter logs by stable
tmux context fields instead of parsing message text.

### What's new

#### Lifecycle operations emit structured log records (#637)

Create, kill, rename, split, and command-execution paths now log with stable
`extra` keys such as `tmux_subcommand`, `tmux_session`, `tmux_window`,
`tmux_pane`, and `tmux_target`. The library also installs a `NullHandler`,
uses lazy `%s` logging, guards heavier debug data, and removes ad-hoc stack
printing.

### Fixes

#### `Window.rename_window()` now propagates tmux failures (#637)

{meth}`~libtmux.Window.rename_window` no longer catches and logs every
exception. tmux errors now surface to callers like the rest of the command API.

#### `Server.kill()` handles expected dead-server states (#637)

{meth}`~libtmux.Server.kill` now captures stderr, ignores expected "no server
running" style states, and raises for unexpected tmux errors.

#### `Server.new_session(kill_session=True)` checks failed cleanup (#637)

If the pre-create `kill-session` step fails, {meth}`~libtmux.Server.new_session`
now raises {exc}`~libtmux.exc.LibTmuxException` instead of continuing as though
the old session had been removed.

## libtmux 0.53.1 (2026-02-18)

libtmux 0.53.1 fixes a session-creation race and moves the developer command
surface from Make to Just.

### Fixes

#### `Server.new_session()` no longer races its own initialization query (#625)

{meth}`~libtmux.Server.new_session` now parses all required session fields from
the `tmux new-session -P` output instead of creating the session and then
immediately querying `list-sessions`. That removes a race that could raise
{exc}`~libtmux.exc.TmuxObjectDoesNotExist` in PyInstaller, Python 3.13+, Docker,
and other slower-startup environments. Fixes #624. Thanks @neubig.

### Documentation

#### Documentation publishing uses GitHub OIDC

The docs deployment path moved to GitHub OIDC and AWS CLI credentials.

### Development

#### Developer tasks use `just` (#617)

The project moved from `Makefile` to `justfile`, and docs now reference the
`just` command names.

## libtmux 0.53.0 (2025-12-14)

libtmux 0.53.0 narrows the semantics of interactive attachment and fixes a
shutdown edge case around attached sessions.

### Breaking changes

#### `Session.attach()` no longer refreshes after returning (#616)

{meth}`~libtmux.Session.attach` no longer calls
{meth}`~libtmux.neo.Obj.refresh` after `attach-session` returns. The tmux command
is interactive and blocking, so arbitrary state may change while the user is
attached. Code that needs fresh state after attaching should call
{meth}`~libtmux.Session.refresh` explicitly.

### Fixes

#### Killing the attached session no longer breaks `Session.attach()` (#616)

{meth}`~libtmux.Session.attach` no longer raises
{exc}`~libtmux.exc.TmuxObjectDoesNotExist` when the attached session is killed
before the user detaches.

## libtmux 0.52.1 (2025-12-07)

libtmux 0.52.1 hardens package publishing.

### Development

#### PyPI publishing uses Trusted Publisher (#615)

PyPI releases now use OIDC-based Trusted Publisher instead of API tokens,
enabling attestations and reducing long-lived secret exposure.

## libtmux 0.52.0 (2025-12-07)

libtmux 0.52.0 expands pane capture so applications can preserve more of the
terminal's rendered output.

### What's new

#### `Pane.capture_pane()` exposes more `capture-pane` flags (#614)

{meth}`~libtmux.Pane.capture_pane` now supports `escape_sequences`,
`escape_non_printable`, `join_wrapped`, `preserve_trailing`, and
`trim_trailing`.

| Parameter | tmux flag | Description |
|-----------|-----------|-------------|
| `escape_sequences` | `-e` | Include ANSI escape sequences. |
| `escape_non_printable` | `-C` | Escape non-printable characters as octal. |
| `join_wrapped` | `-J` | Join wrapped lines back together. |
| `preserve_trailing` | `-N` | Preserve trailing spaces. |
| `trim_trailing` | `-T` | Trim trailing empty positions on tmux 3.4+. |

```python
pane.send_keys('printf "\\033[31mRED\\033[0m"', enter=True)
output = pane.capture_pane(escape_sequences=True)
```

## libtmux 0.51.0 (2025-12-06)

libtmux 0.51.0 turns the long-running 0.16-0.33 deprecation period into hard
errors for the oldest API spellings. The migration target is the modern object
attribute and {class}`~libtmux.common.QueryList` interface documented in
{doc}`migration`.

### Breaking changes

#### Legacy API methods now raise `DeprecatedError` (#611)

APIs deprecated in earlier releases now raise
{exc}`~libtmux.exc.DeprecatedError` instead of emitting
{class}`DeprecationWarning`.

| Deprecated API | Replacement | Deprecated | Raises | Note |
|----------------|-------------|------------|--------|------|
| `kill_server()` | {meth}`~libtmux.Server.kill` | 0.30.0 | 0.51.0 | Server |
| `attach_session()`, `kill_session()` | {meth}`~libtmux.Session.attach`, {meth}`~libtmux.Session.kill` | 0.30.0 | 0.51.0 | Session |
| `select_window()`, `kill_window()`, `split_window()` | {meth}`~libtmux.Window.select`, {meth}`~libtmux.Window.kill`, {meth}`~libtmux.Window.split` | 0.30.0 / 0.33.0 | 0.51.0 | Window |
| `resize_pane()`, `select_pane()`, `split_window()` | {meth}`~libtmux.Pane.resize`, {meth}`~libtmux.Pane.select`, {meth}`~libtmux.Pane.split` | 0.28.0 / 0.30.0 / 0.33.0 | 0.51.0 | Pane |
| `attached_window`, `attached_pane` | {attr}`~libtmux.Session.active_window`, {attr}`~libtmux.Session.active_pane` / {attr}`~libtmux.Window.active_pane` | 0.31.0 | 0.51.0 | Session / Window |
| `list_*()`, `_list_*()`, `_update_*()`, `children`, `where()`, `find_where()`, `get_by_id()` | {attr}`~libtmux.Server.sessions` / {attr}`~libtmux.Session.windows` / {attr}`~libtmux.Window.panes` with {meth}`~libtmux.common.QueryList.filter` / {meth}`~libtmux.common.QueryList.get` | 0.16.0 / 0.17.0 | 0.51.0 | Query helpers |
| Dict-style access (`obj["key"]`, `obj.get(...)`) | Attribute access, such as {attr}`~libtmux.Window.window_name` | 0.17.0 | 0.51.0 | All tmux objects |

The 0.50.0 option/hook deprecations remain soft warnings for now:

| Deprecated API | Replacement | Deprecated | Note |
|----------------|-------------|------------|------|
| `set_window_option()`, `show_window_option()`, `show_window_options()` | {meth}`~libtmux.Window.set_option`, {meth}`~libtmux.Window.show_option`, {meth}`~libtmux.Window.show_options` | 0.50.0 | Window |
| `g` option parameter | `global_` on {meth}`~libtmux.options.OptionsMixin.set_option`, {meth}`~libtmux.options.OptionsMixin.show_option`, {meth}`~libtmux.options.OptionsMixin.show_options` | 0.50.0 | Options and hooks |

## libtmux 0.50.1 (2025-12-06)

libtmux 0.50.1 is a documentation repair release for the 0.50 option and hook
API.

### Documentation

#### API documentation anchors and return types were cleaned up (#612)

The docs now use normalized headings and Sphinx module directives for more
stable anchors and indexes. Type-hints configuration was adjusted to avoid RST
indentation problems and forward-reference warnings, and
{meth}`~libtmux.Pane.capture_pane` / {meth}`~libtmux.Pane.display_message`
now document their list-returning behavior correctly.

## libtmux 0.50.0 (2025-11-30)

libtmux 0.50.0 is the options and hooks release. It adds one typed API for
reading and writing tmux options across every object type, adds programmatic
hook management, and introduces an indexed container for tmux's sparse option
arrays.

### Breaking changes

#### Window option aliases are deprecated (#516)

The window-specific option helpers remain available but now emit
{class}`DeprecationWarning`. Use the shared option API instead.

| Deprecated | Replacement |
|------------|-------------|
| `Window.set_window_option()` | {meth}`~libtmux.Window.set_option` |
| `Window.show_window_option()` | {meth}`~libtmux.Window.show_option` |
| `Window.show_window_options()` | {meth}`~libtmux.Window.show_options` |

```python
window.set_window_option("automatic-rename", "on")
# DeprecationWarning: Window.set_window_option() is deprecated

window.set_option("automatic-rename", True)
```

### What's new

#### Options share one API across Server, Session, Window, and Pane (#516)

{class}`~libtmux.options.OptionsMixin` gives
{class}`~libtmux.Server`, {class}`~libtmux.Session`,
{class}`~libtmux.Window`, and {class}`~libtmux.Pane` the same
{meth}`~libtmux.options.OptionsMixin.show_options`,
{meth}`~libtmux.options.OptionsMixin.show_option`,
{meth}`~libtmux.options.OptionsMixin.set_option`, and
{meth}`~libtmux.options.OptionsMixin.unset_option` methods.

```python
session.show_option("base-index")
window.set_option("automatic-rename", True)
window.unset_option("automatic-rename")
```

{meth}`~libtmux.options.OptionsMixin.set_option` supports tmux flags for format
expansion, unsetting, global scope, child-pane cleanup, overwrite prevention,
warning suppression, and append mode.

#### Hooks are manageable from Python (#516)

{class}`~libtmux.hooks.HooksMixin` adds hook operations across the tmux object
hierarchy: set, show, list, unset, run, and bulk set indexed hook values.

```python
session.set_hook("session-renamed", 'display-message "Renamed!"')
session.show_hook("session-renamed")
session.unset_hook("session-renamed")
```

#### Sparse tmux arrays have a Python container (#516)

{class}`~libtmux._internal.sparse_array.SparseArray` preserves gaps in tmux
arrays such as `command-alias[0]`, `command-alias[99]`, and
`terminal-features[0]`.

### Development

#### tmux 3.2 is the baseline for options and hooks (#516)

The options and hooks work relies on tmux 3.2+ behavior. Hook scope flags for
windows and panes require tmux 3.2+, `client-active` and `window-resized` hooks
require tmux 3.3+, and `pane-title-changed` requires tmux 3.5+.

## libtmux 0.49.0 (2025-11-29)

libtmux 0.49.0 completes the tmux 3.2 baseline transition announced in 0.48.0.

### Breaking changes

#### tmux 1.8 through 3.1c support was removed (#608)

{data}`~libtmux.common.TMUX_MIN_VERSION` is now tmux 3.2a. The
`TMUX_SOFT_MIN_VERSION` compatibility constant, its warning path, and older
version guards were removed. Users who need older tmux releases should stay on
libtmux 0.48.x.

## libtmux 0.48.0 (2025-11-28)

libtmux 0.48.0 starts the tmux 3.2 baseline transition and adds tmux 3.6 to
the compatibility grid.

### Breaking changes

#### tmux below 3.2a is deprecated (#606)

tmux versions below 3.2a emit {class}`FutureWarning` on first use. Set
`LIBTMUX_SUPPRESS_VERSION_WARNING=1` to silence the transition warning. 0.48.x
is the final line intended to support tmux below 3.2a.

### What's new

#### tmux 3.6 is covered in tests (#607)

The test grid now includes tmux 3.6, and {data}`~libtmux.common.TMUX_MAX_VERSION`
was raised from 3.4 to 3.6.

### Development

#### `TMUX_SOFT_MIN_VERSION` marks the transition floor (#606)

The temporary soft-minimum constant records tmux 3.2a as the deprecation
threshold for the 0.48.x compatibility window.

## libtmux 0.47.0 (2025-11-01)

libtmux 0.47.0 moves the supported Python baseline forward.

### Breaking changes

#### Python 3.9 support was dropped (#602)

Python 3.10 is now the minimum supported Python version. Python 3.9 reached
end of life on October 31, 2025; see the [Python release
status](https://devguide.python.org/versions/) and
[PEP 596](https://peps.python.org/pep-0596/) for the upstream timeline.

### Development

#### Python 3.14 is in the test matrix (#601)

The CI matrix now includes Python 3.14.

## libtmux 0.46.2 (2025-05-26)

libtmux 0.46.2 broadens path handling for start directories.

### What's new

#### Start-directory arguments accept path-like objects (#596, #597, #598)

{meth}`~libtmux.Server.new_session`,
{meth}`~libtmux.Session.new_window`, {meth}`~libtmux.Pane.split`,
{meth}`~libtmux.Window.split`, and their compatibility aliases accept
`os.PathLike` values in addition to strings. Thanks @Data5tream for the
initial work.

## libtmux 0.46.1 (2025-03-16)

libtmux 0.46.1 is a maintenance release for the 0.46.x line.

### Documentation

#### `Pane.send_keys` typo fixed (#593)

The {meth}`~libtmux.Pane.send_keys` documentation had a typo fixed. Thanks
@subbyte.

## libtmux 0.46.0 (2025-02-25)

libtmux 0.46.0 finishes the `libtmux.test` helper split by removing root-level
imports.

### Breaking changes

#### Root imports from `libtmux.test` were removed (#580)

Import test helpers from their focused modules.

```python
# Before 0.46.0
from libtmux.test import namer

# From 0.46.0 onward
from libtmux.test.random import namer
```

```python
# Before 0.46.0
from libtmux.test import RETRY_INTERVAL_SECONDS

# From 0.46.0 onward
from libtmux.test.constants import RETRY_INTERVAL_SECONDS
```

### Development

#### Test helpers gained more coverage (#580)

The test-helper modules gained stronger coverage for environment cleanup,
constants, random-name helpers, docstrings, and coverage markers.

## libtmux 0.45.0 (2025-02-23)

libtmux 0.45.0 splits the historical `libtmux.test` module into focused helper
modules.

### Breaking changes

#### Test helpers moved to focused modules (#578)

Import paths changed from the root `libtmux.test` module to
`libtmux.test.constants`, `libtmux.test.environment`,
`libtmux.test.random`, and `libtmux.test.temporary`.

```python
# Old
from libtmux.test import TEST_SESSION_PREFIX, EnvironmentVarGuard, namer

# New
from libtmux.test.constants import TEST_SESSION_PREFIX
from libtmux.test.environment import EnvironmentVarGuard
from libtmux.test.random import namer
```

### Development

#### CI checks runtime dependencies (#574)

CI now includes a runtime-dependency check, inspired by @ppentchev's review
comments on #572.

## libtmux 0.44.2 (2025-02-17)

libtmux 0.44.2 fixes typing import behavior and cleans up version tests.

### Fixes

#### `typing_extensions` imports are guarded (#572)

`typing_extensions` is now imported only when needed for type checking, fixing
runtime dependency issues. This continues the #564 work.

### Development

#### Version tests are clearer and more stable (#570)

Version-related tests were consolidated into parametrized fixtures with named
cases, and the broken `test_window_rename` test was repaired.

## libtmux 0.44.1 (2025-02-17)

libtmux 0.44.1 is a small packaging fix.

### Development

#### `typing_extensions` is optional at runtime (#563)

Runtime imports now avoid `typing_extensions` unless the running Python needs
it. Thanks @ppentchev.

## libtmux 0.44.0 (2025-02-16)

libtmux 0.44.0 adds context-manager support for tmux objects.

### What's new

#### Server, Session, Window, and Pane can clean themselves up (#566)

{class}`~libtmux.Server`, {class}`~libtmux.Session`,
{class}`~libtmux.Window`, and {class}`~libtmux.Pane` implement context manager
protocols that kill the object on exit.

```python
with Server() as server:
    with server.new_session() as session:
        with session.new_window() as window:
            with window.split() as pane:
                pane.send_keys('echo "Hello"')
```

## libtmux 0.43.0 (2025-02-15)

libtmux 0.43.0 improves server initialization and testing ergonomics.

### What's new

#### Server initialization can be customized (#565)

{class}`~libtmux.Server` accepts `socket_name_factory` and `on_init`
callbacks, making it easier to create multiple servers with unique names and
track initialized instances.

#### `TestServer` creates isolated tmux servers (#565)

The {fixture}`TestServer` fixture creates temporary tmux servers with unique
socket names, cleanup, tests, documentation, and doctest namespace support.

### Documentation

#### Traversal links were repaired (#567)

The topic docs gained fixed "Topics" links and more traversal guidance.

## libtmux 0.42.1 (2024-02-15)

libtmux 0.42.1 repairs a typing import edge case.

### Fixes

#### `Self` is imported only for type checking (#562)

Tests now import `Self` behind `TYPE_CHECKING`, avoiding runtime dependency
issues. Thanks @ppentchev.

### Development

#### Python-version-specific typing dependencies are explicit (#564)

The testing and lint groups include `typing-extensions` for Python versions
that need it.

## libtmux 0.42.0 (2025-02-02)

libtmux 0.42.0 removes the last Python 2 console conversion helpers.

### Fixes

#### `tmux_cmd` uses text-mode subprocess output (#560)

{func}`~libtmux.common.tmux_cmd` now uses `text=True`, deprecating
`console_to_str()` and `str_from_console()`. The compatibility helpers were
removed as Python 2-era artifacts. Fixes #558.

## libtmux 0.41.0 (2025-02-02)

libtmux 0.41.0 fixes default-socket representation and continues annotation
modernization.

### Fixes

#### `Server.__repr__()` uses the effective UID (#557)

{meth}`~libtmux.Server.__repr__` now uses {func}`os.geteuid` when constructing
the default socket path. Fixes #556. Thanks @lazysegtree.

### Documentation

#### `Server.colors` docs list valid values (#544)

The `colors` docstring now documents `88` and `256`. Thanks @TravisDart.

### Development

#### Annotation evaluation is deferred (#555)

All Python files now use `from __future__ import annotations`, and Ruff rules
UP006 / UP007 enforce modern annotation syntax.

## libtmux 0.40.1 (2024-12-24)

libtmux 0.40.1 fixes environment propagation during session creation.

### Fixes

#### `Server.new_session()` handles environment variables correctly (#553)

{meth}`~libtmux.Server.new_session` now passes environment values to new tmux
sessions correctly. Thanks @ppentchev.

## libtmux 0.40.0 (2024-12-20)

libtmux 0.40.0 is a maintenance release with one naming break and broad lint
cleanup.

### Breaking changes

#### `_global` was renamed to `global_`

The keyword spelling now follows the Python-safe convention used elsewhere in
the API.

### Development

#### Ruff handled a broad lint cleanup (#550)

The codebase was reformatted and lint-fixed with Ruff 0.8.4, including preview
and unsafe fixes, and legacy `test_select_pane` stability was improved (#552).

## libtmux 0.39.0 (2024-11-26)

libtmux 0.39.0 moves the Python floor forward.

### Breaking changes

#### Python 3.8 support was dropped (#548)

Python 3.9 became the minimum for this release line. tmuxp 1.48.0 remained the
last tmuxp release for Python 3.8.

## libtmux 0.38.1 (2024-11-26)

libtmux 0.38.1 keeps Python 3.8 support temporarily.

### Development

#### Minimum Python stayed at 3.8

The project held the Python floor at 3.8 for this patch release.

## libtmux 0.38.0 (2024-11-26)

libtmux 0.38.0 changes the project management and build backend stack.

### Breaking changes

#### Package management moved from Poetry to uv (#547)

[uv](https://github.com/astral-sh/uv) replaced Poetry for project and
dependency management.

#### Builds moved from Poetry to hatchling (#547)

[hatchling](https://hatch.pypa.io/latest/) replaced Poetry as the build
backend, following Python packaging guidance.

### Documentation

#### Query-list docstrings were fixed

The docs for `ObjectDoesNotExist` and `MultipleObjectsReturned` in the query
list internals were corrected.

### Development

#### Ruff modernized more string formatting (#540)

Ruff 0.4.2 applied more f-string modernization across the codebase.

## libtmux 0.37.0 (04-21-2024)

libtmux 0.37.0 is a test and maintenance release focused on parallel test runs
and flaky-test cleanup.

### Development

#### pytest can run in parallel (#522)

`pytest-xdist` is available for parallel test runs.

```console
$ py.test -n auto
```

pytest-watcher can also inherit the option:

```console
$ env PYTEST_ADDOPTS='-n auto' make start
```

The release also relaxed timing-sensitive `retry_until()` assertions and made
`test_capture_pane_start` poll for the expected state.

#### Poetry and docs tooling were refreshed (#522)

Poetry moved from 1.8.1 to 1.8.2, and links that had previously been plain
text are now automatically linkified.

## libtmux 0.36.0 (2024-03-24)

libtmux 0.36.0 is an automated lint-cleanup release.

### Development

#### Ruff applied aggressive automated fixes (#539)

Ruff 0.3.4 was used to apply lint and format fixes across the codebase,
including preview and unsafe fixes.

## libtmux 0.35.1 (2024-03-23)

libtmux 0.35.1 fixes attached-session detection.

### Fixes

#### `Server.attached_sessions` handles multiple clients (#537, #538)

{attr}`~libtmux.Server.attached_sessions` now reports attached sessions
correctly when multiple clients are attached. Thanks @patrislav1.

## libtmux 0.35.0 (2024-03-17)

libtmux 0.35.0 removes redundant target/index handling.

### Breaking changes

#### Redundant targets and window indexes were removed (#536)

Internal command construction no longer carries duplicate target and
`window_index` values through the codebase.

## libtmux 0.34.0 (2024-03-17)

libtmux 0.34.0 clarifies how custom command targets are passed.

### Breaking changes

#### `cmd()` target overrides are keyword-only (#535)

All object-level `cmd()` methods require the `target=` keyword for custom or
overridden tmux targets. This avoids confusing tmux command targets with inner
shell arguments that may also include `-t`.

Affected methods include {meth}`~libtmux.Server.cmd`,
{meth}`~libtmux.Session.cmd`, {meth}`~libtmux.Window.cmd`, and
{meth}`~libtmux.Pane.cmd`.

## libtmux 0.33.0 (2024-03-17)

libtmux 0.33.0 reshapes session/window creation and pane splitting around
clearer direction objects and keyword-only calls.

### Breaking changes

#### Window creation and splitting use modern names (#532, #534)

{meth}`~libtmux.Session.new_window` learned `direction` via
{class}`~libtmux.constants.WindowDirection`, and
{meth}`~libtmux.Window.new_window` was added as a shorthand from an existing
window's position. Arguments after the window name are keyword-only following
[PEP 3102](https://www.python.org/dev/peps/pep-3102/).

{meth}`~libtmux.Window.split_window` is deprecated in favor of
{meth}`~libtmux.Window.split`, and pane splitting moves from `vertical` /
`horizontal` booleans to {class}`~libtmux.constants.PaneDirection`. The split
API also gained `zoom`.

### What's new

#### Pane edge-position helpers were added (#532)

{class}`~libtmux.Pane` exposes boolean helpers for pane position within a
window: {attr}`~libtmux.Pane.at_left`, {attr}`~libtmux.Pane.at_right`,
{attr}`~libtmux.Pane.at_top`, and {attr}`~libtmux.Pane.at_bottom`.

### Development

#### Poetry moved to 1.8.1

The development dependency manager was updated to Poetry 1.8.1.

## libtmux 0.32.0 (2024-03-01)

libtmux 0.32.0 is a packaging and tooling maintenance release.

### Development

#### Package imports and Ruff were refreshed (#531)

Root package implicit imports were added to `__init__.py` thanks to @ssbarnea,
and Ruff moved from 0.2.2 to 0.3.0.

## libtmux 0.31.0 (2024-02-17)

libtmux 0.31.0 cleans up command method signatures and renames attached-object
properties to active-object properties.

### Breaking changes

#### `cmd()` methods were streamlined (#527)

{meth}`~libtmux.Server.cmd`, {meth}`~libtmux.Session.cmd`,
{meth}`~libtmux.Window.cmd`, and {meth}`~libtmux.Pane.cmd` now use the command
string as the first positional argument and drop unused keyword arguments.

#### Attached-object names became active-object names (#527)

`Session.attached_window`, `Session.attached_pane`, and `Window.attached_pane`
were renamed to {attr}`~libtmux.Session.active_window`,
{attr}`~libtmux.Session.active_pane`, and
{attr}`~libtmux.Window.active_pane`. The old names were deprecated.

### Documentation

#### Command methods gained docs and doctests (#527)

README and quickstart content now document `.cmd()` usage, and the command
methods gained docstrings and doctests.

### Development

#### `Server.attached_windows` uses `QueryList.filter()` (#527)

The implementation now relies on {meth}`~libtmux.common.QueryList.filter`.

### Post-release

#### v0.31.0post0 (2024-02-17)

Documentation-only updates followed the main release.

## libtmux 0.30.2 (2024-02-16)

libtmux 0.30.2 updates known tmux version bounds.

### Development

#### `TMUX_MAX_VERSION` moved to 3.4

The known tmux maximum version changed from 3.3 to 3.4.

## libtmux 0.30.1 (2024-02-16)

libtmux 0.30.1 aligns tests with the 0.30.0 method renames.

### Fixes

#### pytest plugin tests use current method names

The pytest plugin and test modules were updated to call the renamed 0.30.0
methods.

## libtmux 0.30.0 (2024-02-16)

libtmux 0.30.0 continues the modern object-method naming pass and adds pane
kill support.

### What's new

#### Panes can be killed directly

{meth}`~libtmux.Pane.kill` was added.

#### Creation and split methods gained useful arguments

{meth}`~libtmux.Server.new_session` gained environment-variable support, and
{meth}`~libtmux.Window.split_window` learned `size` for row/column counts or
percentage values.

### Development

#### Legacy method names were deprecated

`Window.select_window`, `Pane.select_pane`, `Session.attach_session`,
`Server.kill_server`, `Session.kill_session`, and `Window.kill_window` were
renamed to their shorter modern methods and left behind deprecation warnings.

## libtmux 0.29.0 (2024-02-16)

libtmux 0.29.0 prepares users for the method-renaming transition.

### Fixes

#### Deprecation warnings use the standard warning class (#526)

APIs scheduled for deprecation now emit {class}`DeprecationWarning`, and pytest
ignores those expected warnings by default.

## libtmux 0.28.1 (2024-02-15)

libtmux 0.28.1 is maintenance for the 0.28 transition.

### Documentation

#### 0.28 migration docs were refined

The docs and migration guide were updated for the 0.28.0 behavior changes.

### Development

#### CI actions moved to Node 20

GitHub Actions dependencies were bumped to Node 20-compatible versions.

## libtmux 0.28.0 (2024-02-14)

libtmux 0.28.0 changes default attachment behavior and modernizes pane/window
resizing.

### Breaking changes

#### New windows and splits are detached by default (#523)

{meth}`~libtmux.Session.new_window` and
{meth}`~libtmux.Window.split_window` no longer attach/select by default.
Pass `attach=True` to keep the older behavior.

#### Pane resizing moved to `Pane.resize()` (#523)

`Pane.resize_pane()` was renamed to {meth}`~libtmux.Pane.resize`. Directional
flags now flow through {class}`~libtmux.constants.ResizeAdjustmentDirection`,
and `height`, `width`, and zoom controls are supported.

### What's new

#### Windows can be resized directly (#523)

{meth}`~libtmux.Window.resize` was added. If pane resizing was ineffective in
older releases, resizing the window first may be the better approach.

### Fixes

#### Refresh and pane listing behavior improved (#523)

{meth}`~libtmux.Window.refresh`, {meth}`~libtmux.Pane.refresh`, and the internal
refresh path now capture more state, and `Server.panes` lists panes across the
server instead of only the attached session.

### Development

#### tmux 3.4 entered the test matrix (#909)

The test matrix gained tmux 3.4, and pytest fixture warnings were fixed (#519).

## libtmux 0.27.1 (2024-02-07)

libtmux 0.27.1 repairs source distribution contents.

### Development

#### `MIGRATION` is included in sdists (#517)

The source distribution now includes the migration guide needed by downstream
packagers. Related to #508.

## libtmux 0.27.0 (2024-02-07)

libtmux 0.27.0 improves typed collection access.

### What's new

#### `QueryList` annotations cover descendant collections (#515)

{class}`~libtmux.common.QueryList` typing improved for
{attr}`~libtmux.Server.sessions`, {attr}`~libtmux.Session.windows`, and
{attr}`~libtmux.Window.panes`, with doctests and pytest coverage ported from
libvcs.

## libtmux 0.26.0 (2024-02-06)

libtmux 0.26.0 tightens a deprecated lookup signature and strengthens linting.

### Breaking changes

#### Deprecated `get_by_id()` keyword names became explicit (#514)

The already-deprecated `get_by_id()` helpers now use object-specific keyword
names: `session_id`, `window_id`, and `pane_id`.

### Documentation

#### Docstrings were refreshed (#514)

Several docstrings were corrected and clarified.

### Development

#### Ruff lint coverage expanded (#514)

The project enabled flake8-commas, flake8-builtins, and flake8-errmsg rules
through Ruff, and CodeQL moved from an advanced configuration file to GitHub's
default setup.

## libtmux 0.25.0 (2023-11-25)

libtmux 0.25.0 makes equality comparisons safer and continues docstring
coverage work.

### Fixes

#### Object equality returns `False` on type mismatch (#505, #510)

{meth}`~libtmux.Server.__eq__`, {meth}`~libtmux.Session.__eq__`,
{meth}`~libtmux.Window.__eq__`, and {meth}`~libtmux.Pane.__eq__` now return
`False` instead of raising {class}`AssertionError` when compared with another
type. Thanks @m1guelperez for the window implementation.

### Documentation

#### Docstrings were expanded (#509)

Functions, methods, classes, and packages gained docstrings.

### Development

#### pydocstyle is enforced through Ruff (#509)

CI now includes the pydocstyle rule set.

## libtmux 0.24.1 (2023-11-23)

libtmux 0.24.1 removes obsolete packaging files.

### Development

#### Legacy requirements files were removed (#507)

The unused `requirements/` directory was removed in favor of `pyproject.toml`,
and `gp-libs` was added to the test dependency group.

## libtmux 0.24.0 (2023-11-19)

libtmux 0.24.0 drops Python 3.7 and moves more configuration into modern
project files.

### Breaking changes

#### Python 3.7 support was dropped (#497)

Python 3.7 reached end of life on June 27, 2023. A 0.23.x branch can be kept
for limited security maintenance if needed.

### Development

#### pytest and dependency groups moved into `pyproject.toml` (#499)

pytest configuration moved into `pyproject.toml`, Poetry moved through the
1.6/1.7 line, and development dependencies now use Poetry dependency groups.

#### Ruff format replaced Black (#506)

Formatting moved from Black to `ruff format`, keeping the same style while
removing a separate dependency.

#### CI dependencies were refreshed

`dorny/paths-filter` and `codecov/codecov-action` were updated.

## libtmux 0.23.2 (2023-09-09)

libtmux 0.23.2 marks the final Python 3.7 cut of the 0.23.x line.

### Breaking changes

#### Python 3.7 is at end of life

This release exists as the final Python 3.7-compatible point before the
project moves forward.

## libtmux 0.23.1 (2023-09-02)

libtmux 0.23.1 is a typo and lint-rule maintenance release.

### Development

#### typos-cli cleaned up spelling issues

Automated typo fixes were applied with [typos-cli](https://github.com/crate-ci/typos).
The Ruff ERA / eradicate rule was removed because its false positives were too
costly.

## libtmux 0.23.0 (2023-08-20)

libtmux 0.23.0 is a Ruff-driven code-quality release.

### Development

#### More Ruff rules were applied (#488)

Additional Ruff rules, including import sorting, were applied by hand and with
automated fixes.

### Post-release

#### v0.23.0post0 (2023-08-20)

Code comments missed during the initial Ruff QA pass were repaired.

#### v0.23.0post1 (2023-08-26)

Additional ERA001 cleanups were applied.

#### v0.23.0post2 (2023-08-28)

More ERA001 cleanups followed.

## libtmux 0.22.2 (2023-08-20)

libtmux 0.22.2 removes an obsolete build dependency.

### Development

#### `setuptools` is no longer required (#495)

The build system no longer requires setuptools. Related to #493 and #494.

## libtmux 0.22.1 (2023-05-28)

libtmux 0.22.1 keeps Black available while Ruff formatting matures.

### Development

#### Black returned as a companion formatter

Black was added back temporarily until Ruff fully replaced it for formatting.

## libtmux 0.22.0 (2023-05-27)

libtmux 0.22.0 starts the migration to Ruff for linting, import sorting, and
formatting.

### Development

#### Ruff replaces several Python quality tools

[Ruff](https://ruff.rs) replaces Black, isort, flake8, and several flake8
plugins for the main quality loop. Poetry also moved from 1.4.0 to 1.5.0.

## libtmux 0.21.1 (2023-04-07)

libtmux 0.21.1 keeps mypy compatibility current.

### Fixes

#### Skip-default-fields repr typing works with mypy 1.2.0

The repr mixin typing was fixed for mypy 1.2.0.

### Development

#### mypy moved to 1.2.0

The type checker dependency was updated.

## libtmux 0.21.0 (2023-01-29)

libtmux 0.21.0 changes the internal separator used for tmux format parsing.

### Breaking changes

#### The format separator changed from `|` to `␞` (#475)

`LIBTMUX_TMUX_FORMAT_SEPARATOR` now defaults to the record-separator glyph,
fixing `buffer_sample` and similar tmux format values that legitimately contain
pipes. Related to #471 and #472.

## libtmux 0.20.0 (2023-01-15)

libtmux 0.20.0 improves session sizing and test fixture customization.

### What's new

#### Session creation accepts dimensions (#469)

{meth}`~libtmux.Server.new_session` accepts `x` and `y` for tmux session size.
Thanks @rockandska.

#### The `session_params` fixture can override session creation (#470)

{fixture}`session_params` is a dictionary consumed directly by the
{fixture}`session` pytest fixture.

## libtmux 0.19.1 (2022-01-07)

libtmux 0.19.1 removes a problematic refresh from window option setting.

### Fixes

#### `Window.set_window_option()` no longer refreshes (#467)

The compatibility method stopped refreshing after setting a window option,
matching downstream tmuxp expectations.

## libtmux 0.19.0 (2022-01-07)

libtmux 0.19.0 adds ranged pane capture.

### What's new

#### `Pane.capture_pane()` accepts `start` and `end` (#465)

{meth}`~libtmux.Pane.capture_pane` can capture a specific line range.

## libtmux 0.18.3 (2023-01-07)

libtmux 0.18.3 improves failed-object lookup errors.

### Fixes

#### `fetch_objs()` reports lookup details (#466)

{func}`~libtmux.neo.fetch_objs` now raises lookup errors with details about the
failed search.

## libtmux 0.18.2 (2022-12-30)

libtmux 0.18.2 fixes default-socket session creation.

### Fixes

#### Server session launch works on the default socket (#857)

Creating a new session on the default socket was repaired.

## libtmux 0.18.1 (2022-12-28)

libtmux 0.18.1 is a documentation cleanup release.

### Fixes

#### Window pane docs were corrected

`Window.panes` docstrings and unused documentation were cleaned up.

## libtmux 0.18.0 (2022-12-27)

libtmux 0.18.0 gives servers useful representations and default socket paths.

### Breaking changes

#### `Server.__repr__` now reports socket identity

{meth}`~libtmux.Server.__repr__` reports `socket_name` or `socket_path` instead
of the default Python object repr.

## libtmux 0.17.2 (2022-12-27)

libtmux 0.17.2 continues moving pane listing internals behind deprecation
paths.

### Development

#### Server pane-listing internals were deprecated

`Server._list_panes` and `Server._update_panes` moved to the deprecated API
surface.

## libtmux 0.17.1 (2022-12-27)

libtmux 0.17.1 tightens documentation and child-collection deprecations.

### Fixes

#### Child collection deprecation warnings were added

Documentation was fixed, and `Server.children`, `Session.children`, and
`Window.children` now warn.

## libtmux 0.17.0 (2022-12-26)

libtmux 0.17.0 introduces the modern collection and attribute access model.

### Breaking changes

#### Relationships moved to collection attributes (#426)

Use relation attributes such as {attr}`~libtmux.Session.windows` instead of
methods such as `session.list_windows()` or `session._windows()`.

```python
# 0.16 and earlier
session.find_where({"window_name": my_window})

# 0.17 and later
session.windows.get(window_name=my_window, default=None)
```

Missing results raise
{exc}`~libtmux._internal.query_list.ObjectDoesNotExist`; ambiguous results raise
{exc}`~libtmux._internal.query_list.MultipleObjectsReturned`.

#### tmux data moved from mapping access to attributes (#426)

Use attributes such as `window.id` instead of `window["id"]` or
`window.get("id")`. Optional access can use Python's `getattr()`.

### What's new

#### Server liveness helpers were added (#448)

{meth}`~libtmux.Server.is_alive` and
{meth}`~libtmux.Server.raise_if_dead` report whether the tmux server is
available.

### Development

#### `sphinx-click` was removed

The unused development dependency was dropped.

## libtmux 0.16.1 (2022-12-12)

libtmux 0.16.1 removes an unnecessary version-parsing dependency.

### Fixes

#### `packaging.version.Version` is no longer required (#461)

libtmux now avoids strict `packaging` version parsing so it does not pin or
interfere with unrelated application dependencies.

## libtmux 0.16.0 (2022-12-10)

libtmux 0.16.0 removes `distutils` version parsing and improves environment
support for new windows.

### Breaking changes

#### tmux version parsing no longer relies on `distutils` (#351)

The project vendorizes legacy version handling instead of using
`distutils.version.LooseVersion`, which cannot correctly model tmux versions
such as `3.1a`.

### What's new

#### Window and session creation accept environment dictionaries (#453)

{meth}`~libtmux.Window.split_window` and
{meth}`~libtmux.Session.new_window` can pass environment variables into new tmux
processes. Thanks @zappolowski.

## libtmux 0.15.10 (2022-11-05)

libtmux 0.15.10 continues shell/environment test stabilization.

### Development

#### Shell-specific test assumptions were reduced (#452, #455)

`test_capture_pane` and environment tests were made more portable, and more
Bash-specific assumptions were removed. Thanks @zappolowski.

## libtmux 0.15.9 (2022-10-30)

libtmux 0.15.9 fixes command-not-found behavior and updates Python metadata.

### Fixes

#### `tmux_cmd()` raises `TmuxCommandNotFound` correctly (#450)

{func}`~libtmux.common.tmux_cmd` now reports missing tmux binaries through
{exc}`~libtmux.exc.TmuxCommandNotFound`.

### Development

#### Python 3.11 support metadata was added (#451)

CI uses Python 3.11, trove classifiers include it, and local version-tooling
configuration was updated.

## libtmux 0.15.8 (2022-10-02)

libtmux 0.15.8 improves compatibility with tmuxp's empty window names.

### Fixes

#### Empty `window_name` is supported in `Session.new_window()` (#444)

{meth}`~libtmux.Session.new_window` handles `window_name=""` more reliably for
downstream tmuxp. Thanks @trankchung.

## libtmux 0.15.7 (2022-09-23)

libtmux 0.15.7 consolidates coverage configuration.

### Development

#### coverage config moved to `pyproject.toml` (#443)

The separate `.coveragerc` file was removed.

## libtmux 0.15.6 (2022-09-23)

libtmux 0.15.6 removes an obsolete manifest file.

### Development

#### `MANIFEST.in` was removed

Poetry's `pyproject.toml` include configuration now owns source distribution
contents.

## libtmux 0.15.5 (2022-09-23)

libtmux 0.15.5 cleans up tmuxp workspace metadata.

### Development

#### `.tmuxp-before-script.sh` was removed from `.tmuxp.yaml`

The tmuxp workspace config no longer references that helper.

## libtmux 0.15.4 (2022-09-21)

libtmux 0.15.4 fixes packaging and pytest compatibility.

### Fixes

#### Stable pytest imports support downstream packagers (#441, #442)

pytest API imports now use stable paths where possible, helping downstream
packages such as Arch.

### Development

#### source distributions include test support files (#441, #442)

`.tmuxp-before-script.sh` and `conftest.py` are included in source
distributions.

## libtmux 0.15.3 (2022-09-20)

libtmux 0.15.3 improves pytest plugin examples and doctest discovery.

### Documentation

#### pytest plugin examples were added (#439, #440)

Examples for the pytest plugin were added, and `conftest.py` moved to the repo
root so README doctests can run without proxying through `docs/index.md`.

## libtmux 0.15.2 (2022-09-17)

libtmux 0.15.2 is a maintenance release for test plugin coverage and CI speed.

### Development

#### pytest plugin tests and CI speedups landed (#423, #428)

The pytest plugin gained initial self-tests, trove classifiers note pytest
support, and CI avoids unnecessary package downloads while splitting release
work into a separate job.

## libtmux 0.15.1 (2022-09-11)

libtmux 0.15.1 is a small packaging and docs cleanup.

### Documentation

#### Quickstart documentation was cleaned up

The quickstart page was simplified.

### Development

#### Packaging groups were cleaned up

Old issue package metadata and an extra package grouping were removed.

## libtmux 0.15.0 (2022-09-10)

libtmux 0.15.0 adds the pytest plugin and moves the package into the modern
`src/` layout.

### Breaking changes

#### `common.which()` was replaced with `shutil.which()` (#407)

The project now relies on {func}`shutil.which` for executable lookup. Thanks
@rocksandska.

#### `tmux_cmd` preserves interior empty lines (#405)

{func}`~libtmux.common.tmux_cmd` now strips only trailing empty lines. This
better matches {meth}`~libtmux.Pane.capture_pane` output. Fixes #402. Thanks
@rockandska.

#### Source files moved into `src/` (#414)

The package adopted the `src/` layout.

### What's new

#### pytest plugin added (#411)

libtmux now ships a pytest plugin for tests that need tmux fixtures.

### Documentation

#### Docs doctests and changelog rendering improved (#410, #412)

Documentation examples were corrected, doctests are exercised through
pytest-doctest-docutils, changelog issue references are linkified, and autodoc
table-of-contents rendering was repaired.

### Development

#### flake8 plugins were added (#408, #409)

flake8-bugbear and flake8-comprehensions joined the development toolchain.

## libtmux 0.14.2 (2022-08-17)

libtmux 0.14.2 completes the `new_session()` fix started in 0.14.1.

### Fixes

#### `Server.new_session()` works without `session_name` (#401)

{meth}`~libtmux.Server.new_session` no longer passes `None` as the session
name. Fixes #399.

## libtmux 0.14.1 (2022-08-17)

libtmux 0.14.1 starts fixing unnamed session creation.

### Fixes

#### `Server.new_session()` accepts omitted `session_name` (#400)

{meth}`~libtmux.Server.new_session` can be called without `session_name`,
although 0.14.2 completed the remaining `None` handling. Fixes #399.

## libtmux 0.14.0 (2022-08-05)

libtmux 0.14.0 changes the `send_keys` history default and sets up executable
doctests.

### Breaking changes

#### `Pane.send_keys(suppress_history)` defaults to `False` (#395)

{meth}`~libtmux.Pane.send_keys` no longer suppresses shell history unless asked
to do so.

### Documentation

#### Doctest fixtures were introduced (#394)

Initial doctest examples landed, `temp_window()` was fixed, and pytest config
moved so doctests can discover the libtmux fixtures.

## libtmux 0.13.0 (2022-08-05)

libtmux 0.13.0 reaches strict mypy compliance and removes older item-lookup
shortcuts.

### Breaking changes

#### Individual option/environment item lookups were removed (#390)

Bulk methods such as `show_environment()` and `show_options()` now keep their
dictionary-returning behavior, while single-key access moves to explicit
methods such as `getenv()` and `show_option()`.

```python
# Before
server.show_environment("DISPLAY")

# After
server.getenv("DISPLAY")
```

```python
# Before
session.show_options("base-index")

# After
session.show_option("base-index")
```

`libtmux.test.retry()` was removed after its 0.12 deprecation period (#393).

### What's new

#### Typing reached `mypy --strict` (#383, #392)

Core modules now satisfy strict mypy checks.

### Development

#### A stray legacy name was fixed (#391)

The incorrect `findWhere()` spelling was corrected.

## libtmux 0.12.0 (2022-07-13)

libtmux 0.12.0 restores Python 3.7/3.8 support, expands tmux compatibility, and
adds the retry helper that replaced the old test retry API.

### What's new

#### tmux 3.3a is in the supported range

tmux 3.3a was added to CI, and `TMUX_MAX_VERSION` moved from 2.4 to 3.3.

#### `retry_until()` replaces the old retry helper (#368, #372)

{func}`libtmux.test.retry.retry_until` polls a callback until it succeeds or
times out, raising {exc}`~libtmux.exc.WaitTimeout` by default. Thanks
@categulario.

### Documentation

#### API documentation was reorganized (#367)

The docs gained a renewed logo, split API pages for utilities, exceptions, and
test helpers, and new Reference sections for server, session, window, and pane
objects.

### Development

#### Python 3.7 and 3.8 returned (#375)

Support for Python 3.7 and 3.8 was restored, tox was removed, and core object
relations gained type annotations (#385).

## libtmux 0.11.0 (2022-03-10)

libtmux 0.11.0 adds early typing work and documents the format-separator escape
hatch.

### Compatibility

#### Python 3.7 and 3.8 support was extended later

This release originally marked Python 3.7/3.8 as ending, but 0.12.0 restored
support.

#### tmux format splitting became configurable (#289, #343)

The internal separator used to split tmux format output is configurable through
`LIBTMUX_TMUX_FORMAT_SEPARATOR`. Thanks @JonathanRaiman and @jagguli.

### Documentation

#### The sidebar and development-release docs were reorganized

The docs gained sectioned navigation and instructions for installing
developmental releases.

### Development

#### Basic type annotations were added (#359, #361)

Early annotations, cleanup, and one-time Black formatting landed. Thanks
@otherJL0.

## libtmux 0.10.3 (2022-01-10)

libtmux 0.10.3 is the first experimental Poetry-built release.

### Compatibility

#### Python 3.6 support was dropped (#344)

Python 3.10 metadata was added, with a note that version constraints still
needed more compatibility work.

### Development

#### Poetry build support landed (#347)

The project started using `poetry build`, moved Poetry to 1.1.12, and added
pre-commit configuration. Packagers were directed to #346 for issues.

## libtmux 0.10.2 (2021-10-30)

libtmux 0.10.2 updates Poetry-era CI and attached-session handling.

### Fixes

#### Multiple attached sessions are supported (#341, #342)

`Server.attached_sessions()` no longer assumes only one attached client. Thanks
@timoses.

### Development

#### Poetry 1.1 tooling was refreshed (#324, #339)

CI uses Poetry 1.1.7, Python was locked at 3.9 to avoid the `dataclasses`
issue, and docs publishing was repaired.

## libtmux 0.10.1 (2021-06-16)

libtmux 0.10.1 updates a window-selection compatibility path.

### Fixes

#### `Window.select_window()` was updated for #271

The compatibility method picked up the session-target fix.

## libtmux 0.10.0 (2021-06-16)

libtmux 0.10.0 moves the changelog to Markdown, fixes window selection, and
drops Python 3.5.

### Breaking changes

#### Python 3.5 support was dropped

The supported Python range moved forward.

### Fixes

#### `select_window()` targets the session ID (#271)

Window selection now passes the session ID to tmux's `-t` argument. Thanks
@Flowdalic.

### Documentation

#### CHANGES was converted to Markdown (#321)

The changelog moved from reStructuredText to Markdown.

## libtmux 0.9.0 (2021-06-14)

libtmux 0.9.0 drops Python 2.7 and updates the Python 3 toolchain.

### Breaking changes

#### Python 2.7 support was dropped (#306)

The codebase moved fully to Python 3 syntax. The CI matrix added tmux 3.2a, and
Black moved to 21.6b0 (#312, #314).

### Fixes

#### `select_window()` targets the session ID (#271)

The session-target fix also appears in this release line.

## libtmux 0.8.5 (2020-10-25)

libtmux 0.8.5 improves subprocess interaction, version reporting, and
environment tests.

### What's new

#### Subprocess pipes handle large buffers better (#297)

stdin/stdout/stderr handling was improved for large buffer interaction, fixing
#251. Thanks @gil-obradors.

#### `get_libtmux_version()` reports tmux-compatible versions (#303)

`common.get_libtmux_version` was added, docs links were repaired, and duplicate
Sphinx module descriptions were removed.

### Fixes

#### Environment tests no longer hang on local values (#266)

Local environment variables no longer cause `show-environment` tests to pause
indefinitely.

## libtmux 0.8.4 (2020-10-25)

libtmux 0.8.4 updates split-window support, packaging, docs, and CI.

### What's new

#### `Window.split_window` accepts percentages (#234)

`Window.split_window` can pass percentage sizing. Thanks @jinankjain.

### Fixes

#### Invalid escape warnings were fixed (#289)

Warnings from invalid escape sequences were fixed. Thanks @tirkarthi.

### Documentation

#### Documentation moved to `docs/` (#295)

Docs publishing moved to the project's own action, development instructions
were refreshed, and the old `doc/` tree moved to `docs/`.

### Development

#### Poetry and CI were expanded (#295, #296)

More packaging moved to Poetry while retaining `setup.py`, and CI was updated
for Python 2.7 caching and internal PR behavior.

## libtmux 0.8.3 (2020-08-16)

libtmux 0.8.3 is a Python warning, packaging, and CI cleanup release.

### Fixes

#### Python deprecation warnings were fixed (#278)

Deprecation warnings were cleaned up. Thanks @d1618033 and Flowdalic.

### Development

#### Packaging and CI moved forward (#293)

`project_urls` were added, the project moved from Pipfile to Poetry, tmux 3.0
option tests were fixed, option-error comments were cleaned up, and CI moved to
GitHub Actions.

## libtmux 0.8.2 (2019-06-02)

libtmux 0.8.2 is a packaging and changelog-format release.

### Documentation

#### CHANGES used plain reStructuredText

The changelog was converted to plain reStructuredText.

### Development

#### PyPI metadata and Pipfile constraints were updated

`project_urls` were added to `setup.py`, Pipfile constraints were loosened, and
`Pipfile.lock` was added.

## libtmux 0.8.1 (2019-01-26)

libtmux 0.8.1 fixes several tmux compatibility gaps and moves docs toward
NumPy-style docstrings.

### What's new

#### Pane capture, display, and literal key support landed (#119, #120, #121)

{meth}`~libtmux.Pane.capture_pane`,
{meth}`~libtmux.Pane.display_message`, and `literal=True` support for
{meth}`~libtmux.Pane.send_keys` were added. Thanks @ritiek.

### Fixes

#### Client renaming works on tmux 2.7 BSD/macOS (#117)

Renaming clients on BSD/macOS with tmux 2.7 was repaired.

#### Unicode commands and next-version support improved (#131, #172)

Unicode command handling was fixed for Python 2 thanks to @myw, and next-X.Y
version parsing gained support thanks to @sloria.

### Documentation

#### Docs moved to NumPy-style docstrings

Imports were sorted, sphinxcontrib-napoleon was added, and docstrings moved to
NumPy style.

## libtmux 0.8.0 (2018-03-11)

libtmux 0.8.0 moves the project to the tmux-python organization and broadens
session-start support.

### Breaking changes

#### License and organization changed (#46)

The license changed from BSD to MIT, and the project moved into the
tmux-python organization.

### What's new

#### `Server.new_session()` can run commands at startup (#103)

{meth}`~libtmux.Server.new_session` learned how to run commands in the new
window on session start. Thanks @grimpy.

### Fixes

#### `Server.has_session()` uses tmux return codes (#68)

{meth}`~libtmux.Server.has_session` became more robust by checking tmux's return
code. Thanks @jlargentaye.

### Development

#### Dependencies and CI were refreshed

pytest, Sphinx, Travis, PyPy, and supported Python versions were updated.

## libtmux 0.7.8 (2018-03-04)

libtmux 0.7.8 ports tmuxp retry support.

### What's new

#### `retry` moved in from tmuxp

The retry helper was ported from tmuxp for shared behavior.

## libtmux 0.7.7 (2017-11-10)

libtmux 0.7.7 fixes tmux 2.6 session sizing from inside clients.

### Fixes

#### tmux 2.6 no longer receives unsupported `-x` / `-y`

libtmux avoids those flags when running from inside a client on tmux 2.6+.

## libtmux 0.7.6 (2017-11-09)

libtmux 0.7.6 repairs layout selection and option ambiguity tests.

### Fixes

#### `Window.select_layout` can be called without arguments

The layout-selection helper accepts the tmux default path again, and tests were
updated for tmux 2.6 option ambiguity behavior.

## libtmux 0.7.5 (2017-10-07)

libtmux 0.7.5 is a tmux 2.6 hotfix.

### Fixes

#### tmux 2.6 session creation works

Session creation was patched for tmux 2.6 compatibility.

## libtmux 0.7.4 (2017-08-19)

libtmux 0.7.4 fixes command targeting.

### Fixes

#### Commands include session IDs (#65)

tmux commands now include the relevant session id. Thanks @askedrelic.

## libtmux 0.7.3 (2017-05-29)

libtmux 0.7.3 records exact-match support limits.

### Compatibility

#### Exact matches require tmux 2.1+

Exact matching is only supported on tmux 2.1 and later.

## libtmux 0.7.2 (2017-05-29)

libtmux 0.7.2 adds exact matching to session lookup.

### What's new

#### `Server.has_session` supports exact matching

{meth}`~libtmux.Server.has_session` can check for exact session names.

## libtmux 0.7.1 (2017-04-28)

libtmux 0.7.1 improves formatted option handling.

### Fixes

#### Formatted options such as `pane-border-status` are supported (#37)

Option parsing works better for formatted tmux options. Thanks @kaushalmodi.

## libtmux 0.7.0 (2017-04-27)

libtmux 0.7.0 drops Python 2.6, adds tmux 2.4 support, and overhauls option
errors and version checks.

### Breaking changes

#### Python 2.6 support was dropped

Python 2.7 became the minimum supported Python version.

#### Version helper names changed

`has_version` was renamed to `get_version`,
`has_required_tmux_version` was renamed to `has_minimum_version`, and
comparison helpers such as `has_gt_version`, `has_gte_version`,
`has_lt_version`, and `has_lte_version` were added.

### What's new

#### Option errors have a dedicated hierarchy

{exc}`libtmux.exc.OptionError` became the base class for
{exc}`libtmux.exc.InvalidOption`, `libtmux.exc.AmbiguousOption`, and
{exc}`libtmux.exc.UnknownOption`.

#### tmux master and OpenBSD versions are represented explicitly

`get_version` reports tmux built from master with a `-master` suffix and OpenBSD
base tmux with an `-openbsd` suffix.

### Documentation

#### Session method docs were improved

Session documentation and option-method exception details were cleaned up.

### Development

#### tmux 2.4, PyPy, and version bounds were added

The release added support for tmux 2.4, PyPy/PyPy3,
`TMUX_MIN_VERSION`, and `TMUX_MAX_VERSION`.

## libtmux 0.6.5 (2017-04-02)

libtmux 0.6.5 improves tmux binary lookup.

### What's new

#### `tmux_cmd` can search custom paths

`tmux_search_paths` and `append_env_path` were added, and
{exc}`~libtmux.exc.TmuxCommandNotFound` reports missing tmux executables.

## libtmux 0.6.4 (2017-03-25)

libtmux 0.6.4 adds OpenBSD tmux support.

### Compatibility

#### OpenBSD tmux is supported (#32)

The version and command handling paths now account for OpenBSD tmux.

## libtmux 0.6.3 (2017-02-08)

libtmux 0.6.3 supports tmux built from master.

### Compatibility

#### tmux master builds are recognized (#25)

Version handling supports tmux built from unreleased master. Thanks @sloria.

## libtmux 0.6.2 (2017-01-19)

libtmux 0.6.2 relaxes version parsing and updates packaging.

### Fixes

#### Loose version parsing handles more tmux versions (#197)

`LooseVersion` replaced `StrictVersion` for tmux version checks. Thanks
@minijackson.

### Documentation

#### README fixes landed (#21)

The README was corrected. Thanks @huwenchao.

### Development

#### Package pins were maintained with pyup.io

Dependency pin maintenance moved through pyup.io.

## libtmux 0.6.1 (2016-12-20)

libtmux 0.6.1 fixes logging, start directories, and tmux 2.3 support.

### What's new

#### start directories are supported for sessions and panes (#19)

New sessions and panes can receive `start_directory`. Thanks @gandelman-a.

### Fixes

#### Logger behavior was repaired (#18)

Logging was fixed thanks to @geekli.

### Development

#### tmux 2.3 is officially supported

Tests were fixed and tmux 2.3 support was added.

## libtmux 0.6.0 (2016-09-16)

libtmux 0.6.0 validates session names and trims unused attachment parameters.

### Fixes

#### Invalid session names raise errors

tmux session names cannot be empty or contain periods or colons; libtmux now
raises for those invalid names.

### Development

#### Unused attach/switch parameters were removed

Unused `target_session` parameters were removed from `Server.attach_session` and
`Server.switch_client`.

## libtmux 0.5.1 (2016-08-18)

libtmux 0.5.1 fixes missing-tmux logging.

### Fixes

#### Missing tmux in `PATH` logs clearly (#12)

The logger message for a missing tmux executable was corrected.

## libtmux 0.5 (2016-06-15)

libtmux 0.5 improves option errors and documentation.

### What's new

#### Unknown options and unset valid options are distinct (#8)

{exc}`libtmux.exc.UnknownOption` was added, and valid-but-unset options now
return `None`.

### Documentation

#### Major documentation overhaul (#6)

The documentation was substantially refreshed.

## libtmux 0.4.1 (2016-05-23)

libtmux 0.4.1 fixes tmux discovery through `PATH`.

### Fixes

#### `which()` reads `PATH`

tmux lookup now uses `os.environ["PATH"]`. See <https://redd.it/4laeut>.

## libtmux 0.4.0 (2016-05-23)

libtmux 0.4.0 makes tmux format metadata available as object attributes.

### Breaking changes

#### `_TMUX` metadata became `_info`

The internal metadata object was renamed.

### What's new

#### Session, Window, and Pane expose format fields as attributes

Format-backed properties such as `session.name`, `window.name`,
`pane.current_path`, `session.id`, `window.id`, `pane.id`, `session.index`,
`window.index`, and `pane.index` are available directly. Attached-session,
window, and pane relationships also became properties.

### Development

#### `findWhere()` became `find_where`

The old camelCase lookup helper was renamed, and README usage was updated.

## libtmux 0.3.0 (2016-05-23)

libtmux 0.3.0 switches the project test runner.

### Development

#### pytest became the test runner

The project moved to pytest.

## libtmux 0.1.0 (2016-05-22)

libtmux 0.1.0 is the initial standalone libtmux release.

### What's new

#### libtmux forked from tmuxp

The library began as a fork from [tmuxp].

[tmuxp]: https://github.com/tmux-python/tmuxp
[@askedrelic]: https://github.com/askedrelic

<!---
# vim: set filetype=markdown:
-->
