# libtmux for Erlang > The Erlang library (libtmux_erlang). These pages include its guides, tested examples and API documentation. - [Erlang API reference](https://libtmux.org/en/erlang/latest/reference/): every public symbol, generated from the source. Hosted on libtmux.org. --- # Concepts Source: https://libtmux.org/en/erlang/latest/concepts/ > Concepts for libtmux_erlang. Understand captured queries, object identities, and operations. - [Architecture decisions](https://libtmux.org/en/erlang/latest/concepts/architecture/): Read about adr 0001: immutable values and owned tmux execution. - [Batched graph capture](https://libtmux.org/en/erlang/latest/concepts/capture-strategy/): Read about adr 0002: batch complete-graph field hydration. - [Object graph](https://libtmux.org/en/erlang/latest/concepts/object-graph/): Read about query a shared window without losing its memberships. - [Selections and queries](https://libtmux.org/en/erlang/latest/concepts/queries/): Read about capture locally; fetch explicitly. --- # Architecture decisions Source: https://libtmux.org/en/erlang/latest/concepts/architecture/ > Architecture decisions: libtmux_erlang documentation. ## Status Accepted architecture, 2026-11-08. Implementation and delivery remain partial. This record describes the design selected for the [recorded source baseline](https://github.com/libtmux/libtmux-erlang/tree/9a1ca749f7bf6f082c910c99f961bb586781ab0b). It does not qualify unfinished APIs or announce a release. [Support and gaps](https://libtmux.org/en/erlang/latest/guides/compatibility/) owns the current implementation and platform inventory. A later decision that changes these boundaries should identify which part of this record it supersedes. [ADR 0002](https://libtmux.org/en/erlang/latest/concepts/capture-strategy/) supersedes AD-4's field hydration strategy with escaped entity scans and an explicit isolated option. Upstream code references use release tags. This repository has no release tag at this baseline; implementation links pin the recorded source commit. The decisions below distinguish that implementation from required follow-up work. ## Context tmux owns mutable sessions, physical windows, membership links and panes in a separate server. Several sessions can link the same window, and one session can contain several links to it. tmux's [pane-list traversal](https://github.com/tmux/tmux/blob/3.3/cmd-list-panes.c#L70-L84) walks those links. Treating a window as a session-owned object would lose that structure and could count one physical pane several times. Observing the graph, acting on it and managing a client process have different lifetimes. A captured pane can disappear before an action. A timed-out waiter can leave a command running. A client can retire after tmux has already made an irreversible change. The API must preserve those distinctions while fitting ordinary Erlang programs. The core targets the single current stable OTP baseline and tmux 3.3a–3.8 on Linux, including intermediate releases. It does not carry older-OTP compatibility branches. The [project policy](https://libtmux.org/en/erlang/latest/topics/project-policy/) defines the runtime dependency and application boundaries. ## Decision drivers - Preserve tmux identity, linked-window membership and observed coverage. - Give callers predictable errors, ownership and cleanup evidence. - Bound native I/O, queued operations and retained results. - Make source-call cost and observation intervals inspectable. - Keep ordinary Erlang use concise and downstream installation reproducible. - Review public record compatibility independently from OTP upgrades. ## Architectural decisions ### AD-1: Use native Erlang values and explicit module functions Use exported OTP native records for session, window, window-link and pane rows. Keep selections, queries, filters and operation handles opaque. Criteria and options use maps; text and terminal bytes use binaries; ordinary lists remain the exchange format for collections. [Native records in OTP 29](https://github.com/erlang/otp/blob/OTP-29.1.2/system/doc/reference_manual/ref_man_native_records.md#L31) provide module-owned definitions and record export/import without distributing a header. Their experimental status is an explicit dependency: assess record construction, consumers and upgrades before accepting another OTP line. Do not serialize record internals as a public format. [Constructors](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_model.erl#L100) and action boundaries validate values; typespecs and nominal IDs assist tooling without enforcing runtime invariants. Exported record definitions are a versioned library contract. A value retains the definition used when it was constructed; adding a field does not add that field to retained values. Each release must state whether older rows and snapshots remain usable, require conversion, or must be discarded and freshly observed. Field renames, defaults and model-version changes need the same review. A documented consumer restart is an acceptable initial upgrade policy. Experimental status permits future incompatibilities; it does not establish that every future OTP release or code upgrade will break these values. Use [to_list/1](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_select.erl#L159) and [fold/3](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_select.erl#L165) at library boundaries. The opaque selection itself is not an Erlang list. Arbitrary transformations return ordinary values rather than preserving an entity selection after its rows have changed type. Keeping a selection retains its snapshot context. Store the extracted rows when relationship evaluation is finished. A future compact selection must declare its retained relationship closure and coverage; dropping related rows cannot turn an incomplete relation into an empty complete one. Measure that need before adding another extraction alias or pruning API. Companion APIs provide behavioral references, with their own language interfaces: Python's [QueryList](https://github.com/tmux-python/libtmux/blob/v0.62.0/src/libtmux/_internal/query_list.py#L327) extends a list, Elixir's [Selection](https://github.com/libtmux/libtmux-elixir/blob/v0.1.1/lib/libtmux/selection.ex#L1-L13) implements Enumerable, and the OCaml core [Map.S interface](https://github.com/ocaml/ocaml/blob/5.5.2/stdlib/map.mli#L65) describes an abstract container. Erlang uses module functions and pattern matching. None of those companion runtimes is a core dependency. ### AD-2: Separate physical identity, membership and observation [tmux_model](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_model.erl#L4) distinguishes Session, Window, WindowLink and Pane. A physical window has no universal session or session-relative index. A window link records the observed session, index and expected physical window; it is not a stable tmux link ID. Session window traversal deduplicates physical windows while preserving every membership in window-link traversal. [Snapshots](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_snapshot.erl#L3) retain immutable indexes, coverage, source calls, capture intervals and endpoint/server generation. Server-wide physical entities use numeric ID order. Link and pane traversal use their documented observed indexes. Filtering preserves that order instead of exposing map iteration. Coverage distinguishes a known value, known absence, not-loaded data and an unavailable capability. An unloaded relationship cannot become an empty list. [require/2](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_snapshot.erl#L187) checks the fields and relationships needed by an evaluation, including when its selection is empty. Constructed rows are detached. [bind/2](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_server.erl#L267) performs an explicit fresh observation before registering an action-capable row. Actions validate the registered origin, generation and expected membership. A vanished target does not permit fallback to a positional target. At the recorded baseline, the [origin registry](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_server.erl#L282) identifies an endpoint and generation, while [target resolution](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_target.erl#L9) takes the ID from the supplied row. Exported records permit construction and updates, including that ID and their provenance fields. The origin therefore does not authenticate an unchanged observation. The selected correction binds the captured target in a private, unexported native record carried by the public row. Actions compare its entity, origin, snapshot ID and target fields with the supplied row before dispatch. Edited identities require fresh [`tmux_server:bind/2`]() observation. The private value retains identifiers rather than a graph or a per-row registry entry. Edited-row regressions cover IDs, origins, snapshot IDs and link memberships. The [model upgrade policy](https://libtmux.org/en/erlang/latest/guides/compatibility/#retained-rows-and-upgrades) requires discarding version-1 values when adopting this model version 2 representation. These checks provide library provenance, not authorization against trusted code in the Erlang VM or callers of internal construction functions. ### AD-3: Keep selections, portable filters and source queries distinct | Value | Meaning | Execution boundary | | --- | --- | --- | | Selection | Ordered rows from one captured graph | Local reads and transformations | | Filter | Validated, versioned predicate data | Preparation against explicit snapshot coverage | | Query | A future source observation and its plan | Explicit fetch | [where/2](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_select.erl#L107) accepts declarative criteria or a portable filter. [filter/2](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_select.erl#L132) accepts a unary Boolean function; callback failures propagate. A trusted matcher behaviour prepares local executable code. A serialized filter cannot select a module or carry a closure. Criteria use one map grammar with field-specific operators, Boolean composition and explicit relationship quantifiers. A single existential child must satisfy all conditions inside that child. Separate existential clauses may match different children and must not be merged during normalization. Complete coverage is required for relationship counts, every and none. [Portable filters](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_filter.erl#L3) contain stable schema identifiers and normalized values. [Prepared evaluation](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_filter.erl#L169) may cache membership sets, compiled patterns and relation indexes, but remains bound to the captured context. Checked cardinality distinguishes absence from ambiguity and stops after a second match establishes the latter. Composition should depend on the normalized expression, not the sequence of query-builder calls. Compose validated filters internally and flatten adjacent Boolean conjunctions before applying normalized limits. Preserve bounds during external parsing and preserve separate existential nodes. The recorded implementation still nests conjunctions through wire conversion; chained and flat construction need an equivalent-semantics and resource-accounting test. [OTP JSON](https://github.com/erlang/otp/blob/OTP-29.1.2/lib/stdlib/src/json.erl#L880) owns parsing and encoding. The [wire boundary](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_json.erl#L5) adds document and nesting limits, duplicate-key and trailing-input rejection, exact-number bounds and explicit field mappings. Payload keys never create atoms. Shared regex support uses the tested restricted dialect; full local regex behavior belongs in trusted callbacks, without an interoperability claim. ### AD-4: Make observation and optimization explicit [snapshot/2](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_server.erl#L245) and [fetch/2](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_query.erl#L212) perform source I/O. Query construction, explanation and local selection reads do not refresh or hydrate data implicitly. Capture brackets hydration with identity/scalar scans and rejects detected disagreements. It remains an interval of observations. A change followed by a reversal can escape detection; immutable storage does not make capture atomic. Stable IDs and observed process identity do not make later actions atomic. The current `fetch/2` permits one opt-in inconsistent-capture retry within the original deadline; `snapshot/2` has no retry option. Changing that default or accepting disagreements in volatile fields changes the observation contract. Measure churn before making that decision. `max_rows` bounds each raw scan and the aggregate session/window/pane observations in each spine; repeated linked memberships count before physical deduplication. Native tmux filtering is a candidate optimization. For the same observed state, the full predicate must imply the candidate predicate. The complete residual still runs locally, required relationships remain complete, and limits apply after residual filtering and identity handling. Unknown translations broaden the candidate; negation requires an exact child translation. Numeric formats need their own conversion and range qualification. Erlang term ordering and tmux string comparison must not stand in for schema numeric semantics. [explain/1](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_query.erl#L172) exposes the plan and its temporal limits. Disabling pushdown avoids an earlier candidate exclusion, while retaining the capture interval. Later filtering cannot recover a row excluded earlier. #### Capture cost and optimization gate The [capture sequence](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_observe.erl#L29) hydrates the complete graph even when a candidate filter is present. With the recorded field schema, a successful nonempty capture performs `6 + S + 2W + 3P + C` logical data commands: two three-command spine scans, one text field per session, two per physical window, three text/byte fields per physical pane, and an optional candidate scan `C` of zero or one. Each successful command also performs an identity preflight. Three sessions, nine windows and 27 panes therefore require 108 logical commands and 216 tmux client launches without a candidate scan. Startup, retries and failures are outside this calculation; it is not a latency measurement. Complete-graph queries default to pushdown disabled. Enabling it can reduce local residual work, but does not reduce hydration and adds an earlier exclusion point. `explain/1` and the query guide report this choice. Equivalent workload measurements are required before changing the default. Measure the Erlang/helper path on small, linked, changing and 200-pane graphs. Record commands, client launches, elapsed distributions, bytes, retained memory, capture failures and cleanup. Require identical successful payloads, IDs, ordering and attribution before comparing one-shot and control timings. A literal newline inside a line-framed control command can change the request; a successful reply guard alone cannot validate a benchmark's work. Compare qualified persistent control, lossless batching and an in-server guard before changing the source strategy. tmux's [command queue](https://github.com/tmux/tmux/blob/3.3/cmd-queue.c#L719-L790) can wait for external work, so chaining commands does not establish general snapshot atomicity. [if-shell -F](https://github.com/tmux/tmux/blob/3.3/cmd-if-shell.c#L73-L103) provides a candidate synchronous guard, subject to identity precision, alias, hook, membership, parsing and concurrent-client qualification. Qualify text framing per field and tmux version; paths cannot inherit a title codec merely because one release sanitizes titles. Candidate-scoped hydration is a later strategy if measurements justify its coverage complexity. A subset of matching children must never be represented as the complete relationship. Candidate implication tests must execute the translated predicate through the CI endpoints, tmux 3.3a and 3.8. ### AD-5: Supervise resource owners and keep domain rows as values The endpoint, transport and owned-daemon lifecycle require supervised processes. Sessions, panes, snapshots and selections remain values; there is no process for every domain row. [start_owned/1](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_server.erl#L118) creates a private server namespace and returns a separate ownership token. Borrowed endpoint close retires library clients while preserving the borrowed daemon. Stopping an owned daemon requires its ownership token and cleanup proof. No operation gains permission to stop a default or borrowed server from a socket path alone. The initiating process owns an [operation](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_operation.erl#L3). Ownership transfer registers the new owner before acknowledging the old owner. Submission is non-blocking with respect to command completion. Waiting, command deadlines, cancellation, remote outcome and native cleanup are separate contracts. [OTP response abandonment](https://github.com/erlang/otp/blob/OTP-29.1.2/lib/stdlib/src/gen_server.erl#L1524) does not undo remote effects. Cancellation after dispatch can leave the tmux outcome unknown; an uncertain mutation must not be retried automatically. A transfer timeout can also leave an uncertain ownership outcome: abandoning the response does not retract the queued owner change. Callers reconcile the current owner through [tmux_operation:status/1](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_operation.erl#L104) before relying on ownership. A delayed-endpoint regression must cover the late transfer and owner-death ordering. Keep an executable transition model for cancellation before dispatch, partial writes, terminal responses and late retirement. Duplicate or stale events must release admission once; stronger cleanup evidence cannot invent a known remote outcome. Adopt a different OTP behaviour or supervisor layout only when it improves these invariants or a measured bottleneck. ### AD-6: Use a separate bounded Linux helper for native I/O The OTP transport launches the [bundled C11 helper](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_transport.erl#L324) with spawn_executable. It sends the child's executable and argument vector through the helper's framed protocol. The helper runs outside the VM and uses Linux process and pipe interfaces. It is built from packaged source; there is no runtime executable download. The [private protocol](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/apps/libtmux_erlang/c_src/README.md) separates stdout and stderr, grants output read credits, bounds frames and queues, acknowledges input writes, and distinguishes terminal delivery from observed helper exit. The helper owns its child tree and retains incomplete cleanup as an explicit failure. A successful tmux reply, pipe write or helper exit alone cannot prove every later aftereffect. [Descendant retirement](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/c_src/owned_io.c#L291) reads `/proc/self/task//children`; the Linux kernel must expose that interface through [CONFIG_PROC_CHILDREN](https://man7.org/linux/man-pages/man5/proc_tid_children.5.html). A mounted procfs alone is insufficient. The recorded helper first attempts the interface during cleanup and ignores open failure; remaining descendants can then produce `cleanup_incomplete`. Required follow-up is admission before child launch, with a specific capability error and underlying OS error, plus a negative test that proves no child started. Missing support must not silently select a weaker cleanup contract. The helper is reused from the [tagged Elixir source](https://github.com/libtmux/libtmux-elixir/blob/v0.1.1/c_src/owned_io.c#L380), with [provenance and license records](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/apps/libtmux_erlang/c_src/provenance.json). Its source identity does not transfer Elixir runtime qualification to Erlang. Separate processes also do not provide a sandbox: inherited authority, hostile forks, helper SIGKILL and concurrently replaced filesystem entries retain documented limits. Carry helper fixes with their source/protocol provenance and qualify each port independently. Focused frame fuzzing, sanitizer checks and installed source consumers complement lifecycle tests; matching the upstream digest is not a substitute for them. Executable argv, tmux command syntax, formats and explicit shell-command arguments are separate interpreter boundaries. Avoiding an implicit host shell does not suppress tmux aliases, hooks or terminal-program behavior. ### AD-7: Qualify persistent control separately from one-shot execution [attach/3](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang/src/tmux_control.erl#L55) currently establishes explicit control-client lifetime and identity on that persistent connection. Attachment changes attached_count. The selected no-output/ignore-size and environment-update policies remain visible. Existing hooks and destruction policies can still produce effects; closing a client is not a rollback. The [control guide](https://libtmux.org/en/erlang/latest/topics/control/) limits current qualification to attachment. Command submission and groups need separate framing, ordering, eligibility, certainty and cleanup evidence. tmux's [reply guards](https://github.com/tmux/tmux/blob/3.8/control.c#L523-L543) coexist with asynchronous notifications. Its [alias-expansion path](https://github.com/tmux/tmux/blob/3.3/cmd-parse.y#L744-L779) means a canonical command name alone cannot establish what configured tmux will do. The ambient-alias contract also applies to the existing attachment command and its identity probe. Qualify those paths against configured aliases while preserving borrowed-server configuration. Record the library's attached client where possible; retain the raw attached count and hook effects. Any adjusted view needs a separately named contract rather than silently subtracting the observer. Public output subscriptions and sampled observation streams are also unfinished. The helper's internal credit protocol does not establish a public streaming API. Any such API must define credits, gaps, acknowledgement and retirement, and describe sampled observations without promising unobserved terminal history. ### AD-8: Keep workspace execution downstream and MCP excluded Use a Rebar3 umbrella to develop independent OTP applications together. libtmux_erlang owns the core; libtmux_erlang_workspace consumes its public API. The core has no dependency on the workspace application. Each package owns metadata, license and changelog material, and needs an installed-consumer check outside the umbrella before independent delivery. The [workspace loader](https://github.com/libtmux/libtmux-erlang/blob/9a1ca749f7bf6f082c910c99f961bb586781ab0b/apps/libtmux_erlang_workspace/src/tmux_workspace.erl#L71) validates versioned JSON into inert desired state. The later [planner](https://github.com/libtmux/libtmux-erlang/blob/2e681477ed015e61f03c393ded111c2d5e6dd665/apps/libtmux_erlang_workspace/src/tmux_workspace_plan.erl#L34) stores canonical operations and observed preconditions; the [apply engine](https://github.com/libtmux/libtmux-erlang/blob/2e681477ed015e61f03c393ded111c2d5e6dd665/apps/libtmux_erlang_workspace/src/tmux_workspace_apply.erl#L40) checks their derivation against the stored observation and hash-checked input. Fresh tmux state can reject a plan without supplying replacement operations. Ownership tags bind resource keys, parent manifests, server incarnation and launch hashes. Explicit adoption establishes ownership; changed launch intent requires respawning. Ordered windows/panes use stable IDs for explicit swaps. Pane creation uses the saved, unzoomed tiled layout to schedule fixed targets and discard exhausted split cells. New windows use a breadth-first schedule until their geometry is observable. Axis selection remains an explicit stored policy, evaluated at each checked step. Custom tmux options and available area can reject this geometric schedule; it is not a complete packing algorithm. Apply recaptures the complete projected graph around each step, retaining a verified prefix on failure. Source work therefore grows with both graph size and step count. This initial strategy favors explicit drift evidence; measured large-workspace performance remains a qualification gate. No atomic reservation or automatic rollback is claimed. The standalone Rebar3 escript materializes its bundled helper, license and provenance in a private runtime directory; BEAM code stays in the archive. SIGTERM follows explicit cancellation, while Ctrl-C receipt semantics remain unqualified. See the [workspace guide](https://libtmux.org/en/erlang/latest/guides/workspace-json/) for current contracts and executable examples. Ownership metadata reads use bounded batches of three workers. A private coordinator monitors the caller and joins its workers; the caller gates each new batch after checking cancellation. Results retain row order and the worst cleanup evidence across the drained batch. Worker exit alone cannot prove native retirement. [ADR 0003](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/docs/adr-0003-scoped-option-batches.md) further groups up to seven local scalar reads per native sequence. Every graph and ownership read remains; complete apply cost still grows with graph size and step count. Endpoint names need host policy; loading shell text does not authorize its execution. Shell execution needs both host policy and a recorded plan opt-in. File loading and path resolution are synchronous trusted-filesystem operations without an I/O deadline or atomic filesystem-snapshot guarantee. Erlang runtime dependencies stay within OTP, alongside the recorded external helper exception. Build, test and documentation dependencies have separate roles. An additional runtime dependency needs a concrete capability requirement and a new recorded decision. MCP packages, servers and SDK integration are excluded by [project policy](https://libtmux.org/en/erlang/latest/topics/project-policy/); they are not pending packages. ### AD-9: Keep contracts and verification native to Erlang Keep specs, exported type/callback documentation and module/function docs beside their definitions. Native record exports and compiler documentation support API browsers. [ct_doctest](https://github.com/erlang/otp/blob/OTP-29.1.2/lib/common_test/src/ct_doctest.erl#L24) executes Erlang-shell examples; reader programs exercise real tmux through owned fixtures and installed core packages. Generated field/operator documentation shares the validation schema. Keep failure examples useful when both an operation and cleanup fail: retain both outcomes instead of masking the original exception in an `after` clause. Validate more precise query/constructor/error specs through an external Dialyzer consumer with deliberate entity mixups. Generated recursive filters and linked graphs should agree with a small reference evaluator. Use bounded [OTP Logger reports](https://libtmux.org/en/erlang/latest/topics/diagnostics/) for transport failures, cleanup, IPC duration, capture rejection and held read credit. The implemented one-shot and attachment lanes emit these reports; later lanes must preserve their data and cost boundaries. Give structured programming errors useful native error formatting. Keep payloads and environment secrets out of ordinary diagnostics, and keep optional telemetry outside core dependencies. EUnit, Common Test, properties, Dialyzer, documentation and installed-consumer checks cover different contracts. Preserve failed or skipped evidence instead of treating it as a passing subset. Exact source/tool/platform identities and individual matrix conclusions determine qualification. Continuous CI uses the latest stable Erlang/OTP release and the oldest supported and newest stable tmux releases on both Linux architectures. Support includes the releases between those endpoints; earlier results retain their recorded scope. Test-loop durations do not establish throughput or a control-versus-streaming performance claim. Source installation is a separate gate from consuming a compiled `ebin`/`priv` archive. Build the exact source package outside the umbrella without a prebuilt helper or checkout-relative resources, on each supported architecture. This gate remains open at the recorded baseline. ## Alternatives considered | Alternative | Decision and consequence | | --- | --- | | Map-only domain rows | Native records provide named shapes and downstream patterns; maps remain appropriate for criteria and options. Runtime validation is still required. | | A general collection or ORM framework | Keep the entity-aware operations small and exchange ordinary lists. Arbitrary transformations leave the selection type. | | Mutable shared storage as the snapshot contract | Use immutable captured indexes. An internal cache or optional adapter must preserve observation identity and coverage. | | Direct ports without the helper | A replacement must prove separate bounded output, input accounting and owned-tree retirement. The selected helper exposes those contracts explicitly. | | A native extension inside the VM | Keep the transport helper outside the VM, accepting Linux build and IPC costs. | | Transparent lazy relationship reads | Reject incomplete local coverage. Arrange hydration only during explicit source execution. | | One application for core and consumers | Separate OTP applications preserve dependency direction and expose installed-package integration failures. | | QLC, graph or ETS as the public predicate language | Defer adapters; portable filters remain data and local callers retain native Erlang tools. | ## Consequences The public API follows Erlang conventions and supports local reuse without transport calls. Captured context makes relationship filtering predictable, but retaining a selection can retain its complete snapshot graph. Callers that only need rows should exchange lists. Native records require deliberate upgrade qualification. Linux helper builds require a C11 compiler, make, libc and the documented Linux interfaces. Platform support follows the tested matrix rather than the availability of an Erlang VM. Resource ownership and bounded protocols make failure evidence explicit. They do not make multi-command tmux actions transactional, turn socket access into confinement, or bound arbitrary application callbacks. Observed identity checks and filesystem cleanup retain concurrency races stated in their contracts. At the recorded baseline, the core graph/query/one-shot path and control attachment exist; workspace JSON loading exists; control submission, groups, public streams, workspace plan/apply/CLI and complete delivery remain open. Subsequent workspace planning/apply and CLI work follows AD-8; the baseline statement above remains the historical review scope. Control submission, groups, public streams, full adoption and complete delivery remain open. Registry and shared-site publication require their own verified delivery steps. Consult [support and gaps](https://libtmux.org/en/erlang/latest/guides/compatibility/) before selecting an execution lane. ## When to reconsider Revisit the native-record choice when another OTP line changes representation, construction or upgrade behavior. Revisit the helper boundary when another platform or transport can prove the same bounded-I/O and retirement contracts. Revisit observation guarantees if tmux supplies a server-side atomic capture or compare-and-act primitive. Qualify control and streams before changing the default execution lane; compare equal workloads, errors and cleanup outcomes. Revisit caching or advanced query adapters when measured workloads justify their additional state and lifecycle costs. Record a separate consumer decision if MCP is brought back into scope or if a new runtime dependency is proposed. Do not infer either change from artwork, an empty package directory or an implementation plan. ## References The linked upstream code is pinned to OTP 29.1.2, tmux 3.3/3.8, Python libtmux v0.62.0, Elixir libtmux v0.1.1 and OCaml 5.5.2. Companion references explain interfaces or source provenance, without adding runtime dependencies. --- # Batched graph capture Source: https://libtmux.org/en/erlang/latest/concepts/capture-strategy/ > Batched graph capture: libtmux_erlang documentation. ## Status Accepted architecture. Implementation qualification remains separate from release and full-product adoption. This supersedes the capture execution strategy in [ADR 0001, AD-4](https://libtmux.org/en/erlang/latest/concepts/architecture/#ad-4-make-observation-and-optimization-explicit). The graph model, interval semantics, identity checks, coverage, limits and explicit execution boundary remain the governing contracts. ## Context The original one-shot capture reads each text or byte field separately. A successful nonempty capture needs `6 + S + 2W + 3P + C` logical commands for sessions, physical windows, physical panes and an optional candidate scan. Each successful command also starts an identity-preflight client. Complete hydration dominates the cost even when a query returns one pane. A delimiter alone cannot frame paths containing tabs or newlines. A separate length expression is also insufficient: tmux's [format lookup](https://github.com/tmux/tmux/blob/3.3a/format.c#L3432) invokes built-in callbacks on each lookup, and [pane_current_path](https://github.com/tmux/tmux/blob/3.3a/format.c#L844) reads an external process. Length and value could therefore describe different observations. The field must be observed once before framing. ## Decision Hydrate each nonempty entity collection with one bounded list command. The schema explicitly admits each current text/byte field to `escaped_columns_v1`. A field without that admission retains isolated reads. Each field expansion applies three literal [substitutions](https://github.com/tmux/tmux/blob/3.3a/format.c#L4513) to one value: escape backslashes, then replace tabs and newlines with their textual escapes. Only then add column tabs and row newlines. No payload is expanded again as a format, command or shell program. List commands use ordinary format expansion, preserving literal percent sequences. The decoder requires the final newline, exact column counts, valid escapes and bounded raw row counts. It reverses the selected tmux print layer before field validation, including the older VIS and dollar encodings. Native qualification covers every non-NUL byte, empty values and protocol-looking text; NUL is outside tmux's string representation. Text fields retain schema UTF-8 validation, while paths remain bytes. Validate every hydrated identity against the initial spine. Repeated physical rows from linked memberships must agree before deduplication. Missing or new identities reject the capture; conflicting repeated values reject it too. The final identity/scalar spine must still agree with the first. Multiple commands and external process reads retain interval semantics, including the possibility of undetected change and reversal. Default snapshot and query hydration is `batched`. The existing options maps also accept `hydration => isolated` for one field per physical row. [Query plans](https://libtmux.org/en/erlang/latest/concepts/queries/#source-plans) describe both command templates; [snapshot metadata](https://libtmux.org/en/erlang/latest/guides/api-documentation/) records the requested strategy and actual calls. There is no automatic fallback after an overflowing batch. The current successful nonempty batched capture needs `9 + C` logical commands and `18 + 2C` tmux clients: six spine scans, three hydration scans, and the optional candidate scan. Empty collections skip their hydration command. Unqualified schema fields can increase this cost through isolated fallback. Native candidate filtering remains opt-in and still hydrates the complete graph. Limits apply after full residual evaluation and identity handling. ## Resource tradeoffs The command stdout bound remains 1 MiB, and the capture total remains 8 MiB by default. A batch combines entity output under that command bound. Callers with larger entity output can explicitly choose isolated hydration, distributing it across commands under the same total and deadline. Output overflow remains an explicit error with cleanup evidence; the library neither enlarges bounds nor silently retries the observation. See the native capture options in the [API guide](https://libtmux.org/en/erlang/latest/guides/api-documentation/). The native limit regression uses 37 panes with 30,000-byte titles. Batched capture returns `output_limit` with its bounded prefix and completed cleanup; an explicitly requested isolated capture returns every full title. Linked windows can increase raw batch output because the list traversal repeats memberships. Row bounds count those observations before physical deduplication. Fewer commands do not imply fewer transferred bytes. The decoder rebuilds field binaries rather than retaining slices of the batch frame. A snapshot-backed selection still retains the complete captured graph. After relationship evaluation, callers can keep extracted rows and release their other snapshot and selection references. Extraction preserves field values, including any backing allocations shared by caller-created rows; see the selection contracts in the [API guide](https://libtmux.org/en/erlang/latest/guides/api-documentation/). ## Qualification and measurements The linked-graph regression first returned 21 logical commands, then returned nine with equal row maps under both strategies. The real-path regression retains tabs, newlines, carriage returns, format syntax, backslashes and a non-UTF-8 byte. Native framing tests run at the CI endpoints, tmux 3.3a and 3.8; focused local probes also checked the distinct older print encodings. Support remains continuous through the intermediate releases. A controlled Linux x86_64 experiment used OTP 29.1.2, tmux 3.8, the real Erlang/helper path and cooperating pane programs with per-process readiness. Both strategies observed the same owned graph, and all successful full row maps had equal hashes. Three repetitions alternated strategy order after one default-deadline attempt per strategy. The figures below are capture medians; they exclude fixture setup and are observations on that host, not latency promises. | Graph | Batched commands | Isolated commands | Batched median | Isolated median | | --- | ---: | ---: | ---: | ---: | | 1 session, 1 window, 1 pane | 9 | 12 | 0.065 s | 0.084 s | | 1 session, 5 windows, 20 panes | 9 | 77 | 0.066 s | 0.556 s | | 2 sessions, 9 linked windows, 27 panes | 9 | 107 | 0.072 s | 0.858 s | | 2 sessions, 20 linked windows, 200 panes | 9 | 648 | 0.125 s | 6.772 s | The isolated 200-pane default attempt reached its deadline. Its median uses three successful repetitions with an explicit 60-second deadline; the other cells each have four successful observations. All owned helpers, servers and pane roots retired, and their namespaces were removed. The complete sweep, including fresh source builds and fixture setup, took about 40 seconds. These measurements qualify this one-shot strategy choice. They establish no control-mode speedup, churn rate or general workload distribution. ## Alternatives and reconsideration Persistent control submission remains a separate qualification task with alias, framing, attribution and lifecycle obligations. A single command batch does not establish a general atomic snapshot. In-server guards also retain their identity and configuration qualification requirements. Candidate-scoped hydration would reduce complete coverage and needs a distinct contract before adoption. Reconsider this strategy if measured transferred bytes, regex-substitution cost, large-field overflow or repeated memberships outweigh the saved round trips. A future strategy must preserve the current byte, coverage, identity and cleanup contracts or name its weaker guarantees. --- # Object graph Source: https://libtmux.org/en/erlang/latest/concepts/object-graph/ > Object graph: libtmux_erlang documentation. This program creates two sessions, a shared two-pane window, and two extra window links. It then checks the physical object graph and session-relative membership counts. [`tmux_window_link`]() acts on a session/index membership and checks its expected physical window before dispatch. Selecting a window membership changes that session's current window. [`tmux_session:select/2`]() switches one explicitly named attached client to a session. It never attaches a client or chooses a current client implicitly. Its [`tmux_session:select/3`]() variant updates the destination environment only when requested. Client names can be reused after disconnection; this call does not provide an atomic client-incarnation check. The native API contract documents name lookup and environment-removal semantics. Run it on a private server after compiling: ```console $ mise exec -- escript tools/run_examples.escript graph ``` ```erlang -module(linked_graph). -moduledoc "Distinguish physical windows from their session memberships.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> Endpoint = #{socket_path => Socket, executable => Executable}, {ok, Server} = tmux_server:open(Endpoint), tmux_scope:run_or_error(fun() -> {ok, Work} = tmux_session:create(Server, #{name => <<"work">>, launch => #{argv => [<<"/bin/cat">>]}}), tmux_scope:run_or_error(fun() -> {ok, Mirror} = tmux_session:create(Server, #{name => <<"mirror">>, launch => #{argv => [<<"/bin/cat">>]}}), tmux_scope:run_or_error(fun() -> {ok, Shared} = tmux_window:create(Work, #{name => <<"shared">>, launch => #{argv => [<<"/bin/cat">>]}}), Launch = #{launch => #{argv => [<<"/bin/cat">>]}}, {ok, _} = tmux_pane:split(Shared, Launch), WorkId = tmux_model:get(id, Work), WindowId = tmux_model:get(id, Shared), {ok, Before} = tmux_server:snapshot(Server), {ok, Source} = tmux_select:one(#{window_id => WindowId}, tmux_select:window_links(Before)), {ok, _} = tmux_window_link:link(Source, Work, #{index => 7}), {ok, _} = tmux_window_link:link( Source, Mirror, #{index => 9}), {ok, Snapshot} = tmux_server:snapshot(Server), 3 = length(tmux_snapshot:windows(Snapshot)), 4 = length(tmux_snapshot:panes(Snapshot)), 5 = length(tmux_snapshot:window_links(Snapshot)), {ok, CapturedWork} = tmux_snapshot:get( session, WorkId, Snapshot), {ok, Physical} = tmux_snapshot:related( windows, CapturedWork, Snapshot), {ok, Memberships} = tmux_snapshot:related( window_links, CapturedWork, Snapshot), 2 = length(Physical), 3 = length(Memberships), Criteria = #{window_links => #{count => 3}, panes => #{every => #{current_command => <<"cat">>}, count => 2}}, {ok, Only} = tmux_select:one( Criteria, tmux_select:windows(Snapshot)), WindowId = tmux_model:get(id, Only), #{physical_windows => 3, physical_panes => 4, window_links => 5, work_windows => 2, work_memberships => 3, shared_window_panes => 2} end, fun() -> {ok, _} = tmux_session:kill(Mirror), ok end) end, fun() -> {ok, _} = tmux_session:kill(Work), ok end) end, fun() -> ok = tmux_server:close(Server) end). ``` There are three physical windows and four physical panes. Five window links remain because the shared window occurs at two indexes in `work` and once in `mirror`. The windows relationship yields two unique windows for `work`; its window_links relationship retains all three memberships. Both traversals use [`tmux_snapshot:related/3`](). A link is identified within a capture by session, index and expected physical window. It has no stable tmux link ID. Captured index references cannot promise atomic compare-and-act after another client moves a link. Use [`tmux_window_link:get/3`]() for a fresh membership. `link/3` adds a membership; `move/3` moves just the checked membership; `swap/3` exchanges two memberships' physical windows. Their input rows must share one registered owner. Actions return command results and leave captured values unchanged. `select/1` selects the checked window in its session. `unlink/2` removes one membership, retaining tmux's last-link protection by default. Explicit `force => true` can destroy the physical window if its final membership goes. [`tmux_window:kill/1`]() destroys that window across all links. If a captured index disappears or names another physical window, actions return `stale_link` before dispatch. [`tmux_server:bind/2`]() applies this same precondition when rebinding a link to an owner. It does not adopt the new occupant of an old index. The one-shot preflight and action are separate; another client can still change that membership between them. The relation query checks the full captured graph. Filtering a window selection does not replace its panes with only matching panes. `some`, `every`, `none` and `count` require complete membership coverage, including empty selections. The [query guide](https://libtmux.org/en/erlang/latest/concepts/queries/) explains validation and correlation. ## Compare captured server incarnations Live [`tmux_snapshot:metadata/1`]() includes an opaque server_instance value. [`tmux_identity:fingerprint/1`]() derives a versioned binary comparison key from that captured identity without I/O. The key survives reconnecting through another endpoint handle and changes when the observed process incarnation changes. The installed consumer checks its JSON round trip. An endpoint's generation identifies that handle's lifetime; it changes when the handle is reopened. A persisted incarnation key serves a different purpose: comparing the server observed by those handles. It cannot make a stale row actionable, establish current liveness or authorize an action. Use [`tmux_server:bind/2`]() to obtain a fresh actionable row. --- # Selections and queries Source: https://libtmux.org/en/erlang/latest/concepts/queries/ > Selections and queries: libtmux_erlang documentation. A snapshot is observed data. A selection is ordered rows plus their captured context. A filter is portable predicate data. A query describes a future tmux observation. Only `fetch` executes a query. The [README program](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/examples/readme_demo.erl) shows both paths against real tmux. It retains a captured name after renaming the live window, then executes a fresh source query. All ordinary snapshot and selection reads stay local, even after the endpoint closes. ## Criteria Local criteria use atom-keyed maps and binary text. Bare scalars mean equality; fields and operators in one map conjoin. Boolean branches use quoted `'and'`, `'or'` and `'not'`. Empty AND is true and empty OR is false. Callbacks belong to [`tmux_select:filter/2`]() and must return Booleans; callback failures propagate. Relations use `some/every/none/count` for to-many values and `is/is_not` for to-one values. One `some` containing two conditions requires the same related row. Two separate `some` conditions can match different rows. Empty to-many relations make `some` false and `every` and `none` true. [Fields and operators](https://libtmux.org/en/erlang/latest/reference/fields/) come from the runtime validator. Unknown fields, invalid operations, type mismatches and incomplete coverage fail before row traversal. An unloaded relationship never becomes an empty relationship. `from_list` keeps supplied order and duplicates but cannot infer relationships. ## Cardinality | Call | Result | | --- | --- | | `first` | `{ok, Row}` or `none`; more matches are allowed | | `one` | `{ok, Row}`, `{error, no_match}`, or a multiple-match error | | `one_or_none` | `{ok, Row}`, `{ok, none}`, or a multiple-match error | | `one_or_error` | Row directly; raises on zero or multiple matches | | `size` | Cached materialized size | | `count` | Current size, or exact count after supplied criteria | Criteria come first and the selection last. Ambiguity stops after the second match once validation is complete. `to_list/1` and `fold/3` keep ordinary Erlang list consumers available; a selection is not a list protocol. ## Portable input [`tmux_filter:decode_json/1`]() rejects duplicate keys, trailing input and excessive size/depth. `from_wire/2` maps generated wire names explicitly; it never creates atoms from payload keys. `to_wire/1` exports filter data, not closures or native record internals. Integral numbers normalize only within the exact shared JSON integer range. Text is case-sensitive and is not implicitly normalized. Run this complete local recipe. It uses captured rows and needs no tmux server: ```console $ mise exec -- escript tools/run_examples.escript filter ``` ```erlang -module(filter_demo). -moduledoc "Validate portable JSON and filter captured rows without tmux I/O.". -export([run/0]). -spec run() -> map(). run() -> {ok, Editor} = tmux_model:pane(#{id => <<"%1">>, active => true, width => 120, current_command => <<"nvim">>}), {ok, Shell} = tmux_model:pane(#{id => <<"%2">>, active => false, width => 80, current_command => <<"bash">>}), Panes = tmux_select:from_list(pane, [Editor, Shell]), Criteria = #{active => true, 'or' => [ #{current_command => #{in => [<<"nvim">>, <<"vim">>]}}, #{width => #{gte => 160}} ]}, {ok, Filter} = tmux_filter:new(pane, Criteria), Encoded = iolist_to_binary(json:encode(tmux_filter:to_wire(Filter))), {ok, Document} = tmux_filter:decode_json(Encoded), {ok, RoundTrip} = tmux_filter:from_wire(pane, Document), {ok, Editor} = tmux_select:one(RoundTrip, Panes), [Editor] = tmux_select:to_list(tmux_select:where(Filter, Panes)), {error, #{code := duplicate_key}} = tmux_filter:decode_json( <<"{\"version\":1,\"version\":2}">>), Invalid = #{active => #{contains => <<"yes">>}}, try tmux_select:where(Invalid, Panes) of _ -> error(expected_validation_error) catch error:{bad_filter, #{code := unsupported_operator} = Detail}:Stack -> [active, contains] = maps:get(path, Detail), Reason = {bad_filter, Detail}, Message = erl_error:format_exception(error, Reason, Stack), Text = unicode:characters_to_binary(Message), {_, _} = binary:match(Text, <<"Allowed:">>) end, #{matched_ids => [tmux_model:get(id, Editor)], wire_round_trip => true, duplicate_keys_rejected => true}. ``` It selects `%1`, preserves the meaning of the JSON round trip, and rejects ambiguous duplicate keys. The installed-archive check runs the same program. The [restricted ASCII regex guide](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/tools/regex-conformance/README.md) gives its grammar and resource limits. Non-ASCII subjects and exhausted match limits are errors, not nonmatches. Local callbacks provide other regex semantics. ## Source plans Queries filter the complete captured graph locally by default. Enable native candidate exclusion explicitly with `tmux_query:pushdown(true, Query)`. It can add a candidate scan and an earlier observation without reducing graph hydration. [`tmux_query:explain/1`]() reports the choice in its `pushdown` field. [`tmux_query:explain/1`]() performs no I/O. It reports command templates, native candidate conditions, full residual data, complete hydration, required fields, ordering, identity policy and temporal assumptions. ID, Boolean and qualified unsigned numeric conditions can reach tmux's `-f`. Text, nullable fields and relations remain local. Numeric comparisons use tmux arithmetic formats, not string ordering. Hydration defaults to one framed list scan per nonempty entity collection. Each field is expanded once and escaped before row/column framing, preserving paths containing tabs, newlines and non-UTF-8 bytes. A successful nonempty capture uses nine logical commands, plus an optional candidate scan. Identity preflights add one tmux client per command. Linked memberships can increase the bytes returned even though physical rows remain unique. Each command remains bounded to 1 MiB of stdout. If a whole entity exceeds that bound, use `hydration => isolated` in snapshot or fetch options to read one field per physical row. The total capture bound and deadline still apply. The hydration entry of the commands metadata describes the default templates; its isolated_hydration entry describes isolated reads and unqualified-schema fallback. Snapshot metadata records the chosen strategy and actual calls. [ADR 0002](https://libtmux.org/en/erlang/latest/concepts/capture-strategy/) records the framing, measurements and tradeoffs. A candidate is a necessary condition: it can admit extra rows but must not exclude a same-state full-filter match. Unsupported leaves become true; AND and OR compose conservatively; NOT translates only exact children. Membership trees are balanced to respect tmux's recursion limit. Fetch retains a complete captured graph, validates any candidate scalar agreement, evaluates the full local filter, and only then applies limits. Physical entities deduplicate by ID; window links retain membership identity. `pushdown(false, Q)` disables earlier candidate exclusion. Capture options bound rows, output and time; `retry => 1` requests at most one inconsistent-capture retry within the original capture deadline. The default is no retry. Captures span several commands and are not atomic. Local re-evaluation cannot recover rows excluded before their state changed. Atomic consistency and a same-connection identity promise remain unsupported by this one-shot path. --- # tmux client library for Erlang Source: https://libtmux.org/en/erlang/latest/core/ > tmux client library for Erlang. Control tmux, connect to and create servers, navigate sessions, windows, and panes, send keys, capture pane contents Control tmux, connect to and create servers, navigate sessions, windows, and panes, send keys, capture pane contents. ## At a glance | Type | Wraps | | ---- | ----- | | [`tmux_server:t/0`](https://libtmux.org/en/erlang/latest/reference/t-tmux_server-t-0/) | A tmux server | | [`#tmux_model:session{}`](https://libtmux.org/en/erlang/latest/reference/tmux_model-session/) | A session, ID `$n` | | [`#tmux_model:window{}`](https://libtmux.org/en/erlang/latest/reference/tmux_model-window/) | A physical tmux window; session membership uses window links, ID `@n` | | [`#tmux_model:pane{}`](https://libtmux.org/en/erlang/latest/reference/tmux_model-pane/) | A pane in a window, ID `%n` | ## Typed API - Typed objects instead of parsed format strings: [`#tmux_model:pane{}`](https://libtmux.org/en/erlang/latest/reference/tmux_model-pane/) - Addressing by tmux ID: [`tmux_model:pane_id/0`](https://libtmux.org/en/erlang/latest/reference/t-tmux_model-pane_id-0/) - Filtering and queries over tmux objects: [`tmux_filter`](https://libtmux.org/en/erlang/latest/reference/tmux_filter/) - Typed errors instead of exit codes and stderr: [`tmux_operation:failure/0`](https://libtmux.org/en/erlang/latest/reference/t-tmux_operation-failure-0/) ## What you get over the tmux CLI - Connect to or start a tmux server: [`tmux_server:open/1`](https://libtmux.org/en/erlang/latest/reference/tmux_server-open-1/) - Traversal from a server down to its panes: [`tmux_snapshot:panes/1`](https://libtmux.org/en/erlang/latest/reference/tmux_snapshot-panes-1/) - Send keys to a pane: [`tmux_pane:send_keys/2`](https://libtmux.org/en/erlang/latest/reference/tmux_pane-send_keys-2/) - Capture pane contents: [`tmux_pane:capture/2`](https://libtmux.org/en/erlang/latest/reference/tmux_pane-capture-2/) - Arguments passed as a list, with no shell quoting: [`tmux_command`](https://libtmux.org/en/erlang/latest/reference/tmux_command/) - A typed error when the running tmux lacks a feature: [`tmux_capability`](https://libtmux.org/en/erlang/latest/reference/tmux_capability/) - Isolated tmux servers for tests: [`tmux_server:start_owned/1`](https://libtmux.org/en/erlang/latest/reference/tmux_server-start_owned-1/) - Async operations: [`tmux_operation`](https://libtmux.org/en/erlang/latest/reference/tmux_operation/) - [Guides](https://libtmux.org/en/erlang/latest/guides/): Installation, queries and owned operations. - [Topics](https://libtmux.org/en/erlang/latest/topics/): Object identity, command execution and compatibility. - [Examples](https://libtmux.org/en/erlang/latest/examples/): Complete programs from the tested source checkout. - [API reference](https://libtmux.org/en/erlang/latest/reference/): Native records, modules, functions and types. --- # API glossary Source: https://libtmux.org/en/erlang/latest/reference/glossary/ > Kinds, modifiers and package labels in the Erlang API reference. ## Symbol kinds Kinds identify declarations in the Erlang API reference. ### module An Erlang module grouping function, type and record declarations under an atom name. Exports identify which functions, types and native records callers can use. Maps, lists and records are values passed explicitly to module functions. References: [Erlang modules](https://github.com/erlang/otp/blob/OTP-29.1.2/system/doc/reference_manual/modules.md). ### struct An exported Erlang native record with a fixed set of named fields, owned by its defining module. Session, window, window-link and pane rows use native records. Import an exported definition with -import_record(tmux_model, [pane]). Native records remain experimental in OTP 29.1.2; their internals are not a wire format. References: [Erlang native records](https://github.com/erlang/otp/blob/OTP-29.1.2/system/doc/reference_manual/ref_man_native_records.md). ### function An Erlang function identified by its module, name and arity, the number of arguments. Functions sharing a name with different arities are distinct. Multiple clauses belong to one function; patterns and guards select the clause to execute. References: [Erlang functions](https://github.com/erlang/otp/blob/OTP-29.1.2/system/doc/reference_manual/ref_man_functions.md). ### typealias An Erlang type declaration written with -type, -opaque or -nominal, identified by module, name and arity. The shared typealias badge includes nominal IDs: Dialyzer distinguishes their declared names even when each is represented by a binary. Typespecs support analysis and documentation; runtime input validation remains necessary. References: [Erlang user-defined types](https://github.com/erlang/otp/blob/OTP-29.1.2/system/doc/reference_manual/typespec.md#type-declarations-of-user-defined-types). ## Modifiers Modifiers add information about calling, implementing, or accessing a declaration. Their precise effect follows the language and the signature. ### opaque An Erlang type declared with -opaque, whose representation callers must not depend on. Selections and queries are opaque values. Use tmux_select:to_list/1 to obtain rows for lists functions, and tmux_query:fetch/1 to execute a query. Ordinary selection reads and query construction perform no tmux I/O. References: [Erlang opaque types](https://github.com/erlang/otp/blob/OTP-29.1.2/system/doc/reference_manual/typespec.md#type-declarations-of-user-defined-types). ### abstract An Erlang behaviour callback declared with -callback, whose implementation belongs to a callback module. The declaration describes the callback contract; it does not provide a function body to call on the behaviour module. References: [Erlang behaviour callbacks](https://github.com/erlang/otp/blob/OTP-29.1.2/system/doc/reference_manual/modules.md#behaviour-module-attribute). ## Package context Package labels identify where an API is supplied. ### package The OTP application supplying these Erlang modules, described by an application resource file. The core application is libtmux_erlang. Its application name and the names of its modules serve different roles; use the documented source dependency to install it. References: [OTP applications](https://github.com/erlang/otp/blob/OTP-29.1.2/system/doc/design_principles/applications.md). --- # Erlang workspace manager is not published Source: https://libtmux.org/en/erlang/latest/workspace/ > The Erlang source application validates JSON desired state. Its plan and apply workflow and command-line tool are unfinished, and no package or loader command is available. Erlang has no published libtmux workspace manager. The source application validates JSON desired state, but its plan and apply workflow and its command-line tool are unfinished. There is no workspace package to install, loader command to run, or workspace API reference yet. The current public core observes tmux, holds the object graph as native records and sends explicit tmux operations. Start with the [core library](https://libtmux.org/en/erlang/latest/core/). The [guides](https://libtmux.org/en/erlang/latest/guides/) cover installation and the first connection. --- # Examples Source: https://libtmux.org/en/erlang/latest/examples/ > Run Erlang programs with private tmux servers and checked cleanup. Each guide includes its complete program, setup command and expected result. The core checks run these programs against private tmux servers and repeat them as installed consumers. Follow the guide's cleanup contract when adapting a program to an existing server. - [Create and query a graph](https://libtmux.org/en/erlang/latest/guides/getting-started/): Create sessions, windows and panes, then filter captured rows. - [Traverse a linked window](https://libtmux.org/en/erlang/latest/concepts/object-graph/): Compare physical windows with their session-relative memberships. - [Capture and send text](https://libtmux.org/en/erlang/latest/guides/panes/): Send literal text and inspect pane output on an owned server. - [Work with byte buffers](https://libtmux.org/en/erlang/latest/guides/buffers/): Load, inspect, paste and delete named byte buffers. --- # Getting started Source: https://libtmux.org/en/erlang/latest/guides/getting-started/ > Getting started: libtmux_erlang documentation. Create tmux sessions, windows and panes from Erlang. Capture their object graph, filter it as immutable data, and execute source queries and owned operations explicitly. ## Install Use Erlang/OTP **29.1.2**, Rebar3 **3.28.0**, Linux, tmux **3.3a–3.8**, and `make` with a C11 compiler. Native records are experimental in OTP 29. The core uses OTP libraries and a compiled external helper, with no NIF or third-party runtime packages. This checkout is unreleased. Add its core application to your `rebar.config`: ```erlang {deps, [ {libtmux_erlang, {git_subdir, "https://github.com/libtmux/libtmux-erlang.git", {branch, "master"}, "apps/libtmux_erlang"}} ]}. ``` Commit `rebar.lock` to keep the resolved commit. The [installation guide](https://libtmux.org/en/erlang/latest/guides/installation/) covers application startup and building a consumer. No Hex release is advertised. ## Create, capture and query From this checkout, compile with the pinned tools: ```console $ mise exec -- rebar3 compile ``` Run the complete program below on a private tmux server: ```console $ mise exec -- escript tools/run_examples.escript readme ``` The program starts an empty daemon on a unique private socket, verifies its assertions, and retires the owned server and clients. It leaves your existing tmux sessions alone. It uses only public core APIs and OTP runtime libraries; the archive check also runs it outside this checkout. Save it as `readme_demo.erl` when reusing it in an application. ```erlang -module(readme_demo). -moduledoc "Create a workspace, query its graph and preserve captured values.". -export([run/1]). -import_record(tmux_model, [pane]). -spec run(binary()) -> map(). run(Executable) -> Options = #{executable => Executable}, {ok, Result} = tmux_server:with_owned(Options, fun(Server) -> {ok, Session} = tmux_session:create(Server, #{name => <<"workspace">>, window_name => <<"editor">>, width => 120, height => 30, launch => #{argv => [<<"/bin/cat">>]}}), {ok, Worker} = tmux_window:create(Session, #{name => <<"workers">>, launch => #{argv => [<<"/bin/cat">>]}}), {ok, Right} = tmux_pane:split(Worker, #{direction => horizontal, launch => #{argv => [<<"/bin/cat">>]}}), {ok, _} = tmux_window:select_layout(Worker, even_horizontal), {ok, _} = tmux_pane:resize(Right, #{width => 40}), {ok, Snapshot} = tmux_server:snapshot(Server), Windows = tmux_select:windows(Snapshot), Workers = #{name => <<"workers">>, panes => #{count => 2, every => #{current_command => <<"cat">>}}}, {ok, Captured} = tmux_select:one(Workers, Windows), {ok, Children} = tmux_snapshot:related(panes, Captured, Snapshot), Ids = [Id || #pane{id = Id} <:- Children], 2 = length(Ids), Criteria = #{width => #{gte => 20}, window => #{is => #{name => <<"workers">>}}}, Query = tmux_query:where(Criteria, tmux_query:panes(Server)), {ok, Fetched} = tmux_query:fetch(Query), 2 = tmux_select:size(Fetched), {ok, _} = tmux_window:rename(Worker, <<"finished">>), <<"workers">> = tmux_model:get(name, Captured), {ok, Fresh} = tmux_query:fetch(tmux_query:where( #{name => <<"finished">>}, tmux_query:windows(Server))), {ok, Renamed} = tmux_select:one(Fresh), <<"finished">> = tmux_model:get(name, Renamed), 1 = length(tmux_snapshot:sessions(Snapshot)), 2 = length(tmux_snapshot:windows(Snapshot)), 3 = length(tmux_snapshot:panes(Snapshot)), #{sessions => 1, windows => 2, panes => 3, matched_panes => 2, captured_name => <<"workers">>, immutable => true} end), Result. ``` The result includes this checked output. Captured rows keep their original values after a rename; actions and `fetch` perform explicit I/O. [`tmux_server:with_owned/2`]() returns success after verified daemon cleanup. If cleanup fails, its error preserves the callback outcome and ownership token for recovery. ```json { "sessions": 1, "windows": 2, "panes": 3, "matched_panes": 2, "captured_name": "workers", "immutable": true } ``` ## Follow the graph A window can have several links in one session and belong to more than one session. Physical windows and panes remain unique; window links retain each session/index membership. - [Linked windows and relationship queries](https://libtmux.org/en/erlang/latest/concepts/object-graph/): build two sessions, link a shared window twice, and verify physical and membership counts. - [Daemon ownership](https://libtmux.org/en/erlang/latest/topics/ownership/): choose private startup or a borrowed socket, keep their lifetimes explicit and handle incomplete cleanup. - [Build command values](https://libtmux.org/en/erlang/latest/guides/commands/): prepare a rename and resize, submit them explicitly and inspect fresh state without changing captured rows. - [Control attachments](https://libtmux.org/en/erlang/latest/topics/control/): verify connection identity, inspect attachment effects and retire the client explicitly. - [Plan and apply a workspace](https://libtmux.org/en/erlang/latest/guides/workspace-json/): validate desired sessions, windows and panes, review saved operations, and handle drift or cancellation. - [Run a job and capture its result](https://libtmux.org/en/erlang/latest/guides/operations/): wait for a pane's completion event, check its exit status, capture bytes, and cancel a separate operation. - [Local filters and source queries](https://libtmux.org/en/erlang/latest/concepts/queries/): Boolean criteria, quantifiers, portable JSON, cardinality, coverage and execution plans. - [Fields and operators](https://libtmux.org/en/erlang/latest/reference/fields/): generated from the runtime schema. - [Scoped options](https://libtmux.org/en/erlang/latest/guides/options/): local ownership markers, explicit inheritance and sparse arrays, with a source-pinned option catalogue. - [Buffers and paste](https://libtmux.org/en/erlang/latest/guides/buffers/): preserve binary artifacts, inspect names and control terminal delivery. - [Rearrange panes](https://libtmux.org/en/erlang/latest/guides/panes/): isolate a running job in a window and join it back, preserving its process and the original snapshot. - [Apply configuration and await a signal](https://libtmux.org/en/erlang/latest/guides/configuration/): load settings from stdin, observe the event and verify parse-only behavior. - [Pipe terminal output](https://libtmux.org/en/erlang/latest/guides/piping/): save a job's bytes, await its consumer acknowledgement and verify the resulting log. - [Hooks and completion](https://libtmux.org/en/erlang/latest/guides/hooks/): register a split callback, await its acknowledgement and remove the local hook. - [Key tables](https://libtmux.org/en/erlang/latest/guides/keys/): register application bindings, inspect native listings and remove the owned table. - [Native commands](https://libtmux.org/en/erlang/latest/reference/commands/): source-derived parser metadata and feature minimums, separate from library API and runtime qualification. - [API browser and source docs](https://libtmux.org/en/erlang/latest/guides/api-documentation/): build searchable native reference pages with specs, types and links to the exact source revision. ## Decide whether it fits The current path uses bounded one-shot tmux clients. Operations support non-blocking submission, explicit waits, cancellation and ownership transfer. An await timeout abandons that wait; it does not cancel the operation. Cancellation after dispatch can leave the tmux outcome unknown. An explicit control attachment verifies identity on its persistent connection and owns its client cleanup. The workspace application plans and applies JSON files through a standalone escript. Control command submission and output streams remain implementation work. The [support and gaps](https://libtmux.org/en/erlang/latest/guides/compatibility/) page lists what is exercised, what remains open, and the required Linux/tmux matrix. There is no control-versus-streaming performance claim. The [project policy](https://libtmux.org/en/erlang/latest/topics/project-policy/) keeps core and workspace in separate OTP applications with OTP runtime dependencies. MCP is excluded from this port's scope. ## Verify and contribute ```console $ time python3 tools/check.py mid ``` ```console $ time python3 tools/check.py outer ``` The outer check owns its tmux fixtures and tests installed consumers. See [contributor setup](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/.github/CONTRIBUTING.md) for prerequisites and test budgets, [CI](https://github.com/libtmux/libtmux-erlang/actions/workflows/ci.yml) for individual release/architecture results, and the [MIT license](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/LICENSE). [Branding assets](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/docs/branding.md) include the logo, icons, and social cards. --- # Guides Source: https://libtmux.org/en/erlang/latest/guides/ > Guides for libtmux_erlang. Connect to tmux and work with its sessions, windows, and panes. - [Getting started](https://libtmux.org/en/erlang/latest/guides/getting-started/): Read about libtmux for erlang. - [Installation](https://libtmux.org/en/erlang/latest/guides/installation/): Read about install the core application. - [Apply configuration and await its completion signal](https://libtmux.org/en/erlang/latest/guides/configuration/): Read about apply configuration and await its completion signal. - [Build commands before running them](https://libtmux.org/en/erlang/latest/guides/commands/): Read about build commands before running them. - [Install application keybindings](https://libtmux.org/en/erlang/latest/guides/keys/): Read about install application keybindings. - [Isolate and rejoin a running pane](https://libtmux.org/en/erlang/latest/guides/panes/): Read about isolate and rejoin a running pane. - [Native API documentation](https://libtmux.org/en/erlang/latest/guides/api-documentation/): Read about build and browse the native api. - [Owned operations](https://libtmux.org/en/erlang/latest/guides/operations/): Read about wait for a terminal job, then capture its output. - [Pipe pane output](https://libtmux.org/en/erlang/latest/guides/piping/): Read about save a job's output and verify the consumer received it. - [Preserve byte buffers and paste deliberately](https://libtmux.org/en/erlang/latest/guides/buffers/): Read about preserve byte buffers and paste deliberately. - [Read and change scoped options](https://libtmux.org/en/erlang/latest/guides/options/): Read about read and change scoped options. - [Register a hook and await its effect](https://libtmux.org/en/erlang/latest/guides/hooks/): Read about register a hook and await its effect. - [Support and remaining gaps](https://libtmux.org/en/erlang/latest/guides/compatibility/): Read about support and remaining gaps. - [Workspace JSON loader](https://libtmux.org/en/erlang/latest/guides/workspace-json/): Read about plan and apply a workspace. --- # Installation Source: https://libtmux.org/en/erlang/latest/guides/installation/ > Installation: libtmux_erlang documentation. The core OTP application is `libtmux_erlang`. It lives in an umbrella, so a Rebar3 source dependency must use `git_subdir` with `apps/libtmux_erlang`. Using the repository root as an ordinary single-app Git dependency does not select the core application. The [README](https://libtmux.org/en/erlang/latest/guides/getting-started/#install) contains the dependency declaration tested in an isolated Rebar3 consumer. Rebar3 resolves the branch to a commit in `rebar.lock`; commit that file. To choose a reviewed commit directly, use Rebar3's `{ref, Commit}` form instead of `{branch, "master"}`. Add `libtmux_erlang` to your application's `applications` list in its `.app.src`. For an interactive consumer, compile and start the Rebar3 shell: ```console $ rebar3 compile ``` ```console $ rebar3 shell ``` ## Inspect an existing server `open/1` borrows an existing daemon. It does not start tmux or create a session. From a shell attached to the server you intend to inspect, obtain its socket: ```console $ export LIBTMUX_SOCKET="$(tmux display-message -p '#{socket_path}')" ``` Save this module as `src/inspect_demo.erl` in the consumer application: ```erlang -module(inspect_demo). -moduledoc "Inspect an existing tmux socket without changing its sessions.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> {ok, _} = application:ensure_all_started(libtmux_erlang), Endpoint = #{socket_path => Socket, executable => Executable}, {ok, Result} = tmux_server:with_server(Endpoint, fun(Server) -> {ok, Snapshot} = tmux_server:snapshot(Server), #{sessions => length(tmux_snapshot:sessions(Snapshot)), windows => length(tmux_snapshot:windows(Snapshot)), panes => length(tmux_snapshot:panes(Snapshot))} end), Result. ``` Run it through the consumer's Rebar shell. The executable path comes from PATH; the socket must be the absolute path selected above: ```console $ rebar3 shell \ --eval ' Socket = list_to_binary(os:getenv("LIBTMUX_SOCKET")), Tmux = list_to_binary(os:find_executable("tmux")), io:format("~p~n", [inspect_demo:run(Socket, Tmux)]), halt().' ``` The returned map counts physical objects in one captured view. Closing the library handle preserves the borrowed daemon and its sessions. This module also runs against the installed archive in the outer check. The private-server [README program](https://libtmux.org/en/erlang/latest/guides/getting-started/#create-capture-and-query) adds creation, native record patterns, graph traversal and a fresh query. Direct native-record construction needs [`tmux_model`]() loaded first; its constructors load normally and validate observations. Do not distribute record headers or serialize record internals as a wire format. ## Requirements | Component | Current requirement | | --- | --- | | Erlang/OTP | Exactly the qualified latest-stable baseline, 29.1.2 | | Build tool | Rebar3 3.28.0 | | tmux | 3.3a–3.8, including intermediate releases; CI tests both endpoints | | Runtime platform | Linux x86_64 and arm64 qualification cells | | Native build | C11 compiler, libc headers and make | | Core dependencies | OTP kernel, stdlib and crypto; no JSON package or NIF | | Checkout example runner | Python 3.12+ for owned-server readiness observation | The helper builds from its packaged C source. Installation must fail if that build fails; there is no runtime executable download. The helper's original license is retained separately from the project's MIT license. There is no published Hex package or release artifact for this checkout. [API docs](https://libtmux.org/en/erlang/latest/guides/api-documentation/) describe the local browser build. [Compatibility](https://libtmux.org/en/erlang/latest/guides/compatibility/) separates current checks from the remaining suite and delivery gates. --- # Apply configuration and await its completion signal Source: https://libtmux.org/en/erlang/latest/guides/configuration/ > Apply configuration and await its completion signal: libtmux_erlang documentation. Submit a wait without blocking the Erlang caller, then load configuration that sets an owned session option and signals the channel. The signal works whether the waiter arrives before or after it. The program verifies the stored value and checks that parse-only loading leaves it unchanged. The runner owns the daemon and verifies session and process cleanup. Compile the project first: ```console $ mise exec -- rebar3 compile ``` Run the complete program: ```console $ mise exec -- escript tools/run_examples.escript config ``` ```erlang -module(config_demo). -moduledoc "Apply session configuration and wait for its explicit signal.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> {ok, Server} = tmux_server:open( #{socket_path => Socket, executable => Executable}), tmux_scope:run_or_error(fun() -> {ok, Session} = tmux_session:create(Server, #{name => <<"configured-job">>, launch => #{argv => [<<"/bin/cat">>]}}), tmux_scope:run_or_error(fun() -> Id = tmux_model:get(id, Session), Suffix = binary:encode_hex(crypto:strong_rand_bytes(8), lowercase), Channel = <<"configured-", Suffix/binary>>, {ok, Wait} = tmux_command:wait_for(Channel, wait), {ok, Operation} = tmux_operation:start(Server, Wait, #{}), {ok, Source} = tmux_command:source_file(stdin, #{}), Scope = [<<"-t">>, Id, <<"@state">>], {ok, Settings} = tmux_command:raw(<<"set-option">>, Scope ++ [<<"configured">>]), {ok, Signal} = tmux_command:wait_for(Channel, signal), {ok, Text} = tmux_command:to_config([Settings, Signal]), {ok, _} = tmux_server:command(Server, Source, #{stdin => Text}), {ok, #{cleanup := complete}} = tmux_operation:await(Operation, 900), State = <<"@state">>, {ok, <<"configured">>} = tmux_option:get(Session, State, #{}), ParseOptions = #{parse_only => true}, {ok, Parse} = tmux_command:source_file(stdin, ParseOptions), {ok, NewValue} = tmux_command:raw(<<"set-option">>, Scope ++ [<<"changed">>]), {ok, Change} = tmux_command:to_config(NewValue), {ok, _} = tmux_server:command(Server, Parse, #{stdin => Change}), {ok, <<"configured">>} = tmux_option:get(Session, State, #{}), #{configuration_applied => true, event_received => true, parse_only_kept_value => true} end, fun() -> {ok, _} = tmux_session:kill(Session), ok end) end, fun() -> ok = tmux_server:close(Server) end). ``` ```json { "configuration_applied": true, "event_received": true, "parse_only_kept_value": true } ``` The archive check repeats this program using the installed core package. [Jobs and operations](https://libtmux.org/en/erlang/latest/guides/operations/) covers operation ownership, cancellation and application-level completion events. ## Choose input and execution separately [`tmux_command:to_config/1`]() renders one validated command value or a nonempty flat list as native configuration text. Lists contain at most 256 commands and share the 32 KiB rendered limit, including native separators. Rendering a list does not provide atomic execution or rollback. Argument quoting preserves literal bytes through the lexer, including variables, semicolons, newline indentation and non-UTF-8 byte values. It returns ASCII text without performing I/O. Escaping growth is bounded by a 32 KiB rendered limit. This covers one lexer pass; native commands that accept command strings can parse those strings again. Render each inner command separately for its own boundary. Native commands still interpret their arguments and formats normally; this renderer does not quote shell code. [`tmux_command:source_file/2`]() builds a command value without I/O. The source is `stdin` or one absolute POSIX byte path. Path glob characters and backslashes are quoted for tmux's glob parser; hash formats are not expanded. The builder never opens the file. Reading and parsing occur when the command executes. The file's size is not bounded by the command builder. For stdin, pass bytes through the execution options of [`tmux_server:command/3`]() or [`tmux_operation:start/3`](). The transport bounds stdin and rendered arguments together to 256 KiB. `parse_only` requests native `-n`: parse the input without executing its command list. `quiet` requests native missing-file suppression; syntax and execution errors remain errors. Both options default to false. Configuration is trusted tmux code, with native directives and variable expansion. Parse-only is not a sandbox. Execution can change state before reporting an error, and cancellation cannot roll back those effects. A successful source command does not establish that background work launched by that configuration has finished. Check its actual completion event. ## Coordinate channels explicitly [`tmux_command:wait_for/2`]() accepts a binary channel name and one action: `wait`, `signal`, `lock` or `unlock`. Submit its result through the same execution APIs. Native channel names are server-wide; use a name unique to the operation when other clients share the server. A signal wakes current waiters. On an unlocked channel with no waiters or pending wakeup, it retains one wakeup for a later wait. Signaling again before a wait can clear that pending state. Send once per expected wait; repeated signals are neither counted nor reliably coalesced. Use separate names for signaling and locking. `lock` and `unlock` expose native advisory channel locks. A lock remains held after the acquiring command client exits, until an explicit unlock. They are not library-owned leases. Cancelling a command does not undo a signal or release a possibly acquired lock. An uncertain lock outcome requires application coordination before unlocking; blindly unlocking can release another client's lock. --- # Build commands before running them Source: https://libtmux.org/en/erlang/latest/guides/commands/ > Build commands before running them: libtmux_erlang documentation. Prepare a literal session rename and a pane resize, then submit the values explicitly. Building validates their captured target and arguments without contacting tmux. Execution checks the endpoint origin and returns the native one-shot result. The resize uses an operation handle so waiting is explicit. This complete program checks the name before execution, awaits the resize, reads fresh dimensions and verifies that earlier rows keep their values. The runner owns the private fixture and verifies cleanup: ```console $ mise exec -- escript tools/run_examples.escript commands ``` ```erlang -module(command_demo). -moduledoc "Build captured-target commands, then execute and inspect them.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> Endpoint = #{socket_path => Socket, executable => Executable}, {ok, Server} = tmux_server:open(Endpoint), tmux_scope:run_or_error(fun() -> {ok, Session} = tmux_session:create(Server, #{name => <<"commands">>, width => 120, height => 30, launch => #{argv => [<<"/bin/cat">>]}}), tmux_scope:run_or_error(fun() -> SessionId = tmux_model:get(id, Session), {ok, Snapshot} = tmux_server:snapshot(Server), [Anchor] = tmux_snapshot:panes(Snapshot), {ok, Pane} = tmux_pane:split(Anchor, #{direction => horizontal, size => {cells, 40}, launch => #{argv => [<<"/bin/cat">>]}}), {ok, Rename} = tmux_session:rename_command( Session, <<"commands-ready">>), {ok, Resize} = tmux_pane:resize_command(Pane, #{width => 60}), {ok, OtherEndpoint} = tmux_server:open(Endpoint), tmux_scope:run_or_error(fun() -> {error, #{code := different_owner, submitted := false}} = tmux_server:command(OtherEndpoint, Rename, #{}) end, fun() -> ok = tmux_server:close(OtherEndpoint) end), {ok, Before} = tmux_session:get(Server, SessionId), <<"commands">> = tmux_model:get(name, Before), 40 = tmux_model:get(width, Pane), {ok, #{exit_status := 0, cleanup := complete}} = tmux_server:command(Server, Rename, #{}), {ok, Operation} = tmux_operation:start(Server, Resize, #{}), {ok, #{exit_status := 0, cleanup := complete}} = tmux_operation:await(Operation, 900), {ok, Current} = tmux_pane:get(Server, tmux_model:get(id, Pane)), 60 = tmux_model:get(width, Current), {ok, Renamed} = tmux_session:get(Server, SessionId), <<"commands-ready">> = tmux_model:get(name, Renamed), <<"commands">> = tmux_model:get(name, Session), 40 = tmux_model:get(width, Pane), #{name => <<"commands-ready">>, initial_width => 40, actual_width => 60, captured_values_unchanged => true, foreign_origin_rejected => true} end, fun() -> {ok, _} = tmux_session:kill(Session), ok end) end, fun() -> ok = tmux_server:close(Server) end). ``` ```json { "name": "commands-ready", "initial_width": 40, "actual_width": 60, "captured_values_unchanged": true, "foreign_origin_rejected": true } ``` The archive check runs this program through the installed public package. [`tmux_session:rename/2`]() and [`tmux_pane:resize/2`]() perform their operations immediately; their command builders return reusable values. Reusing a value requires explicit intent each time. An uncertain mutation result must not trigger an automatic retry. A command keeps the originating row's endpoint token. Submitting it through another endpoint returns `different_owner` with `submitted = false`, even if both servers happen to use the same pane or session ID. Building alone does not establish endpoint liveness. The example rejects a second endpoint handle to the same daemon too. To act through another endpoint, bind the row there and build a new command. Bind detached rows with [`tmux_server:bind/2`]() before building their commands. [`tmux_command:to_config/1`]() renders command syntax without executing it. Serialized configuration carries no origin token; the caller must choose and validate that destination explicitly. See [jobs and operations](https://libtmux.org/en/erlang/latest/guides/operations/) for wait timeouts, ownership and cancellation, the [configuration guide](https://libtmux.org/en/erlang/latest/guides/configuration/) for rendering, and [current support](https://libtmux.org/en/erlang/latest/guides/compatibility/) for transport qualification. --- # Install application keybindings Source: https://libtmux.org/en/erlang/latest/guides/keys/ > Install application keybindings: libtmux_erlang documentation. Use a separate key table when an application needs its own bindings. This program binds `z` to zoom and show a status message, and `s` to show the workspace name. It reads the native listing and removes its table. It does not attach a client or press a key. From the checkout, after [building the core](https://libtmux.org/en/erlang/latest/guides/installation/), run: ```console $ mise exec -- escript tools/run_examples.escript keys ``` ```erlang -module(key_demo). -moduledoc "Install and remove an application-owned key table.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> {ok, Server} = tmux_server:open( #{socket_path => Socket, executable => Executable}), tmux_scope:run_or_error(fun() -> Suffix = binary:encode_hex(crypto:strong_rand_bytes(8), lowercase), Table = <<"workspace-", Suffix/binary>>, {ok, Zoom} = tmux_command:raw(<<"resize-pane">>, [<<"-Z">>]), {ok, Status} = tmux_command:raw(<<"display-message">>, [<<"Workspace: #{session_name}">>]), {ok, _} = tmux_key:bind(Server, <<"z">>, [Zoom, Status], #{table => Table, note => <<"Zoom the current workspace pane">>}), tmux_scope:run_or_error(fun() -> {ok, _} = tmux_key:bind(Server, <<"s">>, Status, #{table => Table, note => <<"Show the workspace name">>}), {ok, Listing} = tmux_key:listing(Server, #{table => Table}), true = binary:match(Listing, <<"resize-pane">>) =/= nomatch, true = binary:match(Listing, <<"display-message">>) =/= nomatch, #{bindings => 2, native_listing => true, execution => <<"requires a client key press">>} end, fun() -> {ok, _} = tmux_key:clear_table(Server, Table), ok end) end, fun() -> ok = tmux_server:close(Server) end). ``` ```json { "bindings": 2, "native_listing": true, "execution": "requires a client key press" } ``` The runner owns an isolated server. The program uses the public core API, and the installed-archive check repeats it outside the source checkout. Common Test separately drives a real terminal client's key input, verifies the bound command's bytes and acknowledgement, and proves client retirement on success, failure and cancellation. ## Registration and execution are separate [`tmux_key:bind/3`]() registers in the native prefix table. [`tmux_key:bind/4`]() accepts an explicit `table`, Boolean `repeat` and byte `note`. It accepts one command or a flat nonempty command list, with the bounds of [`tmux_command:to_config/1`](): at most 256 commands and 32 KiB of rendered text. tmux parses the body before replacing an existing binding. Replacement resets the previous commands, repeat flag and note. Tables belong to the server. Creating one does not select it for any client. Choose a session's default through the [`key-table`](https://libtmux.org/en/tmux/latest/catalog/options/key-table/) option in [`tmux_option`](https://libtmux.org/en/erlang/latest/guides/options/); native prefix, repeat and client table-switching rules still apply. The example leaves client selection to the application. Registration quotes arguments for the stored command parser. A command can still interpret formats when a client executes it: the example's [`#{session_name}`](https://libtmux.org/en/tmux/latest/catalog/formats/session_name/) is evaluated then. See [configuration boundaries](https://libtmux.org/en/erlang/latest/guides/configuration/) before storing nested command strings or explicit shell commands. An accepted registration does not prove future execution; arrange a completion signal when an application needs one, as in the [hook example](https://libtmux.org/en/erlang/latest/guides/hooks/). ## Read listings and remove owned bindings [`tmux_key:listing/1`]() and [`tmux_key:listing/2`]() return native bytes unchanged. Options can restrict `table` and `key`. Spacing, quoting and included metadata follow the daemon release. This is a presentation view: retain original command values for reinstalling bindings. tmux 3.4 may escape dollar signs in this view. On tmux 3.7c, a single matching entry can go to the native status-message path and produce empty stdout when no target client is attached. Empty output does not prove a binding is absent. The example lists multiple bindings to avoid that path. The tmux 3.3 baseline has no custom listing format option. Explicit newer-server options remain available through [`tmux_command:raw/2`](). [`tmux_key:unbind/2`]() and [`tmux_key:unbind/3`]() remove one binding; an absent key in an existing table is a native no-op. Removing the final custom binding may remove its table. Missing explicitly named tables and invalid native key names remain errors. [`tmux_key:clear_table/2`]() requires an explicit name and removes the entire table. It can affect attached clients and does not restore default bindings or cancel commands already queued by a client. Calls use the registered endpoint identity and preserve backend diagnostics. They do not start a missing server or retry uncertain mutations. The native [`tmux_key` API browser](https://libtmux.org/en/erlang/latest/guides/api-documentation/) documents input bounds, results and errors. --- # Isolate and rejoin a running pane Source: https://libtmux.org/en/erlang/latest/guides/panes/ > Isolate and rejoin a running pane: libtmux_erlang documentation. Move a job into its own window, then join it back without respawning it. This complete program checks the process ID, changed parent window, removal of the temporary window and immutability of the earlier capture. The runner owns the server and verifies cleanup: ```console $ mise exec -- escript tools/run_examples.escript panes ``` ```erlang -module(pane_demo). -moduledoc "Isolate a running pane, then join it back without respawning.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> {ok, Server} = tmux_server:open( #{socket_path => Socket, executable => Executable}), tmux_scope:run_or_error(fun() -> {ok, Session} = tmux_session:create(Server, #{name => <<"pane-workflow">>, window_name => <<"editor">>, launch => #{argv => [<<"/bin/cat">>]}}), tmux_scope:run_or_error(fun() -> {ok, Initial} = tmux_server:snapshot(Server), {ok, Link} = tmux_select:one( #{session_id => tmux_model:get(id, Session)}, tmux_select:window_links(Initial)), {ok, Window} = tmux_snapshot:related(window, Link, Initial), {ok, [Anchor]} = tmux_snapshot:related(panes, Window, Initial), WindowId = tmux_model:get(id, Window), {ok, Pane} = tmux_pane:split(Anchor, #{launch => #{argv => [<<"/bin/cat">>]}}), Id = tmux_model:get(id, Pane), Pid = tmux_model:get(pid, Pane), {ok, Before} = tmux_server:snapshot(Server), {ok, _} = tmux_pane:break(Pane, Link, Session, #{index => 9, name => <<"isolated #{pane_id}">>}), {ok, Isolated} = tmux_pane:get(Server, Id), Pid = tmux_model:get(pid, Isolated), Temporary = tmux_model:get(window_id, Isolated), true = Temporary =/= WindowId, {ok, OldPane} = tmux_snapshot:get(pane, Id, Before), WindowId = tmux_model:get(window_id, OldPane), {ok, _} = tmux_pane:join(Pane, Anchor, #{direction => horizontal, size => {percent, 40}}), {ok, Joined} = tmux_pane:get(Server, Id), WindowId = tmux_model:get(window_id, Joined), Pid = tmux_model:get(pid, Joined), {error, #{code := target_gone}} = tmux_window:get(Server, Temporary), {ok, Final} = tmux_server:snapshot(Server), 2 = length(tmux_snapshot:panes(Final)), #{same_process => true, snapshot_unchanged => true, temporary_window_removed => true, panes_after_join => 2} end, fun() -> {ok, _} = tmux_session:kill(Session), ok end) end, fun() -> ok = tmux_server:close(Server) end). ``` ```json { "same_process": true, "snapshot_unchanged": true, "temporary_window_removed": true, "panes_after_join": 2 } ``` The archive check repeats this reader program outside the source checkout. Its separate native consumer also exercises same-window move and pane swap. ## Supply a membership when breaking a pane A physical window can be linked several times, even within one session. A pane therefore has no single source membership. [`tmux_pane:break/4`]() takes the pane, an explicit source window link, the destination session and placement options. `index` is required. `detach` defaults to true; false selects the destination membership. `name` is a literal UTF-8 argument, without format expansion. | Source window | What tmux changes | | --- | --- | | Several panes | Creates a physical window and moves the pane into it; the original links remain | | Only one pane | Moves the selected membership of the existing physical window; other links remain | Pane IDs and running processes survive both cases. Moving the final membership out of a session can destroy that source session. Session groups retain tmux's native synchronization behavior. An occupied destination index is refused. The API checks the link's expected window and the pane's observed parent. It then sends a session/index selector qualified by the stable pane ID. An absent pane cannot become whichever pane later occupies its old positional index. The preflight and action remain separate commands: concurrent changes after the check, including an index moving away and back, can remain undetected. There is no atomic compare-and-act guarantee. Literal means unexpanded, not stored verbatim. tmux's own name cleaning still applies. For example, 3.3/3.4 stores an added backslash before dollar-variable prefixes; later releases changed that behavior. The library returns the stored name instead of guessing which escapes a caller intended. See the [object graph guide](https://libtmux.org/en/erlang/latest/concepts/object-graph/) for physical windows and memberships. ## Move and swap by physical pane ID [`tmux_pane:join/3`]() and [`tmux_pane:move/3`]() use the source and destination pane IDs. Their native commands share placement behavior and permit rearrangement within one window. Geometry uses [`t:tmux_pane:join_options/0`](): vertical by default, optional direction, cells/percent size, `before` and `full_size`. Both reject identical source/destination IDs. [`tmux_pane:swap/3`]() exchanges layout positions within or across windows. Its `detach` defaults to true; `zoom` maps to tmux's `-Z` retention flag. Swapping a pane with itself exchanges nothing, but native zoom handling still runs: the default can unzoom even that same-pane call. Across windows, active positions can receive different pane IDs even in detached mode. Moving the last pane out destroys its physical window and every link to it, and can remove sessions. Shared windows affect all memberships. Existing processes keep their process environment and working directory; inherited window options can change when the pane changes parent. With `detach` false, join/move selection uses tmux's resolved destination-session context. Supply window-link actions separately when a particular session membership must be selected. ## Keep captures and action results separate These calls return the completed command result for both [new-window](https://libtmux.org/en/tmux/latest/manual/new-window/) and existing-window cases. They never refresh input records or captures. Use [`tmux_pane:get/2`](), [`tmux_window_link:get/3`]() or [`tmux_server:snapshot/1`]() to observe the resulting graph. Source/destination rows must use the same registered owner; rebind explicitly when working through another endpoint owner. A disappeared pane or session remains an operational error. A replaced source link returns `stale_link`; a different observed pane parent returns `pane_link_mismatch`. Even an eventual native layout error can unzoom windows. These operations are not transactions and are never automatically retried. The [support page](https://libtmux.org/en/erlang/latest/guides/compatibility/) separates implemented APIs from remaining control, consumer and delivery qualification. --- # Native API documentation Source: https://libtmux.org/en/erlang/latest/guides/api-documentation/ > Native API documentation: libtmux_erlang documentation. Core and workspace contracts live in Erlang `-moduledoc`, `-doc` and specs. OTP's compiler stores EEP-48 documentation chunks; ExDoc renders searchable module, function and type pages. Source links open captured files with line anchors and content digests. An unchanged file also links to its exact Git commit; changed files are labelled as working-tree previews. Compile the project: ```console $ mise exec -- rebar3 compile ``` Prepare the checksum-pinned ExDoc tool. This step uses the network: ```console $ python3 tools/build_docs.py --prepare ``` Build the browser without fetching dependencies: ```console $ mise exec -- python3 tools/build_docs.py ``` Open `_build/docs/core/index.html`. This is a local build, not a published HexDocs URL. The build refreshes compiled modules before rendering. The renderer treats warnings as failures and uses the OTP 29 build of ExDoc. It consumes compiler chunks directly because the older EDoc source-extraction path rejects native-record attributes. ## Read by task | Task | API modules | | --- | --- | | Open, inspect and close an endpoint | [`m:tmux_server`]() | | Preserve work and cleanup failures | [`m:tmux_scope`](), [`tmux_server:with_owned/2`](), [`tmux_server:with_server/2`]() | | Create and act on terminal objects | [`m:tmux_session`](), [`m:tmux_window`](), [`m:tmux_pane`]() | | Switch one explicitly named attached client | [`tmux_session:select/2`](), [`tmux_session:select/3`]() | | Break, join, move and swap running panes | [`tmux_pane:break/4`](), [`tmux_pane:join/3`](), [`tmux_pane:move/3`](), [`tmux_pane:swap/3`]() | | Act on session-relative window memberships | [`m:tmux_window_link`]() | | Read local or inherited options and change explicit tables | [`m:tmux_option`]() | | Register, inspect and explicitly run native hooks | [`m:tmux_hook`]() | | Register and remove keys in explicit server tables | [`m:tmux_key`]() | | Inspect native command declarations and feature minimums | [`m:tmux_capability`]() | | Store byte buffers and paste into a pane | [`m:tmux_buffer`]() | | Read a captured graph | [`m:tmux_snapshot`](), [`m:tmux_model`]() | | Filter captured data | [`m:tmux_select`](), [`m:tmux_filter`](), [`m:tmux_matcher`]() | | Plan source retrieval | [`m:tmux_query`]() | | Submit, await and cancel work | [`m:tmux_operation`](), [`m:tmux_command`]() | | Render/load configuration and build channel waits or signals | [`tmux_command:to_config/1`](), [`tmux_command:source_file/2`](), [`tmux_command:wait_for/2`]() | | Connect a shell consumer to live pane bytes | [`tmux_pane:pipe/3`](), [`tmux_pane:stop_pipe/1`]() | | Inspect schema and wire validation | [`m:tmux_schema`](), [`m:tmux_json`](), [`m:tmux_version`]() | | Explain local library exceptions in the shell | [`m:tmux_error`]() | | Load and inspect desired workspace files | `m:tmux_workspace` | | Inspect observed process identities | [`m:tmux_identity`]() | The [field reference](https://libtmux.org/en/erlang/latest/reference/fields/) is generated from the same registry and operator validator used by filtering. [Contributor checks](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/.github/CONTRIBUTING.md) execute native shell examples and complete programs; compilation alone is not the example gate. ## Types at application boundaries Entity constructors accept generated maps such as [`t:tmux_model:pane_input/0`](). Required fields and scalar categories are visible to Dialyzer. Optional observations retain `not_loaded` and `unavailable`; nullable fields also accept `none`. Numeric fields accept integral floats, which normalize to integers. Runtime validation checks bounds, ID syntax, UTF-8 and derived values. Use [`tmux_model:new/2`]() when validating dynamic maps and handle its [`t:tmux_schema:error_detail/0`]() result. [`t:tmux_select:t/1`]() describes the intended row type. Dialyzer in OTP 29.1.2 does not always substitute actual argument types into generic return variables. For example, a selection passed through [`tmux_select:one/1`]() can lose its specific entity type during analysis. A successful analysis does not prove every pane/window relationship. Keep native patterns and runtime action validation at those boundaries. The [OTP contract solver](https://github.com/erlang/otp/blob/OTP-29.1.2/lib/dialyzer/src/dialyzer_contracts.erl#L477-L502) records this generic constraint limitation. The installed-consumer outer check executes valid constructor calls and requires Dialyzer to reject wrong Boolean/numeric fields and missing session identity or window-link index. It analyzes the installed core outside the umbrella; a green library analysis alone does not establish those diagnostics. --- # Owned operations Source: https://libtmux.org/en/erlang/latest/guides/operations/ > Owned operations: libtmux_erlang documentation. A successful send or command frame does not prove that a terminal program processed input. This example runs an owned job that acknowledges terminal parsing before it exits, then waits for tmux's [`pane-died`](https://libtmux.org/en/tmux/latest/catalog/hooks/pane-died/) event, checks the exit status and captures the completed output. The companion [terminal job](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/examples/terminal_job.py) writes its result and an ANSI device-status request. It exits successfully only after reading tmux's reply. tmux generates that reply after parsing the preceding output. The job writes no more output afterward. Python 3.12+ is an example dependency only. [`pane-died`](https://libtmux.org/en/tmux/latest/catalog/hooks/pane-died/) alone is **not** a general output-drain barrier on tmux 3.3. This protocol applies to this cooperating job; it does not establish completion for an arbitrary program or reconstruct output that scrolled out of history. The example changes options and a hook only on its new window. [`remain-on-exit`](https://libtmux.org/en/tmux/latest/catalog/options/remain-on-exit/) keeps the pane addressable; an empty exit banner preserves the first line. The hook signals a tmux [`wait-for`](https://libtmux.org/en/tmux/latest/manual/wait-for/) channel. There are no sleeps or capture retries. Run from the checkout so the companion job can be located: ```console $ mise exec -- escript tools/run_examples.escript job ``` ```erlang -module(job_demo). -moduledoc "Capture a job that acknowledges terminal parsing before it exits.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> Endpoint = #{socket_path => Socket, executable => Executable}, {ok, Server} = tmux_server:open(Endpoint), tmux_scope:run_or_error(fun() -> {ok, Session} = tmux_session:create(Server, #{name => <<"jobs">>, width => 120, height => 30, launch => #{argv => [<<"/bin/cat">>]}}), tmux_scope:run_or_error(fun() -> {ok, Window} = tmux_window:create(Session, #{launch => #{argv => [<<"/bin/cat">>]}}), Target = [<<"-w">>, <<"-t">>, tmux_model:get(id, Window)], Deadline = #{deadline_ms => 2000}, {ok, _} = tmux_option:set(Window, <<"remain-on-exit">>, <<"on">>), {ok, _} = tmux_option:set( Window, <<"remain-on-exit-format">>, <<>>), {ok, Hook} = tmux_command:raw(<<"set-hook">>, Target ++ [<<"pane-died">>, <<"wait-for -S job-finished">>]), {ok, _} = tmux_server:command(Server, Hook, #{}), {ok, Wait} = tmux_command:raw(<<"wait-for">>, [<<"job-finished">>]), {ok, Operation} = tmux_operation:start(Server, Wait, Deadline), {error, #{code := await_timeout}} = tmux_operation:await(Operation, 0), JobFile = filename:absname("examples/terminal_job.py"), Launch = #{argv => [<<"/usr/bin/python3">>, list_to_binary(JobFile)]}, {ok, Job} = tmux_pane:split(Window, #{launch => #{shell => <<>>}}), {ok, _} = tmux_pane:respawn(Job, #{launch => Launch}), {ok, #{exit_status := 0, cleanup := complete}} = tmux_operation:await(Operation, 900), {ok, Completed} = tmux_pane:get(Server, tmux_model:get(id, Job)), true = tmux_model:get(dead, Completed), 0 = tmux_model:get(exit_status, Completed), {ok, <<"build complete\n">>} = tmux_pane:capture( Completed, #{start => 0, 'end' => 0}), {ok, Never} = tmux_command:raw( <<"wait-for">>, [<<"not-signalled">>]), {ok, Cancelled} = tmux_operation:start(Server, Never, Deadline), {ok, _} = tmux_operation:await_started(Cancelled, 900), {ok, cancel_requested} = tmux_operation:cancel(Cancelled), {error, #{outcome := unknown, cleanup := complete}} = tmux_operation:await(Cancelled, 900), #{output => <<"build complete\n">>, job_status => 0, await_timeout_kept_operation => true, cancelled_outcome => unknown} end, fun() -> {ok, _} = tmux_session:kill(Session), ok end) end, fun() -> ok = tmux_server:close(Server) end). ``` The output is `build complete` followed by a newline, and the exit status is zero. The zero-duration await proves that abandoning a wait leaves the operation usable. The separate cancelled wait reports an unknown tmux outcome and complete client cleanup; cancellation does not undo submitted work. The example prepares an empty pane, then starts its job with [`tmux_pane:respawn/2`](). Respawn keeps the pane ID. Its default launch mode, `previous`, reuses tmux's saved command; this example supplies new argv instead. Running panes require explicit `force => true`. Use a job-specific completion condition and fresh observations to check the result. Use an empty shell command to prepare a process-free pane with [`tmux_pane:split/2`](). Session creation on every supported version, and window creation before tmux 3.8, can finish that command immediately and remove the new object. This example uses `/bin/cat` to keep its parent session and window available across versions. `await_started/2` returns lifecycle status, including when an operation already failed or retired. Use `await/2` for its command result. Successful command results preserve separate stdout/stderr binaries, stdin bytes delivered to the client pipe, exit status, outcome and cleanup. Validation and wait errors can contain only a code; do not assume every error contains output or certainty. The native API defines [`t:tmux_operation:completed/0`](), [`t:tmux_operation:failure/0`]() and [`t:tmux_operation:state/0`](). Treat a pane's exit_status field independently from its dead flag. tmux exposes a numeric status after collecting a normal child exit; signal termination has no numeric value in that field. The captured absence value is none, which does not mean success. The native pane_dead_signal format can identify a signal when diagnosing an unexpected exit. This distinction appears in the [tmux 3.3a status callback](https://github.com/tmux/tmux/blob/3.3a/format.c#L1792) and the [tmux 3.8 status callback](https://github.com/tmux/tmux/blob/3.8/format.c#L2288). ## Operation ownership The process that starts an operation owns it. Other processes can await its handle without becoming owners. The endpoint confirms a transfer after monitoring the new owner and releasing the old monitor; the new process does not perform a handshake. Owner death and cancellation retire queued or possibly-sent clients; they do not replay mutations. An `await_timeout` from [`tmux_operation:transfer/2`]() leaves the transfer outcome uncertain: the endpoint may process the owner change after the caller stops waiting. Read [`tmux_operation:status/1`]() to establish the current owner before relying on ownership. The timeout does not prove the old owner still owns the operation. Retired results are retained for at most 60 seconds. The endpoint also evicts the oldest results when retention exceeds 64 results or 4 MiB of stdout/stderr. Use [`tmux_operation:status/1`]() while a handle is valid, and handle `operation_expired` after retention. Closing an endpoint retires its library clients and preserves the tmux server. [Daemon ownership](https://libtmux.org/en/erlang/latest/topics/ownership/) explains the separate token used to stop an owned daemon. Current operations use one-shot clients. Persistent control, grouping and stream delivery are not yet available; see [support and gaps](https://libtmux.org/en/erlang/latest/guides/compatibility/). --- # Pipe pane output Source: https://libtmux.org/en/erlang/latest/guides/piping/ > Pipe pane output: libtmux_erlang documentation. This program opens a pane pipe before releasing the producer. A shell consumer reads the expected bytes into a log and signals completion only after that write succeeds. The Erlang caller verifies the file contents before stopping the pipe. It does not infer delivery from pipe creation or command completion. Compile the project: ```console $ mise exec -- rebar3 compile ``` Run on an owned server. The runner verifies session and process cleanup: ```console $ mise exec -- escript tools/run_examples.escript pipe ``` ```erlang -module(pipe_demo). -moduledoc "Save terminal bytes after a consumer acknowledgement.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> Suffix = binary:encode_hex(crypto:strong_rand_bytes(8), lowercase), Directory = <<"/tmp/ltm-pipe-example-", Suffix/binary>>, ok = file:make_dir(Directory), tmux_scope:run_or_error(fun() -> ok = file:change_mode(Directory, 8#700), Log = <>, {ok, Server} = tmux_server:open( #{socket_path => Socket, executable => Executable}), tmux_scope:run_or_error(fun() -> Native = <<(quote(Executable))/binary, " -N -S ", (quote(Socket))/binary, " wait-for ">>, Start = <<"start-", Suffix/binary>>, Done = <<"consumed-", Suffix/binary>>, Producer = <<"stty -onlcr && ", Native/binary, Start/binary, " && printf 'build complete\\n' && exec /bin/cat">>, {ok, Session} = tmux_session:create(Server, #{name => <<"pipe-example">>, launch => #{argv => [<<"/bin/sh">>, <<"-c">>, Producer]}}), tmux_scope:run_or_error(fun() -> {ok, Snapshot} = tmux_server:snapshot(Server), [Pane] = tmux_snapshot:panes(Snapshot), Payload = <<"build complete\n">>, Size = integer_to_binary(byte_size(Payload)), Consumer = <<"/usr/bin/head -c ", Size/binary, " > ", (quote(Log))/binary, " && ", Native/binary, "-S ", Done/binary, " && exec /bin/cat >/dev/null">>, {ok, Wait} = tmux_command:wait_for(Done, wait), {ok, Operation} = tmux_operation:start(Server, Wait, #{}), {ok, _} = tmux_pane:pipe(Pane, #{shell => Consumer}, #{}), {ok, Signal} = tmux_command:wait_for(Start, signal), {ok, _} = tmux_server:command(Server, Signal, #{}), {ok, #{cleanup := complete}} = tmux_operation:await(Operation, 900), {ok, Payload} = file:read_file(Log), {ok, _} = tmux_pane:stop_pipe(Pane), #{log => Payload, bytes_written => byte_size(Payload), consumer_acknowledged => true} end, fun() -> {ok, _} = tmux_session:kill(Session), ok end) end, fun() -> ok = tmux_server:close(Server) end) end, fun() -> ok = file:del_dir_r(Directory) end). quote(Value) -> Escaped = binary:replace(Value, <<"'">>, <<"'\\''">>, [global]), <<"'", Escaped/binary, "'">>. ``` ```json { "log": "build complete\n", "bytes_written": 15, "consumer_acknowledged": true } ``` The example uses Linux shell utilities `stty`, `/usr/bin/head` and `/bin/cat`. It disables newline translation on the producer's terminal, so the expected log contains LF bytes. The temporary log is removed after verification. The archive check repeats the program with the installed core package. ## Choose direction and replacement behavior [`tmux_pane:pipe/3`]() requires an explicit shell-command map and a registered physical pane. It escapes hash and strftime directives before tmux expands that text. The shell still interprets the command; the example's `quote/1` handles values inserted into its shell code. This native operation takes shell code rather than executable argv. [`tmux_command:literal_format/2`]() documents the encoding limits. Percent-bearing commands above tmux's 8191-byte intermediate time-format limit return `format_limit` before dispatch. That check preserves an existing pipe when a replacement cannot be represented safely. | Direction | Connection | | --- | --- | | `output` (default) | Pane PTY output to child stdin | | `input` | Child stdout to pane input | | `both` | Both connections | Terminal modes affect these bytes. This is neither rendered screen capture nor a replay of prior terminal history. It is not an Erlang subscription with library flow control. Child stderr is discarded; unused directions use tmux's native null-device routing. The API does not copy the pane's cwd or environment into the child process. Starting a pipe normally replaces an existing one. `toggle => true` maps to native `-o`: an open pipe is closed without starting another, while a closed pipe is opened. It does not mean preserve an already open pipe. ## Distinguish the pipe from its process A successful action proves command completion, not shell execution success, consumer readiness, delivered bytes or process exit. The example observes the consumer's actual file write. Native integration tests independently verify all 256 byte values in both directions, literal hash/percent shell text, replacement, toggle and process retirement. [`tmux_pane:stop_pipe/1`]() closes the native connection and can discard pending bytes. Wait for the consumer's acknowledgement before closing when delivery matters. Closing does not kill or wait for an arbitrary shell process; a consumer that does not finish on EOF needs application-level coordination. [`tmux_server:close/1`]() preserves the borrowed pane and its tmux-owned pipe. [Jobs and operations](https://libtmux.org/en/erlang/latest/guides/operations/) covers library-owned command clients; [configuration and signals](https://libtmux.org/en/erlang/latest/guides/configuration/) explains native wait channels. --- # Preserve byte buffers and paste deliberately Source: https://libtmux.org/en/erlang/latest/guides/buffers/ > Preserve byte buffers and paste deliberately: libtmux_erlang documentation. Store a binary artifact without sending it through a shell, terminal renderer or Unicode conversion. Loading uses tmux client stdin; showing a buffer reads its exact bytes, including NUL, invalid UTF-8 and protocol-like lines. Run this complete program against the runner's isolated server: ```console $ mise exec -- escript tools/run_examples.escript buffers ``` ```erlang -module(buffer_demo). -moduledoc "Store a binary artifact without terminal or text conversion.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> Name = <<"libtmux-example-", (binary:encode_hex(crypto:strong_rand_bytes(8), lowercase))/binary>>, {ok, Server} = tmux_server:open( #{socket_path => Socket, executable => Executable}), tmux_scope:run_or_error(fun() -> tmux_scope:run_or_error(fun() -> Bytes = <<0, 255, "build\n%end 1 2 3\n\\r">>, {ok, _} = tmux_buffer:load(Server, Name, Bytes), {ok, Bytes} = tmux_buffer:show(Server, Name), {ok, [#{name := Name, size := Size} | _]} = tmux_buffer:list(Server), Size = byte_size(Bytes), {ok, _} = tmux_buffer:load(Server, Name, <<>>), {ok, Bytes} = tmux_buffer:show(Server, Name), #{byte_count => Size, exact_round_trip => true, empty_load_kept_bytes => true} end, fun() -> case tmux_buffer:delete(Server, Name) of {ok, _} -> ok; {error, #{code := buffer_not_found}} -> ok; Failure -> error({buffer_cleanup_failed, Failure}) end, ok end) end, fun() -> ok = tmux_server:close(Server) end). ``` ```json { "byte_count": 21, "exact_round_trip": true, "empty_load_kept_bytes": true } ``` The program uses a unique name and removes its buffer in cleanup. The runner also retires the owned server; the archive check repeats this program outside the source checkout against the installed core application. ## Choose a name or the newest buffer [`tmux_buffer:load/3`]() accepts a binary name or `automatic`, which lets tmux allocate a name. `show/2`, `delete/2` and `paste/3` accept an observed binary name or `latest`. `list/1` returns ordinary metadata maps in tmux's newest-first insertion order, with name, size in bytes and Unix creation time. It does not load payloads. Renaming keeps the order; loading replacement data inserts a new buffer. Names are NUL-free bytes. tmux 3.7+ applies its own name cleaning, which can reject controls and escape backslashes. Subsequent calls need the actual stored name from `list/1`. The list codec preserves embedded delimiters, newlines and invalid UTF-8 on releases that allow those names. It never uses a newline inside a name as a row boundary. Empty load input is a native no-op: it neither creates a buffer nor truncates an existing one. Delete explicitly when the buffer should disappear. A named rename refuses an occupied destination on tmux 3.3/3.3a; 3.4+ replaces it. Identical rename inputs fail before dispatch because some legacy versions have unsafe handling of that case. On 3.3/3.3a, native named delete/rename falls back to the newest buffer when the requested name is absent. These APIs first perform a targeted existence read with zero output allowance and return `buffer_not_found` for a missing name. The read retains no payload and is independent of list bounds. That preflight is not atomic: concurrent removal after the check can still trigger the native fallback. Serialize external changes or use tmux 3.4+ when that race is unacceptable. Buffer names do not provide stable object identities or transactional updates. ## Paste bytes into a registered pane [`tmux_buffer:paste/3`]() takes a registered pane, a buffer name or `latest`, and an options map. Defaults preserve bytes: LF separators, no sanitization, no bracketing and no deletion. Set `separator` to replace each LF with a chosen NUL-free byte string. It is passed literally, without format expansion. `sanitize => true` requires tmux 3.7+; older releases return `unsupported_capability` before dispatch. The default raw path uses `-S` on newer releases. `bracketed => true` adds markers only when the target has enabled bracketed paste. `delete => true` removes the buffer after the native paste call, including cases where native input-off handling discards input. A completed paste is a tmux command result, not proof that a child consumed input. The integration test uses a raw terminal receiver and a separate socket acknowledgment to verify all 256 byte values and custom separators. The [job guide](https://libtmux.org/en/erlang/latest/guides/operations/) explains completion signals and operation ownership. ## Bound reads and preserve errors Load input shares the endpoint's 256 KiB command admission budget with argv. `show/3` accepts `max_bytes` from 0 through 1 MiB and `deadline_ms` from 1 through 600000. Defaults are 1 MiB and 2500 ms. Overflow returns `output_limit` with partial command evidence; it never returns a successful truncated buffer. Lists are bounded to 4096 rows and 1 MiB of encoded output. Missing buffers, gone panes and closed endpoints remain distinct errors. Timeouts do not undo a completed load or paste, and mutations are not retried. [`tmux_buffer:capabilities/1`]() describes source-defined behavior without I/O; the [support page](https://libtmux.org/en/erlang/latest/guides/compatibility/) separates that metadata from qualification. --- # Read and change scoped options Source: https://libtmux.org/en/erlang/latest/guides/options/ > Read and change scoped options: libtmux_erlang documentation. Use a local user option to record which workspace created a session. Read it without inheritance when deciding whether the session belongs to that workspace. `only_if_unset` refuses an existing local value; it does not compare an expected owner or provide a workspace transaction. The complete example also sets and removes a window override, checks that the inherited value is restored, and preserves an empty sparse array entry. It opens the supplied endpoint and creates/removes its own session. The repository runner supplies an isolated server and verifies cleanup: ```console $ mise exec -- escript tools/run_examples.escript options ``` ```erlang -module(options_demo). -moduledoc "Use local options to mark workspace ownership without inheritance.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> {ok, Server} = tmux_server:open( #{socket_path => Socket, executable => Executable}), tmux_scope:run_or_error(fun() -> {ok, Session} = tmux_session:create(Server, #{name => <<"options">>, launch => #{argv => [<<"/bin/cat">>]}}), tmux_scope:run_or_error(fun() -> Owner = <<"@libtmux-owner">>, none = tmux_option:get(Session, Owner, #{}), {ok, _} = tmux_option:set(Session, Owner, <<"build-workspace">>, #{only_if_unset => true}), {ok, <<"build-workspace">>} = tmux_option:get(Session, Owner, #{}), {ok, Window} = tmux_window:create(Session, #{launch => #{argv => [<<"/bin/cat">>]}}), {ok, [<<"build-workspace">>, none]} = tmux_option:get_many([Session, Window], Owner, #{}), none = tmux_option:get(Window, <<"remain-on-exit">>, #{}), {ok, Effective} = tmux_option:get(Window, <<"remain-on-exit">>, #{inherit => true}), {ok, _} = tmux_option:set(Window, <<"remain-on-exit">>, <<"on">>), {ok, <<"on">>} = tmux_option:get(Window, <<"remain-on-exit">>, #{}), {ok, _} = tmux_option:unset(Window, <<"remain-on-exit">>), none = tmux_option:get(Window, <<"remain-on-exit">>, #{}), {ok, Effective} = tmux_option:get(Window, <<"remain-on-exit">>, #{inherit => true}), Env = <<"update-environment">>, {ok, _} = tmux_option:set(Session, {Env, 7}, <<>>), {ok, #{7 := <<>>}} = tmux_option:get(Session, Env, #{}), none = tmux_option:get(Session, {Env, 8}, #{}), #{owner => <<"build-workspace">>, restored_inheritance => true, empty_entry_preserved => true, missing_entry => true} end, fun() -> {ok, _} = tmux_session:kill(Session), ok end) end, fun() -> ok = tmux_server:close(Server) end). ``` ```json { "owner": "build-workspace", "restored_inheritance": true, "empty_entry_preserved": true, "missing_entry": true } ``` ## Select the table explicitly | Scope argument | Table | | --- | --- | | Registered session record | Local session options | | Registered physical window record | Local window options, shared by its memberships | | Registered pane record | Local pane options | | `{server, Server}` | Server-wide options | | `{session_defaults, Server}` | Global session defaults | | `{window_defaults, Server}` | Global window defaults | A physical window has no universal parent session. Session options require a session record; passing a pane to a session option fails rather than choosing an incidental session. Built-in names can override tmux's native scope flags; the wrapper checks their source metadata before dispatch to prevent that. `get/3` uses local-only reads with `#{}`. `#{inherit => true}` follows the selected table's parents: session defaults, or window/window defaults for a pane. User options follow the same table ancestry. Server options have no parent. There is no inheritance from a session table to a window table. [`tmux_option:get_many/3`]() reads one scalar key from one to seven local rows on the same registered endpoint. Results preserve input order, including `none` for absent values. The example checks session ownership and the window's independent local table together. Arrays, indexed entries, command options, global tables and names outside the batch API's ASCII grammar use `get/3`. Each batch uses one native command sequence plus the normal identity-preflight client, with native ID observations around every row's read. Aggregate stdout is limited to 1 MiB and stderr to 64 KiB, with a 2500 ms command deadline. Command or decoding failures reject the entire batch. These are interval observations: a queued reference may outlive a removed window, and target checks do not establish atomic topology or stronger server-incarnation identity. See [ADR 0003](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/docs/adr-0003-scoped-option-batches.md). ## Preserve absence and bytes `none` means the selected local option or requested array entry is absent. `{ok, <<>>}` means a known empty value. A whole array returns `{ok, Entries}` with numeric indexes as map keys; an empty local array returns `{ok, #{}}`. An unloaded graph field is unrelated to these live reads. Set array entries with `{Name, Index}`. The API deliberately avoids whole-array assignment and its separator grammar. `unset/2` removes an entry or local option; removing a local option restores inheritance. Unsetting a global built-in resets its tmux default. Non-numeric array keys are outside this API; an observed array with such keys fails decoding instead of silently dropping entries. Values are NUL-free binaries, including arbitrary bytes. Names are literal; `#{...}` in a user-option name does not expand. Prefixes, aliases and bracket syntax in names are rejected. A scalar value is passed without `-F`, although tmux may interpret a stored format or executable option later. Use this API only with trusted option names and values; it is not an external write policy. `append` uses tmux's `-a` behavior for the selected type. `only_if_unset` uses `-o` and reports already-set as an error. Empty flag values retain tmux's toggle behavior; use explicit `<<"on">>` or `<<"off">>` when state must be predictable. Mutations are not retried after a timeout or unknown outcome. ## Discover version support The [generated catalogue](https://libtmux.org/en/erlang/latest/reference/options/) lists canonical names, scopes, parser types, arrays and hooks from pinned release commits. [`tmux_option:describe/2`]() and `catalogue/1` read that metadata without I/O. Built-ins have exact source catalogues for every release from 3.3a through 3.8, including intermediate patch releases. Tracking builds and unknown versions return `unsupported_option_catalogue`; unavailable built-ins return `unsupported_tmux_option`. User options do not depend on a built-in catalogue. Hooks are executable commands and are rejected by this API, including hook names discovered in the catalogue. Use [`tmux_hook:get/3`]() to read hooks and [`tmux_hook:set/3`]() for registration; the [hook guide](https://libtmux.org/en/erlang/latest/guides/hooks/) covers their scope, execution and cleanup. Raw commands are also available for deliberate newer-version integration. A missing target remains an operational error, never a missing option. --- # Register a hook and await its effect Source: https://libtmux.org/en/erlang/latest/guides/hooks/ > Register a hook and await its effect: libtmux_erlang documentation. Register a split hook, submit a wait without blocking the Erlang caller, then split a pane. The hook writes a session option and signals the unique channel. The program checks that effect, removes the local hook and verifies cleanup. The runner owns the daemon and checks that its sessions and processes exit. Compile the project first: ```console $ mise exec -- rebar3 compile ``` Run the complete program: ```console $ mise exec -- escript tools/run_examples.escript hooks ``` ```erlang -module(hook_demo). -moduledoc "Acknowledge a registered split hook before reading its effect.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> {ok, Server} = tmux_server:open( #{socket_path => Socket, executable => Executable}), tmux_scope:run_or_error(fun() -> Launch = #{launch => #{argv => [<<"/bin/cat">>]}}, {ok, Session} = tmux_session:create(Server, Launch#{name => <<"hooks">>}), tmux_scope:run_or_error(fun() -> {ok, Snapshot} = tmux_server:snapshot(Server), [Pane] = tmux_snapshot:panes(Snapshot), Suffix = binary:encode_hex(crypto:strong_rand_bytes(8), lowercase), Channel = <<"hook-", Suffix/binary>>, {ok, Mark} = tmux_command:raw(<<"set-option">>, [<<"-t">>, tmux_model:get(id, Session), <<"@last-event">>, <<"split complete">>]), {ok, Signal} = tmux_command:wait_for(Channel, signal), {ok, Wait} = tmux_command:wait_for(Channel, wait), {ok, Operation} = tmux_operation:start(Server, Wait, #{}), tmux_scope:run_or_error(fun() -> Name = <<"after-split-window">>, {ok, _} = tmux_hook:set(Session, {Name, 4}, [Mark, Signal]), {ok, _} = tmux_pane:split(Pane, Launch), {ok, #{cleanup := complete}} = tmux_operation:await(Operation, 900), {ok, <<"split complete">>} = tmux_option:get(Session, <<"@last-event">>, #{}), {ok, #{4 := _}} = tmux_hook:get(Session, Name, #{}), {ok, _} = tmux_hook:unset(Session, Name), none = tmux_hook:get(Session, Name, #{}), #{event => <<"split complete">>, hook_acknowledged => true, local_hook_removed => true} end, fun() -> tmux_scope:run_or_error(fun() -> {ok, _} = tmux_operation:cancel(Operation) end, fun() -> case tmux_operation:await(Operation, 900) of {ok, #{cleanup := complete}} -> ok; {error, #{cleanup := complete}} -> ok end end), ok end) end, fun() -> {ok, _} = tmux_session:kill(Session), ok end) end, fun() -> ok = tmux_server:close(Server) end). ``` ```json { "event": "split complete", "hook_acknowledged": true, "local_hook_removed": true } ``` The archive check repeats this program using the installed core package. [Jobs and operations](https://libtmux.org/en/erlang/latest/guides/operations/) explains why an await timeout abandons only that wait. The program cancels and awaits its operation during cleanup even if registration or the split fails. ## Choose the table explicitly [`tmux_hook:set/3`]() requires a `{Name, Index}` key and validated [`tmux_command`]() values. It replaces that indexed entry while preserving other entries. `append/3` chooses tmux's first vacant local index, which can precede existing sparse entries. Commands run in index order. Bodies can be one command or a nonempty list; rendering is bounded before dispatch. Local tables use registered session, physical window or pane rows. Global tables use `{session_defaults, Server}` or `{window_defaults, Server}`. The [source catalogue](https://libtmux.org/en/erlang/latest/reference/options/) defines each builtin hook's permitted scope and version. Prefixes, aliases, ordinary options and custom event/monitor interfaces are rejected by this API. `get/3` reads local values by default. `inherit => true` follows parent tables. An absent local array returns `none`; an empty array returns `{ok, #{}}` and masks inheritance. `clear/2` leaves that empty override. `unset/2` removes an entry or restores inheritance for the whole array. Unsetting an entry can leave its local array empty. Global unset resets the native default. Read values are tmux's canonical command-list text, including its own quoting and escapes. They are not individual argument values or the original source text. A read never executes them. ## Separate registration, context and completion Registration confirms that tmux stored the commands. Those commands still interpret their values and formats when they run. Native parsing can fail; a failed first indexed write can already leave an empty local override. There is no rollback or automatic retry of an uncertain mutation. [`tmux_hook:run/2`]() requests native execution in an explicit context. Use a session for its current window/pane, a checked window link for one membership, or `{pane, Pane, Link}` for that pane and membership. This preserves the chosen session and index when a physical window is linked more than once. A physical window alone cannot choose that execution context. Existence and membership checks precede dispatch. If the target disappears after preflight, tmux can still fall back to another context. These separate observations do not provide atomic compare-and-act. A native command result does not acknowledge background work launched by a hook. The program waits for its own signal after the option write. Clearing or unsetting a hook does not cancel effects tmux has already queued. [Window memberships](https://libtmux.org/en/erlang/latest/concepts/object-graph/) and [scoped options](https://libtmux.org/en/erlang/latest/guides/options/) explain the related graph and inheritance rules. --- # Support and remaining gaps Source: https://libtmux.org/en/erlang/latest/guides/compatibility/ > Support and remaining gaps: libtmux_erlang documentation. Support covers tmux **3.3a–3.8**, including intermediate releases, on Linux x86_64 and arm64. The [workflow](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/.github/workflows/ci.yml) tests the oldest supported and newest stable tmux releases on both architectures. OTP 29.1.2 is the only supported Erlang baseline; older-OTP compatibility branches are not maintained. Native records remain an experimental language dependency in OTP 29. Do not persist their internals or assume compatibility with another OTP line. | Platform | tmux releases in the required matrix | | --- | --- | | Ubuntu 24.04 x86_64 | 3.3a, 3.8 | | Ubuntu 24.04 arm64 | 3.3a, 3.8 | CI uses only the latest stable Erlang/OTP release. Testing the endpoints keeps the routine matrix small; it does not exclude releases between them from support. Earlier intermediate-version results retain their recorded scope. Inspect the individual jobs at the commit you will consume. A minimum-version check does not prove runtime support on every newer release. Tracking builds, macOS, native Windows and psmux are not advertised as qualified platforms. Linux must provide readable `/proc/self/task//children`, enabled by CONFIG_PROC_CHILDREN. The helper checks this interface before launching a child. An unavailable interface returns `unsupported_capability` with `capability => proc_children`, the OS `errno` and `outcome => not_started`. See the [helper protocol](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/apps/libtmux_erlang/c_src/README.md) for cleanup evidence and the limits of native process ownership. ## Retained rows and upgrades Native model version 2 adds a private captured target association to each observed row. Actions check the entity, stable ID, origin and snapshot ID; pane associations also retain the observed window and index, and window-link associations retain their session, index and expected physical window. Actions reject edited target fields before dispatch. Valid-shaped binding mismatches return `observation_mismatch`; detached and malformed rows retain their validation errors. [`tmux_server:bind/2`]() reads the requested target and returns a new actionable row. Ordinary record matching and detached constructors remain available. The private value retains identifiers, not the snapshot graph. It prevents accidental retargeting through public row updates; it is not an authorization boundary against trusted code running inside the VM. The internal construction functions remain implementation details. Discard version-1 rows and snapshots when upgrading to model version 2. Stop consumers that retain them, clear their process/ETS state and freshly observe the server after restart. This release supplies no `appup`/`relup` conversion. Old or unknown model versions fail row validation. New code must validate a retained value before accessing fields added by another model version. Every exported-field addition, rename, removal or default change requires a model compatibility review independently of the OTP version. Its changelog must state whether retained values remain usable, need an explicit validated conversion, or must be discarded. Do not assume hot loading changes fields in existing native values. [`tmux_model:to_map/1`]() extracts the documented domain fields from a valid row. Validate those fields with the destination model's constructor when migrating data. The map loses actionable provenance; bind it through a freshly constructed row before an action. It is not a versioned storage or cross-port wire format: absence atoms, binary bytes and field inventories still require an application-defined schema. ## Implemented surfaces | Surface | Current behavior | | --- | --- | | Model | Exported native session/window/window-link/pane records; runtime validation | | Capture | Immutable complete graph, coverage, ordering, conflict detection and read intervals | | Local query | Map predicates, Boolean callbacks, quantifiers, cardinality and bounded JSON | | Source query | Explicit plans/fetch, conservative candidates, full residuals and final limits | | Operations | Bounded one-shot submission, waits, cancellation, transfer and cleanup | | Control attachment | Explicit session, same-connection identity, no-output/ignore-size, skipped environment update and separate native cleanup | | Daemon ownership | Empty private startup, separate ownership token, caller lifetime, explicit stop and identity-checked namespace cleanup | | Domain commands | Initial create/read/rename/kill calls, explicit client/session selection, checked window memberships, pane split/break/join/move/swap/resize, pane/window respawn, window layouts, literal/key input and capture | | Options | Explicit local/global tables, local or inherited reads, indexed writes/unsets and generated source metadata; hooks remain outside the option API | | Hooks | Versioned builtin arrays, indexed command values, inheritance and explicit execution contexts | | Buffers | Named or automatic binary load, exact show, metadata lists, delete/rename and paste; native version differences are explicit | | Server utilities | Command values for literal source-file/stdin configuration and native [wait-for](https://libtmux.org/en/tmux/latest/manual/wait-for/) signals, waits and explicit advisory locks | | Pane pipe | Literal shell command, output/input/both directions, native toggle and explicit stop; tmux-owned process and delivery checks | The [examples](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/examples) exercise the current public API. Real integration checks use private sockets and verify owned process retirement. A captured row can disappear before an action; stable IDs are not permission to reinterpret a missing target positionally. ## Not yet shipped Control command submission and groups and output subscriptions/streams remain implementation work. Workspace planning/apply and the CLI use the one-shot path. The [workspace guide](https://libtmux.org/en/erlang/latest/guides/workspace-json/) includes executable loader and apply examples. SIGTERM exercises explicit cancellation and returns JSON. Installed-consumer checks also cover terminal Ctrl-C and SIGKILL: both exit by signal without a receipt, retire observed helper/client processes, and preserve the borrowed server and existing panes. Remote steps can remain applied and temporary files can remain; see [CLI interruption](https://libtmux.org/en/erlang/latest/guides/workspace-json/#interrupt-the-cli). Complete performance qualification remains open. MCP packages, servers and SDK integration are excluded by [project policy](https://libtmux.org/en/erlang/latest/topics/project-policy/). Typed command coverage, generated capability inventory, registry delivery, public cross-port filter conformance, published native API pages, shared-site documentation and independent implementation reviews remain open. Current test success does not pass those unfinished surfaces. No registry or documentation publication is claimed. ## Source installation The [source-package check](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/tools/check_source_package.py) builds each application separately with pinned `rebar3_hex` tooling. It serves the exact tarballs through a signed local registry, then creates a fresh Rebar3 consumer whose only dependency is workspace. Core must resolve transitively and compile its helper from packaged C source. Missing compiler support fails installation. The installed examples, native-record imports, model-upgrade check and owned transport checks run against that consumer. CI runs this gate on both supported architectures with tmux 3.3a and 3.8. Inspect its receipt for the commit being consumed. These local source artifacts retain the development version; the check neither publishes to Hex nor proves an independently retrieved registry release. The older compiled-archive check remains separate evidence for its own payload. ## Performance evidence The current suite checks behavior and resource limits. It does not establish a control/grouping/streaming comparison because those execution lanes are not implemented. Any published benchmark must compare equal workloads and values, state the source/tool/platform identities, and report errors and cleanup as well as time. Test-loop durations are not throughput benchmarks. --- # Workspace JSON loader Source: https://libtmux.org/en/erlang/latest/guides/workspace-json/ > Workspace JSON loader: libtmux_erlang documentation. Load desired sessions, windows and panes with the workspace application's load function, then inspect the normalized graph with its to_map function. The workspace application depends on the core's public JSON API and OTP libraries. Loading performs filesystem I/O. Planning observes tmux without mutations; applying executes the saved operations. The standalone CLI uses the same workspace application and the core's public one-shot operations. ## Describe the desired graph [This input file](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/examples/workspace.json) declares one session, one window and two panes. `endpoint` names a host-configured connection; it cannot choose a socket. `argv` is literal executable data. `shell` explicitly requests shell syntax. Apply requires both the plan's shell opt-in and host policy approval. ```json { "version": 1, "id": "demo", "endpoint": "dev", "sessions": [ { "name": "editor", "windows": [ { "name": "api", "layout": "even-horizontal", "panes": [ {"cwd": ".", "argv": ["rebar3", "shell"]}, {"cwd": ".", "shell": "exec erl"} ] } ] } ] } ``` Relative working directories use the canonical workspace file directory. Symlinks resolve before `..`; directories must already exist. There is no environment interpolation. Each pane requires exactly one launch form. An explicit `id` keeps workspace identity stable when moving the file. Otherwise the loader hashes its canonical filename. Optional entity `key` fields identify sessions, windows and panes across edits. Without a key, the loader uses the entry's JSON pointer; reordering entries changes identity. Keys must be unique across the workspace. Explicit keys preserve identity when reordering entries. Apply orders managed windows and panes as listed, preserving unmanaged resources. Changing argv or cwd plans a respawn: it replaces that pane's running process. Current command names cannot reconstruct the original launch. ## Build the CLI Use the pinned OTP and Rebar3 toolchain plus the Linux C11 build prerequisites in [Contributing](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/.github/CONTRIBUTING.md#setup). From this source checkout: ```console $ mise exec -- rebar3 escriptize ``` Inspect the command help: ```console $ mise exec -- _build/default/bin/libtmux-workspace --help ``` The resulting escript includes the compiled helper, its MIT license and source provenance. Each invocation materializes those assets in an owned temporary directory, starts its core application, closes its endpoint and removes the directory before returning its JSON result. BEAM modules remain in the archive. Run the copied escript with OTP 29.1.2 installed on the same Linux architecture. It needs neither a compiler nor this checkout at runtime. Registry publication is a separate gate; no published workspace version is claimed here. ## Configure the endpoint Create a trusted host configuration file. Replace the socket path below with the absolute path of your existing tmux server; no default server is selected or started. The optional executable is an absolute tmux path, otherwise PATH selects it. Workspace input cannot override either path. ```json { "version": 1, "allowShell": false, "endpoints": { "dev": {"socketPath": "/tmp/project/tmux.sock"} } } ``` Save that file as host.json. The CLI also accepts LIBTMUX_WORKSPACE_CONFIG when the config option is omitted. Shell launches need host allowShell true and an explicit allow-shell option when creating the plan. ## Review a plan, then execute it The [argv-only example](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/examples/workspace_apply.json) declares a session, one window and two long-lived panes. Replace cat with your own programs after trying the complete owned-server example below. From the checkout, plan it: ```console $ mise exec -- _build/default/bin/libtmux-workspace plan \ examples/workspace_apply.json \ --config host.json \ --output plan.json ``` Planning writes canonical JSON with mode 0600 and prints its hash and step count. The file records stable targets, ownership, preconditions, schema and input hashes. It retains the source filename and observed names, while omitting launch argv, shell text and cwd. Review it before applying: ```console $ mise exec -- _build/default/bin/libtmux-workspace apply plan.json \ --config host.json ``` Apply reloads the desired file and verifies its hash. It checks that the stored operations follow from that file and the stored observation, then executes exactly those operations. Fresh state can reject the plan; it never supplies replacement operations. Each step checks IDs, names, memberships, pane order, layouts and ownership before and after its command. Captures span commands, so concurrent changes can still intervene. There is no atomic reservation, automatic retry or terminal-effect rollback. Ownership reads group up to seven rows of one entity kind per native sequence, using [`tmux_option:get_many/3`]() with inheritance disabled. At most three workers run concurrently, retaining the captured row order. Every row's metadata is still read; graph observations and per-step preconditions remain. Cancellation stops the next worker batch and drains reads already in flight before returning. The core deadline applies to each native sequence; there is no additional workspace batch deadline. Lost results leave cleanup unverified, and a later cleanup failure remains visible alongside an earlier metadata error. [ADR 0003](https://github.com/libtmux/libtmux-erlang/blob/d1b6308440cf9eb8f6647e7ae434bce60e849368/docs/adr-0003-scoped-option-batches.md) records the client-cost tradeoff and interval semantics. Pane creation uses fixed targets and the saved unzoomed layout. It distributes splits across tiled cells, then applies the requested arrangement and pane order. Floating cells are excluded. For a new window, the plan stores a breadth-first target schedule; apply chooses the longer usable axis from each checked cell. Available area and options such as reserved scrollbars can still reject a split. The failure retains the completed prefix; apply never substitutes another target. A pane count within the file limit does not promise that the server's window geometry can accommodate it. Run the plan command again with unchanged managed state: its step count is zero. An existing untagged session/window name instead conflicts. To adopt it, add one adopt option for each explicit resource key you intend to manage; pane adoption respawns its ordered target. Linked windows with another membership, duplicate ownership and missing/tampered metadata conflict. Removal requires matching ownership for the whole affected subtree. ### Interrupt the CLI Completed CLI calls write one JSON line to stdout; help writes text. OTP diagnostics use stderr. Exit codes are 0 for success, 2 for validation, 3 for changed input or observed conflict, and 4 for operational failure, cancellation or uncertain outcome. Failures retain the verified completed prefix and native command outcome separately. A native creation can return success while its process exits before observation; that returns creation_not_observed with the reported IDs for explicit recovery. SIGTERM requests cancellation and waits for owned client cleanup. A command possibly delivered to tmux can return unknown; earlier steps remain applied. Ctrl-C sends SIGINT. OTP 29's escript launcher disables the VM break handler, so the standalone CLI exits by signal without a JSON receipt. SIGKILL also returns no receipt. These exits retire observed helpers and tmux clients in the installed-consumer checks; the borrowed server and existing panes remain. Completed remote steps remain applied. Abrupt exit can leave the CLI's private temporary directory behind, so callers must not infer rollback or file cleanup from process exit. See the [OTP escript launcher](https://github.com/erlang/otp/blob/OTP-29.1.2/erts/etc/common/escript.c#L509-L522) and [emulator flags](https://www.erlang.org/doc/apps/erts/erl_cmd.html#emulator-flags). Cancellation in Erlang uses an application-owned reference and a cancel message, as documented by the apply module. The initial execution strategy recaptures the complete projected graph per step. It favors drift detection over source-call cost; large-workspace performance remains unqualified. See [snapshot costs](https://libtmux.org/en/erlang/latest/concepts/queries/). ## Run the complete apply example This program owns its tmux server, applies a real input/plan file, inspects the resulting object graph and verifies an empty second plan. Scope cleanup keeps operation and cleanup failures together, then retires the owned server. ```console $ mise exec -- escript tools/run_examples.escript workspace-apply ``` ```erlang -module(workspace_apply_demo). -moduledoc "Apply a workspace and verify an empty second plan.". -export([run/1]). -spec run(binary()) -> map(). run(Executable) -> Suffix = binary:encode_hex(crypto:strong_rand_bytes(10), lowercase), Directory = <<"/tmp/ltm-workspace-apply-", Suffix/binary>>, ok = file:make_dir(Directory), Result = tmux_scope:run_or_error(fun() -> ok = file:change_mode(Directory, 8#700), Source = filename:join(Directory, <<"workspace.json">>), PlanFile = filename:join(Directory, <<"plan.json">>), {ok, _} = file:copy("examples/workspace_apply.json", Source), {ok, Output} = tmux_server:with_owned(#{executable => Executable}, fun(Server) -> {ok, Plan} = tmux_workspace_plan:new(Source, Server, #{}), ok = tmux_workspace_plan:write(Plan, PlanFile), {ok, Stored} = tmux_workspace_plan:read(PlanFile), {ok, #{completed := Completed}} = tmux_workspace_apply:run(Stored, Server, #{}), true = length(Completed) > 0, {ok, Snapshot} = tmux_server:snapshot(Server), [Session] = tmux_snapshot:sessions(Snapshot), <<"project">> = tmux_model:get(name, Session), {ok, [Window]} = tmux_snapshot:related(windows, Session, Snapshot), <<"api">> = tmux_model:get(name, Window), {ok, Panes} = tmux_snapshot:related(panes, Window, Snapshot), 2 = length(Panes), {ok, Settled} = tmux_workspace_plan:new(Source, Server, #{}), #{<<"steps">> := []} = tmux_workspace_plan:to_map(Settled), {ok, #{completed := []}} = tmux_workspace_apply:run(Settled, Server, #{}), #{sessions => 1, windows => 1, panes => 2, plan_round_trip => true, second_plan_empty => true} end), Output end, fun() -> file:del_dir_r(Directory) end), {error, enoent} = file:read_file_info(Directory), Result#{files_removed => true}. ``` ```json { "sessions": 1, "windows": 1, "panes": 2, "plan_round_trip": true, "second_plan_empty": true, "files_removed": true } ``` ## Read and inspect it Compile this checkout first: ```console $ mise exec -- rebar3 compile ``` Run the complete program below: ```console $ mise exec -- escript tools/run_examples.escript workspace ``` The program copies the real JSON file to an owned temporary directory, checks the desired object graph and canonical cwd, and verifies removal of its files. The outer check repeats it using installed core and workspace OTP archives. ```erlang -module(workspace_demo). -moduledoc "Load a real workspace file and inspect its desired object graph.". -export([run/0]). -spec run() -> map(). run() -> Suffix = binary:encode_hex(crypto:strong_rand_bytes(10), lowercase), Directory = <<"/tmp/ltm-workspace-demo-", Suffix/binary>>, ok = file:make_dir(Directory), Output = tmux_scope:run_or_error(fun() -> ok = file:change_mode(Directory, 8#700), Path = filename:join(Directory, <<"workspace.json">>), {ok, _} = file:copy("examples/workspace.json", Path), {ok, Workspace} = tmux_workspace:load(Path), #{id := Id, endpoint := Endpoint, sessions := [Session]} = tmux_workspace:to_map(Workspace), #{name := SessionName, windows := [Window]} = Session, #{name := WindowName, layout := <<"even-horizontal">>, panes := [Build, Shell]} = Window, #{cwd := Directory, launch := #{argv := Arguments}} = Build, [<<"rebar3">>, <<"shell">>] = Arguments, #{cwd := Directory, launch := #{shell := <<"exec erl">>}} = Shell, #{workspace_id => Id, endpoint => Endpoint, session => SessionName, window => WindowName, panes => 2, first_pane_key => maps:get(key, Build), canonical_cwd => true, shell_declared => true, launched => false} end, fun() -> ok = file:del_dir_r(Directory) end), {error, enoent} = file:read_file_info(Directory), Output#{files_removed => true}. ``` ```json { "workspace_id": "demo", "endpoint": "dev", "session": "editor", "window": "api", "panes": 2, "first_pane_key": "/sessions/0/windows/0/panes/0", "canonical_cwd": true, "shell_declared": true, "launched": false, "files_removed": true } ``` ## Handle validation failures Errors include a source basename, a `code` and a JSON `path` with zero-based array indexes. Unknown fields, duplicate JSON object keys and duplicate entity keys fail before any tmux operation. A pane with both launch forms returns `ambiguous_launch`; a nonexistent directory returns `invalid_directory`. The loader accepts version 1, at most 256 KiB of JSON and 32 nested containers. Collections contain 1–64 entries and a workspace has at most 2048 entities. IDs and keys use at most 128 UTF-8 bytes; names use at most 256. Names exclude controls and backslashes; session names also exclude periods and colons because tmux rewrites them. Launch argv has at most 256 elements and a 32 KiB aggregate bound. Layouts use the five standard named tmux arrangements. Local filesystem checks are synchronous and assume trusted directories. They provide byte bounds and canonicalization, not a filesystem sandbox, an I/O deadline or protection against concurrent replacement of path entries. See the [API browser](https://libtmux.org/en/erlang/latest/guides/api-documentation/) for native types and [project policy](https://libtmux.org/en/erlang/latest/topics/project-policy/) for application boundaries. --- # Linking and consuming our docs Source: https://libtmux.org/en/erlang/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/erlang/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/erlang/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/erlang/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/erlang/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. --- # Command capabilities Source: https://libtmux.org/en/erlang/latest/reference/commands/ > Command capabilities: libtmux_erlang documentation. Generated from pinned tmux source profiles. These are native parser declarations, not an inventory of implemented Erlang facades, complete argument validation or runtime qualification. Canonical names are lookup keys; aliases are reported as metadata. The [`m:tmux_capability`]() performs pure lookups. Trusted raw commands remain available through [`tmux_command:raw/2`](). ## Capability minimums Capability minimums name the earliest catalogued source profile for each feature. Runtime support covers tmux 3.3a–3.8, including intermediate releases. Routine CI samples only 3.3a and 3.8 on both supported architectures. See [compatibility](https://libtmux.org/en/erlang/latest/guides/compatibility/) for platform and API qualification. | Capability | Minimum tmux | Native behavior | | --- | --- | --- | | `key_list_format` | 3.7 | Native [list-keys](https://libtmux.org/en/tmux/latest/manual/list-keys/) -F custom formatting. | | `layout_json` | 3.8 | Native JSON layout parsing, including the v2 layout representation. | | `native_list_filter` | 3.3 | Native -f filters on session, window and pane list commands. | | `send_client_keys` | 3.4 | Native [send-keys](https://libtmux.org/en/tmux/latest/manual/send-keys/) -K and -c for client-directed key input. | ## Source profiles Exact parser discovery uses the profiles below. The 3.3 profile is retained as upstream history; the library's runtime floor is 3.3a. | Profile | Pinned command table | Commands | | --- | --- | --- | | 3.3 | [Source](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/cmd.c) | 90 | | 3.3a | [Source](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/cmd.c) | 90 | | 3.4 | [Source](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/cmd.c) | 90 | | 3.5 | [Source](https://github.com/tmux/tmux/blob/ac44566c9c7e3e94d23be6def4c7ae83472543f5/cmd.c) | 90 | | 3.5a | [Source](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd.c) | 90 | | 3.6 | [Source](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/cmd.c) | 90 | | 3.6a | [Source](https://github.com/tmux/tmux/blob/cc117b5048f77a4842820f8ebbe3a86e5c077224/cmd.c) | 90 | | 3.6b | [Source](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd.c) | 90 | | 3.7 | [Source](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/cmd.c) | 91 | | 3.7a | [Source](https://github.com/tmux/tmux/blob/0e418b62d259ce8da8970f75732cc6632ee4c3a0/cmd.c) | 91 | | 3.7b | [Source](https://github.com/tmux/tmux/blob/e802909de06012a4df6209d55e86487c56223163/cmd.c) | 91 | | 3.7c | [Source](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd.c) | 91 | | 3.8 | [Source](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd.c) | 92 | ## Parser declarations The argument spec is tmux's native flag declaration. Positional bounds exclude flags; an unlimited upper bound is shown as unbounded. Callbacks and command bodies can impose additional constraints. This catalogue does not interpret formats, shell commands or stored command syntax. | Command | Alias | Profiles | Argument spec | Positionals | Source | | --- | --- | --- | --- | --- | --- | | [`attach-session`](https://libtmux.org/en/tmux/latest/manual/attach-session/) | attach | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `c:dEf:rt:x` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-attach-session.c) | | [`bind-key`](https://libtmux.org/en/tmux/latest/manual/bind-key/) | bind | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `nrN:T:` | 1..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-bind-key.c) | | [`break-pane`](https://libtmux.org/en/tmux/latest/manual/break-pane/) | breakp | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `abdPF:n:s:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-break-pane.c) | | [`break-pane`](https://libtmux.org/en/tmux/latest/manual/break-pane/) | breakp | 3.8 | `abdPF:n:s:t:Wx:X:y:Y:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-break-pane.c) | | [`capture-pane`](https://libtmux.org/en/tmux/latest/manual/capture-pane/) | capturep | 3.3, 3.3a | `ab:CeE:JNpPqS:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/cmd-capture-pane.c) | | [`capture-pane`](https://libtmux.org/en/tmux/latest/manual/capture-pane/) | capturep | 3.4, 3.5, 3.5a | `ab:CeE:JNpPqS:Tt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd-capture-pane.c) | | [`capture-pane`](https://libtmux.org/en/tmux/latest/manual/capture-pane/) | capturep | 3.6, 3.6a, 3.6b | `ab:CeE:JMNpPqS:Tt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-capture-pane.c) | | [`capture-pane`](https://libtmux.org/en/tmux/latest/manual/capture-pane/) | capturep | 3.7, 3.7a, 3.7b, 3.7c | `ab:CeE:FHJLMNpPqS:Tt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-capture-pane.c) | | [`capture-pane`](https://libtmux.org/en/tmux/latest/manual/capture-pane/) | capturep | 3.8 | `ab:CeE:FHIJLMNpPqRS:Tt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-capture-pane.c) | | [`choose-buffer`](https://libtmux.org/en/tmux/latest/manual/choose-buffer/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a | `F:f:K:NO:rt:Z` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd-choose-tree.c) | | [`choose-buffer`](https://libtmux.org/en/tmux/latest/manual/choose-buffer/) | — | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `F:f:K:NO:rt:yZ` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-choose-tree.c) | | [`choose-buffer`](https://libtmux.org/en/tmux/latest/manual/choose-buffer/) | — | 3.8 | `F:f:K:kNO:rt:yZ` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-choose-tree.c) | | [`choose-client`](https://libtmux.org/en/tmux/latest/manual/choose-client/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a | `F:f:K:NO:rt:Z` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd-choose-tree.c) | | [`choose-client`](https://libtmux.org/en/tmux/latest/manual/choose-client/) | — | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `F:f:K:NO:rt:yZ` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-choose-tree.c) | | [`choose-client`](https://libtmux.org/en/tmux/latest/manual/choose-client/) | — | 3.8 | `F:f:hiK:kNO:rt:yZ` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-choose-tree.c) | | [`choose-tree`](https://libtmux.org/en/tmux/latest/manual/choose-tree/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a | `F:f:GK:NO:rst:wZ` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd-choose-tree.c) | | [`choose-tree`](https://libtmux.org/en/tmux/latest/manual/choose-tree/) | — | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `F:f:GK:NO:rst:wyZ` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-choose-tree.c) | | [`choose-tree`](https://libtmux.org/en/tmux/latest/manual/choose-tree/) | — | 3.8 | `F:f:GhK:kNO:rst:wyZ` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-choose-tree.c) | | [`clear-history`](https://libtmux.org/en/tmux/latest/manual/clear-history/) | clearhist | 3.3, 3.3a | `t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/cmd-capture-pane.c) | | [`clear-history`](https://libtmux.org/en/tmux/latest/manual/clear-history/) | clearhist | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `Ht:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-capture-pane.c) | | [`clear-prompt-history`](https://libtmux.org/en/tmux/latest/manual/clear-prompt-history/) | clearphist | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `T:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-show-prompt-history.c) | | [`clock-mode`](https://libtmux.org/en/tmux/latest/manual/clock-mode/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-copy-mode.c) | | [`command-prompt`](https://libtmux.org/en/tmux/latest/manual/command-prompt/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a | `1bFkiI:Np:t:T:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd-command-prompt.c) | | [`command-prompt`](https://libtmux.org/en/tmux/latest/manual/command-prompt/) | — | 3.6, 3.6a, 3.6b | `1bFkliI:Np:t:T:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-command-prompt.c) | | [`command-prompt`](https://libtmux.org/en/tmux/latest/manual/command-prompt/) | — | 3.7, 3.7a, 3.7b, 3.7c | `1CbeFiklI:Np:t:T:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-command-prompt.c) | | [`command-prompt`](https://libtmux.org/en/tmux/latest/manual/command-prompt/) | — | 3.8 | `1CbeFiklI:NPp:t:T:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-command-prompt.c) | | [`confirm-before`](https://libtmux.org/en/tmux/latest/manual/confirm-before/) | confirm | 3.3, 3.3a | `bp:t:` | 1..1 | [Declaration](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/cmd-confirm-before.c) | | [`confirm-before`](https://libtmux.org/en/tmux/latest/manual/confirm-before/) | confirm | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `bc:p:t:y` | 1..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-confirm-before.c) | | [`copy-mode`](https://libtmux.org/en/tmux/latest/manual/copy-mode/) | — | 3.3, 3.3a, 3.4 | `eHMs:t:uq` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/cmd-copy-mode.c) | | [`copy-mode`](https://libtmux.org/en/tmux/latest/manual/copy-mode/) | — | 3.5, 3.5a | `deHMs:t:uq` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd-copy-mode.c) | | [`copy-mode`](https://libtmux.org/en/tmux/latest/manual/copy-mode/) | — | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `deHMqSs:t:u` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-copy-mode.c) | | [`copy-mode`](https://libtmux.org/en/tmux/latest/manual/copy-mode/) | — | 3.8 | `dekHMqSs:t:u` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-copy-mode.c) | | [`customize-mode`](https://libtmux.org/en/tmux/latest/manual/customize-mode/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a | `F:f:Nt:Z` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd-choose-tree.c) | | [`customize-mode`](https://libtmux.org/en/tmux/latest/manual/customize-mode/) | — | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `F:f:Nt:yZ` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-choose-tree.c) | | [`customize-mode`](https://libtmux.org/en/tmux/latest/manual/customize-mode/) | — | 3.8 | `F:f:kNt:yZ` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-choose-tree.c) | | [`delete-buffer`](https://libtmux.org/en/tmux/latest/manual/delete-buffer/) | deleteb | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `b:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-set-buffer.c) | | [`detach-client`](https://libtmux.org/en/tmux/latest/manual/detach-client/) | detach | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `aE:s:t:P` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-detach-client.c) | | [`display-menu`](https://libtmux.org/en/tmux/latest/manual/display-menu/) | menu | 3.3, 3.3a | `c:t:OT:x:y:` | 1..unbounded | [Declaration](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/cmd-display-menu.c) | | [`display-menu`](https://libtmux.org/en/tmux/latest/manual/display-menu/) | menu | 3.4 | `b:c:C:H:s:S:Ot:T:x:y:` | 1..unbounded | [Declaration](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/cmd-display-menu.c) | | [`display-menu`](https://libtmux.org/en/tmux/latest/manual/display-menu/) | menu | 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `b:c:C:H:s:S:MOt:T:x:y:` | 1..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-display-menu.c) | | [`display-message`](https://libtmux.org/en/tmux/latest/manual/display-message/) | display | 3.3, 3.3a | `ac:d:INpt:F:v` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/cmd-display-message.c) | | [`display-message`](https://libtmux.org/en/tmux/latest/manual/display-message/) | display | 3.4, 3.5, 3.5a | `ac:d:lINpt:F:v` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd-display-message.c) | | [`display-message`](https://libtmux.org/en/tmux/latest/manual/display-message/) | display | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `aCc:d:lINpt:F:v` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-display-message.c) | | [`display-message`](https://libtmux.org/en/tmux/latest/manual/display-message/) | display | 3.8 | `aCc:d:jlINpt:F:v` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-display-message.c) | | [`display-panes`](https://libtmux.org/en/tmux/latest/manual/display-panes/) | displayp | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `bd:Nt:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-display-panes.c) | | [`display-panes`](https://libtmux.org/en/tmux/latest/manual/display-panes/) | displayp | 3.8 | `d:kNs:t:Z` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-choose-tree.c) | | [`display-popup`](https://libtmux.org/en/tmux/latest/manual/display-popup/) | popup | 3.3, 3.3a, 3.4, 3.5, 3.5a | `Bb:Cc:d:e:Eh:s:S:t:T:w:x:y:` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd-display-menu.c) | | [`display-popup`](https://libtmux.org/en/tmux/latest/manual/display-popup/) | popup | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `Bb:Cc:d:e:Eh:kNs:S:t:T:w:x:y:` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-display-menu.c) | | [`find-window`](https://libtmux.org/en/tmux/latest/manual/find-window/) | findw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `CiNrt:TZ` | 1..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-find-window.c) | | [`has-session`](https://libtmux.org/en/tmux/latest/manual/has-session/) | has | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-new-session.c) | | [`if-shell`](https://libtmux.org/en/tmux/latest/manual/if-shell/) | if | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `bFt:` | 2..3 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-if-shell.c) | | [`join-pane`](https://libtmux.org/en/tmux/latest/manual/join-pane/) | joinp | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `bdfhvp:l:s:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-join-pane.c) | | [`kill-pane`](https://libtmux.org/en/tmux/latest/manual/kill-pane/) | killp | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `at:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-kill-pane.c) | | [`kill-pane`](https://libtmux.org/en/tmux/latest/manual/kill-pane/) | killp | 3.8 | `af:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-kill-pane.c) | | [`kill-server`](https://libtmux.org/en/tmux/latest/manual/kill-server/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-kill-server.c) | | `kill-session` | — | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `aCt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-kill-session.c) | | `kill-session` | — | 3.7, 3.7a, 3.7b, 3.7c | `aCgt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-kill-session.c) | | `kill-session` | — | 3.8 | `aCgf:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-kill-session.c) | | `kill-window` | killw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `at:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-kill-window.c) | | `kill-window` | killw | 3.8 | `af:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-kill-window.c) | | `last-pane` | lastp | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `det:Z` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-select-pane.c) | | `last-window` | last | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-select-window.c) | | `link-window` | linkw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `abdks:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-move-window.c) | | `list-buffers` | lsb | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `F:f:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-list-buffers.c) | | `list-buffers` | lsb | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `F:f:O:r` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-list-buffers.c) | | `list-clients` | lsc | 3.3, 3.3a | `F:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/cmd-list-clients.c) | | `list-clients` | lsc | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `F:f:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-list-clients.c) | | `list-clients` | lsc | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `F:f:O:rt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-list-clients.c) | | `list-commands` | lscm | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `F:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-list-keys.c) | | `list-commands` | lscm | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `F:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-list-commands.c) | | `list-keys` | lsk | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `1aNP:T:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-list-keys.c) | | `list-keys` | lsk | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `1aF:NO:P:rT:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-list-keys.c) | | `list-panes` | lsp | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `asF:f:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-list-panes.c) | | `list-panes` | lsp | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `aF:f:O:rst:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-list-panes.c) | | `list-sessions` | ls | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `F:f:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-list-sessions.c) | | `list-sessions` | ls | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `F:f:O:r` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-list-sessions.c) | | `list-windows` | lsw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `F:f:at:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-list-windows.c) | | `list-windows` | lsw | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `aF:f:O:rt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-list-windows.c) | | `load-buffer` | loadb | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `b:t:w` | 1..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-load-buffer.c) | | `lock-client` | lockc | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-lock-server.c) | | `lock-server` | lock | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-lock-server.c) | | [`lock-session`](https://libtmux.org/en/tmux/latest/manual/lock-session/) | locks | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-lock-server.c) | | [`move-pane`](https://libtmux.org/en/tmux/latest/manual/move-pane/) | movep | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `bdfhvp:l:s:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-join-pane.c) | | [`move-pane`](https://libtmux.org/en/tmux/latest/manual/move-pane/) | movep | 3.8 | `bdD::fhMvl:L::P:R::s:t:U::X:Y:z:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-join-pane.c) | | [`move-window`](https://libtmux.org/en/tmux/latest/manual/move-window/) | movew | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `abdkrs:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-move-window.c) | | [`new-pane`](https://libtmux.org/en/tmux/latest/manual/new-pane/) | newp | 3.7, 3.7a, 3.7b, 3.7c | `bc:de:EfF:hIkl:Lm:p:PR:s:S:t:vx:X:y:Y:Z` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-split-window.c) | | [`new-pane`](https://libtmux.org/en/tmux/latest/manual/new-pane/) | newp | 3.8 | `AbB:Cc:Dde:EfF:hIkl:KLMm:Op:PR:s:S:t:T:vWx:X:y:Y:Z` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-split-window.c) | | [`new-session`](https://libtmux.org/en/tmux/latest/manual/new-session/) | new | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `Ac:dDe:EF:f:n:Ps:t:x:Xy:` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-new-session.c) | | [`new-window`](https://libtmux.org/en/tmux/latest/manual/new-window/) | neww | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `abc:de:F:kn:PSt:` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-new-window.c) | | [`new-window`](https://libtmux.org/en/tmux/latest/manual/new-window/) | neww | 3.8 | `abc:de:EF:kn:PSt:` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-new-window.c) | | [`next-layout`](https://libtmux.org/en/tmux/latest/manual/next-layout/) | nextl | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-select-layout.c) | | [`next-window`](https://libtmux.org/en/tmux/latest/manual/next-window/) | next | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `at:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-select-window.c) | | [`paste-buffer`](https://libtmux.org/en/tmux/latest/manual/paste-buffer/) | pasteb | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `db:prs:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-paste-buffer.c) | | [`paste-buffer`](https://libtmux.org/en/tmux/latest/manual/paste-buffer/) | pasteb | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `db:prSs:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-paste-buffer.c) | | [`pipe-pane`](https://libtmux.org/en/tmux/latest/manual/pipe-pane/) | pipep | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `IOot:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-pipe-pane.c) | | [`previous-layout`](https://libtmux.org/en/tmux/latest/manual/previous-layout/) | prevl | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-select-layout.c) | | [`previous-window`](https://libtmux.org/en/tmux/latest/manual/previous-window/) | prev | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `at:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-select-window.c) | | [`refresh-client`](https://libtmux.org/en/tmux/latest/manual/refresh-client/) | refresh | 3.3, 3.3a, 3.4 | `A:B:cC:Df:F:l::LRSt:U` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/cmd-refresh-client.c) | | [`refresh-client`](https://libtmux.org/en/tmux/latest/manual/refresh-client/) | refresh | 3.5, 3.5a, 3.6, 3.6a, 3.6b | `A:B:cC:Df:r:F:l::LRSt:U` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-refresh-client.c) | | [`refresh-client`](https://libtmux.org/en/tmux/latest/manual/refresh-client/) | refresh | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `A:B:cC:Df:r:F:lLRSt:U` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-refresh-client.c) | | [`rename-session`](https://libtmux.org/en/tmux/latest/manual/rename-session/) | rename | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:` | 1..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-rename-session.c) | | [`rename-window`](https://libtmux.org/en/tmux/latest/manual/rename-window/) | renamew | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:` | 1..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-rename-window.c) | | [`resize-pane`](https://libtmux.org/en/tmux/latest/manual/resize-pane/) | resizep | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `DLMRTt:Ux:y:Z` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-resize-pane.c) | | [`resize-pane`](https://libtmux.org/en/tmux/latest/manual/resize-pane/) | resizep | 3.8 | `D::L::MR::Tt:U::x:y:Z` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-resize-pane.c) | | [`resize-window`](https://libtmux.org/en/tmux/latest/manual/resize-window/) | resizew | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `aADLRt:Ux:y:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-resize-window.c) | | [`respawn-pane`](https://libtmux.org/en/tmux/latest/manual/respawn-pane/) | respawnp | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `c:e:kt:` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-respawn-pane.c) | | [`respawn-pane`](https://libtmux.org/en/tmux/latest/manual/respawn-pane/) | respawnp | 3.8 | `c:e:Ekt:` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-respawn-pane.c) | | [`respawn-window`](https://libtmux.org/en/tmux/latest/manual/respawn-window/) | respawnw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `c:e:kt:` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-respawn-window.c) | | [`respawn-window`](https://libtmux.org/en/tmux/latest/manual/respawn-window/) | respawnw | 3.8 | `c:e:Ekt:` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-respawn-window.c) | | [`rotate-window`](https://libtmux.org/en/tmux/latest/manual/rotate-window/) | rotatew | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `Dt:UZ` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-rotate-window.c) | | [`run-shell`](https://libtmux.org/en/tmux/latest/manual/run-shell/) | run | 3.3, 3.3a | `bd:Ct:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/cmd-run-shell.c) | | [`run-shell`](https://libtmux.org/en/tmux/latest/manual/run-shell/) | run | 3.4, 3.5, 3.5a | `bd:Ct:c:` | 0..2 | [Declaration](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/cmd-run-shell.c) | | [`run-shell`](https://libtmux.org/en/tmux/latest/manual/run-shell/) | run | 3.6, 3.6a, 3.6b | `bd:Ct:Es:c:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-run-shell.c) | | [`run-shell`](https://libtmux.org/en/tmux/latest/manual/run-shell/) | run | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `bd:Ct:Es:c:` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-run-shell.c) | | [`save-buffer`](https://libtmux.org/en/tmux/latest/manual/save-buffer/) | saveb | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `ab:` | 1..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-save-buffer.c) | | [`select-layout`](https://libtmux.org/en/tmux/latest/manual/select-layout/) | selectl | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `Enopt:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-select-layout.c) | | [`select-pane`](https://libtmux.org/en/tmux/latest/manual/select-pane/) | selectp | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `DdegLlMmP:RT:t:UZ` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-select-pane.c) | | [`select-window`](https://libtmux.org/en/tmux/latest/manual/select-window/) | selectw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `lnpTt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-select-window.c) | | [`send-keys`](https://libtmux.org/en/tmux/latest/manual/send-keys/) | send | 3.3, 3.3a | `FHlMN:Rt:X` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/cmd-send-keys.c) | | [`send-keys`](https://libtmux.org/en/tmux/latest/manual/send-keys/) | send | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `c:FHKlMN:Rt:X` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-send-keys.c) | | [`send-prefix`](https://libtmux.org/en/tmux/latest/manual/send-prefix/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `2t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-send-keys.c) | | [`server-access`](https://libtmux.org/en/tmux/latest/manual/server-access/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `adlrw` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-server-access.c) | | [`server-access`](https://libtmux.org/en/tmux/latest/manual/server-access/) | — | 3.8 | `adglrw` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-server-access.c) | | [`set-buffer`](https://libtmux.org/en/tmux/latest/manual/set-buffer/) | setb | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `ab:t:n:w` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-set-buffer.c) | | [`set-environment`](https://libtmux.org/en/tmux/latest/manual/set-environment/) | setenv | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `Fhgrt:u` | 1..2 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-set-environment.c) | | [`set-hook`](https://libtmux.org/en/tmux/latest/manual/set-hook/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `agpRt:uw` | 1..2 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-set-option.c) | | [`set-hook`](https://libtmux.org/en/tmux/latest/manual/set-hook/) | — | 3.8 | `agpERTt:uB:w` | 0..2 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-set-option.c) | | [`set-option`](https://libtmux.org/en/tmux/latest/manual/set-option/) | set | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `aFgopqst:uUw` | 1..2 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-set-option.c) | | [`set-window-option`](https://libtmux.org/en/tmux/latest/manual/set-window-option/) | setw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `aFgoqt:u` | 1..2 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-set-option.c) | | [`show-buffer`](https://libtmux.org/en/tmux/latest/manual/show-buffer/) | showb | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `b:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-save-buffer.c) | | [`show-environment`](https://libtmux.org/en/tmux/latest/manual/show-environment/) | showenv | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `hgst:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-show-environment.c) | | [`show-hooks`](https://libtmux.org/en/tmux/latest/manual/show-hooks/) | — | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `gpt:w` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-show-options.c) | | [`show-hooks`](https://libtmux.org/en/tmux/latest/manual/show-hooks/) | — | 3.8 | `BF:gpt:w` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-show-options.c) | | [`show-messages`](https://libtmux.org/en/tmux/latest/manual/show-messages/) | showmsgs | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `JTt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-show-messages.c) | | [`show-options`](https://libtmux.org/en/tmux/latest/manual/show-options/) | show | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `AgHpqst:vw` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-show-options.c) | | [`show-options`](https://libtmux.org/en/tmux/latest/manual/show-options/) | show | 3.8 | `AgF:Hpqst:vw` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-show-options.c) | | [`show-prompt-history`](https://libtmux.org/en/tmux/latest/manual/show-prompt-history/) | showphist | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `T:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-show-prompt-history.c) | | [`show-window-options`](https://libtmux.org/en/tmux/latest/manual/show-window-options/) | showw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `gvt:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-show-options.c) | | [`show-window-options`](https://libtmux.org/en/tmux/latest/manual/show-window-options/) | showw | 3.8 | `F:gvt:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-show-options.c) | | [`source-file`](https://libtmux.org/en/tmux/latest/manual/source-file/) | source | 3.3, 3.3a | `Fnqv` | 1..unbounded | [Declaration](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/cmd-source-file.c) | | [`source-file`](https://libtmux.org/en/tmux/latest/manual/source-file/) | source | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:Fnqv` | 1..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-source-file.c) | | [`split-window`](https://libtmux.org/en/tmux/latest/manual/split-window/) | splitw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `bc:de:fF:hIl:p:Pt:vZ` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-split-window.c) | | [`split-window`](https://libtmux.org/en/tmux/latest/manual/split-window/) | splitw | 3.7, 3.7a, 3.7b, 3.7c | `bc:de:EfF:hIkl:m:p:PR:s:S:t:vZ` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-split-window.c) | | [`split-window`](https://libtmux.org/en/tmux/latest/manual/split-window/) | splitw | 3.8 | `bB:c:de:EfF:hIkl:m:p:PR:s:S:t:T:vWZ` | 0..unbounded | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-split-window.c) | | [`start-server`](https://libtmux.org/en/tmux/latest/manual/start-server/) | start | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-kill-server.c) | | [`suspend-client`](https://libtmux.org/en/tmux/latest/manual/suspend-client/) | suspendc | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-detach-client.c) | | [`swap-pane`](https://libtmux.org/en/tmux/latest/manual/swap-pane/) | swapp | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `dDs:t:UZ` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-swap-pane.c) | | [`swap-window`](https://libtmux.org/en/tmux/latest/manual/swap-window/) | swapw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `ds:t:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-swap-window.c) | | [`switch-client`](https://libtmux.org/en/tmux/latest/manual/switch-client/) | switchc | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | `lc:EFnpt:rT:Z` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/cmd-switch-client.c) | | [`switch-client`](https://libtmux.org/en/tmux/latest/manual/switch-client/) | switchc | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `c:EFlnO:pt:rT:Z` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-switch-client.c) | | `switch-mode` | — | 3.8 | `F:kst:wZ` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-choose-tree.c) | | [`unbind-key`](https://libtmux.org/en/tmux/latest/manual/unbind-key/) | unbind | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `anqT:` | 0..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-unbind-key.c) | | [`unlink-window`](https://libtmux.org/en/tmux/latest/manual/unlink-window/) | unlinkw | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | `kt:` | 0..0 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-kill-window.c) | | [`wait-for`](https://libtmux.org/en/tmux/latest/manual/wait-for/) | wait | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | `LSU` | 1..1 | [Declaration](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/cmd-wait-for.c) | | [`wait-for`](https://libtmux.org/en/tmux/latest/manual/wait-for/) | wait | 3.8 | `EF:LSUlvw:` | 1..1 | [Declaration](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/cmd-wait-for.c) | --- # Fields and operators Source: https://libtmux.org/en/erlang/latest/reference/fields/ > Fields and operators: libtmux_erlang documentation. Generated from the compiled schema and operator validator. Do not edit the tables by hand. Field names on the left are Erlang atoms; wire names are JSON strings. IDs are strings, never numbers. Text is case-sensitive UTF-8. Bytes use a single-key base64 object on the wire. Nullable values use `none` locally and `null` on the wire. `not_loaded` and `unavailable` are coverage states, not null values. ## session | Field | Wire name | Type | Nullable | Operators | | --- | --- | --- | --- | --- | | `id` | `id` | [`session_id`](https://libtmux.org/en/tmux/latest/catalog/formats/session_id/) | false | `equals`, `'not'`, `in`, `not_in` | | `attached` | `attached` | `boolean` | false | `equals`, `'not'`, `in`, `not_in` | | `attached_count` | `attachedCount` | `uint` | false | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte` | | `created` | `created` | `uint` | false | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte` | | `name` | `name` | `text` | false | `equals`, `'not'`, `in`, `not_in`, `contains`, `starts_with`, `ends_with`, `regex` | | Relationship | Wire name | Target | Cardinality | | --- | --- | --- | --- | | `window_links` | `windowLinks` | `window_link` | many | | `windows` | `windows` | `window` | many | ## window | Field | Wire name | Type | Nullable | Operators | | --- | --- | --- | --- | --- | | `id` | `id` | [`window_id`](https://libtmux.org/en/tmux/latest/catalog/formats/window_id/) | false | `equals`, `'not'`, `in`, `not_in` | | `height` | `height` | `uint` | false | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte` | | `layout` | `layout` | `text` | false | `equals`, `'not'`, `in`, `not_in`, `contains`, `starts_with`, `ends_with`, `regex` | | `name` | `name` | `text` | false | `equals`, `'not'`, `in`, `not_in`, `contains`, `starts_with`, `ends_with`, `regex` | | `pane_count` | `paneCount` | `uint` | false | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte` | | `width` | `width` | `uint` | false | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte` | | Relationship | Wire name | Target | Cardinality | | --- | --- | --- | --- | | `panes` | `panes` | `pane` | many | | `window_links` | `windowLinks` | `window_link` | many | ## window_link | Field | Wire name | Type | Nullable | Operators | | --- | --- | --- | --- | --- | | `index` | `index` | `uint` | false | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte` | | [`session_id`](https://libtmux.org/en/tmux/latest/catalog/formats/session_id/) | `sessionId` | [`session_id`](https://libtmux.org/en/tmux/latest/catalog/formats/session_id/) | false | `equals`, `'not'`, `in`, `not_in` | | [`window_id`](https://libtmux.org/en/tmux/latest/catalog/formats/window_id/) | `windowId` | [`window_id`](https://libtmux.org/en/tmux/latest/catalog/formats/window_id/) | false | `equals`, `'not'`, `in`, `not_in` | | `active` | `active` | `boolean` | false | `equals`, `'not'`, `in`, `not_in` | | Relationship | Wire name | Target | Cardinality | | --- | --- | --- | --- | | `session` | `session` | `session` | one | | `window` | `window` | `window` | one | ## pane | Field | Wire name | Type | Nullable | Operators | | --- | --- | --- | --- | --- | | `id` | `id` | [`pane_id`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_id/) | false | `equals`, `'not'`, `in`, `not_in` | | `active` | `active` | `boolean` | false | `equals`, `'not'`, `in`, `not_in` | | `current_command` | `currentCommand` | `text` | false | `equals`, `'not'`, `in`, `not_in`, `contains`, `starts_with`, `ends_with`, `regex` | | `current_path` | `currentPath` | `bytes` | false | `equals`, `'not'`, `in`, `not_in`, `contains`, `starts_with`, `ends_with` | | `dead` | `dead` | `boolean` | false | `equals`, `'not'`, `in`, `not_in` | | `exit_status` | `exitStatus` | `integer` | true | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte`, `present` | | `height` | `height` | `uint` | false | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte` | | `index` | `index` | `uint` | false | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte` | | `pid` | `pid` | `uint` | true | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte`, `present` | | `title` | `title` | `text` | false | `equals`, `'not'`, `in`, `not_in`, `contains`, `starts_with`, `ends_with`, `regex` | | `width` | `width` | `uint` | false | `equals`, `'not'`, `in`, `not_in`, `lt`, `lte`, `gt`, `gte` | | [`window_id`](https://libtmux.org/en/tmux/latest/catalog/formats/window_id/) | `windowId` | [`window_id`](https://libtmux.org/en/tmux/latest/catalog/formats/window_id/) | false | `equals`, `'not'`, `in`, `not_in` | | Relationship | Wire name | Target | Cardinality | | --- | --- | --- | --- | | `window` | `window` | `window` | one | --- # Options Source: https://libtmux.org/en/erlang/latest/reference/options/ > Options: libtmux_erlang documentation. Generated from pinned tmux `options-table.c` files by `tools/generate_options.py`. [Scoped options](https://libtmux.org/en/erlang/latest/guides/options/) defines the public API. Types describe tmux's parser; values use binary text. Hooks appear for discovery and are rejected by the option API. ## Sources | Version | Source | SHA-256 | Entries | | --- | --- | --- | --- | | 3.3 | [Table](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c) | `dbf0432e6620735554e798a0aef55c5dd2a1021518261fef4b3f93e60989d2b4` | 181 | | 3.3a | [Table](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/options-table.c) | `dbf0432e6620735554e798a0aef55c5dd2a1021518261fef4b3f93e60989d2b4` | 181 | | 3.4 | [Table](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/options-table.c) | `b50f5da4d81dfd26089d35510b96f8f1cf5457d05835d8494feeea0c5cf4e1ea` | 186 | | 3.5 | [Table](https://github.com/tmux/tmux/blob/ac44566c9c7e3e94d23be6def4c7ae83472543f5/options-table.c) | `b3d678c0f3a52c6cd742fb16b8e57c4e808223e814d88422f7344b7ef5e4bb92` | 190 | | 3.5a | [Table](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/options-table.c) | `b3d678c0f3a52c6cd742fb16b8e57c4e808223e814d88422f7344b7ef5e4bb92` | 190 | | 3.6 | [Table](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c) | `bede62bb7230e59e81447287179875c8c0a7ff6a1eb6be71f4a35de999ef66b2` | 210 | | 3.6a | [Table](https://github.com/tmux/tmux/blob/cc117b5048f77a4842820f8ebbe3a86e5c077224/options-table.c) | `bede62bb7230e59e81447287179875c8c0a7ff6a1eb6be71f4a35de999ef66b2` | 210 | | 3.6b | [Table](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/options-table.c) | `bede62bb7230e59e81447287179875c8c0a7ff6a1eb6be71f4a35de999ef66b2` | 210 | | 3.7 | [Table](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c) | `c1245a284d540f4c5160617c2f762718b9bc264236c5cf1524b34f51621b56c2` | 221 | | 3.7a | [Table](https://github.com/tmux/tmux/blob/0e418b62d259ce8da8970f75732cc6632ee4c3a0/options-table.c) | `c1245a284d540f4c5160617c2f762718b9bc264236c5cf1524b34f51621b56c2` | 221 | | 3.7b | [Table](https://github.com/tmux/tmux/blob/e802909de06012a4df6209d55e86487c56223163/options-table.c) | `c1245a284d540f4c5160617c2f762718b9bc264236c5cf1524b34f51621b56c2` | 221 | | 3.7c | [Table](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/options-table.c) | `c1245a284d540f4c5160617c2f762718b9bc264236c5cf1524b34f51621b56c2` | 221 | | 3.8 | [Table](https://github.com/tmux/tmux/blob/7f2a35ad3321f9ba57a1062ca73b1f3ff26aca53/options-table.c) | `cbf3b034785b30aeee3d67032f99e9d9b173a321e11b19be1a11c9e9914fc866` | 272 | ## Options and hooks | Name | Versions | Scopes | Type | Array | Hook | | --- | --- | --- | --- | --- | --- | | [`activity-action`](https://libtmux.org/en/tmux/latest/catalog/options/activity-action/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`after-bind-key`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-bind-key/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-capture-pane`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-capture-pane/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-copy-mode`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-copy-mode/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-display-message`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-display-message/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-display-panes`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-display-panes/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-kill-pane`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-kill-pane/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-list-buffers`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-list-buffers/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-list-clients`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-list-clients/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-list-keys`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-list-keys/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-list-panes`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-list-panes/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-list-sessions`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-list-sessions/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-list-windows`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-list-windows/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-load-buffer`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-load-buffer/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-lock-server`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-lock-server/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-new-session`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-new-session/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-new-window`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-new-window/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-paste-buffer`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-paste-buffer/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-pipe-pane`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-pipe-pane/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-queue`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-queue/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command | true | true | | [`after-refresh-client`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-refresh-client/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-rename-session`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-rename-session/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-rename-window`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-rename-window/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-resize-pane`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-resize-pane/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-resize-window`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-resize-window/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-save-buffer`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-save-buffer/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-select-layout`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-select-layout/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-select-pane`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-select-pane/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-select-window`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-select-window/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-send-keys`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-send-keys/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-set-buffer`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-set-buffer/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-set-environment`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-set-environment/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-set-hook`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-set-hook/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-set-option`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-set-option/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-show-environment`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-show-environment/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-show-messages`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-show-messages/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-show-options`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-show-options/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`after-split-window`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-split-window/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | `after-swap-window` | 3.8 | session | command | true | true | | [`after-unbind-key`](https://libtmux.org/en/tmux/latest/catalog/hooks/after-unbind-key/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`aggressive-resize`](https://libtmux.org/en/tmux/latest/catalog/options/aggressive-resize/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | flag | false | false | | [`alert-activity`](https://libtmux.org/en/tmux/latest/catalog/hooks/alert-activity/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`alert-bell`](https://libtmux.org/en/tmux/latest/catalog/hooks/alert-bell/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`alert-silence`](https://libtmux.org/en/tmux/latest/catalog/hooks/alert-silence/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`allow-passthrough`](https://libtmux.org/en/tmux/latest/catalog/options/allow-passthrough/) | 3.3, 3.3a | window, pane | flag | false | false | | [`allow-passthrough`](https://libtmux.org/en/tmux/latest/catalog/options/allow-passthrough/) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | choice | false | false | | [`allow-rename`](https://libtmux.org/en/tmux/latest/catalog/options/allow-rename/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | flag | false | false | | [`allow-set-title`](https://libtmux.org/en/tmux/latest/catalog/options/allow-set-title/) | 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | flag | false | false | | [`alternate-screen`](https://libtmux.org/en/tmux/latest/catalog/options/alternate-screen/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | flag | false | false | | [`assume-paste-time`](https://libtmux.org/en/tmux/latest/catalog/options/assume-paste-time/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | number | false | false | | [`automatic-rename`](https://libtmux.org/en/tmux/latest/catalog/options/automatic-rename/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | flag | false | false | | [`automatic-rename-format`](https://libtmux.org/en/tmux/latest/catalog/options/automatic-rename-format/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | `backspace` | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | key | false | false | | [`base-index`](https://libtmux.org/en/tmux/latest/catalog/options/base-index/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | number | false | false | | [`bell-action`](https://libtmux.org/en/tmux/latest/catalog/options/bell-action/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`buffer-limit`](https://libtmux.org/en/tmux/latest/catalog/options/buffer-limit/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | number | false | false | | `clear-on-attach` | 3.8 | server | flag | false | false | | [`client-active`](https://libtmux.org/en/tmux/latest/catalog/hooks/client-active/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`client-attached`](https://libtmux.org/en/tmux/latest/catalog/hooks/client-attached/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | `client-closed` | 3.8 | session | command | true | true | | `client-created` | 3.8 | session | command | true | true | | [`client-dark-theme`](https://libtmux.org/en/tmux/latest/catalog/hooks/client-dark-theme/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`client-detached`](https://libtmux.org/en/tmux/latest/catalog/hooks/client-detached/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`client-focus-in`](https://libtmux.org/en/tmux/latest/catalog/hooks/client-focus-in/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`client-focus-out`](https://libtmux.org/en/tmux/latest/catalog/hooks/client-focus-out/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`client-light-theme`](https://libtmux.org/en/tmux/latest/catalog/hooks/client-light-theme/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`client-resized`](https://libtmux.org/en/tmux/latest/catalog/hooks/client-resized/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`client-session-changed`](https://libtmux.org/en/tmux/latest/catalog/hooks/client-session-changed/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`clock-mode-colour`](https://libtmux.org/en/tmux/latest/catalog/options/clock-mode-colour/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | colour | false | false | | [`clock-mode-colour`](https://libtmux.org/en/tmux/latest/catalog/options/clock-mode-colour/) | 3.8 | window | string | false | false | | [`clock-mode-style`](https://libtmux.org/en/tmux/latest/catalog/options/clock-mode-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | choice | false | false | | [`codepoint-widths`](https://libtmux.org/en/tmux/latest/catalog/options/codepoint-widths/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | string | true | false | | [`command-alias`](https://libtmux.org/en/tmux/latest/catalog/options/command-alias/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | string | true | false | | [`command-error`](https://libtmux.org/en/tmux/latest/catalog/hooks/command-error/) | 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`copy-command`](https://libtmux.org/en/tmux/latest/catalog/options/copy-command/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | string | false | false | | [`copy-mode-current-line-number-style`](https://libtmux.org/en/tmux/latest/catalog/options/copy-mode-current-line-number-style/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | `copy-mode-current-line-style` | 3.8 | window | string | false | false | | [`copy-mode-current-match-style`](https://libtmux.org/en/tmux/latest/catalog/options/copy-mode-current-match-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`copy-mode-line-number-style`](https://libtmux.org/en/tmux/latest/catalog/options/copy-mode-line-number-style/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`copy-mode-line-numbers`](https://libtmux.org/en/tmux/latest/catalog/options/copy-mode-line-numbers/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | choice | false | false | | [`copy-mode-mark-style`](https://libtmux.org/en/tmux/latest/catalog/options/copy-mode-mark-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`copy-mode-match-style`](https://libtmux.org/en/tmux/latest/catalog/options/copy-mode-match-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`copy-mode-position-format`](https://libtmux.org/en/tmux/latest/catalog/options/copy-mode-position-format/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | string | false | false | | [`copy-mode-position-style`](https://libtmux.org/en/tmux/latest/catalog/options/copy-mode-position-style/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`copy-mode-selection-style`](https://libtmux.org/en/tmux/latest/catalog/options/copy-mode-selection-style/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`cursor-colour`](https://libtmux.org/en/tmux/latest/catalog/options/cursor-colour/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | colour | false | false | | [`cursor-colour`](https://libtmux.org/en/tmux/latest/catalog/options/cursor-colour/) | 3.8 | window, pane | string | false | false | | [`cursor-style`](https://libtmux.org/en/tmux/latest/catalog/options/cursor-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | choice | false | false | | `dark-theme-black` | 3.8 | server | string | false | false | | `dark-theme-blue` | 3.8 | server | string | false | false | | `dark-theme-cyan` | 3.8 | server | string | false | false | | `dark-theme-dark-grey` | 3.8 | server | string | false | false | | `dark-theme-green` | 3.8 | server | string | false | false | | `dark-theme-light-grey` | 3.8 | server | string | false | false | | `dark-theme-magenta` | 3.8 | server | string | false | false | | `dark-theme-red` | 3.8 | server | string | false | false | | `dark-theme-white` | 3.8 | server | string | false | false | | `dark-theme-yellow` | 3.8 | server | string | false | false | | [`default-client-command`](https://libtmux.org/en/tmux/latest/catalog/options/default-client-command/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | command | false | false | | [`default-command`](https://libtmux.org/en/tmux/latest/catalog/options/default-command/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`default-shell`](https://libtmux.org/en/tmux/latest/catalog/options/default-shell/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`default-size`](https://libtmux.org/en/tmux/latest/catalog/options/default-size/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`default-terminal`](https://libtmux.org/en/tmux/latest/catalog/options/default-terminal/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | string | false | false | | [`destroy-unattached`](https://libtmux.org/en/tmux/latest/catalog/options/destroy-unattached/) | 3.3, 3.3a | session | flag | false | false | | [`destroy-unattached`](https://libtmux.org/en/tmux/latest/catalog/options/destroy-unattached/) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`detach-on-destroy`](https://libtmux.org/en/tmux/latest/catalog/options/detach-on-destroy/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`display-panes-active-colour`](https://libtmux.org/en/tmux/latest/catalog/options/display-panes-active-colour/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | colour | false | false | | [`display-panes-active-colour`](https://libtmux.org/en/tmux/latest/catalog/options/display-panes-active-colour/) | 3.8 | window | string | false | false | | `display-panes-border-style` | 3.8 | window | string | false | false | | [`display-panes-colour`](https://libtmux.org/en/tmux/latest/catalog/options/display-panes-colour/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | colour | false | false | | [`display-panes-colour`](https://libtmux.org/en/tmux/latest/catalog/options/display-panes-colour/) | 3.8 | window | string | false | false | | `display-panes-format` | 3.8 | window | string | false | false | | [`display-panes-time`](https://libtmux.org/en/tmux/latest/catalog/options/display-panes-time/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | number | false | false | | [`display-panes-time`](https://libtmux.org/en/tmux/latest/catalog/options/display-panes-time/) | 3.8 | window | number | false | false | | [`display-time`](https://libtmux.org/en/tmux/latest/catalog/options/display-time/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | number | false | false | | `editor` | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | string | false | false | | [`escape-time`](https://libtmux.org/en/tmux/latest/catalog/options/escape-time/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | number | false | false | | [`exit-empty`](https://libtmux.org/en/tmux/latest/catalog/options/exit-empty/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | flag | false | false | | [`exit-unattached`](https://libtmux.org/en/tmux/latest/catalog/options/exit-unattached/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | flag | false | false | | [`extended-keys`](https://libtmux.org/en/tmux/latest/catalog/options/extended-keys/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | choice | false | false | | [`extended-keys-format`](https://libtmux.org/en/tmux/latest/catalog/options/extended-keys-format/) | 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | choice | false | false | | [`fill-character`](https://libtmux.org/en/tmux/latest/catalog/options/fill-character/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`focus-events`](https://libtmux.org/en/tmux/latest/catalog/options/focus-events/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | flag | false | false | | [`focus-follows-mouse`](https://libtmux.org/en/tmux/latest/catalog/options/focus-follows-mouse/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | flag | false | false | | [`get-clipboard`](https://libtmux.org/en/tmux/latest/catalog/options/get-clipboard/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | choice | false | false | | [`history-file`](https://libtmux.org/en/tmux/latest/catalog/options/history-file/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | string | false | false | | [`history-limit`](https://libtmux.org/en/tmux/latest/catalog/options/history-limit/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | number | false | false | | [`initial-repeat-time`](https://libtmux.org/en/tmux/latest/catalog/options/initial-repeat-time/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | number | false | false | | [`input-buffer-size`](https://libtmux.org/en/tmux/latest/catalog/options/input-buffer-size/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | number | false | false | | [`key-table`](https://libtmux.org/en/tmux/latest/catalog/options/key-table/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | `light-theme-black` | 3.8 | server | string | false | false | | `light-theme-blue` | 3.8 | server | string | false | false | | `light-theme-cyan` | 3.8 | server | string | false | false | | `light-theme-dark-grey` | 3.8 | server | string | false | false | | `light-theme-green` | 3.8 | server | string | false | false | | `light-theme-light-grey` | 3.8 | server | string | false | false | | `light-theme-magenta` | 3.8 | server | string | false | false | | `light-theme-red` | 3.8 | server | string | false | false | | `light-theme-white` | 3.8 | server | string | false | false | | `light-theme-yellow` | 3.8 | server | string | false | false | | [`lock-after-time`](https://libtmux.org/en/tmux/latest/catalog/options/lock-after-time/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | number | false | false | | [`lock-command`](https://libtmux.org/en/tmux/latest/catalog/options/lock-command/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`main-pane-height`](https://libtmux.org/en/tmux/latest/catalog/options/main-pane-height/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`main-pane-width`](https://libtmux.org/en/tmux/latest/catalog/options/main-pane-width/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | `marked-pane-changed` | 3.8 | session | command | true | true | | [`menu-border-lines`](https://libtmux.org/en/tmux/latest/catalog/options/menu-border-lines/) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | choice | false | false | | [`menu-border-style`](https://libtmux.org/en/tmux/latest/catalog/options/menu-border-style/) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`menu-selected-style`](https://libtmux.org/en/tmux/latest/catalog/options/menu-selected-style/) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`menu-style`](https://libtmux.org/en/tmux/latest/catalog/options/menu-style/) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`message-command-style`](https://libtmux.org/en/tmux/latest/catalog/options/message-command-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`message-format`](https://libtmux.org/en/tmux/latest/catalog/options/message-format/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`message-limit`](https://libtmux.org/en/tmux/latest/catalog/options/message-limit/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | number | false | false | | [`message-line`](https://libtmux.org/en/tmux/latest/catalog/options/message-line/) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`message-style`](https://libtmux.org/en/tmux/latest/catalog/options/message-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`mode-keys`](https://libtmux.org/en/tmux/latest/catalog/options/mode-keys/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | choice | false | false | | [`mode-style`](https://libtmux.org/en/tmux/latest/catalog/options/mode-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`monitor-activity`](https://libtmux.org/en/tmux/latest/catalog/options/monitor-activity/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | flag | false | false | | [`monitor-bell`](https://libtmux.org/en/tmux/latest/catalog/options/monitor-bell/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | flag | false | false | | [`monitor-silence`](https://libtmux.org/en/tmux/latest/catalog/options/monitor-silence/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | number | false | false | | `mouse` | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | flag | false | false | | [`other-pane-height`](https://libtmux.org/en/tmux/latest/catalog/options/other-pane-height/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`other-pane-width`](https://libtmux.org/en/tmux/latest/catalog/options/other-pane-width/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`pane-active-border-style`](https://libtmux.org/en/tmux/latest/catalog/options/pane-active-border-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | window | string | false | false | | [`pane-active-border-style`](https://libtmux.org/en/tmux/latest/catalog/options/pane-active-border-style/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | string | false | false | | `pane-activity` | 3.8 | window, pane | command | true | true | | [`pane-base-index`](https://libtmux.org/en/tmux/latest/catalog/options/pane-base-index/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | number | false | false | | `pane-bell` | 3.8 | window, pane | command | true | true | | [`pane-border-format`](https://libtmux.org/en/tmux/latest/catalog/options/pane-border-format/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | string | false | false | | [`pane-border-indicators`](https://libtmux.org/en/tmux/latest/catalog/options/pane-border-indicators/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | choice | false | false | | [`pane-border-lines`](https://libtmux.org/en/tmux/latest/catalog/options/pane-border-lines/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | choice | false | false | | [`pane-border-lines`](https://libtmux.org/en/tmux/latest/catalog/options/pane-border-lines/) | 3.8 | window, pane | choice | false | false | | [`pane-border-status`](https://libtmux.org/en/tmux/latest/catalog/options/pane-border-status/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | choice | false | false | | [`pane-border-status`](https://libtmux.org/en/tmux/latest/catalog/options/pane-border-status/) | 3.8 | window, pane | choice | false | false | | [`pane-border-style`](https://libtmux.org/en/tmux/latest/catalog/options/pane-border-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | window | string | false | false | | [`pane-border-style`](https://libtmux.org/en/tmux/latest/catalog/options/pane-border-style/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | string | false | false | | [`pane-colours`](https://libtmux.org/en/tmux/latest/catalog/options/pane-colours/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | colour | true | false | | `pane-command-finished` | 3.8 | window, pane | command | true | true | | `pane-command-started` | 3.8 | window, pane | command | true | true | | `pane-created` | 3.8 | window, pane | command | true | true | | [`pane-died`](https://libtmux.org/en/tmux/latest/catalog/hooks/pane-died/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | command | true | true | | [`pane-exited`](https://libtmux.org/en/tmux/latest/catalog/hooks/pane-exited/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | command | true | true | | [`pane-focus-in`](https://libtmux.org/en/tmux/latest/catalog/hooks/pane-focus-in/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | command | true | true | | [`pane-focus-out`](https://libtmux.org/en/tmux/latest/catalog/hooks/pane-focus-out/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | command | true | true | | [`pane-mode-changed`](https://libtmux.org/en/tmux/latest/catalog/hooks/pane-mode-changed/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | command | true | true | | `pane-mode-entered` | 3.8 | window, pane | command | true | true | | `pane-mode-exited` | 3.8 | window, pane | command | true | true | | `pane-moved` | 3.8 | window, pane | command | true | true | | `pane-prompt-closed` | 3.8 | window, pane | command | true | true | | `pane-prompt-opened` | 3.8 | window, pane | command | true | true | | `pane-resized` | 3.8 | window, pane | command | true | true | | [`pane-scrollbars`](https://libtmux.org/en/tmux/latest/catalog/options/pane-scrollbars/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | choice | false | false | | [`pane-scrollbars-position`](https://libtmux.org/en/tmux/latest/catalog/options/pane-scrollbars-position/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | choice | false | false | | [`pane-scrollbars-style`](https://libtmux.org/en/tmux/latest/catalog/options/pane-scrollbars-style/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | string | false | false | | `pane-scrollbars-timeout` | 3.8 | window | number | false | false | | [`pane-set-clipboard`](https://libtmux.org/en/tmux/latest/catalog/hooks/pane-set-clipboard/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | command | true | true | | `pane-shell-prompt` | 3.8 | window, pane | command | true | true | | [`pane-status-current-style`](https://libtmux.org/en/tmux/latest/catalog/options/pane-status-current-style/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`pane-status-style`](https://libtmux.org/en/tmux/latest/catalog/options/pane-status-style/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`pane-title-changed`](https://libtmux.org/en/tmux/latest/catalog/hooks/pane-title-changed/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | command | true | true | | [`popup-border-lines`](https://libtmux.org/en/tmux/latest/catalog/options/popup-border-lines/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | choice | false | false | | [`popup-border-style`](https://libtmux.org/en/tmux/latest/catalog/options/popup-border-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`popup-style`](https://libtmux.org/en/tmux/latest/catalog/options/popup-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | `prefix` | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | key | false | false | | [`prefix-timeout`](https://libtmux.org/en/tmux/latest/catalog/options/prefix-timeout/) | 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | number | false | false | | `prefix2` | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | key | false | false | | `prompt-command-cursor-colour` | 3.8 | session | string | false | false | | [`prompt-command-cursor-style`](https://libtmux.org/en/tmux/latest/catalog/options/prompt-command-cursor-style/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`prompt-cursor-colour`](https://libtmux.org/en/tmux/latest/catalog/options/prompt-cursor-colour/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | colour | false | false | | [`prompt-cursor-colour`](https://libtmux.org/en/tmux/latest/catalog/options/prompt-cursor-colour/) | 3.8 | session | string | false | false | | [`prompt-cursor-style`](https://libtmux.org/en/tmux/latest/catalog/options/prompt-cursor-style/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`prompt-history-limit`](https://libtmux.org/en/tmux/latest/catalog/options/prompt-history-limit/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | number | false | false | | [`remain-on-exit`](https://libtmux.org/en/tmux/latest/catalog/options/remain-on-exit/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | choice | false | false | | [`remain-on-exit-format`](https://libtmux.org/en/tmux/latest/catalog/options/remain-on-exit-format/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | string | false | false | | [`renumber-windows`](https://libtmux.org/en/tmux/latest/catalog/options/renumber-windows/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | flag | false | false | | [`repeat-time`](https://libtmux.org/en/tmux/latest/catalog/options/repeat-time/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | number | false | false | | [`scroll-on-clear`](https://libtmux.org/en/tmux/latest/catalog/options/scroll-on-clear/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | flag | false | false | | `session-added-to-group` | 3.8 | session | command | true | true | | [`session-closed`](https://libtmux.org/en/tmux/latest/catalog/hooks/session-closed/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`session-created`](https://libtmux.org/en/tmux/latest/catalog/hooks/session-created/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | `session-removed-from-group` | 3.8 | session | command | true | true | | [`session-renamed`](https://libtmux.org/en/tmux/latest/catalog/hooks/session-renamed/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`session-status-current-style`](https://libtmux.org/en/tmux/latest/catalog/options/session-status-current-style/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`session-status-style`](https://libtmux.org/en/tmux/latest/catalog/options/session-status-style/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`session-window-changed`](https://libtmux.org/en/tmux/latest/catalog/hooks/session-window-changed/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`set-clipboard`](https://libtmux.org/en/tmux/latest/catalog/options/set-clipboard/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | choice | false | false | | [`set-titles`](https://libtmux.org/en/tmux/latest/catalog/options/set-titles/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | flag | false | false | | [`set-titles-string`](https://libtmux.org/en/tmux/latest/catalog/options/set-titles-string/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`silence-action`](https://libtmux.org/en/tmux/latest/catalog/options/silence-action/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | `status` | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`status-bg`](https://libtmux.org/en/tmux/latest/catalog/options/status-bg/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | colour | false | false | | [`status-fg`](https://libtmux.org/en/tmux/latest/catalog/options/status-fg/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | colour | false | false | | [`status-format`](https://libtmux.org/en/tmux/latest/catalog/options/status-format/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | true | false | | [`status-interval`](https://libtmux.org/en/tmux/latest/catalog/options/status-interval/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | number | false | false | | [`status-justify`](https://libtmux.org/en/tmux/latest/catalog/options/status-justify/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`status-keys`](https://libtmux.org/en/tmux/latest/catalog/options/status-keys/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`status-left`](https://libtmux.org/en/tmux/latest/catalog/options/status-left/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`status-left-length`](https://libtmux.org/en/tmux/latest/catalog/options/status-left-length/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | number | false | false | | [`status-left-style`](https://libtmux.org/en/tmux/latest/catalog/options/status-left-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`status-position`](https://libtmux.org/en/tmux/latest/catalog/options/status-position/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`status-right`](https://libtmux.org/en/tmux/latest/catalog/options/status-right/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`status-right-length`](https://libtmux.org/en/tmux/latest/catalog/options/status-right-length/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | number | false | false | | [`status-right-style`](https://libtmux.org/en/tmux/latest/catalog/options/status-right-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`status-style`](https://libtmux.org/en/tmux/latest/catalog/options/status-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | `switch-mode-match-style` | 3.8 | window, pane | string | false | false | | [`synchronize-panes`](https://libtmux.org/en/tmux/latest/catalog/options/synchronize-panes/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | flag | false | false | | [`terminal-features`](https://libtmux.org/en/tmux/latest/catalog/options/terminal-features/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | string | true | false | | [`terminal-overrides`](https://libtmux.org/en/tmux/latest/catalog/options/terminal-overrides/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | string | true | false | | `theme` | 3.8 | server | choice | false | false | | [`tiled-layout-max-columns`](https://libtmux.org/en/tmux/latest/catalog/options/tiled-layout-max-columns/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | number | false | false | | `tree-mode-border-style` | 3.8 | window | string | false | false | | [`tree-mode-preview-format`](https://libtmux.org/en/tmux/latest/catalog/options/tree-mode-preview-format/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | string | false | false | | [`tree-mode-preview-style`](https://libtmux.org/en/tmux/latest/catalog/options/tree-mode-preview-style/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | `tree-mode-selection-style` | 3.8 | window | string | false | false | | [`update-environment`](https://libtmux.org/en/tmux/latest/catalog/options/update-environment/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | true | false | | [`user-keys`](https://libtmux.org/en/tmux/latest/catalog/options/user-keys/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | string | true | false | | [`variation-selector-always-wide`](https://libtmux.org/en/tmux/latest/catalog/options/variation-selector-always-wide/) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | server | flag | false | false | | [`visual-activity`](https://libtmux.org/en/tmux/latest/catalog/options/visual-activity/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`visual-bell`](https://libtmux.org/en/tmux/latest/catalog/options/visual-bell/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`visual-silence`](https://libtmux.org/en/tmux/latest/catalog/options/visual-silence/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | choice | false | false | | [`window-active-style`](https://libtmux.org/en/tmux/latest/catalog/options/window-active-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | string | false | false | | `window-closed` | 3.8 | window | command | true | true | | `window-created` | 3.8 | window | command | true | true | | [`window-layout-changed`](https://libtmux.org/en/tmux/latest/catalog/hooks/window-layout-changed/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | command | true | true | | [`window-linked`](https://libtmux.org/en/tmux/latest/catalog/hooks/window-linked/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | [`window-pane-changed`](https://libtmux.org/en/tmux/latest/catalog/hooks/window-pane-changed/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | command | true | true | | [`window-pane-current-status-format`](https://libtmux.org/en/tmux/latest/catalog/options/window-pane-current-status-format/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`window-pane-status-format`](https://libtmux.org/en/tmux/latest/catalog/options/window-pane-status-format/) | 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`window-renamed`](https://libtmux.org/en/tmux/latest/catalog/hooks/window-renamed/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | command | true | true | | [`window-resized`](https://libtmux.org/en/tmux/latest/catalog/hooks/window-resized/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | command | true | true | | [`window-size`](https://libtmux.org/en/tmux/latest/catalog/options/window-size/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | choice | false | false | | [`window-status-activity-style`](https://libtmux.org/en/tmux/latest/catalog/options/window-status-activity-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`window-status-bell-style`](https://libtmux.org/en/tmux/latest/catalog/options/window-status-bell-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`window-status-current-format`](https://libtmux.org/en/tmux/latest/catalog/options/window-status-current-format/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`window-status-current-style`](https://libtmux.org/en/tmux/latest/catalog/options/window-status-current-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`window-status-format`](https://libtmux.org/en/tmux/latest/catalog/options/window-status-format/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`window-status-last-style`](https://libtmux.org/en/tmux/latest/catalog/options/window-status-last-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`window-status-separator`](https://libtmux.org/en/tmux/latest/catalog/options/window-status-separator/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`window-status-style`](https://libtmux.org/en/tmux/latest/catalog/options/window-status-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | string | false | false | | [`window-style`](https://libtmux.org/en/tmux/latest/catalog/options/window-style/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window, pane | string | false | false | | [`window-unlinked`](https://libtmux.org/en/tmux/latest/catalog/hooks/window-unlinked/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | command | true | true | | `window-unzoomed` | 3.8 | window | command | true | true | | `window-zoomed` | 3.8 | window | command | true | true | | [`word-separators`](https://libtmux.org/en/tmux/latest/catalog/options/word-separators/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | session | string | false | false | | [`wrap-search`](https://libtmux.org/en/tmux/latest/catalog/options/wrap-search/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | flag | false | false | | [`xterm-keys`](https://libtmux.org/en/tmux/latest/catalog/options/xterm-keys/) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c, 3.8 | window | flag | false | false | --- # Topics Source: https://libtmux.org/en/erlang/latest/topics/ > Topics for libtmux_erlang. Understand object ownership, state, and operation behavior. - [Control connections](https://libtmux.org/en/erlang/latest/topics/control/): Read about own a control attachment. - [Diagnostics](https://libtmux.org/en/erlang/latest/topics/diagnostics/): Read about observe transport, operations and captures. - [Ownership and identity](https://libtmux.org/en/erlang/latest/topics/ownership/): Read about own a daemon or borrow an endpoint. - [Project policy](https://libtmux.org/en/erlang/latest/topics/project-policy/): Read about project policy. --- # Control connections Source: https://libtmux.org/en/erlang/latest/topics/control/ > Control connections: libtmux_erlang documentation. Attach to an existing session, verify identity on that persistent connection, inspect its attachment effects and close the client. This currently qualifies connection lifetime only. Commands still execute through the one-shot APIs; control submission and groups remain implementation work. The example owns its session. The runner provides a private tmux fixture and verifies final cleanup: ```console $ mise exec -- escript tools/run_examples.escript control ``` ```erlang -module(control_demo). -moduledoc "Attach explicitly, inspect captured values and prove detachment.". -export([run/2]). -spec run(binary(), binary()) -> map(). run(Socket, Executable) -> {ok, Server} = tmux_server:open( #{socket_path => Socket, executable => Executable}), tmux_scope:run_or_error(fun() -> {ok, Session} = tmux_session:create(Server, #{name => <<"control-demo">>, width => 120, height => 30, launch => #{argv => [<<"/bin/cat">>]}}), tmux_scope:run_or_error(fun() -> Id = tmux_model:get(id, Session), 0 = tmux_model:get(attached_count, Session), {ok, Control} = tmux_control:attach(Server, Session, #{}), tmux_scope:run_or_error(fun() -> {ok, #{phase := open, identity := same_connection}} = tmux_control:status(Control), {ok, Attached} = tmux_session:get(Server, Id), 1 = tmux_model:get(attached_count, Attached), {ok, Graph} = tmux_server:snapshot(Server), [Window] = tmux_snapshot:windows(Graph), 120 = tmux_model:get(width, Window), 30 = tmux_model:get(height, Window), ok = tmux_control:close(Control), {ok, #{phase := closed, cleanup := complete}} = tmux_control:status(Control), {ok, Detached} = tmux_session:get(Server, Id), 0 = tmux_model:get(attached_count, Detached), 0 = tmux_model:get(attached_count, Session), #{identity => same_connection, attached_count => 1, detached_count => 0, window_size => [120, 30], cleanup => complete, session_preserved => true} end, fun() -> ok = tmux_control:close(Control) end) end, fun() -> {ok, _} = tmux_session:kill(Session), ok end) end, fun() -> ok = tmux_server:close(Server) end). ``` ```json { "identity": "same_connection", "attached_count": 1, "detached_count": 0, "window_size": [120, 30], "cleanup": "complete", "session_preserved": true } ``` The archive check repeats this complete program through the installed core package. The initial session record keeps its captured count of zero; fresh reads observe one attachment and later detachment. ignore-size preserves the 120-by-30 window. In this isolated fixture without mutating hooks, closing the client preserves the session and daemon. An attachment requires a session captured or bound through the same endpoint. A second endpoint handle returns different_owner even for the same socket. The library uses [attach-session](https://libtmux.org/en/tmux/latest/manual/attach-session/) with no-output, ignore-size and `-E`. It issues no session-creation or session-option write commands. `-E` skips the native attachment environment update. Configured attachment/detachment hooks can still change state, create or destroy resources. Native policies such as destroy-unattached can remove a session when its last client detaches. Failure and cleanup do not roll back those effects. Other clients may also change state concurrently. Close retires its client/helper without issuing session or daemon destruction commands. Attachment changes attached_count. On tmux 3.6 and newer it also uses no-detach-on-destroy; earlier versions retain native destruction behavior. The caller owns the control lifetime. Caller death, parent closing or parent invalidation requests retirement. Close the control handle before closing its parent endpoint when cleanup proof matters. Parent close proves its one-shot clients' cleanup; it does not wait for separate control clients. [`tmux_control:close/1`]() returns ok only after native client/helper retirement. cleanup_incomplete preserves a supervised owner: retain the handle and retry close after repairing the cleanup problem. status distinguishes closing from closed and reports cleanup explicitly. Successfully closed handles remain usable for status and idempotent close for 60 seconds. Application shutdown alone does not prove cleanup. Unexpected hook output or reply blocks reject attachment and retire the client. The library does not disable borrowed hooks. Bounded startup includes parent registration, native exec and the identity probe. An incomplete error carries its control handle for explicit cleanup recovery. See [daemon ownership](https://libtmux.org/en/erlang/latest/topics/ownership/) for private versus borrowed lifetimes, [jobs](https://libtmux.org/en/erlang/latest/guides/operations/) for one-shot operation waits and cancellation, and [support and gaps](https://libtmux.org/en/erlang/latest/guides/compatibility/) for matrix and delivery evidence. --- # Diagnostics Source: https://libtmux.org/en/erlang/latest/topics/diagnostics/ > Diagnostics: libtmux_erlang documentation. The core emits structured OTP Logger reports under the `[libtmux]` domain. It adds no handler, telemetry dependency or background logging process. Your application's Logger configuration controls delivery and cost. Enable debug reports with `logger:set_module_level(tmux_log, debug)`. Restore the inherited level with `logger:unset_module_level(tmux_log)`, or restore the specific override returned by `logger:get_module_level/1`. A handler must also admit debug events. Filter its metadata by the `[libtmux]` domain prefix or one of its child domains. These are standard [OTP Logger configuration](https://www.erlang.org/doc/apps/kernel/logger_chapter.html#configuration) operations; they affect the Erlang node. The implementation checks the configured module level before constructing a report. Ordinary completion and credit reports use debug. Helper setup failures, incomplete cleanup and owned-daemon failures use warning. An application-shutdown cleanup summary uses error. Use `logger:set_module_level(tmux_log, none)` to suppress these reports together. Reports preserve the recorded outcome and cleanup evidence. Emitting them can increase latency and consume command-deadline or caller-wait budgets. ## Report fields `[libtmux, transport]` reports `transport_result` after a client result becomes available. `transport` is the client's reference ID. Fields include `result`, `code`, `outcome`, `cleanup`, `mode`, `duration_us`, `stdout_bytes`, `stderr_bytes` and `stdin_delivered`. Duration starts when the transport owner initializes, including native setup and retirement. A successful transport result can contain a nonzero client exit status; the endpoint determines the tmux operation's outcome. A later improvement in cleanup evidence produces another result report with the same reference. The same domain reports `transport_credit_held` when a channel delivers a chunk and withdraws further read credit until acknowledgement. `stream`, `sequence` and `held_bytes` identify that delivery. This records a flow-control transition, not proof that a subscriber is slow. It does not claim a backlog size inside tmux. One-shot output exhaustion instead appears as `output_limit` in its result report. See [control attachments](https://libtmux.org/en/erlang/latest/topics/control/) for the currently qualified control surface. `[libtmux, operation]` reports `operation_result` with `generation` and `operation` reference IDs. `phase`, `stage`, `outcome`, `cleanup`, `result`, `code` and output byte counts describe the same evidence as [`tmux_operation:status/1`]() and [`tmux_operation:await/2`](). `tracked_duration_us` starts when the endpoint begins tracking the operation; it excludes time spent holding an unused admission lease. Incomplete cleanup may first produce a `responded` report and later a `retired` report. Retirement does not turn an unknown remote outcome into success. See [jobs and operations](https://libtmux.org/en/erlang/latest/guides/operations/). `[libtmux, query]` reports `capture_result` for an admitted snapshot or query capture, including rejections after its endpoint context is established. `capture` matches the successful snapshot's metadata ID; `generation` matches the endpoint. `duration_us` covers that capture's observation interval and validation. Success includes logical `source_calls` and `observed_bytes`. Failure includes `code` and an atom-valued `reason` when available. Invalid options and failures before endpoint context is available return their normal errors without a capture report. Query retries have separate capture IDs. These counters do not include the transport's identity preflight clients. Snapshot metadata also records the hydration strategy. Batched hydration uses three field scans on a nonempty graph; isolated hydration uses one command per text/byte field per physical row. Both retain the six bracketing spine scans. See [source plans](https://libtmux.org/en/erlang/latest/concepts/queries/#source-plans) for bounds and the explicit option. `[libtmux, ownership]` reports `owned_server_failure`, `owned_server_cleanup_incomplete` and `owned_server_recovery_report_failed`. `ownership` is a reference ID; `code` and an optional atom-valued `reason` describe the failure. Retain the original API error for recovery handles and resource evidence. The report grants no authority to stop a server. Application shutdown reports `owned_server_shutdown_incomplete` in the same domain with `scope => application`, `code` and `failed_owners`. The bounded summary omits nested resource reports. Private recovery files retain the separate cleanup evidence; see [daemon ownership](https://libtmux.org/en/erlang/latest/topics/ownership/). ## Cost and data boundaries Reports contain a fixed set of reference IDs, atoms and integer counters. They omit executable paths, socket paths, argv, environment values, terminal bytes, names, filter criteria and full error maps. They are observations, not durable audit records or a replacement for returned errors. Reference IDs identify this VM's lifetimes; they are not persistent resource identities. Caller-installed Logger metadata, filters and handlers remain under application control. Handler callbacks run in the emitting process. Custom handlers can delay it, and standard handlers can switch to synchronous backpressure under load. Configure handler levels and overload protection for production. Enabling debug on a large capture produces a report per transport and operation. Reports describe the implemented one-shot and attachment lanes; they do not qualify deferred command submission or public streams. The Common Test diagnostics suite installs an owned Logger handler, exercises real helper and tmux operations, and checks reference correlation, capture rejection, read-credit withholding, setup failure, cleanup failure, bounded reports, payload exclusion and disabled logging. ## Local programming errors Library-raised validation, coverage, cardinality and explicit raising-helper exceptions carry native EEP-54 metadata. [`m:tmux_error`]() adds explanations to the shell and [`erl_error:format_exception/3`](), including the input path, allowed names or missing observations when available. Exception reasons and tagged result APIs keep their structured data. Application callback exceptions retain their original stack; the library does not relabel them as filter failures. This formatting performs no I/O and is separate from Logger reports. The [local filter program](https://libtmux.org/en/erlang/latest/concepts/queries/#portable-input) checks a malformed criterion and formats its native exception through the installed package. --- # Ownership and identity Source: https://libtmux.org/en/erlang/latest/topics/ownership/ > Ownership and identity: libtmux_erlang documentation. Use [`tmux_server:with_owned/2`]() for work inside a new private daemon and [`tmux_server:with_server/2`]() for a callback using an existing socket. Use [`tmux_server:start_owned/1`]() and [`tmux_server:open/1`]() when your application manages those lifetimes explicitly. The [README program](https://libtmux.org/en/erlang/latest/guides/getting-started/#create-capture-and-query) uses public owned startup, graph queries and cleanup; it also runs against the installed archive. Owned startup returns an endpoint and an ownership token. The daemon starts empty, without a user config, in a fresh private directory. It disables [`exit-empty`](https://libtmux.org/en/tmux/latest/catalog/options/exit-empty/) on that daemon and keeps one unattached bootstrap client alive. It does not create a session, attach an observer or change a borrowed daemon's policy. The startup budget includes readiness, a no-start socket identity probe and binding the endpoint to the observed Linux process incarnation. These observations do not make connection replacement atomic. [`tmux_server:close/1`]() retires endpoint operations and one-shot clients without issuing daemon destruction commands. Native policies and hooks may still change state. Separate [control attachments](https://libtmux.org/en/erlang/latest/topics/control/) receive an invalidation notice and begin their own retirement; close them before their endpoint to verify their cleanup too. Closing a row's endpoint never conveys the separate ownership token. [`tmux_server:stop_owned/1`]() requires that token and retires the owned endpoint, bootstrap client, daemon and finite descendants. It targets the helper's owned process tree, never a daemon discovered by path. The process that called startup owns this lifetime; its death also starts cleanup. A successful stop remains idempotent for 60 seconds. ## Preserve work and cleanup failures Scoped server callbacks run in the calling process. Successful cleanup returns `{ok, Value}` or re-raises the callback's original error, throw or exit with its stack. A callback returning `{error, Detail}` returns that ordinary value inside `{ok, Value}`; the scope does not interpret application-specific results. If cleanup fails, the result is `{error, Failure}` with [`t:tmux_server:scope_failure/0`](). Its `primary` field retains the callback value or exception, and `cleanup` retains the separate cleanup error or exception. The failure includes `server` and, for an owned scope, `ownership`. Retain these handles for inspection and an explicit cleanup retry. A cleanup timeout leaves the existing supervised owner responsible; it does not establish retirement. For nested resources, [`tmux_scope:run/2`]() preserves the same evidence without acquiring a resource. [`tmux_scope:run_or_error/2`]() returns the callback value directly and raises `{scope_cleanup_failed, Failure}` on cleanup failure. The examples use this raising form so an inner failure propagates while outer cleanup still runs. Each cleanup closure normalizes its resource's successful reply to `ok`. Nested cleanup failures retain their separate evidence. These helpers attempt cleanup once. They do not impose callback duration limits, retry work or retire separately allocated resources automatically. Close a control attachment explicitly before leaving its endpoint scope. ## Handle incomplete cleanup A cleanup deadline is an error, not retirement proof. While the application runs, the supervised controller retains uncertainty and continues receiving retirement events. Errors include separate process, endpoint, probe and namespace results. Incomplete startup also returns the ownership token and captured resources for inspection and a later stop attempt. The controller checks directory and socket filesystem identities before removal. It preserves a changed namespace and unexpected files. It never recursively removes the directory. A replacement socket can therefore remain live after the original daemon retires. A later stop can retry after the application repairs its own namespace. Filesystem checks remain observations; they do not reserve paths against concurrent changes by trusted local code. Stop explicitly before application shutdown when the caller needs a verified result. The application prepares owned cleanup while its supervisors are still running. If cleanup remains incomplete, it logs a diagnostic and writes a private recovery report outside the socket directory, or reports the write failure. The report records captured identities and remaining resources; it never authorizes signalling a PID or deleting a path. No automatic recovery runs. Stopping the OTP application itself does not establish native cleanup, and old ownership tokens expire with that application lifetime. See [jobs and operations](https://libtmux.org/en/erlang/latest/guides/operations/) for per-command ownership, cancellation and uncertain remote effects, and [support and gaps](https://libtmux.org/en/erlang/latest/guides/compatibility/) for the separate control and streaming qualification work. --- # Project policy Source: https://libtmux.org/en/erlang/latest/topics/project-policy/ > Project policy: libtmux_erlang documentation. This port provides an Erlang core and a workspace consumer. An MCP package, server or SDK integration is excluded from implementation and release scope. The [architecture decision record](https://libtmux.org/en/erlang/latest/concepts/architecture/) explains the selected design, alternatives, consequences and conditions for reconsideration. ## OTP application boundaries Develop the applications together in the Rebar3 umbrella. Each application is an independent package boundary with its own metadata, license and changelog. | Application | Responsibility | Library dependencies | | --- | --- | --- | | `libtmux_erlang` | tmux transport, operations, domain objects, snapshots and queries | OTP applications | | `libtmux_erlang_workspace` | JSON workspace loading, plans, apply and CLI | Public core API and OTP applications | The workspace application declares its core dependency in its application metadata. It uses public APIs through installed packages; source paths and private core modules are not integration boundaries. The core is independent of the workspace application. Additional core packages need their own reusable responsibility and explicit consumer dependencies. Package qualification must install each consumer outside the umbrella against the produced core package. A successful umbrella build alone does not prove that an independently installed workspace package works. Qualification builds the workspace CLI from those source packages and runs it outside the checkout; see [current support](https://libtmux.org/en/erlang/latest/guides/compatibility/). ## Runtime dependencies Use the latest stable Erlang/OTP baseline and native OTP facilities. Use OTP JSON for documents and the standard argument parser for the workspace CLI. Prefer module functions, native records, specs, tagged results and supervised processes where ownership requires them. Keep Erlang runtime dependencies within OTP. An exception requires a concrete capability need, maintenance assessment and recorded architecture decision. Test, build and documentation tools are separate from runtime dependencies. Support covers tmux 3.3a–3.8, including intermediate releases, on Linux x86_64 and arm64. CI uses only the latest stable Erlang/OTP release and samples the oldest supported and newest stable tmux releases. Verify upstream releases before updating the exact pins. Historical results retain their recorded scope. The Linux transport uses the bundled C11 executable for bounded I/O and owned process retirement. It is built from packaged source with recorded provenance. Workspace code uses that transport through the public core API. The layout follows [Rebar3 application organization](https://rebar3.org/docs/basic_usage/) and [OTP application boundaries and dependencies](https://www.erlang.org/doc/system/applications.html).