# libtmux for Perl > The Perl library (LibTmux). These pages include its guides, tested examples and API documentation. - [Perl API reference](https://libtmux.org/en/perl/latest/reference/): every public symbol, generated from the source. Hosted on libtmux.org. --- # Concepts Source: https://libtmux.org/en/perl/latest/concepts/ > Concepts for LibTmux. Understand captured queries, object identities, and operations. - [Entity fields](https://libtmux.org/en/perl/latest/concepts/fields/): Read about entity fields. - [Snapshot graph and identity](https://libtmux.org/en/perl/latest/concepts/graph/): Read about graph. --- # Entity fields Source: https://libtmux.org/en/perl/latest/concepts/fields/ > Entity fields: LibTmux documentation. Generated from the packaged field catalog. Missing fields throw; known null is explicit. | Entity | Field | Wire | Type | Nullable | tmux source / minimum | | --- | --- | --- | --- | --- | --- | | client | height | height | integer | no | [`client_height`](https://libtmux.org/en/tmux/latest/catalog/formats/client_height/) / 3.3a | | client | id | id | string | no | [`client_name`](https://libtmux.org/en/tmux/latest/catalog/formats/client_name/) / 3.3a | | client | name | name | string | no | [`client_name`](https://libtmux.org/en/tmux/latest/catalog/formats/client_name/) / 3.3a | | client | pid | pid | integer | no | [`client_pid`](https://libtmux.org/en/tmux/latest/catalog/formats/client_pid/) / 3.3a | | client | session | session | relation | yes | captured graph | | client | tty | tty | bytes | no | [`client_tty`](https://libtmux.org/en/tmux/latest/catalog/formats/client_tty/) / 3.3a | | client | width | width | integer | no | [`client_width`](https://libtmux.org/en/tmux/latest/catalog/formats/client_width/) / 3.3a | | pane | active | active | boolean | no | [`pane_active`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_active/) / 3.3a | | pane | current_command | currentCommand | string | no | [`pane_current_command`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_current_command/) / 3.3a | | pane | current_path | currentPath | bytes | no | [`pane_current_path`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_current_path/) / 3.3a | | pane | cursor_shape | cursorShape | string | no | [`cursor_shape`]() / 3.6 | | pane | dead | dead | boolean | no | [`pane_dead`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_dead/) / 3.3a | | pane | exit_status | exitStatus | integer | yes | [`pane_dead_status`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_dead_status/) / 3.3a | | pane | height | height | integer | no | [`pane_height`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_height/) / 3.3a | | pane | id | id | string | no | [`pane_id`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_id/) / 3.3a | | pane | index | index | integer | no | [`pane_index`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_index/) / 3.3a | | pane | pid | pid | integer | no | [`pane_pid`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_pid/) / 3.3a | | pane | title | title | string | no | [`pane_title`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_title/) / 3.3a | | pane | width | width | integer | no | [`pane_width`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_width/) / 3.3a | | pane | window | window | relation | no | captured graph | | session | attached | attached | integer | no | [`session_attached`](https://libtmux.org/en/tmux/latest/catalog/formats/session_attached/) / 3.3a | | session | created | created | integer | no | [`session_created`](https://libtmux.org/en/tmux/latest/catalog/formats/session_created/) / 3.3a | | session | id | id | string | no | [`session_id`](https://libtmux.org/en/tmux/latest/catalog/formats/session_id/) / 3.3a | | session | name | name | string | no | [`session_name`](https://libtmux.org/en/tmux/latest/catalog/formats/session_name/) / 3.3a | | session | path | path | bytes | no | [`session_path`](https://libtmux.org/en/tmux/latest/catalog/formats/session_path/) / 3.3a | | session | window_links | windowLinks | relation | no | captured graph | | window | active_pane | activePane | relation | yes | captured graph | | window | height | height | integer | no | [`window_height`](https://libtmux.org/en/tmux/latest/catalog/formats/window_height/) / 3.3a | | window | id | id | string | no | [`window_id`](https://libtmux.org/en/tmux/latest/catalog/formats/window_id/) / 3.3a | | window | layout | layout | string | no | [`window_layout`](https://libtmux.org/en/tmux/latest/catalog/formats/window_layout/) / 3.3a | | window | links | links | relation | no | captured graph | | window | name | name | string | no | [`window_name`](https://libtmux.org/en/tmux/latest/catalog/formats/window_name/) / 3.3a | | window | panes | panes | relation | no | captured graph | | window | width | width | integer | no | [`window_width`](https://libtmux.org/en/tmux/latest/catalog/formats/window_width/) / 3.3a | | window_link | active | active | boolean | no | [`window_active`](https://libtmux.org/en/tmux/latest/catalog/formats/window_active/) / 3.3a | | window_link | id | id | string | no | captured graph | | window_link | index | index | integer | no | [`window_index`](https://libtmux.org/en/tmux/latest/catalog/formats/window_index/) / 3.3a | | window_link | session | session | relation | no | captured graph | | window_link | window | window | relation | no | captured graph | --- # Snapshot graph and identity Source: https://libtmux.org/en/perl/latest/concepts/graph/ > Snapshot graph and identity: LibTmux documentation. A physical window can appear at several indexes in one session and in several sessions. [`WindowLink`]() owns session-relative index and active state. A Pane's `window` always returns the physical Window. Session changes use explicit links. Snapshot [`windows`]() and `panes` contain each physical identity once. Raw `listings` retain contextual rows and multiplicity. Selection filters retain their own input order and duplicates. Two occurrences of one identity still make `one` ambiguous. Selections may combine captures from the same server generation. Each handle retains its own observed graph; combining them does not reconcile capture times or create a new snapshot. Mixing server scopes or daemon generations is an [`InvalidSelection`]() error. Use one snapshot when a query needs one capture interval. For example, a retained pane captured before a rename and a fresh pane with the same resource identity can expose different window names. Each traverses its own graph. Capture start/end metadata describes those observation intervals; resource identity alone does not identify an observation. IDs remain strings. Write session IDs as `'$1'` in Perl so regex captures do not interpolate. Identity includes server, daemon generation, kind, and ID. Captured handles prevent silent retargeting after a restart; probes and commands remain separate observations, so they do not form a transaction. The daemon's [`socket_path`](https://libtmux.org/en/tmux/latest/catalog/formats/socket_path/) identifies the server and `pid/start_time` its generation. Raw ID strings deliberately target current resources and convey no historical generation protection. The store owns scalar records and ID adjacency. Handles strongly retain that store, which does not strongly own handles. A retained pane keeps its observed window even when the Snapshot wrapper leaves scope. Retaining one handle can retain the graph; `to_record` exports detached scalar data instead. Current to-many accessors scan related records; repeated relation traversal can repeat that work. Retained-graph memory and indexing improvements require measurements rather than assumptions about typical tmux graph size. Acquisition records start/end and completeness. Strict live capture rejects missing required topology. Unloaded fields and relations throw when needed; null and loaded-empty relations remain distinct. Accessors return independent membership arrays. Query methods are nonmutating, while native arrays remain mutable and every library query validates their members. --- # tmux client library for Perl Source: https://libtmux.org/en/perl/latest/core/ > tmux client library for Perl. Control tmux, connect to and create servers, navigate sessions, windows, and panes, send keys, capture pane contents The core uses stable Perl 5.44 features and standard-library runtime modules. The optional [LibTmux-Async distribution](https://libtmux.org/en/perl/latest/reference/libtmux-async-server/) returns Future values and requires a caller-owned [IO::Async::Loop::Ppoll](https://metacpan.org/pod/IO::Async::Loop::Ppoll) loop. Its [transport reference](https://libtmux.org/en/perl/latest/reference/libtmux-async-transport/) explains admission, cancellation, and cleanup. Linux x86_64 LP64 is qualified; other platforms and ABIs remain unsupported. The distributions are available from source and have no CPAN release.Control tmux, connect to and create servers, navigate sessions, windows, and panes, send keys, capture pane contents. ## At a glance | Type | Wraps | | ---- | ----- | | [`LibTmux::Server`](https://libtmux.org/en/perl/latest/reference/libtmux-server/) | A tmux server | | [`LibTmux::Session`](https://libtmux.org/en/perl/latest/reference/libtmux-session/) | A session, ID `$n` | | [`LibTmux::Window`](https://libtmux.org/en/perl/latest/reference/libtmux-window/) | A physical window linked into sessions, ID `@n` | | [`LibTmux::Pane`](https://libtmux.org/en/perl/latest/reference/libtmux-pane/) | A pane in a window, ID `%n` | | [`LibTmux::WindowLink`](https://libtmux.org/en/perl/latest/reference/libtmux-windowlink/) | A session-window association, with its index and active state | ## Typed API - Typed objects instead of parsed format strings: [`LibTmux::Pane`](https://libtmux.org/en/perl/latest/reference/libtmux-pane/) - Addressing by tmux ID: [`LibTmux::Pane::id`](https://libtmux.org/en/perl/latest/reference/libtmux-pane-id/) - Filtering and queries over tmux objects: [`LibTmux::Selection::where`](https://libtmux.org/en/perl/latest/reference/libtmux-selection-where/) - Typed errors instead of exit codes and stderr: [`LibTmux::X::InvalidFilter`](https://libtmux.org/en/perl/latest/reference/libtmux-x-invalidfilter/) ## What you get over the tmux CLI - Connect to or start a tmux server: [`LibTmux::Server::new`](https://libtmux.org/en/perl/latest/reference/libtmux-server-new/) - Traversal from a server down to its panes: [`LibTmux::Server::snapshot`](https://libtmux.org/en/perl/latest/reference/libtmux-server-snapshot/) - Send keys to a pane: [`LibTmux::Server::send_keys`](https://libtmux.org/en/perl/latest/reference/libtmux-server-send_keys/) - Capture pane contents: [`LibTmux::Server::capture_pane`](https://libtmux.org/en/perl/latest/reference/libtmux-server-capture_pane/) - Arguments passed as a list, with no shell quoting: [`LibTmux::Server::cmd`](https://libtmux.org/en/perl/latest/reference/libtmux-server-cmd/) - A typed error when the running tmux lacks a feature: [`LibTmux::X::Unsupported`](https://libtmux.org/en/perl/latest/reference/libtmux-x-unsupported/) - Async operations: [`LibTmux::Async`](https://libtmux.org/en/perl/latest/reference/libtmux-async/) - [Installation and guides](https://libtmux.org/en/perl/latest/guides/): Install the native distributions and work with captured tmux state. - [Filtering example](https://libtmux.org/en/perl/latest/guides/filtering/): Run a complete snapshot, criteria, callback, and native-array workflow. - [API reference](https://libtmux.org/en/perl/latest/reference/): Native package signatures and interlinked POD for core and optional async. --- # Examples Source: https://libtmux.org/en/perl/latest/examples/ > Examples for LibTmux. Run complete programs with their documented setup and cleanup. - [Create sessions, windows, and panes](https://libtmux.org/en/perl/latest/examples/orchestration/): Read about orchestration. --- # Create sessions, windows, and panes Source: https://libtmux.org/en/perl/latest/examples/orchestration/ > Create sessions, windows, and panes: LibTmux documentation. Constructing [`LibTmux::Server`]() records connection settings without I/O. Pass a socket name or socket path; the library clears inherited `TMUX` and `TMUX_PANE` in subprocess environments. Acquisition and mutations are explicit. ```perl use v5.44; use LibTmux::Server; my $server = LibTmux::Server->new(socket_name => 'example'); my $session = $server->new_session( name => 'main', command => ['/bin/sleep', '120'], ); my $window = $server->new_window( session => $session, name => 'api', command => ['/bin/sleep', '120'], ); my $pane = $window->panes->one; my $split = $server->split_pane( pane => $pane, horizontal => true, command => ['/bin/sleep', '120'], ); $server->select_layout(window => $window, layout => 'even-horizontal'); my $observed = $server->snapshot; $server->kill_session(session => $session); ``` This example creates a session and explicitly removes it. Complete executed programs in [examples](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/examples) add exception-safe owned fixture cleanup. Literal argv does not select a shell. `shell_command` explicitly requests shell interpretation; one-element literal commands use the core exec shim. All mutations live on Server. Entity readers are captured and read-only; renaming a window does not change an old Window handle. Use a new snapshot. `capture_pane` returns bytes including tmux's final newline. `send_text` sends literal text with optional Enter; `send_keys` accepts named tmux keys. Use `set_option`/`get_option`/`unset_option` for explicit scopes, including inherited reads, and environment methods for global or session values. Hooks retain sparse indexes in native output. Buffers use stdin for binary payloads. `cmd` is the checked literal command escape hatch; `execute` retains nonzero command results. Ordered `batch` returns one `{result, error}` record per independent request, not per command inside a tmux command list. Interactive terminal ownership stays with the caller: `attach_argv` returns argv for a caller-owned terminal; `clients` captures client data and `detach_client` reports command acceptance. Observe client exit separately. The complete [quickstart program](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/examples/quickstart.pl) creates a session, splits a pane, adds a window, selects a window link, and filters captured panes. Install core first, then run it from the source checkout: ```console $ perl examples/quickstart.pl ``` The included standard-library fixture owns its private socket and verifies child exit. The standalone demo enables Linux x86_64 LP64 child reaping; the borrowed Server connection API does not change the application's reaper. --- # Getting started Source: https://libtmux.org/en/perl/latest/guides/getting-started/ > Getting started: LibTmux documentation. Control tmux with explicit commands, captured graphs, and ordinary Perl arrays. Targets stable Perl 5.44.0 and Linux x86_64, including WSL. These development distributions are not published on CPAN. ```perl use v5.44; use LibTmux::Server; my $server = LibTmux::Server->new(socket_name => 'example'); my $snapshot = $server->snapshot; # Explicit I/O; server must already exist. my $active = $snapshot->panes ->where({ active => true, width => { -gte => 80 } }) ->grep(sub ($pane) { $pane->current_command eq 'sleep' }); for my $pane ($active->@*) { say $pane->id, ' ', $pane->window->name; } ``` | Distribution | Location | Runtime dependencies | | --- | --- | --- | | [`LibTmux`](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/packages/core/README.md) | [packages/core](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/packages/core) | Perl standard library. | | [`LibTmux-Async`](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/packages/async/README.md) | [packages/async](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/packages/async) | Versioned core, Future, IO::Async::Loop::Ppoll and IO::Ppoll; caller-owned Ppoll loop. | | [`LibTmux-Workspace`](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/packages/workspace/README.md) | [packages/workspace](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/packages/workspace) | Versioned core; packaged JSON loader CLI. | Start with [installation](https://libtmux.org/en/perl/latest/guides/installation/), [basic orchestration](https://libtmux.org/en/perl/latest/examples/orchestration/), and [filtering](https://libtmux.org/en/perl/latest/guides/filtering/). Read [graph identity](https://libtmux.org/en/perl/latest/concepts/graph/) before working with linked windows, [query planning](https://libtmux.org/en/perl/latest/topics/query-planning/) for explicit native filters, [errors and recovery](https://libtmux.org/en/perl/latest/topics/errors/), [async execution](https://libtmux.org/en/perl/latest/guides/async/), and [workspace loading](https://libtmux.org/en/perl/latest/workspace/source-guide/). The [architecture decisions](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/docs/dev/adr/index.md) explain these contracts, their alternatives, and the upstream source models behind them. Installed API documentation uses native POD; for example `perldoc LibTmux::Server` and `perldoc LibTmux::Selection`. [Complete examples](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/examples) run against uniquely owned tmux sockets and assert results and cleanup. [Compatibility](https://libtmux.org/en/perl/latest/topics/compatibility/) records support for tmux 3.3a–3.8 and CI coverage of the range endpoints. Captured selections perform no tmux I/O; their methods preserve order and duplicates and return one fixed type in every calling context. Native array access remains available. MCP is excluded. Persistent control mode, streaming APIs, tmux command lists, serialized regexes, and relation pushdown are deferred. Package publication and shared-site deployment require separate authority. See [contributing](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/.github/CONTRIBUTING.md) for exact checks and tool setup, [Perl choices](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/.github/PERL.md) for source-backed decisions, and [branding assets](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/docs/branding.md) for logos and social cards. --- # Guides Source: https://libtmux.org/en/perl/latest/guides/ > Guides for LibTmux. Connect to tmux and work with its sessions, windows, and panes. - [Getting started](https://libtmux.org/en/perl/latest/guides/getting-started/): Read about libtmux for perl. - [Installation](https://libtmux.org/en/perl/latest/guides/installation/): Read about installation. - [Filtering](https://libtmux.org/en/perl/latest/guides/filtering/): Read about filtering. --- # Installation Source: https://libtmux.org/en/perl/latest/guides/installation/ > Installation: LibTmux documentation. These distributions are unpublished. Use Perl 5.44.0 and install core before workspace or optional async. Use the repository's pinned cpm author setup, or an existing cpm installation. From the repository root: ```console $ cpm install \ --global \ ./packages/core ``` ```console $ cpm install \ --global \ ./packages/workspace ``` ```console $ cpm install \ --global \ ./packages/async ``` Core and workspace need only the Perl standard library at runtime. Async adds Future, IO::Async, IO::Async::Loop::Ppoll and IO::Ppoll. Its caller supplies a Ppoll loop; IO::Ppoll includes an XS extension. See the [async guide](https://libtmux.org/en/perl/latest/guides/async/) for construction and cleanup. Configure/test/develop requirements remain separate. To inspect installed documentation: ```console $ perldoc LibTmux::Server ``` The [contributor guide](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/.github/CONTRIBUTING.md) documents pinned local provisioning, archive builds, and isolated installed-consumer verification. No PAUSE upload, tag, or release is implied by source installation. --- # Filtering Source: https://libtmux.org/en/perl/latest/guides/filtering/ > Filtering: LibTmux documentation. Use `where({...})` for query data and `grep(sub ($pane) {...})` for arbitrary Perl behavior. Native `->@*`, indexing, `grep`, `map`, `sort`, and List::Util remain available. `to_array` returns a fresh unblessed array reference. Fields select comparison semantics: text, safe decimal integers, booleans, nullability, allowed operators, and relation cardinality come from one catalog. False, zero, "0", empty text, and undef remain distinct. Integer operands are bounded to +/-9007199254740991; invalid numeric text never becomes zero. | Grammar | Meaning | | --- | --- | | scalar or `-eq`, `-ne` | Schema-directed equality and complement. | | `-in`, `-not_in` arrays | Explicit membership; empty arrays mean false/true. | | `-lt`, `-lte`, `-gt`, `-gte` | Authorized numeric ordering. | | `-contains`, `-starts_with`, `-ends_with` | Literal, case-sensitive text. | | `-and`, `-or` arrays; `-not` node | Complete criteria nodes. | | `-some`, `-every`, `-none` | To-many quantifiers over the complete captured domain. | | `-is`, `-is_not` | To-one criteria or explicit nullable absence. | Fields/operators in a hash are conjoined. Duplicate Perl hash keys overwrite; use multiple operators or explicit `-and`. Empty criteria and empty AND are true; empty OR is false. On a loaded empty relation, some is false and every/none true. Conditions inside one some apply to the same child; separate existentials may match different children. Unloaded relations never prove empty. Full compilation precedes evaluation, even on empty selections. Hash keys traverse lexically; logical arrays preserve their order. Short-circuiting may avoid unavailable reads once a result is known. Known-null ordering/text is false; negation reverses known results, never missing-data failures. Evaluation order affects failures as well as matches. For an inactive record with unloaded width, an AND array testing `active` before `width` can return false; reversing those nodes reads width first and throws. Flattening them into a hash instead selects lexical order. Wire serialization retains logical-array order; optimizers must preserve availability and error behavior. The depth-64 and 10,000-node compilation limits do not cap membership operands or string bytes. Native arrays remain mutable. Every library method validates all N occurrences before returning even `first`, `count` or `exists`; that validation is O(N). Predicates may then stop early. `where` evaluates and validates its output; `iterator` also copies membership. Raw indexing and dereferencing retain normal Perl behavior. A mutable selection cannot safely cache a prior validation. [`LibTmux::Filter`]() owns normalized criteria, supports plain records and explicit registered readers, and exports JSON with schema `"libtmux.where/v1"`. Wire names use camelCase and dash-free operators. Regex/coderefs/cycles/blessed values are refused at that data boundary. Native Perl `qr//` remains available in callbacks. The complete example below is copied from an executed program. The fixture helper uses an owned socket, observes process exit, and cleans up on failures. ```perl use v5.44; use FindBin; use lib "$FindBin::Bin/../scripts/lib"; use LibTmuxFixture; use LibTmux::Filter; use List::Util qw(any first); LibTmuxFixture->run( sub ($server, $root) { my $session = $server->new_session( name => 'example', command => ['/bin/sleep', '120'] ); my $initial = $session->window_links->one->window->panes->one; $server->split_pane( pane => $initial, horizontal => true, command => ['/bin/sleep', '120'] ); my $snapshot = $server->snapshot; my $panes = $snapshot->panes->where({current_command => 'sleep'}) ->grep(sub ($pane) { $pane->width >= 1 }); die 'expected two panes' unless $panes->count == 2; for my $pane ($panes->@*) { say $pane->id . ' ' . $pane->current_command; } my $only_active = $panes->one({active => true}); die 'active pane unavailable' unless defined $only_active; my $has_active = any { $_->active } $panes->@*; my $first_active = first { $_->active } $panes->@*; die 'List::Util alternatives differ' unless $has_active && $first_active->id eq $only_active->id; my @ids = map { $_->id } $panes->@*; my @positive = grep { $_->width > 0 } $panes->@*; die 'ordinary Perl arrays differ' unless @ids == 2 && @positive == 2; my $filter = LibTmux::Filter->new(entity => 'pane', where => {active => true}); my $decoded = LibTmux::Filter->from_json($filter->to_json); die 'wire filter changed meaning' unless $panes->where($decoded)->one->id eq $only_active->id; my $retained = do { my $observed = $server->snapshot; $observed->pane_by_id($only_active->id); }; die 'retained graph lost a relationship' unless $retained->window->panes->count == 2; my $same_child = $snapshot->windows->where( {panes => {-some => {-and => [{index => 0}, {index => 1}]}}}); my $different_children = $snapshot->windows->where( { -and => [ {panes => {-some => {index => 0}}}, {panes => {-some => {index => 1}}} ] } ); die 'quantifiers conflated children' unless $same_child->count == 0 && $different_children->count == 1; my $where = {active => true, width => {-gte => 1}}; my $local = $server->query_panes(where => $where, pushdown => 'never'); my $verification; my $native = $server->query_panes( where => $where, pushdown => 'require', on_verification => sub ($report) { $verification = $report }, ); die 'native verification was not observed' unless $verification->{status} eq 'agreed' && $verification->{comparison} eq 'exact_ids'; die 'native/local disagreement' unless join(',', map { $_->id } @$local) eq join(',', map { $_->id } @$native); say 'selection, wire, graph lifetime, quantifiers, and query: ok'; } ); ``` ## Independent-port subset The shared fixture vocabulary is proposed for this port. A source-pinned Python QueryList evaluator agrees on the advertised subset: Boolean/integer/text equality, literal contains/prefix/suffix, membership, and empty membership. The adaptation maps wire field names to record keys and operators to native QueryList lookup keywords. It does not claim that Python accepts this wire API. Known-null equality initially disagreed: the pinned Python filter rejects None fields before its equality lookup. That difference remains recorded. Numeric ordering, availability errors, graph quantifiers, validation on empty data, and canonical-name enforcement have no equivalent declared Python contract and are marked unsupported, not passed. Perl fixtures cover those semantics. See [the fixtures](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/conformance/where-v1.json) and [the independent source pin](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/scripts/conformance-reference.json). --- # Optional async execution Source: https://libtmux.org/en/perl/latest/guides/async/ > Optional async execution: LibTmux documentation. Install the separate LibTmux-Async distribution to use an injected [`IO::Async::Loop::Ppoll`](https://metacpan.org/pod/IO::Async::Loop::Ppoll) and a Future-returning Server facade. Core and workspace do not load this dependency. Caller-side Future::AsyncAwait syntax is optional. Construct `IO::Async::Loop::Ppoll->new` explicitly. Installing it does not force `IO::Async::Loop->new` to select it. Other backends are rejected before dispatch. The async distribution requires Ppoll 0.10 and IO::Ppoll 0.14 or newer; IO::Ppoll supplies the native atomic-wait extension. Core and workspace remain standard-library runtime distributions. The caller owns and drives the loop. Each operation resolves to one value; void methods yield one undef. Command preparation, framing, identity, and parsing are shared with core. Captured selections stay synchronous and local. Transport bounds concurrent jobs and pending requests. Queue overflow fails before dispatch. Cancellation suppresses subsequent continuations and requests cleanup; it cannot undo accepted effects. Close cancels queued/running work, rejects new admissions, and returns a fresh cleanup observer. Only successful `is_done` proves cleanup. Cancelling that observer cannot cancel private cleanup. Keep driving the borrowed loop through shutdown; closing preserves the server. Ppoll owns the host's signal-watching policy. It blocks watched signals outside its atomic wait and can retain its shared `SIGCHLD` watch after facade close. Do not change its backend or wait mask while requests or cleanup remain active. Async children unblock only `SIGCHLD`, so a newly started tmux daemon can reap its panes; other mask bits remain unchanged in the child. Synchronous core execution retains the caller's mask. Starting a daemon through synchronous core while the host blocks `SIGCHLD` also passes that blocked mask to the daemon. See [ADR 0004](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/docs/dev/adr/0004-atomic-async-child-exit.md) for the failure evidence and the alternatives considered. The default bounds are four active jobs and 64 queued requests. A command's timeout starts in its execution loop, after queue waiting and supervisor setup. It does not bound the total time of a multi-command operation. Cleanup has a separate allowance; see [failure recovery](https://libtmux.org/en/perl/latest/topics/errors/). Persistent control, streaming subscriptions, and tmux command lists are deferred. Ordered batch requests are independent submissions with individual attribution. ## Failure and cancellation [async-lifecycle.pl](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/examples/async-lifecycle.pl) is a standalone downstream program. It imports only installed distributions and Perl core modules; it does not use the repository fixture. Supply the socket path of an existing tmux server. The program observes that server and closes only its executor. `--fail` exercises a rejected native command; `--cancel` cancels the capture. The program always drives cleanup to completion. An operation failure remains the primary exception, while a secondary cleanup failure is reported separately. Cancellation is checked before `get`; it is readiness without a result and does not prove cleanup. A successful close observer supplies that proof. The repository example runner exercises all three paths against an owned server, including with an isolated installed package prefix. ```perl use v5.44; use Getopt::Long qw(GetOptions); use IO::Async::Loop::Ppoll; use LibTmux::Async::Server; my ($socket, $executable, $fail, $cancel, $help); GetOptions( 'socket=s' => \$socket, 'tmux=s' => \$executable, 'fail' => \$fail, 'cancel' => \$cancel, 'help' => \$help, ) or die "Use --help for arguments\n"; if ($help) { say 'Usage: perl async-lifecycle.pl --socket PATH [--tmux EXE] [--fail | --cancel]'; say 'Observe an existing server and close the executor without destroying that server.'; exit 0; } die "Supply --socket PATH; --fail and --cancel are mutually exclusive\n" if !defined($socket) || @ARGV || ($fail && $cancel); my $loop = IO::Async::Loop::Ppoll->new; my $server = LibTmux::Async::Server->new( loop => $loop, socket_path => $socket, defined($executable) ? (executable => $executable) : (), ); my ($operation_error, $cleanup_error); try { my $operation = $fail ? $server->cmd('libtmux-example-invalid-command') : $server->snapshot; $operation->cancel if $cancel; $loop->await($operation); if ($operation->is_cancelled) { say 'capture cancelled' } else { my $snapshot = $operation->get; say 'captured panes: ' . $snapshot->panes->count; } } catch ($error) { $operation_error = $error } try { my $cleanup = $server->close; $loop->await($cleanup); $cleanup->get; say 'executor cleanup: complete'; } catch ($error) { $cleanup_error = $error } if (defined $operation_error) { warn "executor cleanup also failed: $cleanup_error\n" if defined $cleanup_error; die $operation_error; } die $cleanup_error if defined $cleanup_error; ``` --- # Linking and consuming our docs Source: https://libtmux.org/en/perl/latest/meta/linking/ > Find documentation exports for search engines, bots, LLMs and other documentation sites. We welcome bots, search engines, SEO tools, LLMs and other clients to use our documentation. Read a page in your browser, fetch its Markdown, discover pages through a manifest, or link to documented objects from another site. ## Choose an export The page footer links to the exports for its documentation tree. Use those links to select a language, version or preview. | File or format | Use it for | | --- | --- | | [llms.txt](https://libtmux.org/en/llms.txt) | Discover guides, API references and agent prompts through a Markdown index. | | [llms-full.txt](https://libtmux.org/en/llms-full.txt) | Fetch guides and MCP contracts together as Markdown. API references are linked separately. | | [docs.json](https://libtmux.org/en/docs.json) | Discover page titles, URLs, descriptions, headings and Markdown URLs in a structured manifest. | | Markdown | Read one page as text using its footer's **Markdown** link. | | Raw source | Inspect the source file using its footer's **Raw source** link, where available. | | [objects-full.inv](https://libtmux.org/en/objects-full.inv) | Resolve Sphinx references across shared docs, each port's default version, or its latest until the default has published a catalog, and tmux reference versions. | | objects.inv | Resolve Sphinx references within one port and version, or one tmux documentation tree. | | [targets.json](https://libtmux.org/en/targets.json) | Browse inventory keys, display names and destination URLs as JSON. A scoped catalog sits beside each root inventory. The root one lists fallbacks and ports left out. | The root exports above cover the assembled site. Port exports describe the selected port and version. For a single API declaration, start with `docs.json` and follow its reference and symbol-index links. ## Link from Sphinx The [Intersphinx guide](https://libtmux.org/en/meta/intersphinx/) explains how to configure inventories, choose native roles or portable labels, and preserve references when a page moves or changes its title. Browse [Intersphinx examples](https://libtmux.org/en/meta/intersphinx/examples/) for copyable RST and MyST references to library APIs, tmux C declarations, hooks, format variables, CLI commands and schema fields, paired with their destinations. ## Discover and index pages Use the [sitemap](https://libtmux.org/en/sitemap-index.xml) to discover indexable pages. Follow [robots.txt](https://libtmux.org/robots.txt) and each page's robots metadata: pull-request previews, component demos and search-index shards are excluded from crawling, and alternate versions can carry `noindex`. Choose a versioned documentation tree when a reference needs a particular release. The full inventory follows each port's advertised default; a port's `objects.inv` describes the selected version. --- # Link to libtmux from Sphinx Source: https://libtmux.org/en/perl/latest/meta/intersphinx/ > Use Intersphinx inventories to reference libtmux APIs and documentation. Sphinx can resolve references to libtmux APIs, guides, headings, MCP objects, schema fields, and other documented targets. The footer links to the full inventory and the inventory for the page's port or tmux version. Browse [Intersphinx examples](https://libtmux.org/en/meta/intersphinx/examples/) for copyable RST and MyST references paired with their destinations. For Markdown exports, manifests and crawler discovery, see [Linking and consuming our docs](https://libtmux.org/en/meta/linking/). ## Configure Intersphinx Enable the built-in extension in your project's `conf.py`: Python's [`None`]() discovers `objects.inv` at the configured base URL. The port mapping above selects the Python `latest` tree. Copy the base URL of another port or version to select its inventory. The full inventory includes shared documentation, the configured default version of each assembled port, and distinct tmux reference versions. It is generated after site assembly. Each port inventory includes the rendered targets in that exact version. The tmux inventory includes the shared tmux guides and the latest CLI manual, options, hooks, formats, and C source reference. A version mapping such as `tmux-3-7c` includes only that release's manual, catalog, and C declarations. Manual and C reference pages link to the same version inventory in the footer. Use mapping names without dots when writing MyST reference roles. ## Choose a reference Every exported target has a portable label that works with `std:ref`, without installing a language or MCP domain. Open `targets.json` beside the inventory and copy its `key`. Its `href` and `display` identify the destination. For example, the Python [`libtmux.Pane`]() declaration has this reStructuredText reference: ```rst :external+libtmux:ref:`Pane ` ``` With MyST enabled in your project, the same label works in Markdown: ```markdown {external+libtmux:ref}`Pane ` ``` Native Python, C++, JavaScript, and C objects also have aliases for their built-in roles. A scoped Python inventory supports: ```rst :external+libtmux-python:py:class:`libtmux.Pane` ``` The tmux mapping provides native C roles and portable manual references: ```rst :external+tmux:c:struct:`cmd` :external+tmux:ref:`capture-pane ` ``` Command options also work with Sphinx's program context: ```rst .. program:: tmuxp load :external+libtmux-python:option:`--append` ``` The full inventory qualifies native names by port, such as [`py:libtmux.Pane`](). A fully qualified alias includes the product too: [`py:core:libtmux.Pane`](). Short aliases are offered only when they identify one destination. Configuration values, command options, environment variables, and glossary terms use standard-domain types where their renderers identify those semantics. ## Stable labels A portable key contains `scope:product:category:identity`. Its encoding preserves uppercase letters, punctuation, and Unicode, because `std:ref` lowercases targets. `%50ane` and `pane` therefore remain distinct. Copy the key from the catalog without decoding its percent escapes. Keys are independent of display titles and destination URLs. API public IDs, protocol wire identities, JSON Pointers, named parameters, and native method identities supply their names. Authored documents can retain `inventoryId` and explicit HTML fragment IDs when their titles or routes change. Contributors preserve renamed keys in the inventory alias catalog and use the existing page redirect mechanism for retired routes. ### Preserve published links If `meta/intersphinx.md` moves to `meta/linking.md`, retain its logical ID and list the retired route in the new page's frontmatter: ```yaml inventoryId: intersphinx aliases: - meta/intersphinx ``` The document key remains `site:core:doc:intersphinx`, and the old route redirects to the new page. Retain existing heading fragment IDs when their text changes. When an identity or fragment changes intentionally, map the former keys to current targets in `site/src/data/inventory-aliases.json`. For example, choosing `inventoryId: linking` and changing `stable-labels` to `stable-references` needs these entries: ```json [ { "scope": "site", "from": "site:core:doc:intersphinx", "to": "site:core:doc:linking" }, { "scope": "site", "from": "site:core:heading:intersphinx%23stable-labels", "to": "site:core:heading:linking%23stable-references", "fragment": "stable-labels" } ] ``` The document entry preserves `std:ref` and `std:doc` references. The heading entry preserves `std:ref`; `fragment` also installs the retired HTML anchor at the new destination. Keep the route alias too: inventory aliases do not redirect retired URLs. Copy `to` from the current target catalog. Retain earlier `from` entries and update their destinations when renaming again. Former native role names, such as a Python class name, need preservation in the native metadata. Existing `objects.inv` and `reference/objects.inv` endpoints remain compatibility exports. New integrations should use the full inventory, a port's root inventory, or a tmux root inventory to obtain the complete target catalog and case-safe labels. See the [Sphinx Intersphinx documentation](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html) for named inventories and cross-reference syntax. --- # Intersphinx examples Source: https://libtmux.org/en/perl/latest/meta/intersphinx/examples/ > Compare Sphinx and MyST references to APIs, tmux C declarations, hooks, format variables, CLI commands and schema fields. import { referenceHref } from '../../../../lib/api-models' Copy a reference and compare its destination below. These examples cover native language roles, portable labels, full and scoped inventories, and links into tmux C declarations, hooks, format variables and CLI commands. ## Configure the inventories Add these mappings to your Sphinx project's `conf.py`: Python's [`None`]() discovers `objects.inv` at the mapping's base URL. The full inventory uses each port's advertised default version. The `py` mapping explicitly selects `latest`; `tmux` selects the latest tmux manual and C reference. Use the root URL from an inventory's footer link when selecting a preview or another release. ## Native Python roles A named inventory selects the Python tree: ```rst :external+py:py:class:`libtmux.Pane` ``` Destination: [Pane](https://libtmux.org/en/py/latest/reference/libtmux-pane/#libtmux.Pane). The full inventory qualifies native names by port: ```rst :external+full:py:class:`py:libtmux.Pane` ``` Destination: Pane in the Python default version. For automatic lookup, use the ordinary role. A local definition takes precedence over Intersphinx: ```rst :py:class:`libtmux.Pane` ``` Destination: [Pane](https://libtmux.org/en/py/latest/reference/libtmux-pane/#libtmux.Pane). ## Portable labels Portable labels work with the standard reference role, including languages that have no built-in Sphinx domain. Copy the key from `targets.json`. ```rst :external+full:ref:`Pane ` :external+py:ref:`Pane ` ``` Destinations: Full inventory: Pane, [Scoped inventory: Pane](https://libtmux.org/en/py/latest/reference/libtmux-pane/#libtmux.Pane). The external role searches the configured inventories without selecting one. This native name is unqualified only in the scoped Python inventory: ```rst :external:py:class:`libtmux.Pane` ``` Destination: [Pane](https://libtmux.org/en/py/latest/reference/libtmux-pane/#libtmux.Pane). ## MyST roles and inventory URLs Enable `myst_parser` alongside [`sphinx.ext.intersphinx`](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html) for Markdown sources. Named roles accept the same targets as reStructuredText: ```markdown {external+py:py:class}`libtmux.Pane` ``` Destination: [Pane](https://libtmux.org/en/py/latest/reference/libtmux-pane/#libtmux.Pane). Portable labels retain their percent escapes inside reference roles: ```markdown {external+full:ref}`Pane ` ``` Destination: Pane in the Python default version. MyST's inventory URL syntax also supports native aliases: ```markdown [Pane](inv:py:py:class#libtmux.Pane) ``` Destination: [Pane](https://libtmux.org/en/py/latest/reference/libtmux-pane/#libtmux.Pane). Use role syntax for percent-encoded portable keys: MyST normalizes escapes in `inv:` URLs. Keep mapping names free of dots, as in `tmux-3-7c`, so MyST can parse the role name. When using an inventory URL, specify its domain and object type if a name is both a document and a label. ## tmux C declarations The tmux mapping provides Sphinx's built-in C roles: ```rst :external+tmux:c:struct:`cmd` :external+tmux:c:func:`cmd_find_target` ``` Destinations: [cmd](https://libtmux.org/en/tmux/latest/reference/c-struct-cmd/#c%3Astruct%3Acmd), [cmd_find_target](https://libtmux.org/en/tmux/latest/reference/c-function-cmd_find_target/#c%3Afunction%3Acmd_find_target). Select a release with its own mapping. The full inventory also offers version-qualified native aliases: ```rst :external+tmux-3-7c:c:func:`cmd_find_target` :external+full:c:func:`tmux@3.7c:cmd_find_target` :external+full:c:func:`tmux@latest:cmd_find_target` ``` Destinations: [Scoped: cmd_find_target in 3.7c](https://libtmux.org/en/tmux/3.7c/reference/c-function-cmd_find_target/#c%3Afunction%3Acmd_find_target), [Full: cmd_find_target in 3.7c](https://libtmux.org/en/tmux/3.7c/reference/c-function-cmd_find_target/#c%3Afunction%3Acmd_find_target), [Full: cmd_find_target in latest](https://libtmux.org/en/tmux/latest/reference/c-function-cmd_find_target/#c%3Afunction%3Acmd_find_target). MyST supports the same C roles and a typed inventory URL: ```markdown {external+tmux:c:struct}`cmd` {external+tmux:c:func}`cmd_find_target` {external+full:c:func}`tmux@3.7c:cmd_find_target` [cmd_find_target](inv:tmux:c:function#cmd_find_target) ``` Destinations: [MyST: cmd](https://libtmux.org/en/tmux/latest/reference/c-struct-cmd/#c%3Astruct%3Acmd), [MyST: cmd_find_target](https://libtmux.org/en/tmux/latest/reference/c-function-cmd_find_target/#c%3Afunction%3Acmd_find_target), [MyST full: cmd_find_target in 3.7c](https://libtmux.org/en/tmux/3.7c/reference/c-function-cmd_find_target/#c%3Afunction%3Acmd_find_target), [Inventory URL: cmd_find_target](https://libtmux.org/en/tmux/latest/reference/c-function-cmd_find_target/#c%3Afunction%3Acmd_find_target). The C reference links each declaration to its source file and revision. Portable labels also address its signatures, parameters, and sections. ## tmux hooks Link a hook name to its catalog page with a portable label. The same key works in the scoped tmux inventory and the full inventory: ```rst :external+tmux:ref:`after-new-session ` :external+full:ref:`after-new-session ` ``` Destinations: [Scoped: after-new-session](https://libtmux.org/en/tmux/latest/catalog/hooks/after-new-session/), [Full: after-new-session](https://libtmux.org/en/tmux/latest/catalog/hooks/after-new-session/). In MyST, use the same key inside a reference role. Preserve its percent escapes: ```markdown {external+tmux:ref}`after-new-session ` {external+full:ref}`after-new-session ` ``` Destinations: [MyST scoped: after-new-session](https://libtmux.org/en/tmux/latest/catalog/hooks/after-new-session/), [MyST full: after-new-session](https://libtmux.org/en/tmux/latest/catalog/hooks/after-new-session/). ## tmux formats Link a format variable such as [`#{session_name}`](https://libtmux.org/en/tmux/latest/catalog/formats/session_name/) to its catalog entry: ```rst :external+tmux:ref:`session_name ` :external+full:ref:`session_name ` ``` Destinations: [Scoped: session_name](https://libtmux.org/en/tmux/latest/catalog/formats/session_name/), [Full: session_name](https://libtmux.org/en/tmux/latest/catalog/formats/session_name/). The MyST references select the same scoped or full inventory: ```markdown {external+tmux:ref}`session_name ` {external+full:ref}`session_name ` ``` Destinations: [MyST scoped: session_name](https://libtmux.org/en/tmux/latest/catalog/formats/session_name/), [MyST full: session_name](https://libtmux.org/en/tmux/latest/catalog/formats/session_name/). ## tmux CLI manual The same tmux inventory covers command pages: ```rst :external+tmux:ref:`capture-pane ` ``` Destination: [capture-pane](https://libtmux.org/en/tmux/latest/manual/capture-pane/). The document role works when the target is a whole page: ```rst :external+tmux:doc:`Full manual ` ``` Destination: [Full tmux manual](https://libtmux.org/en/tmux/latest/manual/full/). Select a command's manual page with the document role. Its portable key also works in the full inventory: ```rst :external+tmux:doc:`tmux new-session ` :external+full:doc:`tmux new-session ` ``` Destinations: [Scoped: new-session](https://libtmux.org/en/tmux/latest/manual/new-session/), [Full: new-session](https://libtmux.org/en/tmux/latest/manual/new-session/). Use the same document role in MyST: ```markdown {external+tmux:doc}`tmux new-session ` {external+full:doc}`tmux new-session ` ``` Destinations: [MyST scoped: new-session](https://libtmux.org/en/tmux/latest/manual/new-session/), [MyST full: new-session](https://libtmux.org/en/tmux/latest/manual/new-session/). ## Command options, environment variables, and terms The Python port's workspace documentation exports standard-domain objects. Set the program context before referencing an option: ```rst .. program:: tmuxp load :external+py:option:`--append` ``` Destination: [tmuxp load --append](https://libtmux.org/en/py/latest/workspace/cli/load/#arguments-and-flags-a-append). Environment variables and glossary terms use their own roles. Qualify the product when a term appears in more than one glossary: ```rst :external+py:envvar:`COLUMNS` :external+py:term:`async ` ``` Destinations: [COLUMNS](https://libtmux.org/en/py/latest/workspace/configuration/environment/#cli-and-runtime-variables-columns-lines-rows), [async](https://libtmux.org/en/py/latest/reference/glossary/#async). ## MCP tools and schema fields Portable labels also address protocol objects and individual JSON Schema fields. No custom MCP domain is required: ```markdown {external+py:ref}`Read tools batch ` {external+py:ref}`on_error ` ``` Destinations: [Read tools batch](https://libtmux.org/en/py/latest/mcp/tools/call_read_tools_batch/#mcp.tool.call_read_tools_batch), [on_error](https://libtmux.org/en/py/latest/mcp/tools/call_read_tools_batch/#mcp.tool.call_read_tools_batch.input%2Fproperties%2Fon_error). ## Shared documentation and headings The full inventory includes the shared documentation: ```rst :external+full:doc:`Inventory guide ` :external+full:ref:`Configure Intersphinx ` ``` Destinations: [Inventory guide](https://libtmux.org/en/meta/intersphinx/), [Configure Intersphinx](https://libtmux.org/en/meta/intersphinx/#configure-intersphinx). ## Local files and fallback locations Download an inventory and pass its filename as the second mapping value. The first value remains the documentation URL used in generated links: An ordered list tries a local copy before the HTTP inventory: See the [inventory guide](https://libtmux.org/en/meta/intersphinx/) for key stability and the [Sphinx Intersphinx reference](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html) for configuration options. --- # AI policy Source: https://libtmux.org/en/perl/latest/meta/ai-policy/ > Use the libtmux packages with AI tools. When contributing, check what you submit and wait for a maintainer's invitation before preparing a pull request. Last revised October 25, 2026 Use these packages with AI tools as you like. When contributing, check what you submit and wait for a maintainer's invitation before preparing a pull request. This policy covers the libraries, ports, and documentation in the [libtmux](https://github.com/libtmux) and [tmux-python](https://github.com/tmux-python) organizations, including their issues, comments, discussions, reviews, and pull requests. ## 1. For users: About these packages We encourage you to use AI tools with our libraries and documentation, including to generate code that calls the libraries. We want these projects to be useful in the way you work. Some of what we publish supports that workflow: - [MCP integrations](https://libtmux.org/en/py/latest/mcp/) that let assistants interact with tmux. - Markdown documentation and `llms.txt` and `llms-full.txt` resources linked from documentation pages. - `AGENTS.md` and other repository instructions for tools working on the codebase. Use the documentation for the package, language, and version you are working with. ### How the ports are made The ports build on [tmuxp](https://tmuxp.git-pull.com/), started in 2013, and [libtmux](https://libtmux.git-pull.com/), started in 2016. Both projects predate today's LLM coding tools. Current work on the original projects and the ports uses AI assistance. Maintainers guide the design, review changes, test behavior against real tmux, and decide what ships. They remain responsible for what the projects include and maintain. ### Stability Packages in the [libtmux organization](https://github.com/libtmux) are experimental unless their README says otherwise. Names and APIs may change between releases. Pin an exact version and review changes before upgrading. ## 2. For contributors: How to report issues, ideas, suggestions, and security issues A useful issue is a contribution in its own right. Your experience helps us see what breaks, what feels awkward, and what is missing. You do not need to arrive with a patch. Open bugs, ideas, and suggestions in the repository of the package they concern. Report suspected security vulnerabilities privately using the route below. ### Bugs Tell us what you tried, what happened, and what you expected. Include a small example we can run, the library and tmux versions, and the actual output. Include relevant logs and error messages as they appeared, and distinguish what you observed from possible explanations. Bug reports are welcome whether the code you were running was handwritten or generated. Include the code that ran. A conversation transcript is usually unnecessary; include relevant prompts or tool calls when they are needed to reproduce the problem. ### Ideas and suggestions Explain what you wanted to accomplish and where the current design gets in your way. We welcome feedback on: - Usability: what was hard to find or get right, and where the documentation misled you. - Language conventions: whether a port feels natural in the language you use. - Aesthetics: how an API, a page, or an error message reads. - Missing capabilities: what you could not accomplish with the current API. If an API you expected is missing, describe the task and why that API would help. ### Security issues Report suspected security vulnerabilities privately. Use **Report a vulnerability** on the affected repository's security page where available. Include the affected package and version, the tmux version, what you observed, and reproduction steps or relevant code references if available. Distinguish verified behavior from suspected impact. Please coordinate public disclosure with us so we can investigate and, where needed, prepare a fix. Command execution explicitly requested through documented features is expected behavior and does not, by itself, establish a vulnerability. Explain any additional failure, such as data being interpreted as commands unexpectedly or an intended security boundary being crossed. ### Writing your report Short reports, typos, and imperfect English are fine. Translation and writing assistance are welcome; check that the result says what you mean and preserves the facts you observed. Your experience matters more than a polished report. ### Using AI tools If AI materially helped prepare your issue, comment, discussion, review, or pull request, say which tools you used, what they did, and what you checked yourself. Using these tools does not count against a contribution. You remain responsible for what you submit. Do not send generated code, reports, or explanations you have not checked. ### Pull requests Before preparing a pull request, open an issue or comment on an existing issue about the proposed change. Wait for a maintainer to invite a PR for an agreed scope. Opening an issue alone is not an invitation. PRs submitted without that agreement may be closed without review. Arrange security fixes through the private reporting route. Even when we agree that something should change, we may prefer to write the implementation ourselves. Review must consider correctness, supported tmux versions, language conventions, documentation, and ongoing maintenance. Checking those can take more time than writing the change, whether it was handwritten or generated. If we invite a PR, understand the changes, test them, and be able to explain them. Follow the project's contribution instructions, and describe the tests you ran and the versions you used. Generated code and tests can share the same mistake, so passing tests alone do not show that a change fits the project. Submit only material you have the right to contribute on terms compatible with the project's license. Identify outside code, tests, or text incorporated into the contribution, including material adapted with AI assistance, and provide its source and license. Keep required notices, and raise unclear permissions before including the material. These source and licensing requirements apply to maintainers too.

Acknowledgments: Informed by Pallets’ LLM and AI Policy, tmux’s AI contribution guidelines, and OpenJDK’s Interim Policy on Generative AI. Licensing references: the GNU GPL FAQ on translating code and license compatibility. All sources consulted .

--- # Third-party notices Source: https://libtmux.org/en/perl/latest/meta/third-party-notices/ > Thanks to tmux's creator and contributors, with licences and attribution for the software behind libtmux.org. ## tmux First and foremost, thank you to **[Nicholas Marriott (nicm)](https://github.com/nicm)**, the creator of tmux, and to the many [tmux contributors](https://github.com/tmux/tmux/graphs/contributors). We are grateful for the work that makes tmux possible. libtmux is a separate project. Our libraries and supporting tools control a real tmux server; tmux itself provides the terminal multiplexer. This is the libtmux website. Visit the [official tmux website](https://github.com/tmux/tmux/wiki) for the upstream project and its documentation. See tmux's [COPYING file](https://github.com/tmux/tmux/blob/master/COPYING) and the copyright and permission notices in its source files for its licensing. ### tmux artwork The tmux logomark is by Jason Long. The site uses the unmodified [upstream SVG](https://github.com/tmux/tmux/blob/8f25579c5aef8d93924a20681f394e2a582fd3ad/logo/tmux-logomark.svg) under its [copyright and permission notice](https://libtmux.org/en/brand/tmux/LICENSE.txt). ## Programming-language artwork The homepage language selector uses local copies of the following artwork to identify the selected language. Each source record includes the download URL, retrieval time, file hash, copyright information and usage terms. These marks identify their respective languages and do not imply endorsement of libtmux. The SVG files are copied unchanged except for Scala and Rust. Scala's empty surrounding canvas is cropped; its paths, gradients and colors are preserved, and the original SVG is retained beside the cropped copy. Rust's supplied SVG turns its mark white when the device is in dark mode. A browser does not reliably apply that rule to this site's color setting when the file is shown as an image. The rule is removed, its paths are unchanged, and the page lightens the mark on a dark theme instead. | Language | Credit and terms | Local source record | |---|---|---| | Python | Python Software Foundation. The [PSF logo terms](https://www.python.org/psf/trademarks/) permit the unaltered mark to identify Python. | [Python provenance](https://libtmux.org/en/brand/languages/py/provenance.json) | | Ruby | Copyright © 2006, Yukihiro Matsumoto. The [Ruby logo](https://www.ruby-lang.org/en/about/logo/) is licensed under [CC BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/). | [Ruby provenance](https://libtmux.org/en/brand/languages/ruby/provenance.json) | | Lua | Copyright © 1998 Lua.org; graphic design by Alexandre Nakonechnyj. The Devicon copy carries its [MIT notice](https://libtmux.org/en/brand/languages/lua/LICENSE.txt); [Lua's logo terms](https://www.lua.org/images/) also apply. Visit [Lua.org](https://www.lua.org/). | [Lua provenance](https://libtmux.org/en/brand/languages/lua/provenance.json) | | TypeScript | Microsoft. The [official branding terms](https://www.typescriptlang.org/branding/) govern the mark; the website repository licenses exclude logo and trademark rights. | [TypeScript provenance](https://libtmux.org/en/brand/languages/ts/provenance.json) | | Rust | The Rust Foundation. [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) and the [Rust trademark policy](https://rustfoundation.org/policy/rust-trademark-policy/) apply. | [Rust provenance](https://libtmux.org/en/brand/languages/rs/provenance.json) | | Go | The [Go gopher](https://go.dev/blog/gopher) is by Renee French, licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). | [Go provenance](https://libtmux.org/en/brand/languages/go/provenance.json) | | C++ | Created by Jeremy Kratz and licensed by the Standard C++ Foundation under its [logo-use terms](https://isocpp.org/home/terms-of-use). | [C++ provenance](https://libtmux.org/en/brand/languages/cxx/provenance.json) | | Swift | Apple Inc., under the [Swift Logo Guidelines](https://developer.apple.com/swift/downloads/swift-logo.zip). Swift and the Swift logo are trademarks of Apple Inc. | [Swift provenance](https://libtmux.org/en/brand/languages/swift/provenance.json) | | Java | Devicon collection copyright (c) 2015 konpa, with its [MIT notice](https://libtmux.org/en/brand/languages/java/LICENSE.txt). This does not establish unrestricted rights to the underlying Java logo; [Oracle's logo terms](https://www.oracle.com/legal/logos/) apply. | [Java provenance](https://libtmux.org/en/brand/languages/java/provenance.json) | | Kotlin | Kotlin Foundation brand guidelines preserve JetBrains copyrights. The [icon-use terms](https://kotlinfoundation.org/guidelines/) permit identifying Kotlin alongside other programming-language icons. | [Kotlin provenance](https://libtmux.org/en/brand/languages/kotlin/provenance.json) | | Scala | Copyright EPFL. [Historical permission](https://groups.google.com/g/scala-user/c/bCC-R0FQn1w) covers noncommercial Scala promotion; the [general artwork-license question](https://github.com/scala/scala-lang/issues/1040) remains unresolved. | [Scala provenance](https://libtmux.org/en/brand/languages/scala/provenance.json) | | C# | Copyright the .NET authors. [Brand-use permission](https://github.com/dotnet/brand/issues/10#issuecomment-669465301) allows the unmodified logo to represent .NET. The repository's CC0 statement covers illustrations; no blanket CC0 claim is made for the logo. | [.NET provenance](https://libtmux.org/en/brand/languages/csharp/provenance.json) | | F# | The F# Software Foundation. Its [logo terms](https://foundation.fsharp.org/logo) require unchanged shape, colors and proportions, without implying Foundation representation. | [F# provenance](https://libtmux.org/en/brand/languages/fsharp/provenance.json) | ## Terminal artwork The tmux CLI selector displays the Windows Terminal artwork by Microsoft Corporation, licensed under [CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0/). The SVG is unmodified. See the [source and provenance](https://libtmux.org/en/brand/tools/terminal/provenance.json) and [copyright and license](https://libtmux.org/en/brand/tools/terminal/LICENSE.txt). ## Documentation toolchain libtmux and this site are built with open-source software. The following tools have their own licences and attribution requirements. | Tool | Licence | Role | |---|---|---| | [Astro](https://astro.build/) | MIT | The site shell | | [Tailwind CSS](https://tailwindcss.com/) | MIT | Styling | | [Pagefind](https://pagefind.app/) | MIT | Site-wide search | | [Expressive Code](https://expressive-code.com/) | MIT | Code blocks | | [Sphinx](https://www.sphinx-doc.org/) | BSD-2-Clause | Python and C++ reference | | [Furo](https://github.com/pradyunsg/furo) | MIT | Sphinx theme | | [Breathe](https://github.com/breathe-doc/breathe) | BSD-3-Clause | Doxygen XML into Sphinx | | [Doxygen](https://www.doxygen.nl/) | GPL-2.0-only | Parses C++ headers to XML | | [API Extractor](https://api-extractor.com/) | MIT | TypeScript API model | | [IBM Plex](https://github.com/IBM/plex) | OFL-1.1 | Typeface | ### A note on Doxygen Doxygen is licensed GPL-2.0-only. It runs as a build step that reads libtmux's own headers and emits XML; that XML is rendered by Breathe and Sphinx, and no Doxygen-generated HTML is published. Running a GPL program over your own input does not place its licence on the output, and libtmux does not distribute Doxygen or any modified version of it. ## Reference hosting The [PyPI blocks logo](https://pypi.org/trademarks/) is a trademark of the Python Software Foundation and identifies links to the Python Package Index. Other package-host icons use [Simple Icons](https://simpleicons.org/) (CC0-1.0). The docs.rs mark is its [`docsdotrs` icon](https://github.com/simple-icons/simple-icons/blob/16.35.0/icons/docsdotrs.svg), inlined unchanged. The book beside javadoc.io links is original artwork for this site: the host publishes no vector logo, and the mark does not imitate its favicon. Some ports deep-link to the canonical host their ecosystem already uses, rather than duplicating it here: - Rust: [docs.rs](https://docs.rs/libtmux), for each published crate - Go: [pkg.go.dev](https://pkg.go.dev/github.com/libtmux/libtmux-go/tmux) - Java, Kotlin and Scala: [javadoc.io](https://javadoc.io/doc/io.github.libtmux/libtmux) - Swift: the [Swift Package Index](https://swiftpackageindex.com/libtmux/libtmux-swift/documentation/libtmux) copy of the DocC reference Those sites are operated independently of this project and carry their own terms. ## libtmux itself Each port is MIT licensed. See the `LICENSE` file in that port's repository for the authoritative text. --- # API glossary Source: https://libtmux.org/en/perl/latest/reference/glossary/ > Kinds, modifiers and package labels in the Perl API reference. ## Symbol kinds Kinds identify declarations in the Perl API reference. ### module A loadable Perl source unit, normally a .pm file loaded with use or require. Namespace names use ::; source paths use directories, such as LibTmux/Selection.pm. One distribution can provide many modules. References: [Perl modules and packages](https://perldoc.perl.org/5.44.0/perlmod). ### class A Perl package used as the class of a blessed reference. LibTmux uses ordinary packages and bless. Selection objects retain native array-reference behavior; their documented methods provide validation and filtering. References: [Perl objects and classes](https://perldoc.perl.org/5.44.0/perlobj). ### method A Perl subroutine invoked through a class name or object reference with ->. The invocant is the first positional argument. Read the signature and method documentation for the remaining arguments, return value and I/O behavior. References: [Perl method invocation](https://perldoc.perl.org/5.44.0/perlobj#Method-Invocation). ### exception A typed Perl value thrown with die and caught by an exception handler. LibTmux throws blessed error objects with diagnostic fields and readable stringification. Acquisition failures remain errors rather than empty results. References: [Perl exceptions](https://perldoc.perl.org/5.44.0/functions/die). ## Modifiers Modifiers add information about calling, implementing, or accessing a declaration. Their precise effect follows the language and the signature. ### async An operation returning a Future through the optional LibTmux-Async distribution. Drive completion with the caller-owned IO::Async loop. Cancelling a Future and completing resource cleanup are separate outcomes; successful close completion proves cleanup. References: [Future](https://metacpan.org/pod/Future); [IO::Async::Loop](https://metacpan.org/pod/IO::Async::Loop). ### inherited A method found through Perl package inheritance. The reference names its declaring package. The inherited method keeps that package’s documented return, ownership and I/O contract. References: [Perl inheritance](https://perldoc.perl.org/5.44.0/perlobj#Inheritance). ## Package context Package labels identify where an API is supplied. ### package The installable Perl distribution supplying this API. The package badge names a distribution such as LibTmux-Async. A Perl package declaration introduces a namespace; one distribution can contain several namespaces. References: [Preparing Perl distributions](https://perldoc.perl.org/5.44.0/perlnewmod). --- # Perl-based tmux workspace manager Source: https://libtmux.org/en/perl/latest/workspace/ > Validate, plan, and load versioned JSON workspaces with LibTmux-Workspace. **Workspace Manager concept example** A working example of the core library. It can change without notice. Build `libtmux-workspace` from the source revision in the installation guide. The `LibTmux-Workspace` package supplies this command. Follow the workspace guide for its configuration format. [LibTmux-Workspace](https://libtmux.org/en/perl/latest/workspace/reference/) is a separate native Perl distribution using public core APIs. Its `libtmux-workspace` command validates, plans, and loads the [libtmux.workspace/v1 JSON format](https://libtmux.org/en/perl/latest/workspace/source-guide/). Planning performs no tmux I/O. Loading creates sessions, windows, and panes, with explicit conflict and repeat policies. Install core first, then workspace from the same source checkout. These packages are not published to CPAN. The [workspace guide](https://libtmux.org/en/perl/latest/workspace/source-guide/) contains the configuration contract and installed CLI commands. The [API reference](https://libtmux.org/en/perl/latest/workspace/reference/) documents the public loader and report errors. --- # LibTmux::Workspace API reference Source: https://libtmux.org/en/perl/latest/workspace/reference/ > Public Perl workspace configuration, planning, loading, and error APIs. **Workspace Manager concept example** A working example of the core library. It can change without notice. Use [LibTmux::Workspace](https://libtmux.org/en/perl/latest/workspace/reference/libtmux-workspace/) to validate configuration, inspect a plan, and load sessions, windows, and panes through public core APIs. Planning performs no tmux I/O. Loading reports completed steps, conflicts, and partial failures. The declarations below preserve native signatures, POD links, and source locations. Read the [workspace guide](https://libtmux.org/en/perl/latest/workspace/source-guide/) for the versioned JSON format, source installation, and complete CLI examples. ## API declarations - [LibTmux::Workspace::X::Config](https://libtmux.org/en/perl/latest/workspace/reference/libtmux-workspace-x-config/) - [LibTmux::Workspace::X::Conflict](https://libtmux.org/en/perl/latest/workspace/reference/libtmux-workspace-x-conflict/) - [LibTmux::Workspace::X::Load](https://libtmux.org/en/perl/latest/workspace/reference/libtmux-workspace-x-load/) - [LibTmux::Workspace](https://libtmux.org/en/perl/latest/workspace/reference/libtmux-workspace/) - [LibTmux::Workspace::X](https://libtmux.org/en/perl/latest/workspace/reference/libtmux-workspace-x/) --- # API glossary Source: https://libtmux.org/en/perl/latest/workspace/reference/glossary/ > Kinds, modifiers and package labels in the Perl API reference. ## Symbol kinds Kinds identify declarations in the Perl API reference. ### module A loadable Perl source unit, normally a .pm file loaded with use or require. Namespace names use ::; source paths use directories, such as LibTmux/Selection.pm. One distribution can provide many modules. References: [Perl modules and packages](https://perldoc.perl.org/5.44.0/perlmod). ### class A Perl package used as the class of a blessed reference. LibTmux uses ordinary packages and bless. Selection objects retain native array-reference behavior; their documented methods provide validation and filtering. References: [Perl objects and classes](https://perldoc.perl.org/5.44.0/perlobj). ### method A Perl subroutine invoked through a class name or object reference with ->. The invocant is the first positional argument. Read the signature and method documentation for the remaining arguments, return value and I/O behavior. References: [Perl method invocation](https://perldoc.perl.org/5.44.0/perlobj#Method-Invocation). ### exception A typed Perl value thrown with die and caught by an exception handler. LibTmux throws blessed error objects with diagnostic fields and readable stringification. Acquisition failures remain errors rather than empty results. References: [Perl exceptions](https://perldoc.perl.org/5.44.0/functions/die). ## Modifiers Modifiers add information about calling, implementing, or accessing a declaration. Their precise effect follows the language and the signature. ### async An operation returning a Future through the optional LibTmux-Async distribution. Drive completion with the caller-owned IO::Async loop. Cancelling a Future and completing resource cleanup are separate outcomes; successful close completion proves cleanup. References: [Future](https://metacpan.org/pod/Future); [IO::Async::Loop](https://metacpan.org/pod/IO::Async::Loop). ### inherited A method found through Perl package inheritance. The reference names its declaring package. The inherited method keeps that package’s documented return, ownership and I/O contract. References: [Perl inheritance](https://perldoc.perl.org/5.44.0/perlobj#Inheritance). ## Package context Package labels identify where an API is supplied. ### package The installable Perl distribution supplying this API. The package badge names a distribution such as LibTmux-Async. A Perl package declaration introduces a namespace; one distribution can contain several namespaces. References: [Preparing Perl distributions](https://perldoc.perl.org/5.44.0/perlnewmod). --- # Topics Source: https://libtmux.org/en/perl/latest/topics/ > Topics for LibTmux. Understand object ownership, state, and operation behavior. - [Errors and recovery](https://libtmux.org/en/perl/latest/topics/errors/): Read about errors. - [Linux and tmux compatibility](https://libtmux.org/en/perl/latest/topics/compatibility/): Read about compatibility. - [Live query planning](https://libtmux.org/en/perl/latest/topics/query-planning/): Read about query-planning. --- # Errors and recovery Source: https://libtmux.org/en/perl/latest/topics/errors/ > Errors and recovery: LibTmux documentation. Errors are typed [`LibTmux::X`]() objects with readable stringification and applicable fields such as path, expected/received types, IDs, dispatch state, and process result. Catch objects with stable Perl try/catch and isa: ```perl try { my $only = $snapshot->panes->one({ active => true }); } catch ($error) { if ($error isa LibTmux::X::NoMatch) { say 'No active pane in this captured selection'; } else { die $error; } } ``` `one_or_undef` handles absence and still rejects ambiguity. Acquisition errors never become empty selections. [`Unloaded`]() differs from known null. Complete criteria validation runs before matching, including on empty input and in branches that later short-circuit. Process results distinguish stdout, stderr, exit status, signal, timeout, spawn failure, output limit, cancellation, and dispatch uncertainty. Lifecycle errors retain bounded partial results; unknown status remains undef. Cancellation does not imply rollback or nonexecution. The isolated Linux supervisor reaps its owned process group; intentionally detached daemons have separate ownership. The current verified ABI is x86_64 LP64. Owned supervisor and command branches close unrelated inherited descriptors, including native descriptors without close-on-exec. The caller's handles stay open. Only standard streams and the job's explicit protocol/cancellation pipes survive where needed; a newly started tmux daemon cannot retain an unrelated caller file or socket. This requires the Linux `/proc/self/fd` interface. Descriptor enumeration/closure failure prevents dispatch and remains a typed transport or spawn failure. Forking a host with native threads is unqualified. Transport `timeout` bounds one command's execution loop, excluding supervisor setup and async queue waiting. A snapshot runs several commands, each with its own timeout; this setting is not a total snapshot deadline. Cleanup has a separate allowance and continues after useful work expires. Async callers must drive the borrowed loop until successful close-observer completion. Cancelling the observer or stopping the loop does not prove that processes have exited. [`Creation`]() preserves a generation-scoped minimal created handle when the command succeeded but subsequent capture failed. Inspect `created` and [`cause`]() before deciding cleanup. Other fields on that handle are unloaded. Workspace uses this evidence for owned rollback and records cleanup failures separately. --- # Linux and tmux compatibility Source: https://libtmux.org/en/perl/latest/topics/compatibility/ > Linux and tmux compatibility: LibTmux documentation. The baseline is stable Perl 5.44.0 on Linux x86_64 LP64, including WSL. Supported tmux versions span 3.3a–3.8, including every intermediate release. Plain tmux 3.3 is below the 3.3a support floor. Other operating systems and Linux ABIs have not been qualified. The supervisor refuses unsupported ABIs before dispatch instead of assuming syscall numbers. CI and the local compatibility command use only the latest stable Perl and two tmux releases: the oldest supported release and the newest stable release. The current pins are [Perl 5.44.0](https://dev.perl.org/perl5/), tmux 3.3a, and [tmux 3.8](https://github.com/tmux/tmux/releases/tag/3.8), verified on 2026-11-08. Testing the range endpoints keeps CI small; intermediate tmux releases remain supported without separate CI cells. Older Perl releases have no matrix cells. Update the pins when the latest stable release changes. [The source lock](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/scripts/tmux-lock.json) pins official assets, archive hashes, source commits, and configure flags. Per-build provenance adds compiler and executable hashes. Exact per-cell results are recorded by the compatibility command; a missing or skipped cell remains unverified. Earlier wider matrix runs remain historical evidence for their recorded revisions; they do not add current completion gates. ```console $ mise exec -- make compatibility ``` The original 3.3a run exposed tmux's invalid-layout error-pointer defect. The public select_layout wrapper now rejects unknown/ambiguous names lacking a custom-layout checksum prefix before dispatch. The raw command escape hatch retains native behavior. See the contributor guide for archive consumers, examples, units, and the network-free check/provision split. A local test or build is not hosted CI, a CPAN publication, or a deployed site. No unrun final-revision gate is implied by these requirements. --- # Live query planning Source: https://libtmux.org/en/perl/latest/topics/query-planning/ > Live query planning: LibTmux documentation. `$snapshot->panes->where($criteria)` and callbacks evaluate eagerly without I/O. `query_panes` explicitly acquires a graph and returns a PaneSelection. `explain_panes` creates a local plan using support-floor capabilities; it does not connect. Execution binds capabilities to the captured daemon generation. | Policy | Behavior | | --- | --- | | `never` | Acquire and evaluate locally. | | `auto` | Verify safe scalar native candidates; fall back to captured local results on disagreement. | | `require` | Require complete exact lowering and native/captured agreement. | The current implementation captures and evaluates the complete graph before candidate verification, preserving local error behavior. It makes no I/O-saving claim. Plans identify commands, lowered filters, residual reasons, and capability requirements. Numeric lowering uses tmux numeric expressions. Literal operands are escaped for the tmux grammar independently of argument-vector safety. `auto` is the default. It costs an extra command and supervisor when lowering is available. Select `never` when only the captured answer is needed. To inspect the comparison, supply `on_verification => sub ($report) { ... }`. The observer receives one detached hashref in void context; its return is ignored. It runs inline once after a successful decision, including fallback. Exceptions propagate unchanged unless the operation has already been cancelled; cancellation suppresses subsequent result/error delivery. Failed acquisition, decoding or native commands do not invoke it and remain failures. The report identifies `status`, `comparison`, capture generation/interval, executed filter, residual reasons, and captured/local/native ID arrays. `disabled` means `never`, and `local` means no safe lowering was available. `agreed` distinguishes exact equality from partial candidate inclusion; `disagreed` lists missing, unexpected and uncaptured IDs. `native` reports only captured membership for the expert escape hatch. See [`Server`'s report contract](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/packages/core/lib/LibTmux/Server.pm) and the [tested query example](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/examples/selection.pl). `require` disagreement throws [`LibTmux::X::QueryMismatch`](), with the report under the `verification` key returned by [`LibTmux::X::details`](). The observer does not run before that failure. A mismatch can reflect a race, a compiler defect or a backend difference; it does not establish which occurred. Matching observations also do not prove an atomic capture. [ADR 0003](https://github.com/libtmux/libtmux-perl/blob/352715a4fa66a96eed7763b90daaa536aa2f121d/docs/dev/adr/0003-query-verification-diagnostics.md) records the diagnostic and default-policy decision. A partial AND conjunct can prune candidates. Partial OR/NOT cannot. Relations, null, bytes, and unsupported scalar operators remain local. Relation pushdown and serialized regex dialects are deferred. Complete relation domains are never pruned before `every` or `none` evaluation. `native_filter` is an explicit expert escape hatch, exclusive with portable criteria and pushdown policy. It selects captured root IDs and rejects new IDs that appeared outside capture. It has native tmux semantics, not wire semantics. --- # Workspace guide Source: https://libtmux.org/en/perl/latest/workspace/source-guide/ > Workspace guide: LibTmux documentation. **Workspace Manager concept example** A working example of the core library. It can change without notice. The separate distribution packages the `libtmux-workspace` CLI. Validate and plan without tmux I/O; load explicitly through public core APIs. ```json { "schema": "libtmux.workspace/v1", "sessions": [{ "name": "main", "windows": [{ "name": "api", "layout": "even-horizontal", "panes": [ {"command": ["/bin/sleep", "120"]}, {"command": ["/bin/sleep", "120"], "horizontal": true} ] }] }] } ``` ```console $ libtmux-workspace validate workspace.json ``` ```console $ libtmux-workspace plan workspace.json ``` ```console $ libtmux-workspace load workspace.json \ --socket-name example \ --existing skip ``` `--dry-run` selects a nonmutating plan. Default `existing=error` checks all session-name conflicts before creation. `skip` preserves the entire existing session; repeated loads create only absent sessions. This is not convergence or reconciliation of an existing layout. Each pane requires literal `command` argv or explicit `shell_command`. Environment inherits workspace → session → window → pane; cwd inherits from window unless overridden. Layout applies after splitting. Configuration is versioned JSON; no YAML adapter or MCP consumer is selected. On failure, inspect completed steps, failed step, created IDs, dispatch uncertainty, and cleanup errors. Rollback targets only sessions proven created by this invocation. Application readiness requires caller-specific assertions. CLI exit statuses: success 0; usage/configuration 2; loading 3; conflict 4. [`LibTmux::Workspace::X::Load->report`]() retains each cleanup exception with its captured target identity and attempted action. These entries replace the earlier string-only `cleanup_errors` values. [`cause`]() remains the original load failure; a cleanup failure never replaces it. Catch and inspect the exception class, dispatch evidence, and bounded native result when choosing recovery. [`report_data`]() returns a detached diagnostic export for JSON, including the primary cause and cleanup error classes. Native stdout/stderr use explicit base64 fields to preserve arbitrary octets. The CLI prints this export on standard error; the library report keeps the original exception objects.