# libtmux for PowerShell
> The PowerShell library (LibTmux). These pages include its guides, tested examples and API documentation.
- [PowerShell API reference](https://libtmux.org/en/powershell/latest/reference/): every public symbol, generated from the source. Hosted on libtmux.org.
---
# Concepts
Source: https://libtmux.org/en/powershell/latest/concepts/
> Understand captured objects, stable identities, and local versus remote queries.
LibTmux cmdlets return native .NET objects. Learn which operations contact tmux,
which values are captured, and what identifies the object a later command changes.
Start with captured state before building a polling loop or retaining handles
between operations. Then use the [complete examples](https://libtmux.org/en/powershell/latest/examples/) to run these
ideas against a private server.
- [Captured state and I/O](https://libtmux.org/en/powershell/latest/concepts/captured-state/): Know when data was read and distinguish missing capture from an empty result.
- [Object identity and placement](https://libtmux.org/en/powershell/latest/concepts/identity/): Keep daemon identity, physical windows, and session placements separate.
- [Local selection and source queries](https://libtmux.org/en/powershell/latest/concepts/queries/): Choose Where-Object, structured criteria, or an explicit fresh acquisition.
---
# Captured state and I/O
Source: https://libtmux.org/en/powershell/latest/concepts/captured-state/
> Separate explicit reads from local object traversal and preserve snapshot boundaries.
A captured object describes what tmux reported during a read. Accessing its
properties does not refresh it. This makes formatting, filtering, and inspecting
a saved graph predictable even after the daemon has stopped.
## Choose the read boundary
| Operation | What happens |
| --- | --- |
| [`New-TmuxServer`]() | Describes an explicit endpoint without contacting tmux. |
| [`Connect-TmuxServer`]() | Discovers the generation of an unmaterialized handle; an already connected handle is returned unchanged. |
| [`Get-TmuxSnapshot`]() | Acquires a new object graph at the requested depth. |
| [`Get-TmuxSession`](), [`Get-TmuxWindow`](), [`Get-TmuxPane`]() | Read the selected owner through their command-specific acquisition path. |
| Property access, formatting, or [`Select-TmuxPane`]() | Use captured values locally. |
Keep one snapshot when several decisions must refer to the same captured graph.
Repeated reads can observe different names, placements, or active panes. Taking a
new snapshot returns a replacement graph; it does not update objects retained
from an earlier capture. See the [read guide](https://libtmux.org/en/powershell/latest/guides/read/) for the owner
accepted by each read cmdlet.
## Missing capture is not an empty collection
The default snapshot depth reaches panes. Shallower depths reduce the acquired
state, but relationships below that depth are unavailable. Check their
[`IsCaptured`](https://libtmux.org/en/csharp/latest/reference/libtmux-capturedrelation-iscaptured/)
state before using them. Enumerating an uncaptured relationship
raises an error; it does not return an empty list. Required uncaptured fields
likewise fail instead of inventing a value.
A captured empty list means the read found no children. A captured nullable
active child can have no value. Those results differ from a relationship that
was never acquired. Use the native captured-value contract when that distinction
matters, and choose a nullable convenience projection only when treating missing
capture as no value is intentional.
## A snapshot is a bounded observation
Acquisition takes several tmux commands. The library rejects contradictions it
can detect, such as inconsistent parent or child counts, but concurrent changes
can escape those checks. A snapshot is not an atomic transaction or a reservation
of the objects it contains.
Capture metadata records depth, generation, wall-clock boundaries, and elapsed
time. Use elapsed time for duration; the wall clock can move while a read runs.
Take a fresh snapshot after mutation or event loss when your next decision needs
current topology.
Run [create windows and panes](https://libtmux.org/en/powershell/latest/examples/create-layout/) to create a graph,
read it once, and traverse its windows locally. The
[`Get-TmuxSnapshot` reference](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxsnapshot/) gives
the supported depth and parameter details.
---
# Object identity and placement
Source: https://libtmux.org/en/powershell/latest/concepts/identity/
> Understand endpoint handles, daemon generations, physical windows, and session links.
Select the endpoint explicitly, then keep the identity returned with its native
objects. A textual pane or session ID alone is not enough to identify an object
across different servers or daemon restarts.
## Endpoint and daemon generation
[`New-TmuxServer`]() accepts an explicit socket selector. It creates a description,
not a daemon. [`Connect-TmuxServer`]() discovers the live generation and returns a
connected replacement when the supplied handle is not materialized. Keep that
returned handle when subsequent work needs the discovered identity.
Pass native objects into mutation cmdlets. Their identity and placement guards
can be retained by typed commands. Reconstructing a command from raw target text
throws away that information. Raw `-Target` on control attachment uses tmux target
syntax at attachment time; it is not the identity of a captured session.
## IDs and names serve different purposes
Session, window, and pane IDs have distinct prefixes. PowerShell expands a dollar
sign in a double-quoted string, so write a session ID as `'$0'` when entering it
literally. A window ID such as `'@1'` and a pane ID such as `'%2'` select different
kinds of object.
The read cmdlets' `-Id` and `-Name` filters are exact and case-sensitive. They do
not interpret wildcards. When both are supplied, both must match. A name can
change; retain the native result when you intend to act on the same object.
See [reading objects](https://libtmux.org/en/powershell/latest/guides/read/) for matching and empty-result behavior.
## A window can appear in several sessions
A physical window can be linked into more than one session and can have more
than one placement. Its index belongs to the placement. Do not use a window's
name or one session's index as a global key.
Captured session-window links preserve these occurrences. A physical pane still
belongs to its window; a traversal through multiple session placements can
encounter it more than once. Choose whether your operation is about physical
windows, distinct sessions, or placements before deduplicating results.
Filtering a captured collection changes membership, not the graph referenced by
the selected objects. Parent and sibling navigation still describes the original
capture. Refreshing one pane does not silently recreate an old parent graph;
acquire a new snapshot for a coherent traversal.
The [placement guide](https://libtmux.org/en/powershell/latest/guides/placement/) covers links and moves. Continue
with [ownership and cleanup](https://libtmux.org/en/powershell/latest/topics/ownership/) before deciding which
resources your application may remove.
---
# Local selection and source queries
Source: https://libtmux.org/en/powershell/latest/concepts/queries/
> Choose ordinary pipelines, reusable criteria, or a fresh daemon-side query.
Use a local pipeline to inspect data you already captured. Use an explicit source
query when the decision requires a fresh read from tmux. A filter never makes an
old snapshot current.
## Choose the simplest useful query
| Need | Use |
| --- | --- |
| An ordinary PowerShell predicate over existing objects | [`Where-Object`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/where-object) |
| Reusable, inspectable criteria for captured objects | [`New-TmuxQuery`]() and the matching [`Select-TmuxSession`](), [`Select-TmuxWindow`](), or [`Select-TmuxPane`]() |
| A fresh acquisition with a query plan | [`Invoke-TmuxQuery`]() |
| The allowed fields and operators | [`Get-TmuxQueryField`]() |
The structured selectors preserve order, duplicates, native object identity,
and the captured parent graph. They do not reacquire matching objects. When one
result is required, `-ExactlyOne` makes both zero matches and multiple matches
visible instead of silently taking the first.
## Matching has explicit semantics
Criteria field names accept the documented wire names and native-property
aliases. Keys are case-insensitive, but supplying two aliases for the same field
is an error. Entries in one map combine with AND. A bare field value means
equality; an operator map describes another comparison.
String comparisons are ordinal and case-sensitive by default, unlike many
PowerShell operators. Choose a documented case-insensitive operator deliberately.
Numeric criteria require the accepted integer types; they do not coerce arbitrary
strings. An omitted condition differs from a condition whose value is null.
Relationship predicates operate on captured relationships. If the query needs
panes, capture to that depth first. An unavailable relationship raises an error
rather than making an [`Every`](https://libtmux.org/en/powershell/latest/guides/query/#match-captured-relationships)
or [`None`](https://libtmux.org/en/powershell/latest/guides/query/#match-captured-relationships) condition accidentally true.
## Inspect before dispatching
[`Get-TmuxQueryPlan`]() reports pushed and residual predicates, fields, required
depth, and fallback reasons without contacting tmux. Supply the intended daemon
version when inspecting a version-dependent plan.
[`Invoke-TmuxQuery`]() performs the new acquisition. `-AsResult` retains its complete
captured graph even when the selected collection is empty. A plan can reduce
work; it does not turn a multi-command read into an atomic snapshot.
The [query guide](https://libtmux.org/en/powershell/latest/guides/query/) owns the operator catalog, query JSON,
relationship criteria, and pushdown modes. Run
[create windows and panes](https://libtmux.org/en/powershell/latest/examples/create-layout/) for a complete program
using exact local selection after one snapshot.
---
# tmux client library for PowerShell
Source: https://libtmux.org/en/powershell/latest/core/
> tmux client library for PowerShell. Control tmux, connect to and create servers, navigate sessions, windows, and panes, send keys, watch for changes via control mode, capture pane contents
Control tmux, connect to and create servers, navigate sessions, windows, and panes, send keys, watch for changes via control mode, capture pane contents.
## At a glance
| Type | Wraps |
| ---- | ----- |
| [`LibTmux\Get-TmuxServer`](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxserver/) | A tmux server |
| [`LibTmux\Get-TmuxSession`](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxsession/) | A session, ID `$n` |
| [`LibTmux\Get-TmuxWindow`](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxwindow/) | A window in a session, ID `@n` |
| [`LibTmux\Get-TmuxPane`](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpane/) | A pane in a window, ID `%n` |
## Typed API
- Typed objects instead of parsed format strings: [`LibTmux\Get-TmuxPane`](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpane/)
- Filtering and queries over tmux objects: [`LibTmux\New-TmuxQuery`](https://libtmux.org/en/powershell/latest/reference/libtmux-new-tmuxquery/)
## What you get over the tmux CLI
- Connect to or start a tmux server: [`LibTmux\Connect-TmuxServer`](https://libtmux.org/en/powershell/latest/reference/libtmux-connect-tmuxserver/)
- Traversal from a server down to its panes: [`LibTmux\Get-TmuxSnapshot`](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxsnapshot/)
- Send keys to a pane: [`LibTmux\Send-TmuxKey`](https://libtmux.org/en/powershell/latest/reference/libtmux-send-tmuxkey/)
- Watch for changes through tmux control mode: [`LibTmux\Watch-TmuxEvent`](https://libtmux.org/en/powershell/latest/reference/libtmux-watch-tmuxevent/)
- Capture pane contents: [`LibTmux\Get-TmuxPaneContent`](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/)
- Arguments passed as a list, with no shell quoting: [`LibTmux\Invoke-TmuxCommand`](https://libtmux.org/en/powershell/latest/reference/libtmux-invoke-tmuxcommand/)
- [Guides](https://libtmux.org/en/powershell/latest/guides/): Task guides for PowerShell.
- [Topics](https://libtmux.org/en/powershell/latest/topics/): Subject-by-subject, with PowerShell in every code block.
- [Examples](https://libtmux.org/en/powershell/latest/examples/): Complete programs, sourced from the code each port tests.
- [API reference](https://libtmux.org/en/powershell/latest/reference/): Types and functions of the PowerShell API.
---
# Examples
Source: https://libtmux.org/en/powershell/latest/examples/
> Complete programs with setup, expected output, and owned-server cleanup.
Run a complete program for the task you need. Each page includes the entire
program, dependency setup, a run command, expected output, and cleanup.
The examples create private tmux servers and leave existing sessions alone.
Start with [create windows and panes](https://libtmux.org/en/powershell/latest/examples/create-layout/), then choose another task.
- [Create windows and panes](https://libtmux.org/en/powershell/latest/examples/create-layout/): Create a session with two windows, then query a captured snapshot.
- [Check command completion](https://libtmux.org/en/powershell/latest/examples/command-completion/): Run a shell command and verify its authenticated nonzero exit status.
- [Wait for a service](https://libtmux.org/en/powershell/latest/examples/wait-for-service/): Wait for an HTTP readiness line and check the service responds.
---
# Create windows and panes
Source: https://libtmux.org/en/powershell/latest/examples/create-layout/
> Create a session with two windows, then query a captured snapshot.
Create an isolated tmux server with an editor window containing two
panes and a separate logs window. Read their names and pane IDs from one
captured snapshot, then remove the session and stop its server.
## Setup
PowerShell 7.4.20 with PSResourceGet 1.1.1, POSIX shell and tmux on Linux. Start in an empty directory.
The following commands run in a POSIX shell.
Install [LibTmux](https://www.powershellgallery.com/packages/LibTmux/)
from PowerShell Gallery with PSResourceGet. Installation uses your current
user's module directory; the program loads it with `Import-Module LibTmux`.
```console
$ pwsh -NoLogo -NoProfile -Command '
$ErrorActionPreference = "Stop"
Install-PSResource -Name LibTmux `
-Repository PSGallery -Scope CurrentUser -TrustRepository
'
```
## Program
Save this complete program as `quickstart.ps1`.
```powershell title="quickstart.ps1"
$ErrorActionPreference = 'Stop'
Import-Module LibTmux
$session = $null
$failure = $null
try {
$socket = 'libtmux-home-' + [Guid]::NewGuid().ToString('N')
$server = New-TmuxServer -SocketName $socket -ConfigurationFile /dev/null
$session = $server | New-TmuxSession `
-Name demo -WindowName editor -Command 'exec /bin/cat'
$pane = $session | Get-TmuxPane
$null = $pane | Split-TmuxPane -Horizontal -Command 'exec /bin/cat'
$null = $session | New-TmuxWindow -Name logs -Command 'exec /bin/cat'
$captured = ($server | Get-TmuxSnapshot).Sessions |
Select-TmuxSession -Criteria @{ Name = 'demo' } -ExactlyOne
foreach ($window in $captured.Windows) {
'{0}: {1}' -f $window.Name, ($window.Panes.Id -join ', ')
}
} catch {
$failure = [InvalidOperationException]::new(
"tmux quickstart failed: $($_.Exception.Message)", $_.Exception)
throw $failure
} finally {
if ($session) {
$cleanupErrors = @()
$session | Remove-TmuxSession -Confirm:$false `
-ErrorAction SilentlyContinue -ErrorVariable cleanupErrors
if ($cleanupErrors) {
if ($failure) {
$errors = @($failure) + $cleanupErrors.Exception
throw [AggregateException]::new(
'tmux operation and cleanup failed.',
[Exception[]]$errors)
}
throw $cleanupErrors[0]
}
}
}
```
The private socket name is unique to this run. `-ConfigurationFile /dev/null`
keeps personal tmux configuration out of the example. Each pane runs `/bin/cat`
so it stays alive without a shell prompt or startup commands.
`-ExactlyOne` rejects missing or ambiguous session matches. The `finally` block
removes the only session; tmux then exits. If an operation and cleanup both
fail, the script preserves both errors.
## Run
```console
$ unset TMUX TMUX_PANE
$ export ENV=/dev/null BASH_ENV=/dev/null SHELL=/bin/sh
$ pwsh -NoLogo -NoProfile -File quickstart.ps1
```
Expected output:
```text
editor: %0, %1
logs: %2
```
## Related APIs
- [`New-TmuxSession`](https://libtmux.org/en/powershell/latest/reference/libtmux-new-tmuxsession/)
- [`Split-TmuxPane`](https://libtmux.org/en/powershell/latest/reference/libtmux-split-tmuxpane/)
- [`Get-TmuxSnapshot`](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxsnapshot/)
- [`Select-TmuxSession`](https://libtmux.org/en/powershell/latest/reference/libtmux-select-tmuxsession/)
- [`Remove-TmuxSession`](https://libtmux.org/en/powershell/latest/reference/libtmux-remove-tmuxsession/)
## Source and verification
This program uses [LibTmux at the package source revision](https://github.com/libtmux/libtmux-powershell/blob/fcd0634e9ca887b70d88915c2d8e26c5da2737e5/README.md).
The verification runner executes these displayed files and setup commands
unchanged, checks the output, and checks that the program stopped its private
tmux server. Each example runs independently.
---
# Check command completion
Source: https://libtmux.org/en/powershell/latest/examples/command-completion/
> Run a shell command and verify its authenticated nonzero exit status.
Run `exit 7` inside a disposable shell pane and verify its result.
The program waits for the command's authenticated completion status, then
removes the session. It does not infer success from text in a terminal.
## Setup
PowerShell 7.4.20 with PSResourceGet 1.1.1, POSIX shell and tmux on Linux. Start in an empty directory.
The following commands run in a POSIX shell.
Install [LibTmux](https://www.powershellgallery.com/packages/LibTmux/)
from PowerShell Gallery with PSResourceGet. Installation uses your current
user's module directory; the program loads it with `Import-Module LibTmux`.
```console
$ pwsh -NoLogo -NoProfile -Command '
$ErrorActionPreference = "Stop"
Install-PSResource -Name LibTmux `
-Repository PSGallery -Scope CurrentUser -TrustRepository
'
```
## Program
Save this complete program as `command-completion.ps1`.
```powershell title="command-completion.ps1"
$ErrorActionPreference = 'Stop'
Import-Module LibTmux
$session = $null
$failure = $null
try {
$socket = 'libtmux-example-' + [Guid]::NewGuid().ToString('N')
$server = New-TmuxServer -SocketName $socket -ConfigurationFile /dev/null
$session = $server | New-TmuxSession `
-Name command -Command 'exec /bin/sh'
$pane = $session | Get-TmuxPane
$result = $pane | Invoke-TmuxPaneCommand `
-Command 'exit 7' -Timeout 5 -Confirm:$false
if ($result.TimedOut -or $result.ExitStatus -ne 7) {
throw 'The shell command did not complete with exit status 7.'
}
'exit status: {0}' -f $result.ExitStatus
} catch {
$failure = [InvalidOperationException]::new(
"tmux example failed: $($_.Exception.Message)", $_.Exception)
throw $failure
} finally {
if ($session) {
$cleanupErrors = @()
$session | Remove-TmuxSession -Confirm:$false `
-ErrorAction SilentlyContinue -ErrorVariable cleanupErrors
if ($cleanupErrors) {
if ($failure) {
$errors = @($failure) + $cleanupErrors.Exception
throw [AggregateException]::new(
'tmux operation and cleanup failed.',
[Exception[]]$errors)
}
throw $cleanupErrors[0]
}
}
}
```
[`Invoke-TmuxPaneCommand`]() runs the command in a subshell. A nonzero exit
status is a result, so this example checks [`ExitStatus`]() explicitly.
[`TimedOut`](https://libtmux.org/en/csharp/latest/reference/libtmux-panerunresult-timedout/)
means the command may still be running; the script treats that as
failure and still cleans up its owned session.
This example changes only the private server it creates. The `finally` block
retains cleanup errors, including when the command operation also fails.
## Run
```console
$ unset TMUX TMUX_PANE
$ export ENV=/dev/null BASH_ENV=/dev/null SHELL=/bin/sh
$ pwsh -NoLogo -NoProfile -File command-completion.ps1
```
Expected output:
```text
exit status: 7
```
## Related APIs
- [`Invoke-TmuxPaneCommand`](https://libtmux.org/en/powershell/latest/reference/libtmux-invoke-tmuxpanecommand/)
- [Send input to a pane](https://libtmux.org/en/powershell/latest/guides/input/)
- [`Remove-TmuxSession`](https://libtmux.org/en/powershell/latest/reference/libtmux-remove-tmuxsession/)
## Source and verification
This program uses [LibTmux at the package source revision](https://github.com/libtmux/libtmux-powershell/blob/fcd0634e9ca887b70d88915c2d8e26c5da2737e5/README.md).
The verification runner executes these displayed files and setup commands
unchanged, checks the output, and checks that the program stopped its private
tmux server. Each example runs independently.
---
# Wait for a service
Source: https://libtmux.org/en/powershell/latest/examples/wait-for-service/
> Wait for an HTTP readiness line and check the service responds.
Start Python's HTTP server on an available loopback port, wait for
its readiness line, and make an HTTP request. The session is removed on
success or failure, which also stops the HTTP server.
## Setup
PowerShell 7.4.20 with PSResourceGet 1.1.1, Python 3, a POSIX shell,
and tmux on Linux. Start in an empty directory.
The following commands run in a POSIX shell.
Install [LibTmux](https://www.powershellgallery.com/packages/LibTmux/)
from PowerShell Gallery with PSResourceGet. Installation uses your current
user's module directory; the program loads it with `Import-Module LibTmux`.
```console
$ pwsh -NoLogo -NoProfile -Command '
$ErrorActionPreference = "Stop"
Install-PSResource -Name LibTmux `
-Repository PSGallery -Scope CurrentUser -TrustRepository
'
```
## Program
Save this complete program as `wait-for-service.ps1`.
```powershell title="wait-for-service.ps1"
$ErrorActionPreference = 'Stop'
Import-Module LibTmux
$session = $null
$failure = $null
try {
$socket = 'libtmux-example-' + [Guid]::NewGuid().ToString('N')
$server = New-TmuxServer -SocketName $socket -ConfigurationFile /dev/null
$session = $server | New-TmuxSession -Name http `
-Command 'exec python3 -u -m http.server 0 --bind 127.0.0.1'
$pane = $session | Get-TmuxPane
$ready = $pane | Wait-TmuxPaneText `
-Pattern '^Serving HTTP on 127\.0\.0\.1 port [0-9]+' `
-CaseSensitive -Timeout 10 -TailLines 4 -Confirm:$false
if ($ready.Outcome -notin 'PresentAtEntry', 'Matched') {
throw "HTTP readiness ended with $($ready.Outcome)."
}
$tail = $ready.Tail -join "`n"
$port = [regex]::Match($tail, 'port ([0-9]+)').Groups[1].Value
$response = Invoke-WebRequest "http://127.0.0.1:$port/" `
-TimeoutSec 5 -NoProxy
if ($response.StatusCode -ne 200) {
throw "HTTP returned $($response.StatusCode)."
}
'readiness: observed'
'HTTP status: {0}' -f $response.StatusCode
} catch {
$failure = [InvalidOperationException]::new(
"tmux example failed: $($_.Exception.Message)", $_.Exception)
throw $failure
} finally {
if ($session) {
$cleanupErrors = @()
$session | Remove-TmuxSession -Confirm:$false `
-ErrorAction SilentlyContinue -ErrorVariable cleanupErrors
if ($cleanupErrors) {
if ($failure) {
$errors = @($failure) + $cleanupErrors.Exception
throw [AggregateException]::new(
'tmux operation and cleanup failed.',
[Exception[]]$errors)
}
throw $cleanupErrors[0]
}
}
}
```
[`Wait-TmuxPaneText`]() accepts a line already visible when observation starts
([`PresentAtEntry`]()) or one observed later ([`Matched`]()). Both are valid here.
A matching line only establishes the text condition; [`Invoke-WebRequest`]()
checks that the service actually responds.
The readiness wait has a ten-second limit, and the HTTP request has a
five-second limit. No fixed sleep is needed. The wait closes its control
client; the script separately removes its owned session in `finally`.
## Run
```console
$ unset TMUX TMUX_PANE
$ export ENV=/dev/null BASH_ENV=/dev/null SHELL=/bin/sh
$ pwsh -NoLogo -NoProfile -File wait-for-service.ps1
```
Expected output:
```text
readiness: observed
HTTP status: 200
```
## Related APIs
- [`Wait-TmuxPaneText`](https://libtmux.org/en/powershell/latest/reference/libtmux-wait-tmuxpanetext/)
- [Wait for an application's readiness line](https://libtmux.org/en/powershell/latest/guides/input/#wait-for-an-applications-readiness-line)
- [`Remove-TmuxSession`](https://libtmux.org/en/powershell/latest/reference/libtmux-remove-tmuxsession/)
## Source and verification
This program uses [LibTmux at the package source revision](https://github.com/libtmux/libtmux-powershell/blob/fcd0634e9ca887b70d88915c2d8e26c5da2737e5/README.md).
The verification runner executes these displayed files and setup commands
unchanged, checks the output, and checks that the program stopped its private
tmux server. Each example runs independently.
---
# Getting started
Source: https://libtmux.org/en/powershell/latest/guides/getting-started/
> Getting started: LibTmux documentation.
[](https://github.com/libtmux/libtmux-powershell/actions/workflows/ci.yml)
[](https://www.powershellgallery.com/packages/LibTmux/)
[](https://libtmux.org/en/powershell/)
[](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/LICENSE)
Drive [tmux](https://github.com/tmux/tmux) from PowerShell with native cmdlets.
[Sessions][session], [windows][window] and [panes][pane] come back as typed
objects that an ordinary pipeline can filter.
Run a command and read its exit status with
[`Invoke-TmuxPaneCommand`][invoke-tmuxpanecommand], find what a server holds
with [`Get-TmuxSnapshot`][get-tmuxsnapshot], wait for output with
[`Wait-TmuxPaneText`][wait-tmuxpanetext], and apply a reviewed workspace file
with [`Invoke-TmuxWorkspace`][invoke-tmuxworkspace].
Releases are numbered `0.1.N`, and each release increments `N`. The API is not
settled: any release may change or remove exported identifiers, and the
changelog marks each break. Pin an exact version to avoid one.
Both modules are available on PowerShell Gallery:
[LibTmux](https://www.powershellgallery.com/packages/LibTmux)
and [LibTmux.Workspace](https://www.powershellgallery.com/packages/LibTmux.Workspace).
It needs PowerShell 7.4 or later and tmux 3.3a or newer on the same Linux
host, including WSL. [Compatibility](https://libtmux.org/en/powershell/latest/guides/compatibility/) lists what CI runs.
tmux release candidates are not supported: a feature can require one only
until its release ships, and a candidate such as `X.Y-rcN` ranks below `X.Y`.
See [Release candidates](https://libtmux.org/en/tmux/guides/tmux-support/#release-candidates).
**Contents** — [Quick start](https://libtmux.org/en/powershell/latest/guides/getting-started/#quick-start) ·
[Find things](https://libtmux.org/en/powershell/latest/guides/getting-started/#find-sessions-windows-and-panes) ·
[Service readiness](https://libtmux.org/en/powershell/latest/guides/getting-started/#wait-for-service-readiness) ·
[Choose how to run](https://libtmux.org/en/powershell/latest/guides/getting-started/#choose-how-to-run) ·
[Workspaces](https://libtmux.org/en/powershell/latest/guides/getting-started/#build-a-workspace-from-a-file) · [Packages](https://libtmux.org/en/powershell/latest/guides/getting-started/#packages) ·
[From source](https://libtmux.org/en/powershell/latest/guides/getting-started/#install-from-source) · [Leaves out](https://libtmux.org/en/powershell/latest/guides/getting-started/#what-it-leaves-out) ·
[Support](https://libtmux.org/en/powershell/latest/guides/getting-started/#support-and-status) · [Documentation](https://libtmux.org/en/powershell/latest/guides/getting-started/#documentation)
**Reference** — [Cmdlet reference](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/docs/reference/README.md) ·
[Compatibility](https://libtmux.org/en/powershell/latest/guides/compatibility/) ·
[Troubleshooting](https://libtmux.org/en/powershell/latest/guides/troubleshooting/) ·
[MCP](https://libtmux.org/en/powershell/latest/guides/mcp/#discover-before-calling) · [License](https://libtmux.org/en/powershell/latest/guides/getting-started/#license)
## Quick start
The command-completion example below needs tmux 3.4 or newer. Ordinary reads
and writes support tmux 3.3a; see [optional features](https://libtmux.org/en/powershell/latest/guides/compatibility/#optional-features).
Install the module from the PowerShell Gallery in PowerShell 7.4 or later
(`pwsh`) on Linux, including WSL. [`Install-PSResource`]() ships with PowerShell
7.4; Windows PowerShell 5.1 has no such command and cannot load the module:
```console
$ Install-PSResource -Name LibTmux
```
Import it:
```console
$ Import-Module -Name LibTmux -ErrorAction Stop
```
[`New-TmuxServer`][new-tmuxserver] makes a handle on a socket and an empty tmux
configuration of its own. It contacts nothing, so your default server stays
untouched:
```powershell
$server = LibTmux\New-TmuxServer `
-SocketName ('libtmux-readme-' + [Guid]::NewGuid().ToString('N')) `
-ConfigurationFile /dev/null
```
Without a socket, a handle passes tmux none, so tmux picks the server: the one
in `TMUX` inside a pane, otherwise its default. `LIBTMUX_SOCKET_PATH` or
`LIBTMUX_SOCKET` chooses one instead; [read more](https://libtmux.org/en/powershell/latest/guides/read/).
[`Invoke-TmuxPaneCommand`][invoke-tmuxpanecommand] runs a command in a pane and
returns a [`LibTmux.PaneRunResult`][panerunresult].
[`New-TmuxSession`][new-tmuxsession] starts the shell, and the `finally` block
removes only that session with [`Remove-TmuxSession`][remove-tmuxsession]:
```powershell
& {
$ErrorActionPreference = 'Stop'
$name = 'pane-run-' + [Guid]::NewGuid().ToString('N')
$session = $server | New-TmuxSession -Name $name -Command 'exec /bin/sh'
try {
$pane = $session | Get-TmuxPane
$pane |
Invoke-TmuxPaneCommand -Command 'exit 7' -Timeout 5 -Confirm:$false
} finally {
$session | Remove-TmuxSession -Confirm:$false
}
}
```
The result has `ExitStatus = 7` and `TimedOut = False`. A nonzero exit status
comes back in [`ExitStatus`]() and raises no error. If the timeout passes first, the
command may still be running and the result has no exit status.
[Command completion](https://libtmux.org/en/powershell/latest/guides/input/#run-a-command-to-completion) covers
concurrency and output behavior.
Every PowerShell block on this page is a copy of a tested source. The
[guide test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/GuideExamples.Tests.ps1)
fails when a copy drifts, and the
[installed workflow test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/ReadmeWorkflow.Tests.ps1)
runs the blocks in order on an owned tmux server. Later sections reuse
`$server`.
## Find sessions, windows, and panes
### [`Get-TmuxSnapshot`][get-tmuxsnapshot]: what tmux holds, in one read
One call returns every session, window and pane as native objects.
This example builds a tree with [`New-TmuxSession`][new-tmuxsession],
[`Split-TmuxPane`][split-tmuxpane] and [`New-TmuxWindow`][new-tmuxwindow],
reads it, and removes it with [`Remove-TmuxSession`][remove-tmuxsession]. `cat`
keeps the panes open:
```powershell
$captured = & {
$ErrorActionPreference = 'Stop'
$session = $server |
New-TmuxSession -Name demo -WindowName editor -Command 'exec /bin/cat'
try {
$pane = $session | Get-TmuxPane
$null = $pane | Split-TmuxPane -Horizontal -Command 'exec /bin/cat'
$null = $session | New-TmuxWindow -Name logs -Command 'exec /bin/cat'
($server | Get-TmuxSnapshot).Sessions | Where-Object Name -CEQ demo
} finally {
$session | Remove-TmuxSession -Confirm:$false
}
}
```
`$captured` is a [`LibTmux.Session`][session] that stays readable after
cleanup. Its [`Windows`][session-windows] hold [`LibTmux.Window`][window]
objects, and each window's [`Panes`][window-panes] hold
[`LibTmux.Pane`][pane] objects:
| Expression | Captured result |
| --- | --- |
| `$captured` | A [`Session`]() named `demo` |
| [`$captured.Windows`][session-windows] | Two [`Window`]() objects: `editor` and `logs` |
| [`$captured.Windows[0].Panes`][window-panes] | Two [`Pane`]() objects in `editor`; `logs` has one |
A captured object keeps what tmux reported when you read it. Call
[`Get-TmuxSnapshot`][get-tmuxsnapshot] again to see a later change.
[Snapshots and linked windows](https://libtmux.org/en/powershell/latest/guides/read/) cover IDs, active children and
captured versus unavailable fields.
### Filter the captured graph
Walk it with ordinary PowerShell. [`Where-Object`](), navigation, formatting and
property access use the captured data and start no tmux client:
```powershell
$captured.Windows |
Where-Object { $_.Panes.Count -gt 1 } |
Select-Object Name, @{ Name = 'PaneCount'; Expression = { $_.Panes.Count } }
```
It prints `editor` with a pane count of 2. `logs` has one pane and drops out:
```text
Name PaneCount
---- ---------
editor 2
```
### [`Select-TmuxWindow`][select-tmuxwindow]: pick windows by criteria
The structured equivalent selects the one window with at least two captured
panes. `-ExactlyOne` reports zero or multiple matches. This query performs no
I/O either:
```powershell
$captured.Windows |
Select-TmuxWindow -Criteria @{ 'Panes.Count' = @{ Ge = 2 } } -ExactlyOne
```
It returns the `editor` window, the same object as `$captured.Windows[0]`.
[The query guide](https://libtmux.org/en/powershell/latest/guides/query/) shows native predicates, Boolean and
relationship criteria, and explicit fresh source queries.
## Wait for service readiness
### [`Wait-TmuxPaneText`][wait-tmuxpanetext]: wait for a readiness line
It watches a pane's rendered text and returns a
[`LibTmux.PaneWaitResult`][panewaitresult]. On tmux 3.7 or newer it uses a
temporary control client; on earlier supported releases it polls instead.
[`Send-TmuxText`][send-tmuxtext] and [`Send-TmuxKey`][send-tmuxkey] type into
the pane first, and [`Get-TmuxPaneContent`][get-tmuxpanecontent] reads its
screen. When the application can signal completion itself, use
[`Wait-TmuxChannel`][wait-tmuxchannel] with
[a cooperative channel](https://libtmux.org/en/powershell/latest/guides/input/#send-a-command-and-wait-for-its-output).
With Python 3 on `PATH`, this example starts an HTTP server on a free loopback
port, waits for its readiness line, then requests a page. The session's cleanup
also stops the server:
```powershell
& {
$ErrorActionPreference = 'Stop'
$session = $server | New-TmuxSession `
-Name ('http-' + [Guid]::NewGuid().ToString('N')) `
-Command 'exec python3 -u -m http.server 0 --bind 127.0.0.1'
try {
$pane = $session | Get-TmuxPane
$ready = $pane | Wait-TmuxPaneText `
-Pattern '^Serving HTTP on 127\.0\.0\.1 port [0-9]+' `
-CaseSensitive -Timeout 10 -TailLines 4 -Confirm:$false
if ($ready.Outcome -notin 'PresentAtEntry', 'Matched') {
throw "HTTP readiness ended with $($ready.Outcome)."
}
$tail = $ready.Tail -join "`n"
$port = [regex]::Match($tail, 'port ([0-9]+)').Groups[1].Value
$uri = "http://127.0.0.1:$port/"
$response = Invoke-WebRequest -Uri $uri -TimeoutSec 5 -NoProxy
$ready
$response.StatusCode
} finally {
$session | Remove-TmuxSession -Confirm:$false
}
}
```
The outcome is [`PresentAtEntry`]() or [`Matched`](), followed by HTTP status 200. The
wait closes any control client it creates, and the example removes only its
own session.
A text match shows the readiness line; the HTTP request checks the service.
[Pane-text waits](https://libtmux.org/en/powershell/latest/guides/input/#wait-for-an-applications-readiness-line) cover
stop patterns, bounded tails, cancellation and disclosed event loss.
## Choose how to run
Pick a mode by who owns the client and how a failure is reported:
| Task | Use | Example |
| --- | --- | --- |
| Read or change tmux state | Typed cmdlets and pipelines | [Create sessions and panes](https://libtmux.org/en/powershell/latest/guides/create/) |
| Run a shell command and check its exit status | [`Invoke-TmuxPaneCommand`]() | [Run to completion](https://libtmux.org/en/powershell/latest/guides/input/#run-a-command-to-completion) |
| Wait for a running application's readiness line | [`Wait-TmuxPaneText`]() | [Readiness and an HTTP health check](https://libtmux.org/en/powershell/latest/guides/getting-started/#wait-for-service-readiness) |
| Enter a session interactively | [`Enter-TmuxSession`]() | [Attach your foreground terminal](https://libtmux.org/en/powershell/latest/reference/libtmux-enter-tmuxsession/) |
| Run an ordered batch | [`New-TmuxCommand`]() → [`Invoke-TmuxChain`]() | [Compose commands](https://libtmux.org/en/powershell/latest/guides/commands/) |
| Reuse a connected client | [`Connect-TmuxControl`]() → [`Invoke-TmuxControlCommand`]() | [Control commands and cleanup](https://libtmux.org/en/powershell/latest/guides/commands/) |
| React to output and notifications | [`Watch-TmuxEvent`]() | [Bounded event streams](https://libtmux.org/en/powershell/latest/guides/watch/) |
| Keep the prompt available | [`Start-ThreadJob`]() | [Bounded background jobs](https://libtmux.org/en/powershell/latest/guides/watch/#bound-background-output) |
| Run commands concurrently | `ForEach-Object -Parallel` | [Independent clients](https://libtmux.org/en/powershell/latest/guides/watch/#run-independent-commands-concurrently) |
An older daemon refuses these before anything changes:
[`Invoke-TmuxPaneCommand`][invoke-tmuxpanecommand] needs tmux 3.4, and
[`Connect-TmuxControl`][connect-tmuxcontrol] and
[`Watch-TmuxEvent`][watch-tmuxevent] with a server need 3.7.
Other commands are refused on the releases they harm. The
[optional features](https://libtmux.org/en/powershell/latest/guides/compatibility/#optional-features) table lists each
one, and [`capabilities.json`](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/capabilities.json) holds the same list for an
assistant or a script to read.
The raw-command cmdlets [`Invoke-TmuxCommand`][invoke-tmuxcommand],
[`Invoke-TmuxChain`][invoke-tmuxchain] and
[`Invoke-TmuxControlCommand`][invoke-tmuxcontrolcommand] check the command
they are given and nothing nested in it, such as an [`if-shell`](https://libtmux.org/en/tmux/latest/manual/if-shell/) string, a
[`bind-key`](https://libtmux.org/en/tmux/latest/manual/bind-key/) command or a brace block.
On exactly tmux 3.7, name every [`break-pane`](https://libtmux.org/en/tmux/latest/manual/break-pane/), including the one `prefix !`
runs, or upgrade to 3.7a: a nested nameless one ends the server.
[What the checks do not read](https://libtmux.org/en/powershell/latest/guides/compatibility/#what-the-checks-do-not-read)
lists the other failures.
### [`Connect-TmuxControl`][connect-tmuxcontrol]: one client for repeated commands
It connects one control client. [`New-TmuxCommand`][new-tmuxcommand] builds a
command, [`Invoke-TmuxControlCommand`][invoke-tmuxcontrolcommand] sends it
through the client, and [`Disconnect-TmuxControl`][disconnect-tmuxcontrol] ends
it. [`Invoke-TmuxChain`][invoke-tmuxchain] sends an ordered batch in one
invocation.
This example uses the private endpoint from above, reads a session name, then
disconnects and removes the session it created:
```powershell
& {
$ErrorActionPreference = 'Stop'
$session = $server |
New-TmuxSession -Name control-demo -Command 'exec /bin/cat'
try {
$client = $server |
Connect-TmuxControl -Target 'control-demo' -ErrorAction Stop
try {
$command = New-TmuxCommand -Name display-message -Arguments @(
'-p', '#{session_name}'
)
$client |
Invoke-TmuxControlCommand -Command $command -ErrorAction Stop
} finally {
$client | Disconnect-TmuxControl -Confirm:$false
}
} finally {
$session | Remove-TmuxSession -Confirm:$false
}
}
```
The reply is `control-demo`. The client stays connected across commands inside
the inner `try` block. The [control guide](https://libtmux.org/en/powershell/latest/guides/commands/#reuse-a-control-client)
covers multiple commands and cancellation.
The other modes in short:
- [`Enter-TmuxSession`][enter-tmuxsession] attaches your foreground terminal to
a session.
- Foreground cmdlets and `ForEach-Object -Parallel` occupy their calling
pipeline.
- Thread jobs return the prompt while they run.
- [`Watch-TmuxEvent`][watch-tmuxevent] accepts event-count and text-byte limits.
The [mode guide](https://libtmux.org/en/powershell/latest/guides/commands/) explains when chains merge failure
attribution.
## Build a workspace from a file
Describe a session once in YAML or JSON, review the plan, then apply it.
Installing the workspace module also installs its exact core dependency:
```console
$ Install-PSResource -Name LibTmux.Workspace
```
Import both modules:
```console
$ Import-Module -Name LibTmux, LibTmux.Workspace -ErrorAction Stop
```
### [`Import-TmuxWorkspace`][import-tmuxworkspace]: read a declaration
It parses YAML or JSON without contacting tmux or running the commands in it.
[`Get-TmuxWorkspace`][get-tmuxworkspace] finds declaration files,
[`Resolve-TmuxWorkspace`][resolve-tmuxworkspace] expands directories and
[`Test-TmuxWorkspace`][test-tmuxworkspace] validates one. This declaration has
two panes in one window:
```powershell
$workspace = LibTmux.Workspace\Import-TmuxWorkspace -Yaml @'
session_name: readme-workspace-preview
windows:
- window_name: editor
panes:
- shell_command: exec /bin/sh
- shell_command: exec /bin/sh
'@
```
It returns a [`LibTmux.Workspace.WorkspaceFile`][workspacefile] and prints
nothing.
### [`Get-TmuxWorkspacePlan`][get-tmuxworkspaceplan]: review before anything runs
It plans on the same private endpoint. Planning may read tmux state and creates
nothing:
```powershell
$workspacePlan = $workspace | LibTmux.Workspace\Get-TmuxWorkspacePlan `
-Server $server -ServerStartup CreateOrJoin -ExistingSession Error
```
Review the actions. Their default view keeps command text, option values, paths
and environment values hidden; inspect an action's
[`Request`][workspaceaction-request] only in a trusted terminal:
```powershell
$workspacePlan.Actions
```
It lists the actions in order, from
[`CreateSession`][workspaceactionkind-createsession] to
[`CaptureResult`][workspaceactionkind-captureresult], with command text shown
as `[redacted]`.
### [`Invoke-TmuxWorkspace`][invoke-tmuxworkspace]: preview, then apply
`-WhatIf` previews the plan without applying it:
```powershell
$workspacePlan | LibTmux.Workspace\Invoke-TmuxWorkspace -WhatIf
```
It prints a `What if:` line followed by the plan's actions. Apply that exact
plan, then remove only the session it created. The captured result stays
readable after cleanup:
```powershell
$workspaceResult = & {
$result = $workspacePlan |
LibTmux.Workspace\Invoke-TmuxWorkspace -Confirm:$false -ErrorAction Stop
try { $result } finally {
$result.Session | Remove-TmuxSession -Confirm:$false
}
}
```
The result is a [`LibTmux.Workspace.WorkspaceResult`][workspaceresult]. Read its
windows:
```powershell
$workspaceResult.Windows |
Select-Object Name, @{ Name = 'PaneCount'; Expression = { $_.Panes.Count } }
```
This returns `editor` with two panes. The
[workspace guide](https://libtmux.org/en/powershell/latest/workspace/source-guide/#apply-the-reviewed-plan) covers failure
recovery, attaching and exporting a declaration;
[`ConvertTo-TmuxWorkspace`][convertto-tmuxworkspace] turns a captured session
into a starting declaration.
## Packages
| Product | Use it for |
| --- | --- |
| [LibTmux](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/docs/reference/README.md) | Typed cmdlets, snapshots, input, capture, control clients and event streams |
| [LibTmux.Workspace](https://libtmux.org/en/powershell/latest/workspace/source-guide/#plan-and-review) [](https://www.powershellgallery.com/packages/LibTmux.Workspace) | Discover YAML/JSON declarations, resolve directories, review plans and create workspaces |
| [LibTmux.Mcp](https://libtmux.org/en/powershell/latest/guides/mcp/#discover-before-calling) | Give an assistant tmux tools through the separately installed .NET MCP server |
### [LibTmux](https://github.com/libtmux/libtmux-powershell/tree/master/src/LibTmux.PowerShell): typed cmdlets for tmux
Read, create, arrange and remove sessions, windows and panes, send input and
capture output as native objects. The walkthroughs above run on the installed
module:
- [Read an object graph](https://libtmux.org/en/powershell/latest/guides/getting-started/#find-sessions-windows-and-panes) with
[`Get-TmuxSnapshot`][get-tmuxsnapshot] and
[`Select-TmuxWindow`][select-tmuxwindow].
- [Check a command's exit status](https://libtmux.org/en/powershell/latest/guides/getting-started/#quick-start) with
[`Invoke-TmuxPaneCommand`][invoke-tmuxpanecommand].
- [Wait for a readiness line](https://libtmux.org/en/powershell/latest/guides/getting-started/#wait-for-service-readiness) with
[`Wait-TmuxPaneText`][wait-tmuxpanetext].
- [Choose an execution mode](https://libtmux.org/en/powershell/latest/guides/getting-started/#choose-how-to-run), including
[`Watch-TmuxEvent`][watch-tmuxevent].
Reference: [every LibTmux cmdlet][libtmux-module] and the
[PowerShell Gallery page](https://www.powershellgallery.com/packages/LibTmux).
### [LibTmux.Workspace](https://github.com/libtmux/libtmux-powershell/tree/master/src/LibTmux.Workspace.PowerShell): workspaces from YAML or JSON
Describe a session once, review the plan, then apply it. The commands below run
in this order:
- [`Get-TmuxWorkspace`][get-tmuxworkspace] finds declaration files.
- [`Import-TmuxWorkspace`][import-tmuxworkspace] parses YAML or JSON without
contacting tmux.
- [`Resolve-TmuxWorkspace`][resolve-tmuxworkspace] expands directories and
[`Test-TmuxWorkspace`][test-tmuxworkspace] validates the declaration.
- [`Get-TmuxWorkspacePlan`][get-tmuxworkspaceplan] plans against a server and
[`Invoke-TmuxWorkspace`][invoke-tmuxworkspace] applies the reviewed plan;
`-WhatIf` previews it.
- [`ConvertTo-TmuxWorkspace`][convertto-tmuxworkspace] turns a captured session
into a starting declaration.
[Install it](https://libtmux.org/en/powershell/latest/guides/getting-started/#build-a-workspace-from-a-file) with the core module, at the same
version. Reference: [every LibTmux.Workspace cmdlet][workspace-module] and the
[PowerShell Gallery page](https://www.powershellgallery.com/packages/LibTmux.Workspace).
### [LibTmux.Mcp](https://github.com/libtmux/libtmux-dotnet/tree/master/src/LibTmux.Mcp): tmux tools for assistants
A separate .NET tool that lets an MCP client list, read and drive tmux panes. It
needs no PowerShell. Reference: the
[MCP guide](https://libtmux.org/en/powershell/latest/guides/mcp/), the
[tool reference](https://libtmux.org/en/csharp/latest/mcp/tools/) and
[NuGet](https://www.nuget.org/packages/LibTmux.Mcp).
Install the tool on the Unix host that runs tmux:
```console
$ dotnet tool install --global LibTmux.Mcp \
--version 0.1.1 \
--framework net8.0
```
Register it with Claude Code. This names the tmux socket `work` and offers only
the tools that read tmux:
```console
$ claude mcp add tmux \
-e LIBTMUX_SOCKET=work \
-e LIBTMUX_TOOLSETS=inspect \
-- libtmux-mcp
```
A client that reads a JSON configuration takes the same command and settings:
```json
{
"mcpServers": {
"tmux": {
"command": "libtmux-mcp",
"env": { "LIBTMUX_SOCKET": "work", "LIBTMUX_TOOLSETS": "inspect" }
}
}
}
```
- Find a pane with [`list_sessions`][mcp-list_sessions],
[`list_windows`][mcp-list_windows] and [`list_panes`][mcp-list_panes].
- Read it with [`capture_pane`][mcp-capture_pane], or
[`snapshot_pane`][mcp-snapshot_pane] for structured state.
- Wait for output with [`wait_for_text`][mcp-wait_for_text] and a finite timeout.
- Read the selected tools and socket from the
[`tmux://capabilities` resource][mcp-capabilities] before calling any tool.
The [MCP guide](https://libtmux.org/en/powershell/latest/guides/mcp/) covers
[client configuration](https://libtmux.org/en/powershell/latest/guides/mcp/#install-and-select-a-server),
[discovery before calling](https://libtmux.org/en/powershell/latest/guides/mcp/#discover-before-calling), finite waits
and the other toolsets.
[Its test](https://libtmux.org/en/powershell/latest/guides/mcp/#check-the-client-workflow-from-this-checkout) starts the
installed tool with these settings and checks what it reports.
## Install from source
Install the pinned PowerShell and .NET SDK from [.tool-versions](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/.tool-versions)
with [mise](https://mise.jdx.dev/):
```console
$ mise install
```
Install tmux with your operating system's package manager and check that it
is on `PATH`:
```console
$ tmux -V
```
From the checkout root, restore the published
[.NET 0.1.1 packages](https://www.nuget.org/packages/LibTmux/0.1.1)
and build both PowerShell modules:
```console
$ pwsh -NoLogo -NoProfile -File eng/Build.ps1 \
-Restore
```
Restore checks the committed lockfiles and stages both modules under
`build/Modules`. Developing shared .NET changes uses the optional
[review-package workflow](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/.github/CONTRIBUTING.md#review-package-builds).
Start PowerShell with the staged module path:
```console
$ LIBTMUX_REVIEW_MODULE_ROOT="$PWD/build/Modules" \
pwsh \
-NoLogo \
-NoProfile
```
Import the exact staged manifests so an older installed module cannot shadow
the new build:
```powershell
$modules = $env:LIBTMUX_REVIEW_MODULE_ROOT
Import-Module -Name @(
"$modules/LibTmux/0.1.0/LibTmux.psd1",
"$modules/LibTmux.Workspace/0.1.0/LibTmux.Workspace.psd1"
) -ErrorAction Stop
```
### [`examples/QuickStart.ps1`](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/examples/QuickStart.ps1): a private server and three panes
Run the [quick start](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/examples/QuickStart.ps1) from the checkout root. It
creates a private server, splits the `editor` window, adds `logs`, and returns
a captured [`LibTmux.Session`][session]. Show each window's pane IDs:
```powershell
(./examples/QuickStart.ps1).Windows | Select-Object Name, @{
Name = 'PaneIds'
Expression = { $_.Panes.Id -join ', ' }
}
```
It prints the pane IDs from the private server:
```text
Name PaneIds
---- -------
editor %0, %1
logs %2
```
Assign `./examples/QuickStart.ps1` to a variable to keep the session object. Its
[`Windows`][session-windows] and [`Panes`][session-panes] remain readable after
the script removes its session. The script uses a unique socket, so your
default tmux server stays untouched.
## What it leaves out
- **Live objects.** A captured object keeps what tmux reported when you read it.
[`Get-TmuxSnapshot`][get-tmuxsnapshot] reads again, and
[snapshots and linked windows](https://libtmux.org/en/powershell/latest/guides/read/) list what a capture cannot know.
- **An implicit server.** A handle from [`New-TmuxServer`][new-tmuxserver]
starts no daemon, and importing the module connects to none. The module
leaves `TMUX` and `TMUX_PANE` in your session as they are
([compatibility](https://libtmux.org/en/powershell/latest/guides/compatibility/)).
- **Shell quoting.** [`Send-TmuxText`][send-tmuxtext] sends its text literally
and does not quote it for the shell that receives it
([send input](https://libtmux.org/en/powershell/latest/guides/input/)).
- **Native Windows.** Run PowerShell and tmux inside WSL, in one Linux
environment. Native Windows and psmux are outside this port
([compatibility](https://libtmux.org/en/powershell/latest/guides/compatibility/)).
- **The MCP server.** LibTmux.Mcp is a separate .NET tool that needs no
PowerShell, and the modules install none of its tools
([MCP guide](https://libtmux.org/en/powershell/latest/guides/mcp/)).
## Support and status
- **Releases.** Releases are numbered `0.1.N`, and each release increments `N`.
The API is not settled: any release may change or remove exported
identifiers, and the changelog marks each break. Pin an exact version to
avoid one.
- **PowerShell.** 7.4 or later. CI runs 7.4.20 and 7.6.6.
- **tmux.** 3.3a or newer. CI runs 3.3a and 3.8 on every change, and 3.3a
through 3.8 and tmux master before a release; other releases are
unverified. [Compatibility](https://libtmux.org/en/powershell/latest/guides/compatibility/) holds the contract.
- **Systems.** Linux, including WSL: run PowerShell and tmux in the same Linux
environment. CI runs Linux x64 on every change and macOS as an advisory trial
whose failures never fail the check. CI has no Windows job.
- **Built on [libtmux for .NET](https://github.com/libtmux/libtmux-dotnet).**
It lives in the same [libtmux organization](https://github.com/libtmux) with
the same main author. The cmdlets return its native objects and add
PowerShell parameter binding, help, formatting and `-WhatIf` / `-Confirm`.
## Documentation
- **Read:** [snapshots and filtering](https://libtmux.org/en/powershell/latest/guides/read/), [structured queries](https://libtmux.org/en/powershell/latest/guides/query/),
[pane contents and scrollback](https://libtmux.org/en/powershell/latest/guides/capture/), [attached clients](https://libtmux.org/en/powershell/latest/guides/clients/).
- **Automate:** [create](https://libtmux.org/en/powershell/latest/guides/create/), [send text and keys](https://libtmux.org/en/powershell/latest/guides/input/),
[arrange and resize](https://libtmux.org/en/powershell/latest/guides/layout/), [link and move windows](https://libtmux.org/en/powershell/latest/guides/placement/),
[remove](https://libtmux.org/en/powershell/latest/guides/remove/).
- **Configure:** [options](https://libtmux.org/en/powershell/latest/guides/options/), [hooks](https://libtmux.org/en/powershell/latest/guides/hooks/),
[environment for new panes](https://libtmux.org/en/powershell/latest/guides/environment/).
- **Coordinate:** [chains and control clients](https://libtmux.org/en/powershell/latest/guides/commands/),
[event streams, jobs and parallel workers](https://libtmux.org/en/powershell/latest/guides/watch/).
- **Assistants:** [install and configure the MCP server](https://libtmux.org/en/powershell/latest/guides/mcp/).
- **Workspaces:** [load, review and apply](https://libtmux.org/en/powershell/latest/workspace/source-guide/),
[export a starting declaration](https://libtmux.org/en/powershell/latest/workspace/source-guide/#export-a-starting-declaration),
[edit a declaration](https://libtmux.org/en/powershell/latest/workspace/source-guide/#edit-the-declaration).
Browse cmdlets with `Get-Command -Module LibTmux` and examples with
`Get-Help LibTmux\New-TmuxSession -Examples`. Further reading:
- [Compatibility](https://libtmux.org/en/powershell/latest/guides/compatibility/) — what CI runs and the support contract
- [Troubleshooting](https://libtmux.org/en/powershell/latest/guides/troubleshooting/) — endpoint, package, input and
stream failures
- [Benchmarks](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/benchmarks/README.md) — installed-package workloads,
correctness checks, raw samples and reproduction commands
- [Contributing](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/.github/CONTRIBUTING.md) — the runners and development checks
- [Executable guides](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/examples/Guides.ps1) — run against real tmux through the
installed modules, and the README blocks run together in the
[installed workflow test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/ReadmeWorkflow.Tests.ps1)
## License
[MIT](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/LICENSE). See [third-party notices](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/licenses/THIRD-PARTY-NOTICES.md)
for bundled dependencies.
[libtmux-module]: https://libtmux.org/en/powershell/latest/reference/
[workspace-module]: https://libtmux.org/en/powershell/latest/workspace/reference/
[new-tmuxserver]: https://libtmux.org/en/powershell/latest/reference/libtmux-new-tmuxserver/
[new-tmuxsession]: https://libtmux.org/en/powershell/latest/reference/libtmux-new-tmuxsession/
[split-tmuxpane]: https://libtmux.org/en/powershell/latest/reference/libtmux-split-tmuxpane/
[new-tmuxwindow]: https://libtmux.org/en/powershell/latest/reference/libtmux-new-tmuxwindow/
[get-tmuxsnapshot]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxsnapshot/
[remove-tmuxsession]: https://libtmux.org/en/powershell/latest/reference/libtmux-remove-tmuxsession/
[select-tmuxwindow]: https://libtmux.org/en/powershell/latest/reference/libtmux-select-tmuxwindow/
[invoke-tmuxpanecommand]: https://libtmux.org/en/powershell/latest/reference/libtmux-invoke-tmuxpanecommand/
[wait-tmuxpanetext]: https://libtmux.org/en/powershell/latest/reference/libtmux-wait-tmuxpanetext/
[send-tmuxtext]: https://libtmux.org/en/powershell/latest/reference/libtmux-send-tmuxtext/
[send-tmuxkey]: https://libtmux.org/en/powershell/latest/reference/libtmux-send-tmuxkey/
[get-tmuxpanecontent]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/
[wait-tmuxchannel]: https://libtmux.org/en/powershell/latest/reference/libtmux-wait-tmuxchannel/
[connect-tmuxcontrol]: https://libtmux.org/en/powershell/latest/reference/libtmux-connect-tmuxcontrol/
[new-tmuxcommand]: https://libtmux.org/en/powershell/latest/reference/libtmux-new-tmuxcommand/
[invoke-tmuxcontrolcommand]: https://libtmux.org/en/powershell/latest/reference/libtmux-invoke-tmuxcontrolcommand/
[disconnect-tmuxcontrol]: https://libtmux.org/en/powershell/latest/reference/libtmux-disconnect-tmuxcontrol/
[invoke-tmuxchain]: https://libtmux.org/en/powershell/latest/reference/libtmux-invoke-tmuxchain/
[invoke-tmuxcommand]: https://libtmux.org/en/powershell/latest/reference/libtmux-invoke-tmuxcommand/
[watch-tmuxevent]: https://libtmux.org/en/powershell/latest/reference/libtmux-watch-tmuxevent/
[enter-tmuxsession]: https://libtmux.org/en/powershell/latest/reference/libtmux-enter-tmuxsession/
[get-tmuxworkspace]: https://libtmux.org/en/powershell/latest/workspace/reference/libtmux-workspace-get-tmuxworkspace/
[import-tmuxworkspace]: https://libtmux.org/en/powershell/latest/workspace/reference/libtmux-workspace-import-tmuxworkspace/
[resolve-tmuxworkspace]: https://libtmux.org/en/powershell/latest/workspace/reference/libtmux-workspace-resolve-tmuxworkspace/
[test-tmuxworkspace]: https://libtmux.org/en/powershell/latest/workspace/reference/libtmux-workspace-test-tmuxworkspace/
[get-tmuxworkspaceplan]: https://libtmux.org/en/powershell/latest/workspace/reference/libtmux-workspace-get-tmuxworkspaceplan/
[invoke-tmuxworkspace]: https://libtmux.org/en/powershell/latest/workspace/reference/libtmux-workspace-invoke-tmuxworkspace/
[convertto-tmuxworkspace]: https://libtmux.org/en/powershell/latest/workspace/reference/libtmux-workspace-convertto-tmuxworkspace/
[session]: https://libtmux.org/en/csharp/latest/reference/libtmux-session/
[window]: https://libtmux.org/en/csharp/latest/reference/libtmux-window/
[pane]: https://libtmux.org/en/csharp/latest/reference/libtmux-pane/
[session-windows]: https://libtmux.org/en/csharp/latest/reference/libtmux-session-windows/
[window-panes]: https://libtmux.org/en/csharp/latest/reference/libtmux-window-panes/
[session-panes]: https://libtmux.org/en/csharp/latest/reference/libtmux-session-panes/
[panerunresult]: https://libtmux.org/en/csharp/latest/reference/libtmux-panerunresult/
[panewaitresult]: https://libtmux.org/en/csharp/latest/reference/libtmux-panewaitresult/
[workspacefile]: https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacefile/
[workspaceresult]: https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceresult/
[workspaceaction-request]: https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceaction-request/
[workspaceactionkind-createsession]: https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceactionkind-createsession/
[workspaceactionkind-captureresult]: https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceactionkind-captureresult/
[mcp-list_sessions]: https://libtmux.org/en/csharp/latest/mcp/tools/list_sessions/
[mcp-list_windows]: https://libtmux.org/en/csharp/latest/mcp/tools/list_windows/
[mcp-list_panes]: https://libtmux.org/en/csharp/latest/mcp/tools/list_panes/
[mcp-capture_pane]: https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/
[mcp-snapshot_pane]: https://libtmux.org/en/csharp/latest/mcp/tools/snapshot_pane/
[mcp-wait_for_text]: https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_text/
[mcp-capabilities]: https://libtmux.org/en/csharp/latest/mcp/resources/tmux_capabilities/
---
# Guides
Source: https://libtmux.org/en/powershell/latest/guides/
> Guides for LibTmux.
Connect to tmux and work with its sessions, windows, and panes.
- [Getting started](https://libtmux.org/en/powershell/latest/guides/getting-started/): Read about libtmux for powershell.
- [Attaching to tmux](https://libtmux.org/en/powershell/latest/guides/attaching-to-tmux/): Connect to an existing socket and leave its server running.
- [Arrange panes and resize windows](https://libtmux.org/en/powershell/latest/guides/layout/): Read about arrange panes and resize windows.
- [Capture, refresh and raw commands](https://libtmux.org/en/powershell/latest/guides/capture/): Read about capture, refresh and raw commands.
- [Commands and control clients](https://libtmux.org/en/powershell/latest/guides/commands/): Read about commands and control clients.
- [Compatibility](https://libtmux.org/en/powershell/latest/guides/compatibility/): Read about compatibility.
- [Configure and run hooks](https://libtmux.org/en/powershell/latest/guides/hooks/): Read about configure and run hooks.
- [Create sessions, windows and panes](https://libtmux.org/en/powershell/latest/guides/create/): Read about create sessions, windows and panes.
- [Filter and query tmux objects](https://libtmux.org/en/powershell/latest/guides/query/): Read about filter and query tmux objects.
- [Inspect attached clients](https://libtmux.org/en/powershell/latest/guides/clients/): Read about inspect attached clients.
- [Link and move windows between sessions](https://libtmux.org/en/powershell/latest/guides/placement/): Read about link and move windows between sessions.
- [Read and change options](https://libtmux.org/en/powershell/latest/guides/options/): Read about read and change options.
- [Read tmux objects](https://libtmux.org/en/powershell/latest/guides/read/): Read about read tmux objects.
- [Remove sessions, windows and panes](https://libtmux.org/en/powershell/latest/guides/remove/): Read about remove sessions, windows and panes.
- [Send input to a pane](https://libtmux.org/en/powershell/latest/guides/input/): Read about send input to a pane.
- [Set the environment for new panes](https://libtmux.org/en/powershell/latest/guides/environment/): Read about set the environment for new panes.
- [Troubleshooting](https://libtmux.org/en/powershell/latest/guides/troubleshooting/): Read about troubleshooting.
- [Using the .NET MCP server](https://libtmux.org/en/powershell/latest/guides/mcp/): Read about give an assistant tmux tools.
- [Watch events and use runspaces](https://libtmux.org/en/powershell/latest/guides/watch/): Read about watch events and use runspaces.
---
# Attaching to tmux
Source: https://libtmux.org/en/powershell/latest/guides/attaching-to-tmux/
> Connect to an existing tmux server and find a session with PowerShell.
Connect to an explicit socket, read the existing `work` session, and print
its name. The program leaves the server running. A missing server or session
ends the script with an error.
This controls tmux from PowerShell. To open a session in your terminal, use
[`tmux attach-session`](https://libtmux.org/en/tmux/latest/manual/attach-session/); the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/)
covers interactive attachment and detaching.
## Connect to an existing server
Save the complete program as `connect.ps1`. The environment variable
`LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below sets
it to a private socket for trying the example.
```powershell title="connect.ps1"
$ErrorActionPreference = 'Stop'
Import-Module LibTmux -RequiredVersion 0.1.0
$socket = $env:LIBTMUX_SOCKET_PATH
if ([string]::IsNullOrEmpty($socket)) {
throw 'Set LIBTMUX_SOCKET_PATH to an existing socket.'
}
$server = New-TmuxServer -SocketPath $socket | Connect-TmuxServer
$sessions = @($server | Get-TmuxSession -Name work)
if ($sessions.Count -ne 1) {
throw 'The work session does not exist.'
}
$sessions[0].Name
```
[`New-TmuxServer`](https://libtmux.org/en/powershell/latest/reference/libtmux-new-tmuxserver/) constructs the
endpoint without contacting tmux.
[`Connect-TmuxServer`](https://libtmux.org/en/powershell/latest/reference/libtmux-connect-tmuxserver/)
discovers the existing daemon, then
[`Get-TmuxSession`](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxsession/) reads sessions
and applies an exact, case-sensitive name selector. An unmatched selector
emits no objects, so the program checks its result explicitly.
The handle borrows the daemon. There is no daemon cleanup in this program:
the caller owns the server and any other sessions on it.
## Setup and run
Use an empty directory on Linux with PowerShell 7.4, POSIX shell, and tmux
installed. Run the following commands in a POSIX shell. Install the
[LibTmux 0.1.0 module](https://www.powershellgallery.com/packages/LibTmux/0.1.0)
with PSResourceGet:
```console
$ pwsh -NoLogo -NoProfile -Command '
$ErrorActionPreference = "Stop"
Install-PSResource -Name LibTmux -Version 0.1.0 `
-Repository PSGallery -Scope CurrentUser -TrustRepository
'
```
Save the launcher as `run.sh`. It starts an isolated tmux server, runs the
program, checks that the session still exists, then stops only that server.
Cleanup runs after failures too. A failed shutdown keeps its socket directory
and prints its location for inspection.
```sh title="run.sh"
#!/bin/sh
set -eu
binary=$(command -v tmux)
directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-powershell-attach.XXXXXX")
socket="$directory/tmux.sock"
cleanup() {
status=$?
trap - 0 HUP INT TERM
if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then
printf 'Cannot stop tmux; kept %s\n' "$directory" >&2
exit 1
fi
rm -rf "$directory" || exit 1
exit "$status"
}
trap cleanup 0
trap 'exit 1' HUP INT TERM
unset TMUX TMUX_PANE
export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary"
"$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat
"$@"
"$binary" -S "$socket" has-session -t '=work'
```
```console
$ sh run.sh pwsh -NoLogo -NoProfile -File connect.ps1
```
The program prints `work`. To use your own existing server, set
`LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher.
The launcher owns only the demonstration server.
## Find or create a session
Reading a session does not reserve its name. If your application creates a
session after an unsuccessful lookup, another client may create the same name
between those operations. Handle the creation error as well as the lookup.
[Read tmux objects](https://libtmux.org/en/powershell/latest/guides/read/) explains captured values and selectors.
[Create windows and panes](https://libtmux.org/en/powershell/latest/examples/create-layout/) is a complete
program that creates and cleans up its own session.
The module's [package source revision](https://github.com/libtmux/libtmux-powershell/tree/fcd0634e9ca887b70d88915c2d8e26c5da2737e5)
records the implementation used by this example.
---
# Arrange panes and resize windows
Source: https://libtmux.org/en/powershell/latest/guides/layout/
> Arrange panes and resize windows: LibTmux documentation.
Select native `$window` and `$pane` handles with [`Get-TmuxWindow`]() and
[`Get-TmuxPane`](). Layout and size changes support `-WhatIf` and `-Confirm`.
Without `-PassThru`, they emit no success output. With it, they return a native
replacement handle; previously captured objects remain unchanged.
Give a window explicit dimensions in cells:
```powershell
$window | Set-TmuxWindowSize -Width 120 -Height 40 -PassThru
```
At least one dimension is required. Resizing switches [`window-size`](https://libtmux.org/en/tmux/latest/catalog/options/window-size/) to
`manual`, so the window stops following its clients. Alternatively, use
`-Direction Right -Adjustment 5` to grow an edge, or `-Mode Expand` / [`Shrink`]()
to use the largest / smallest attached client. These forms are mutually
exclusive.
Arrange existing panes side by side:
```powershell
$window | Set-TmuxLayout -Layout 'even-horizontal' -PassThru
```
Other presets include `even-vertical`, `main-horizontal`, `main-vertical` and
`tiled`. Unambiguous prefixes are accepted; unknown or ambiguous names fail
before dispatch. Use `-Mode Next`, [`Previous`]() or [`Spread`]() instead of `-Layout`
to cycle layouts or spread panes.
A captured [`$window.Layout`][window-layout] can be passed back as `-Layout`. On
tmux 3.7 and earlier, restoring its sizes can rotate which pane occupies a
position; it does not guarantee pane identity at each position.
A JSON layout needs tmux 3.8; see [compatibility](https://libtmux.org/en/powershell/latest/guides/compatibility/).
Set a pane's width in a window with a horizontal split:
```powershell
$pane | Set-TmuxPaneSize -Width '40' -PassThru
```
Pane dimensions also accept percentages such as `'50%'`. tmux clamps sizes
that do not fit; inspect the replacement handle for the observed dimensions.
`-Direction` with `-Adjustment` moves a pane edge instead.
Toggle a pane's zoom:
```powershell
$pane | Set-TmuxPaneSize -Zoom
```
Repeating the command turns zoom off. `-Zoom` cannot be combined with a size
or direction. A stale or disappeared target writes a per-target error;
`-ErrorAction Stop` terminates the pipeline. Cancellation does not roll back
an already dispatched change.
[window-layout]: https://libtmux.org/en/csharp/latest/reference/libtmux-window-layout/
---
# Capture, refresh and raw commands
Source: https://libtmux.org/en/powershell/latest/guides/capture/
> Capture, refresh and raw commands: LibTmux documentation.
[`Get-TmuxPaneContent`]() reads rendered text from a native [`LibTmux.Pane`]().
[`Update-TmuxPane`]() reads current pane metadata into a replacement handle.
Both accept a pane directly or through the pipeline and borrow its daemon.
[`Invoke-TmuxCommand`]() accepts a native [`LibTmux.Server`]() and literal tmux
arguments for operations that do not yet have a dedicated cmdlet.
Use the explicit endpoint and pane selection described in
[Read tmux objects](https://libtmux.org/en/powershell/latest/guides/read/). The examples below assume `$pane` and `$server`
refer to that selected pane and server. None chooses a global active server.
## Capture text
Return one string per captured screen line:
```powershell
$pane | Get-TmuxPaneContent
```
Capture the retained history as one string, joining wrapped screen lines:
```powershell
$pane | Get-TmuxPaneContent -History -JoinWrappedLines -Raw
```
Capture an inclusive range, from ten lines before the visible screen through
its fifth line. Zero identifies the top visible line; negative values address
scrollback. Omitted bounds use tmux's normal visible-screen bounds.
```powershell
$pane | Get-TmuxPaneContent -StartLine -10 -EndLine 4
```
`-History` selects the oldest retained history and cannot be combined with
`-StartLine`. It can be combined with `-EndLine`. `-Raw` emits exactly one
string per pane, joining the core's captured lines with LF and adding no
extra trailing newline. Internal empty lines remain empty lines. An empty
capture emits no objects normally and one empty string with `-Raw`.
This is rendered terminal text, not original process output or a byte-exact
stream. Sending input or receiving a pane-output event does not establish
command completion. Use an explicit completion signal from the application,
such as a cooperative wait channel, or
[Invoke-TmuxPaneCommand](https://libtmux.org/en/powershell/latest/guides/input/#run-a-command-to-completion) before asserting
completed command output.
| Switch | Effect |
| --- | --- |
| [`JoinWrappedLines`][-joinwrappedlines] | Join lines that wrapped on screen; tmux applies this in place of trailing-space handling. |
| [`EscapeSequences`][-escapesequences] | Include terminal escape sequences representing captured attributes. |
| [`EscapeNonPrintable`][-escapenonprintable] | Represent nonprintable bytes with octal escapes. |
| [`PreserveTrailingSpaces`][-preservetrailingspaces] | Retain trailing spaces. |
| [`TrimTrailingSpaces`][-trimtrailingspaces] | Request tmux's trailing-space trimming behavior. |
| [`AlternateScreen`][-alternatescreen] | Capture the alternate screen. |
| [`Quiet`][-quiet] | Return empty content when an alternate screen is absent; other failures remain errors. |
| [`ModeScreen`][-modescreen] | Capture a mode screen, such as copy mode. |
| [`Pending`][-pending] | Capture an incomplete pending escape sequence. |
| [`Hyperlinks`][-hyperlinks] | Include supported hyperlink capture metadata. |
| [`LineNumbers`][-linenumbers] | Include supported line-number metadata. |
| [`LineFlags`][-lineflags] | Include supported line-flag metadata. |
`-PreserveTrailingSpaces` and `-TrimTrailingSpaces` together terminate with
[`Tmux.InvalidCapture`][gettmuxpanecontentcommand] before dispatch.
Version-dependent switches retain the core's capability policy; availability
depends on the tmux version and the core connection's configuration.
## Refresh captured metadata
Retain the replacement returned by an explicit refresh:
```powershell
$currentPane = $pane | Update-TmuxPane
```
The original `$pane` keeps its previously captured values. Refresh observes
tmux and returns another native [`LibTmux.Pane`](); it does not mutate terminal
state or acquire ownership of the daemon. It uses the core's refresh and
identity rules. Repeated linked-window placement refresh remains subject to
the core's contextual-target limitations.
## Run literal tmux arguments
Pass each argument as a separate array element. The adapter does not join
arguments into a shell command or expand their contents.
```powershell
$server | Invoke-TmuxCommand -Arguments @(
'list-sessions', '-F', '#{session_name}'
)
```
For tmux features without a dedicated cmdlet, use the same literal argument
boundary. This creates a named paste buffer, reads its text and removes only
that buffer. Deleting a buffer by name needs tmux 3.4 or newer; earlier
releases act on an unrelated buffer when the name is missing, so
[`Invoke-TmuxCommand`]() refuses the command there:
```powershell
& {
$name = 'libtmux-' + [guid]::NewGuid().ToString('N')
$quiet = @{ Confirm = $false; ErrorAction = 'Stop' }
$created = $false
try {
$set = @('set-buffer', '-b', $name, 'hello from PowerShell')
$null = $server | Invoke-TmuxCommand -Arguments $set @quiet
$created = $true
$show = @('show-buffer', '-b', $name)
$shown = $server | Invoke-TmuxCommand -Arguments $show @quiet
$shown.StandardOutputLines
} finally {
if ($created) {
$delete = @('delete-buffer', '-b', $name)
$server | Invoke-TmuxCommand -Arguments $delete @quiet | Out-Null
}
}
}
```
This returns `hello from PowerShell`. [`StandardOutput`]() retains bytes when
line projection is unsuitable. For copy mode, use raw [`copy-mode`](https://libtmux.org/en/tmux/latest/manual/copy-mode/) and
[`send-keys -X`](https://libtmux.org/en/tmux/latest/manual/send-keys/) commands with an explicit pane ID.
`Get-TmuxPaneContent -ModeScreen` reads its rendered screen. Copy-mode
commands change the pane's mode, so leave it explicitly with
[`send-keys -X cancel`](https://libtmux.org/en/tmux/latest/manual/send-keys/) when finished.
Empty non-command arguments are preserved. The first argument must name a
command or alias. An empty, whitespace or leading-option argument terminates
with [`Tmux.InvalidCommand`][invoketmuxcommandcommand] before confirmation or
dispatch. Select the socket on the server handle; global options such as `-S`,
`-L` and `-f` cannot replace the command name. Pipeline input must be a native
[`LibTmux.Server`](); an object with similarly named properties does not bind as an
endpoint.
Raw commands can mutate tmux or execute shell work. They always support
`-WhatIf` and `-Confirm`, including for commands the caller knows are reads.
Confirmation precedes discovery and dispatch. Preview shows the endpoint and
command name; argument contents are not included in the confirmation text.
```powershell
$server | Invoke-TmuxCommand -Arguments @('kill-session', '-t', '$3') -WhatIf
```
Successful execution emits a native [`LibTmux.TmuxCommandResult`]() with exit code,
logical arguments, stdout/stderr bytes and projected lines. A nonzero exit emits
no success result and writes [`Tmux.CommandFailed`][invoketmuxcommandcommand].
Its original [`TmuxCommandException.Result`]() retains those diagnostics, and its
[`Dispatch`]() is [`Dispatched`](). Transport failures preserve their original exception
and dispatch uncertainty. No mutation is automatically retried.
Capture and refresh failures use
[`Tmux.PaneCaptureFailed`][gettmuxpanecontentcommand] and
[`Tmux.PaneRefreshFailed`][updatetmuxpanecommand]. Each error retains the failed
owner, allowing later pipeline owners to continue unless `-ErrorAction Stop` is
selected. Cancellation uses the same core token and pipeline lifecycle as the
read cmdlets; it does not imply rollback or termination of shell work.
The [capture integration test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/Capture.Tests.ps1) exercises these
contracts against an owned daemon with explicit output readiness, literal
argument round trips, error results, refresh replacement and zero-dispatch
`-WhatIf`. It owns its sockets, child processes and temporary files.
[-joinwrappedlines]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.JoinWrappedLines
[-escapesequences]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.EscapeSequences
[-alternatescreen]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.AlternateScreen
[-quiet]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.Quiet
[gettmuxpanecontentcommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/GetTmuxPaneContentCommand.cs
[invoketmuxcommandcommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/InvokeTmuxCommandCommand.cs
[updatetmuxpanecommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/UpdateTmuxPaneCommand.cs
[-escapenonprintable]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.EscapeNonPrintable
[-preservetrailingspaces]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.PreserveTrailingSpaces
[-trimtrailingspaces]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.TrimTrailingSpaces
[-modescreen]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.ModeScreen
[-pending]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.Pending
[-hyperlinks]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.Hyperlinks
[-linenumbers]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.LineNumbers
[-lineflags]: https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxpanecontent/#LibTmux%5CGet-TmuxPaneContent.parameter.LineFlags
---
# Commands and control clients
Source: https://libtmux.org/en/powershell/latest/guides/commands/
> Commands and control clients: LibTmux documentation.
Use native command values when composing operations. [`New-TmuxCommand`]() keeps
literal argv boundaries, including empty arguments, spaces and punctuation;
it does no I/O. Commands can still invoke tmux features that deliberately run
a shell, such as [`run-shell`](https://libtmux.org/en/tmux/latest/manual/run-shell/). Shell programs inside those arguments retain
those features' normal semantics.
[`Connect-TmuxControl`]() needs tmux 3.7 or newer and is refused on an older
daemon before a client attaches; chains and raw commands need only 3.3a.
Literal [`delete-buffer -b`](https://libtmux.org/en/tmux/latest/manual/delete-buffer/) and [`set-buffer -n`](https://libtmux.org/en/tmux/latest/manual/set-buffer/) items need tmux 3.4; see
[optional features](https://libtmux.org/en/powershell/latest/guides/compatibility/#optional-features).
Select `$server` first using [explicit endpoint selection](https://libtmux.org/en/powershell/latest/guides/read/). These
examples require an existing session named `fixture` and borrow its lifetime.
## Execute an ordered chain
Construct the complete array, then execute it once. The result is one native
[`TmuxCommandResult`](); read its [`StandardOutputLines`]() or byte-valued
[`StandardOutput`](). Generation and placement guards on typed request commands
survive chaining.
```powershell
$first = New-TmuxCommand -Name 'display-message' -Arguments @('-p', 'first')
$second = New-TmuxCommand -Name 'display-message' -Arguments @('-p', 'second')
$server | Invoke-TmuxChain -Command @($first, $second)
```
A failure stops later commands, but leaves earlier mutations in place.
Output is merged; the result does not attribute separate receipts to each
command. Cancellation does not roll back dispatched work. Do not retry a
mutation merely because its caller stopped waiting.
Admission defaults to 1024 commands and 1048576 UTF-8 bytes of command names
and argument text, counting a NUL terminator per item. `-MaxCommands` and
`-MaxInputBytes` adjust those limits. Native transport and operating-system
limits also apply. These admission limits are not memory or reply-size bounds.
## Reuse a control client
An explicit client avoids starting a new tmux client for every command. The
native core correlates concurrent replies. Keep its ownership scope visible:
this example closes the client on success or failure and leaves the tmux
server and session running.
```powershell
& {
$control = $server |
Connect-TmuxControl -Target 'fixture' -ErrorAction Stop
try {
$command = New-TmuxCommand -Name 'display-message' -Arguments @(
'-p', '#{session_name}'
)
$control |
Invoke-TmuxControlCommand -Command $command -ErrorAction Stop
} finally {
$control | Disconnect-TmuxControl -Confirm:$false
}
}
```
`-Target` is raw tmux target syntax, resolved at attachment time. It does not
carry the identity captured by a native [`Session`](). A command constructed
from raw text likewise has no entity identity guard; pass a native typed
request's command directly when it supplies one.
[`Invoke-TmuxControlCommand`]() emits native reply strings and emits nothing for
an empty reply. Ctrl+C cancels the current wait; a command already dispatched
may still run. The borrowed client remains usable when that command finishes.
[`Disconnect-TmuxControl`]() explicitly closes the supplied client, including for
other callers sharing it. Its native disposal has no cancellation token, so
cleanup is awaited.
`-WhatIf` performs no dispatch. Previewing a supplied control connection names
that connection; its native interface exposes no endpoint metadata to display.
The cmdlets run on the calling pipeline. They do not return Tasks or claim
that a foreground command leaves the prompt available.
## Collect concurrent command results
Use the [finite concurrent-command recipe](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/examples/ConcurrentCommands.ps1)
when independent commands need separate results. Run it from the repository
root after importing [`LibTmux`](). It accepts native command values, preserves
their identity guards and starts at most `-MaxPending` calls at once.
By default, each bounded wave finishes before its results are emitted in input
order. The next wave then starts. This bounds reordering storage but can leave a
slot idle while another command in the wave finishes. Each result carries its
zero-based [`Index`][command-example], [`Name`][command-example], [`ExitCode`](),
output lines, error lines and [`Utf8Bytes`][command-example].
```powershell
$commands = @(foreach ($name in @('api', 'worker', 'scheduler')) {
New-TmuxCommand -Name 'display-message' -Arguments @('-p', $name)
})
./examples/ConcurrentCommands.ps1 -Server $server -Command $commands `
-MaxPending 2 -MaxResultBytes 4096 -Timeout 1
```
Pass a borrowed control client to reuse its connection. `-CompletionOrder` emits
each result as the caller harvests a completed task; simultaneous completions
have no guaranteed order. [`Index`][command-example] still identifies its input.
The recipe leaves the client open; its owner closes it here.
```powershell
& {
$control = $server |
Connect-TmuxControl -Target 'fixture' -ErrorAction Stop
try {
$commands = @(foreach ($format in @(
'#{session_name}', '#{window_name}', '#{pane_id}')) {
New-TmuxCommand -Name 'display-message' -Arguments @(
'-p', '-t', 'fixture:0.0', $format
)
})
./examples/ConcurrentCommands.ps1 -Connection $control `
-Command $commands -MaxPending 2 -MaxResultBytes 4096 `
-Timeout 1 -CompletionOrder
} finally {
$control | Disconnect-TmuxControl -Confirm:$false
}
}
```
On tmux 3.7 and newer, commands from one server handle share a single control
client, so a command that blocks while the client waits holds the commands
behind it. A command that is a [`wait-for`](https://libtmux.org/en/tmux/latest/manual/wait-for/) on its own runs in its own process
and leaves the others free. A [`wait-for`](https://libtmux.org/en/tmux/latest/manual/wait-for/) nested in a list, such as
[`if-shell -F 1 'wait-for release ; display-message -p done'`](https://libtmux.org/en/tmux/latest/manual/if-shell/), is not seen and
blocks the shared client until it is released. Keep a blocking command at the
top level, or set `LIBTMUX_CONTROL_TRANSPORT=0` before creating the server
handle to send every command from its own process.
The recipe admits 1–64 commands and 1–16 pending calls; the default is four
pending calls. Its cumulative result-text budget defaults to 64 KiB, counting
UTF-8 command names and output/error lines plus one byte per item. A result
that exceeds the remaining budget is rejected before being retained or
emitted. This excludes exception diagnostics, object overhead and downstream
consumer storage. Native buffers are separate: process transport allows
64 MiB per output/error stream; default control limits allow 4 MiB per block
and 16 MiB per reply. High concurrency with large replies can therefore use
substantially more memory than `-MaxResultBytes`.
`-Timeout` supplies one deadline for the entire batch, defaulting to one
second. Supply `-CancellationToken` for caller-managed cancellation. The
script waits synchronously on the calling runspace; it does not promise
immediate Ctrl+C handling. On failure, cancellation or consumer termination,
it cancels and observes every started task before returning; native cleanup
may extend beyond the deadline. Previously emitted results and dispatched
mutations remain. Command failures retain the native exception and identify
their input with `Exception.Data['LibTmux.ConcurrentCommandIndex']`. Do not
automatically retry canceled mutations.
[command-example]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/examples/ConcurrentCommands.ps1
---
# Compatibility
Source: https://libtmux.org/en/powershell/latest/guides/compatibility/
> Compatibility: LibTmux documentation.
This source checkout targets PowerShell 7.4 and .NET 8. The Linux workflow
tests the specific PowerShell and tmux versions below; other combinations
remain unverified. [LibTmux](https://www.powershellgallery.com/packages/LibTmux)
and [LibTmux.Workspace](https://www.powershellgallery.com/packages/LibTmux.Workspace)
are published on PowerShell Gallery. Both pin
[libtmux for .NET](https://github.com/libtmux/libtmux-dotnet).
See the [install guide](https://libtmux.org/en/powershell/latest/guides/getting-started/#quick-start) for package-manager commands
and source builds. Publication does not expand the tested platforms below.
| Environment | Contract |
| --- | --- |
| Linux x64 | The [Linux workflow](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/.github/workflows/ci.yml) exercises PowerShell 7.4.20 and 7.6.6 with tmux 3.3a and 3.8 on every change. A full run, which every release performs, adds 3.4, 3.5, 3.6, 3.7a, 3.7b, 3.7c and the current tmux master (`next-3.9`). Check the run for the commit you use; a green older commit does not verify newer code. |
| WSL2 | Run PowerShell and tmux inside the same Linux environment. The Windows host's PowerShell process is outside this contract. |
| macOS | Intel and Apple Silicon have an advisory [eight-cell trial](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/.github/workflows/macos-trial.yml). Suite failures appear in its job summaries and artifacts without failing the trial check; they do not establish support. |
| Native Windows and psmux | Outside this port's scope. |
## Minimum tmux version
The minimum for ordinary operations is tmux 3.3a. Versions compare as whole
releases, so 3.3 is below the floor and 3.3a is the first supported release.
Development builds and release candidates rank below the release they name:
`next-3.3a` and a candidate of 3.3a do not qualify, and a report without a
dated release, such as `master`, is refused.
tmux release candidates are not supported: a feature can require one only
until its release ships. See [Release candidates](https://libtmux.org/en/tmux/guides/tmux-support/#release-candidates).
## Optional features
A feature that a release cannot run safely is refused for that cmdlet alone,
before the requested operation is sent. Version checks may still contact tmux.
Each requirement is per feature, so the floor for reads, writes, raw commands
and workspaces stays tmux 3.3a.
[`capabilities.json`](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/capabilities.json) is the machine-readable list of
these features: each entry names the capability, the release it needs, the
error and the cmdlets it gates. The `id` in the last column names the entry
and its [evidence](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence).
| Feature | Needs | Below that release | Id |
| --- | --- | --- | --- |
| [`Connect-TmuxControl`](), [`Watch-TmuxEvent`]() with a server | 3.7 | Refused before a control client attaches. | [`control-mode`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
| [`Invoke-TmuxPaneCommand`]() | 3.4 | Refused before it stages a named buffer. | [`buffer-delete-named`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
| Literal [`delete-buffer -b`](https://libtmux.org/en/tmux/latest/manual/delete-buffer/) | 3.4 | Refused by the raw-command cmdlets. | [`buffer-delete-named`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
| Literal [`set-buffer -b ... -n`](https://libtmux.org/en/tmux/latest/manual/set-buffer/) | 3.4 | Refused by the raw-command cmdlets. | [`buffer-rename`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
| Literal [`break-pane`](https://libtmux.org/en/tmux/latest/manual/break-pane/) without `-n` | not exactly 3.7 | Refused on 3.7. Name the window. | [`break-pane-misnames-windows`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
| Session and window names with `:` or `.` | not exactly 3.7 | Refused on 3.7. | [`name-separators-rejected`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
| Literal [`split-window -p`](https://libtmux.org/en/tmux/latest/manual/split-window/) | not exactly 3.4 | Refused on 3.4. Use `-l` with a percentage such as `30%`. | [`split-window-percent-size`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
| Literal [`refresh-client -l`](https://libtmux.org/en/tmux/latest/manual/refresh-client/) | 3.6a | Refused by the raw-command cmdlets. | [`clipboard-query`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
| Literal [`select-layout`](https://libtmux.org/en/tmux/latest/manual/select-layout/) with a layout string | 3.4 for a layout without a checksum | Refused by the raw-command cmdlets. Use a preset name or a layout read from tmux. | [`layout-without-checksum`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
| [`Set-TmuxLayout`]() with `main-horizontal-mirrored` or `main-vertical-mirrored` | 3.5 | Refused. Use another preset. | [`layout-mirrored-main`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
| [`Set-TmuxLayout`]() or a workspace window ([`Get-TmuxWorkspacePlan`]()) with a JSON layout | 3.8 | Refused. Use the checksummed layout from [`$window.Layout`](https://libtmux.org/en/csharp/latest/reference/libtmux-window-layout/). The raw-command cmdlets and control connections are not gated; tmux reports the error. | [`layout-json`](https://libtmux.org/en/powershell/latest/guides/compatibility/#evidence) |
The raw-command cmdlets are [`Invoke-TmuxCommand`](), [`Invoke-TmuxChain`]() and
[`Invoke-TmuxControlCommand`](). [`Wait-TmuxPaneText`]() needs no refusal: it attaches
no control client below 3.7 and polls the pane instead.
Every refusal raises one type, [`LibTmux.TmuxUnsupportedOnReleaseException`](),
whichever cmdlet or literal command meets it. Where a plain release floor
decides, the error is its subclass [`LibTmux.TmuxVersionTooLowException`](), so
one `catch` of the base type covers both and a `catch` of the subclass keeps
working for those rows. The exception carries [`ActualVersion`](), [`SafeReleases`](),
[`CapabilityId`]() and `Command`.
A workspace layout that the daemon's release lacks fails planning with
[`LibTmux.Workspace.WorkspaceFormatException`](), which names the layout path and
carries the refusal as its [`InnerException`](). The error still reports the
[`NotImplemented`]() category.
These inputs are caller errors on every release and are not release refusals:
- A session name with `:` or `.` raises [`System.ArgumentException`]() from
[`New-TmuxSession`]().
- A layout string that is malformed or unknown raises
[`LibTmux.TmuxWindowException`]() from [`Set-TmuxLayout`]().
[`capabilities.json`]() names the error of each entry and each workaround, and its
`apis` list only the cmdlets that raise that error.
### Evidence
Each requirement rests on a published source. The libtmux for .NET links below
record the compatibility investigations; they do not identify this checkout's
dependency version. [Directory.Packages.props](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/Directory.Packages.props)
holds the current package pins.
- `control-mode`: before 3.7, a notification that fires while a control
client identifies itself crashes the whole server, as the
[libtmux for .NET one-shot guide](https://github.com/libtmux/libtmux-dotnet/blob/b1e8156/docs/modes/one-shot.md?plain=1#L46-L50) records with the tmux commit
that changed it. The same package's [version matrix](https://github.com/libtmux/libtmux-dotnet/blob/b1e8156/docs/modes/matrix.md?plain=1#L178)
lists the requirement.
- `buffer-delete-named` and `buffer-rename`: before 3.4, a buffer name that
does not exist acts on the most recent buffer instead of failing. See the
[version matrix](https://github.com/libtmux/libtmux-dotnet/blob/b1e8156/docs/modes/matrix.md?plain=1#L181).
- `break-pane-misnames-windows`: [`break-pane`](https://libtmux.org/en/tmux/latest/manual/break-pane/) without `-n` ends a 3.7 server.
tmux 3.7a lists
["Fix crash in break-pane when no name is provided"](https://github.com/tmux/tmux/blob/0e418b6/CHANGES#L1-L8). See also the
[version matrix](https://github.com/libtmux/libtmux-dotnet/blob/b1e8156/docs/modes/matrix.md?plain=1#L183).
- `name-separators-rejected`: 3.7 rejects `:` and `.` in names. tmux 3.7a lists
["Only forbid #( in names, allow #[, empty names, : and ."](https://github.com/tmux/tmux/blob/0e418b6/CHANGES#L1-L8). See also
the [version matrix](https://github.com/libtmux/libtmux-dotnet/blob/b1e8156/docs/modes/matrix.md?plain=1#L184).
- `split-window-percent-size`: [`split-window -p`](https://libtmux.org/en/tmux/latest/manual/split-window/) is broken on 3.4. tmux 3.5
lists ["Fix split-window -p"](https://github.com/tmux/tmux/blob/ac44566/CHANGES#L88). See also the
[version matrix](https://github.com/libtmux/libtmux-dotnet/blob/b1e8156/docs/modes/matrix.md?plain=1#L185).
- `clipboard-query`: before 3.6a, [`refresh-client -l`](https://libtmux.org/en/tmux/latest/manual/refresh-client/) can end the server when
the attached client leaves before its terminal answers, and on 3.3a it ends
the server with a client attached. tmux 3.6a lists
["Newer libevents do not allow event_del on a zero'd event"](https://github.com/tmux/tmux/blob/cc117b5/CHANGES#L21),
the [commit](https://github.com/tmux/tmux/commit/0af04295f) that sets up the
clipboard query's timer when a client's terminal opens. See also the
[version matrix](https://github.com/libtmux/libtmux-dotnet/blob/b1e8156/docs/modes/matrix.md?plain=1#L187).
- `layout-without-checksum`: a layout string that is neither checksummed nor
a preset name ends tmux 3.3a. The [version matrix](https://github.com/libtmux/libtmux-dotnet/blob/b1e8156/docs/modes/matrix.md?plain=1#L186) lists the
requirement.
- `layout-mirrored-main`: tmux 3.5 lists
["Add mirrored versions of the main-horizontal and main-vertical layouts"](https://github.com/tmux/tmux/blob/ac44566/CHANGES#L27), so
an earlier release rejects the preset. See also the
[refusal types](https://github.com/libtmux/libtmux-dotnet/blob/b1e8156/docs/modes/matrix.md?plain=1#L196-L199).
- `layout-json`: tmux 3.8 lists
["Layout strings now use a JSON subset format"](https://github.com/tmux/tmux/blob/7f2a35a/CHANGES#L38), so an
earlier release rejects the JSON form.
### What the checks do not read
The checks read the command a cmdlet is given. They do not read a refused
command carried inside another command's text: an [`if-shell`](https://libtmux.org/en/tmux/latest/manual/if-shell/) or [`run-shell -C`](https://libtmux.org/en/tmux/latest/manual/run-shell/)
string, a [`bind-key`](https://libtmux.org/en/tmux/latest/manual/bind-key/), [`set-hook`](https://libtmux.org/en/tmux/latest/manual/set-hook/) or [`confirm-before`](https://libtmux.org/en/tmux/latest/manual/confirm-before/) command, a menu, prompt
or choose template, a brace block, or an alias in your tmux configuration.
Commands typed into a pane are outside them too. Nested, a refused command
reaches tmux unchanged, and it fails as follows.
| What happens | Command | Releases |
| --- | --- | --- |
| The server exits | [`break-pane`](https://libtmux.org/en/tmux/latest/manual/break-pane/) without `-n`, direct or nested | Exactly 3.7; fixed in 3.7a |
| The server exits | [`select-layout`](https://libtmux.org/en/tmux/latest/manual/select-layout/) with an invalid layout string that has no checksum | 3.3a; 3.4 answers with an error and stays up |
| The server exits | [`refresh-client -l`](https://libtmux.org/en/tmux/latest/manual/refresh-client/), when an attached client leaves or does not answer the clipboard query | Below 3.6a |
| A different buffer is changed, with no error | [`delete-buffer -b NAME`](https://libtmux.org/en/tmux/latest/manual/delete-buffer/), [`set-buffer -b NAME -n`](https://libtmux.org/en/tmux/latest/manual/set-buffer/), when NAME does not exist | Below 3.4: the most recent buffer is used instead |
| tmux answers with an error and nothing changes | [`split-window -p`](https://libtmux.org/en/tmux/latest/manual/split-window/) | Exactly 3.4 |
| tmux answers with an error and nothing changes | `:` or `.` in a session or window name | Exactly 3.7 |
On exactly tmux 3.7, name every [`break-pane`](https://libtmux.org/en/tmux/latest/manual/break-pane/), including the one the `prefix !`
key runs, or upgrade to 3.7a or later. Do not nest any other command that
this page lists as refused.
## How the check works
Every cmdlet that talks to tmux goes through the
[libtmux for .NET](https://github.com/libtmux/libtmux-dotnet) package, which
reads the version of the connected daemon first and refuses an older or
unreadable one before it sends the requested operation. The client executable
does not decide this: an older daemon is refused even when the selected executable
reports a newer version. Operations return a [`LibTmux.TmuxVersionTooLowException`]()
error rather than an empty result. When no daemon answers, the executable's own
version is checked before it can start one; a read, which starts nothing,
reports the missing daemon instead. The check adds no tmux hook activity: it
asks for a [`run-shell -C`](https://libtmux.org/en/tmux/latest/manual/run-shell/) expansion that tmux rejects while parsing, so no
`after-*` hook and no [`command-error`](https://libtmux.org/en/tmux/latest/catalog/hooks/command-error/) hook fires for it.
Every command list the package sends starts with a guard on the checked
version. If a different daemon replaced the first one in between, the list
fails before any command runs. A replacement that is supported is checked
again and the command is sent once more; one below the floor is refused; a
second mismatch reports that the daemon changed and that the command did not
run. A client that finds the checked daemon gone starts none.
The Linux workflow keeps tmux 3.2a and unpatched 3.3 as rejection lanes. They
run only the version check suite, which checks that reads, creation, raw commands
and chains are refused and that nothing changed.
A daemon older than 3.2 cannot report its version through that check: a 3.1c
daemon answers with the [`run-shell`](https://libtmux.org/en/tmux/latest/manual/run-shell/) usage line, and a 3.0a daemon makes the
client print `server version is too old for client`. A client older than 3.2
rejects the `-N` flag the check passes, so its own version decides. All three
are refused with [`TmuxVersionTooLowException`](), which says what to do: upgrade
tmux and restart the tmux server, or use an older release. The message names
the last libtmux for .NET release that supports older tmux, 0.0.0-alpha.21;
for these modules it is 0.1.0-alpha2.
The Linux workflow also runs real 3.0a and 3.1c daemons behind a 3.3a client
and requires the refusal to come back promptly.
A refusal is a non-terminating error, like every other operation failure in
the module, so it follows `-ErrorAction`. Use `-ErrorAction Stop` where a
refused daemon must not fall through as no output, as in
`Get-TmuxSession -ErrorAction SilentlyContinue`, which hides it.
[`Connect-TmuxControl`]() attaches only after the same check, so
[`Invoke-TmuxControlCommand`]() and [`Watch-TmuxEvent`]() need no check of their own on
the connection it returns.
`Invoke-TmuxCommand kill-server` against an endpoint where no daemon answers
returns an empty successful result without dispatching anything.
The separate [MCP tool](https://libtmux.org/en/powershell/latest/guides/mcp/) is built on the same package and refuses the
same daemons.
One registry in the module holds these requirements, and it writes
[`capabilities.json`](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/capabilities.json) for the capabilities page of the
documentation site. The module reads the daemon's version and infers what that
release can do; tmux does not report its capabilities, so a patched build is
judged as the release it names.
The module checks the typed operations and workspace plans itself. Literal
command items sent through [`Invoke-TmuxCommand`](), [`Invoke-TmuxChain`]() and
[`Invoke-TmuxControlCommand`]() are checked by the libtmux for .NET package, which
reads a command word the way tmux does, by alias, name or unique prefix, and
reads a `;` list one command at a time.
[What the checks do not read](https://libtmux.org/en/powershell/latest/guides/compatibility/#what-the-checks-do-not-read) lists the nested
commands they skip.
The version a guard reads is the daemon's, taken just before the command is
sent. A daemon replaced in that moment is not caught by the guard, though the
package's own check still refuses one below the floor.
Sections of the suites that need a control client or a pane command report
SKIP below their releases rather than pass, and the features suite asserts
the refusals and that nothing changed. The guards for exactly 3.7, a release
the workflow does not run, are tested by reporting that version to the
version probe.
Choose the tmux executable and socket with [New-TmuxServer](https://libtmux.org/en/powershell/latest/guides/read/), or leave
the socket out and tmux picks the server. A handle alone starts no daemon. The
module does not change `TMUX` or `TMUX_PANE` in the calling process, and it
does not connect to a server during import or formatting.
Some tmux flags and format expressions vary by version. The typed API
checks capabilities where it can; [query plans](https://libtmux.org/en/powershell/latest/guides/query/) show source
pushdown and residual work before execution. A failed or unknown capability
check is not an empty result. [Capture options](https://libtmux.org/en/powershell/latest/guides/capture/) identify flags
whose availability depends on tmux. Use an explicit
[raw command](https://libtmux.org/en/powershell/latest/guides/capture/#run-literal-tmux-arguments) for less common tmux
operations and inspect its result or error record.
The workspace module is a separate PowerShell package over the shared .NET
workspace engine. The [MCP server](https://libtmux.org/en/powershell/latest/guides/mcp/) is a separate .NET tool that does
not require PowerShell. Its client protocol, toolsets, and task support must
be discovered from the installed executable rather than inferred from the
PowerShell module version.
See [troubleshooting](https://libtmux.org/en/powershell/latest/guides/troubleshooting/) for endpoint, package, input and
stream failures.
## Install with PowerShellGet
The README installs with PSResourceGet, which PowerShell 7.4 includes.
PowerShellGet installs the same packages. Install the core module:
```console
$ Install-Module -Name LibTmux
```
Or install the workspace module with its matching core dependency:
```console
$ Install-Module -Name LibTmux.Workspace
```
Choose one installer. Both Gallery pages also provide Azure Automation and
manual download options. A manual download does not include dependencies; use
a package manager to resolve them. Azure Automation runs need a host with
PowerShell and tmux as described above.
---
# Configure and run hooks
Source: https://libtmux.org/en/powershell/latest/guides/hooks/
> Configure and run hooks: LibTmux documentation.
Use a native server, session, window or pane to select a hook table. Server
hooks are global; tmux has no separate server hook table. Choose a hook
supported in the selected scope. For reads and changes, `-Scope` overrides the
scope and `-Global` requests global defaults; pane-local hooks stay local.
Inspect a configured hook on a previously selected `$session`:
```powershell
$session | Get-TmuxHook -Name 'alert-bell'
```
Each native [`TmuxHook`]() has a base [`Name`][tmuxhook-name] and
[`Values`][tmuxhook-values], an ordered collection of [`TmuxHookEntry`]() objects
with [`Index`][tmuxhookentry-index] and [`Command`][tmuxhookentry-command]. Get
accepts base names only; inspect [`Values`][tmuxhook-values] for individual
entries. Omit `-Name` to list the selected table. Missing local hooks produce no
objects.
Set one indexed command and inspect the complete grouped hook:
```powershell
$command = 'display-message "build finished"'
$session | Set-TmuxHook -Name 'alert-bell[7]' -Command $command -PassThru
```
The command is tmux syntax, not PowerShell syntax. tmux normalizes it;
readback preserves that normalized text so it can be passed back unchanged.
Without `-PassThru`, setting emits no success output. An unindexed set
replaces entries. `-Append` keeps them and lets tmux choose a free index,
which may precede existing sparse indices. Use explicit indices when order
matters. Multiple changes do not form an atomic replacement.
Run a previously configured base hook without waiting for its event.
[`Invoke-TmuxHook`]() uses tmux's target-context lookup; `-Scope` and `-Global` do
not force a particular table, and an indexed name does not select one entry:
```powershell
$session | Invoke-TmuxHook -Name 'alert-bell'
```
The call confirms acceptance by tmux. A hook can start asynchronous work;
use a producer signal and [Wait-TmuxChannel](https://libtmux.org/en/powershell/latest/reference/libtmux-wait-tmuxchannel/)
to observe that work completing.
Remove one indexed entry, preserving its neighbours:
```powershell
$session | Remove-TmuxHook -Name 'alert-bell[7]'
```
Use the base name to remove the local hook. Mutations support `-WhatIf` and
`-Confirm`; previews perform no tmux I/O. Errors retain the native owner and
core exception. `-ErrorAction Continue` permits later owners;
[`Stop`][erroraction-stop] terminates the pipeline. Cancellation cannot undo a
dispatched command.
[tmuxhook-name]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxhook-name/
[tmuxhook-values]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxhook-values/
[tmuxhookentry-index]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxhookentry-index/
[tmuxhookentry-command]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxhookentry-command/
[erroraction-stop]: https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.actionpreference#system-management-automation-actionpreference-stop
---
# Create sessions, windows and panes
Source: https://libtmux.org/en/powershell/latest/guides/create/
> Create sessions, windows and panes: LibTmux documentation.
[`New-TmuxSession`](), [`New-TmuxWindow`]() and [`Split-TmuxPane`]() create tmux objects
and emit native [`LibTmux.Session`](), [`LibTmux.Window`]() and [`LibTmux.Pane`]()
handles. Each requires its native owner directly or through the pipeline:
a server for a session, a session for a window and a pane for a split.
Use [explicit endpoints and selection](https://libtmux.org/en/powershell/latest/guides/read/) to choose those owners.
Creation supports `-WhatIf` and `-Confirm`. Confirmation occurs before
discovery or dispatch, including when creating the first session would start
a daemon. A preview emits no created object. Creating objects does not
transfer daemon ownership to the module or arrange automatic teardown.
Choose an endpoint you control and remove the created resources when done.
## Create a detached session
The following command assumes `$server` is an endpoint you own. It creates a
detached session with the requested window name and dimensions:
```powershell
$session = $server |
New-TmuxSession -Name 'work' -WindowName 'editor' -Width 100 -Height 30
```
Omitting `-Name` lets tmux choose a name. An existing name remains an error;
this command does not replace or attach to an existing session. Omitting
dimensions retains tmux's defaults. Names and working directories retain
tmux's format expansion rules, including the meaning of `#`.
Dimensions remain subject to tmux's [`window-size`](https://libtmux.org/en/tmux/latest/catalog/options/window-size/) policy.
## Create a window or split
Create a window at an explicit nonnegative index and make it current:
```powershell
$window = $session | New-TmuxWindow -Name 'tools' -Index 5 -Activate
```
Omitting `-Index` lets tmux choose an available index. An occupied index
remains an error. New windows stay unselected unless `-Activate` is present;
selecting one does not attach a PowerShell process to the terminal.
Given a selected native `$pane`, place a new pane to its left and request
twenty columns:
```powershell
$newPane = $pane | Split-TmuxPane -Horizontal -Before -Size 20
```
Splits default to a new pane below the target. `-Horizontal` selects a
left/right split; `-Before` puts the new pane above or left of the target.
Use either positive `-Size` cells or `-Percentage` from 1 through 100.
Omitting both uses tmux's default split size. Geometry still must fit the
available window. `-FullWindow` spans the full window and `-Zoom` requests
zooming the new pane. `-Activate` selects it; otherwise the previously active
pane stays active. The core owns tmux flag generation and version capability
behavior.
## Commands, directories and environment
All three cmdlets accept `-Command`, `-StartDirectory` and `-Environment`.
`-Command` is one tmux shell-command string. tmux runs it through its shell;
quote shell syntax deliberately and keep untrusted input out of that string.
Omitting it uses the configured tmux default command or shell. For example,
on a Unix host with `/bin/sh` available:
```powershell
$window = $session | New-TmuxWindow -Name 'shell' -Command 'exec /bin/sh'
```
`-StartDirectory` is a filesystem path interpreted by the core and tmux.
Use an absolute path for predictable behavior. The core expands `~` and
`~/`; the adapter does not resolve PowerShell provider paths or change the
caller's current directory. tmux may expand formats within the path.
`-Environment` accepts a dictionary of string keys and string values. Empty
values are retained; numeric and null values are rejected before dispatch with
[`Tmux.InvalidCreation`][newtmuxsessioncommand]. Names cannot be empty or
contain `=` or NUL; values cannot contain NUL. Validation also applies to
`-WhatIf`. Entries are copied before processing owners. They become tmux's
per-session or per-process environment entries; the PowerShell host environment
remains unchanged. Spaces, quotes and semicolons in each value remain part of
that argument.
```powershell
$window = $session | New-TmuxWindow -Environment @{
APP_MODE = 'development'
OPTIONAL = ''
}
```
## Failures and results
Success emits the core's captured created object. Keep that returned handle when
later work needs its current metadata; an existing owner handle is not refreshed
in place. An empty owner pipeline emits nothing. Wrap a pipeline in `@(...)`
when the caller needs an array for zero, one or many results. Creation errors
use [`Tmux.SessionCreateFailed`][newtmuxsessioncommand],
[`Tmux.WindowCreateFailed`][newtmuxwindowcommand] and
[`Tmux.PaneSplitFailed`][splittmuxpanecommand], retain the original core
exception and failed owner, and allow later pipeline owners to continue under
`-ErrorAction Continue`. `-ErrorAction Stop` stops at the first error.
Cancellation reaches the core operation; it does not roll back creation or
terminate a command already started in a pane. No mutation is retried.
The [creation integration test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/Create.Tests.ps1) exercises native
return types, literal names and environment values, directory and geometry
requests, zero-dispatch previews and per-owner failures on an owned server.
The [startup integration test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/CreateStartup.Tests.ps1) separately
verifies first-session daemon creation and owned process teardown. Its Linux
child-reaper setting is confined to that disposable test process.
[newtmuxsessioncommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/NewTmuxSessionCommand.cs
[newtmuxwindowcommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/NewTmuxWindowCommand.cs
[splittmuxpanecommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/SplitTmuxPaneCommand.cs
---
# Filter and query tmux objects
Source: https://libtmux.org/en/powershell/latest/guides/query/
> Filter and query tmux objects: LibTmux documentation.
Use [`Where-Object`]() to filter captured objects locally. Use structured criteria
when the same selection needs reuse, serialization or an inspectable source
plan. Both return native tmux objects that can feed other cmdlets.
Import [`LibTmux`]() and select an existing endpoint as `$server` with
[New-TmuxServer](https://libtmux.org/en/powershell/latest/reference/libtmux-new-tmuxserver/). These examples borrow
that endpoint and do not create or remove sessions. Inspect the daemon version
for source planning, then capture its complete pane graph:
```powershell
$captured = $server |
Get-TmuxServer -ErrorAction Stop |
Get-TmuxSnapshot -ErrorAction Stop
```
## Start with PowerShell
Select panes at least 50 columns wide. Property access and filtering use the
captured data; they do not contact tmux.
```powershell
$captured.Panes | Where-Object { $_.Width -ge 50 -and $_.Height -gt 0 }
```
For reuse, construct the same condition as a native [`QueryDocument`]():
```powershell
$query = New-TmuxQuery -Target Pane -Criteria @{
Width = @{ Ge = 50 }
Height = @{ Gt = 0 }
}
```
Apply it to the already captured panes. Input order, duplicates and object
identity remain intact; parent and child relations retain the complete graph.
```powershell
$captured.Panes | Select-TmuxPane -Query $query
```
## Criteria vocabulary
[`Get-TmuxQueryField`]() returns native catalog descriptors. Inspect the numeric
width field and its supported wire operations:
```powershell
Get-TmuxQueryField -Target Pane | Where-Object WireName -CEQ 'pane_width'
```
Criteria accept a field's catalog wire name or native property path. For
example, [`Width`][criteria-parser] and [`pane_width`](https://libtmux.org/en/tmux/latest/catalog/formats/pane_width/) address the same field.
Field and operator keys ignore case; specifying both aliases in one map is an
error. A bare value means equality. Entries in a map are combined with
[`And`][criteria-parser].
The catalog's [`Operators`]() use JSON wire names. Use these PowerShell keys in
criteria maps; unsupported field/operator combinations fail at construction.
| Criteria key | Native wire operation | Value |
| --- | --- | --- |
| Bare value or [`Eq`][criteria-parser]; [`Ne`][criteria-parser] | `equal`; `notEqual` | Native scalar value |
| [`Lt`][criteria-parser], [`Le`][criteria-parser], [`Gt`][criteria-parser], [`Ge`][criteria-parser] | `lessThan`, `lessThanOrEqual`, `greaterThan`, `greaterThanOrEqual` | Int64-representable integer |
| [`StartsWith`][criteria-parser], [`EndsWith`][criteria-parser], [`Contains`][criteria-parser] | `startsWithOrdinal`, `endsWithOrdinal`, `containsOrdinal` | String |
| [`EqualIgnoreCase`][criteria-parser] | `stringEqualOrdinalIgnoreCase` | String |
| [`StartsWithIgnoreCase`][criteria-parser], [`EndsWithIgnoreCase`][criteria-parser], [`ContainsIgnoreCase`][criteria-parser] | `startsWithOrdinalIgnoreCase`, `endsWithOrdinalIgnoreCase`, `containsOrdinalIgnoreCase` | String |
| [`In`][criteria-parser], [`NotIn`][criteria-parser] | `or` of `equal`, optionally `not` | Array or list of scalar values |
| [`IsNull`][criteria-parser], [`IsNotNull`][criteria-parser] | `equal` or `notEqual` with null | `$true` only |
| [`Regex`][criteria-parser] | `regex` | Map with [`Pattern`][criteria-parser] and optional [`Options`][criteria-parser] list |
| [`Some`][criteria-parser], [`Every`][criteria-parser], [`None`][criteria-parser] | `any`, `all`, or negated `any` | Child criteria for a collection relation |
| [`Is`][criteria-parser], [`IsNot`][criteria-parser] | `related`, optionally negated | Child criteria for a to-one relation |
| [`And`][criteria-parser], [`Or`][criteria-parser], [`Not`][criteria-parser] | `and`, `or`, `not` | Criteria lists for And/Or; one criteria map for Not |
Ordinary string equality, membership and substring matching are ordinal and
case-sensitive. Compare with PowerShell `-ceq` or `-cin`, not its normally
case-insensitive `-eq` or `-in`. [`EqualIgnoreCase`][criteria-parser],
[`StartsWithIgnoreCase`][criteria-parser],
[`EndsWithIgnoreCase`][criteria-parser] and
[`ContainsIgnoreCase`][criteria-parser] explicitly request ordinal
case-insensitive matching. No wildcard expansion or string normalization is
implicit. The catalog also exposes `stringEqualOrdinal`; the criteria form uses
bare string equality or [`Eq`][criteria-parser] for that behavior.
Integers are not coerced from strings, Booleans, enums, floating-point or
decimal values. IDs accept the matching native ID type or a correctly prefixed
string; single-quote session IDs such as `'$0'`. `$null` means explicit absence,
while an omitted field is unconstrained. An empty string remains a value.
ScriptBlocks belong in [`Where-Object`](); they are not translated into criteria.
Collection properties have separate scalar and relation paths: use
`'Windows.Count'` for a numeric comparison and [`Windows`][criteria-parser] for
[`Some`][criteria-parser], [`Every`][criteria-parser] or
[`None`][criteria-parser].
Use explicit [`And`][criteria-parser] with separate maps when a condition needs
both paths. [`ActivePane`][criteria-parser] and
[`ActivePane.Value`][criteria-parser] are aliases for the same captured to-one
relation. Uncaptured relations raise an error; they never become empty data.
These construction limits include nodes introduced when membership and
operator maps expand into the native query:
| Limit | Maximum |
| --- | ---: |
| Predicate depth | 32 |
| Predicate node occurrences | 512 |
| String length | 4,096 Unicode scalar values |
| Regex pattern length | 1,024 Unicode scalar values |
| Encoded JSON | 262,144 UTF-8 bytes |
| Membership entries | 128 |
Cycles, duplicate aliases, invalid Unicode and values beyond these limits are
rejected. Accepted documents own their values; editing the original hashtable
or list does not change a query. Serialization uses the one current schema,
`libtmux-query` version 2; the module includes its JSON schema file.
## Match captured relationships
Select windows with at least one pane that meets both size conditions:
```powershell
$captured.Windows | Select-TmuxWindow -Criteria @{
Panes = @{ Some = @{ Width = @{ Ge = 50 }; Height = @{ Gt = 0 } } }
}
```
Both conditions apply to the same pane. Two separate [`Some`][criteria-parser]
clauses may match different panes. [`Every`][criteria-parser] is true for an
empty captured collection; [`Some`][criteria-parser] is false and
[`None`][criteria-parser] is true. [`Is`][criteria-parser] and
[`IsNot`][criteria-parser] traverse one captured related object. Linked windows
retain their session/index placement; a pane ID can therefore appear in several
input placements. Selection does not deduplicate them.
Combine alternatives and exclusions to select API or log windows while
excluding scratch windows:
```powershell
$captured.Windows | Select-TmuxWindow -Criteria @{
Or = @(@{ Name = @{ StartsWith = 'api-' } }, @{ Name = 'logs' })
Not = @{ Name = @{ Contains = 'scratch' } }
}
```
For a regular expression, pass an explicit pattern and semantic option list:
```powershell
$captured.Windows | Select-TmuxWindow -Criteria @{
Name = @{ Regex = @{ Pattern = '^API-'; Options = @('IgnoreCase') } }
}
```
Regex uses the .NET dialect with
[`CultureInvariant`][regexoptions-cultureinvariant] always enabled. Options
accept [`IgnoreCase`][regexoptions-ignorecase],
[`Multiline`][regexoptions-multiline],
[`ExplicitCapture`][regexoptions-explicitcapture],
[`Singleline`][regexoptions-singleline],
[`IgnorePatternWhitespace`][regexoptions-ignorepatternwhitespace] and
[`CultureInvariant`][regexoptions-cultureinvariant]; execution-only flags such
as [`Compiled`][regexoptions-compiled] are rejected. A running match has the
native one-second timeout. This is the shared .NET query contract, not a claim
of cross-language regex compatibility.
## Store a query or acquire a fresh result
[`ConvertTo-TmuxQueryJson`]() returns a JSON string suitable for storage. Restore
that string with `New-TmuxQuery -Json`; this round-trip does not read tmux:
```powershell
New-TmuxQuery -Json ($query | ConvertTo-TmuxQueryJson)
```
Prepare a plan using the daemon version from the earlier capture. Planning
and inspecting `$queryPlan` perform no I/O:
```powershell
$queryPlan = $query | Get-TmuxQueryPlan -DaemonVersion $captured.DaemonVersion
```
[`PushedPredicate`](), [`ResidualPredicate`](), [`RequiredFields`](),
[`RequiredSnapshotDepth`][query-queryplan-requiredsnapshotdepth] and
[`FallbackReasons`]() explain its execution. `-Pushdown Auto` uses exact supported
source evaluation; [`Never`]() evaluates locally; [`Require`]() rejects any local
residual. A plan does not acquire data.
Execute it against the selected endpoint when a fresh result is needed:
```powershell
$server | Invoke-TmuxQuery -Plan $queryPlan -AsResult -ErrorAction Stop
```
`-AsResult` emits one native [`QueryResult`](), even with no matches. Its indexed
rows refer to the complete [`Snapshot`](); filtering does not prune that graph.
Without `-AsResult`, matching native objects flow individually down the
pipeline. Alternatively, `Invoke-TmuxQuery -Query $query` plans against a fresh
observed daemon version. Execution never starts an absent daemon; a prepared
plan must match the observed version. Acquisition is not an atomic transaction.
`-NativeFilter` with `-Target` is a separate expert escape hatch for raw tmux
format filtering. It cannot combine with `-Query`, `-Plan`, `-Pushdown` or
`-AsResult`, and its rows do not promise a complete structured-query snapshot.
## Require exactly one match
Resolve the captured development session before handing it to another command:
```powershell
$captured.Sessions |
Select-TmuxSession -Criteria @{ Name = 'development' } -ExactlyOne
```
`-ExactlyOne` holds the match until finite input completes. Zero or multiple
matches terminate with [`Tmux.NoMatch`][queryselection] or
[`Tmux.MultipleMatches`][queryselection]. Invalid inputs, unavailable relations,
evaluation errors and pipeline stop suppress the retained object. An infinite
stream cannot establish exact cardinality.
The guarantee concerns successful objects received by the selector. An
upstream nonterminating error can skip a requested source while still leaving
one match. Use `-ErrorAction Stop` on every upstream acquisition when complete
input is required before mutation. It does not roll back changes already
made by another command. Local selection never refreshes captured objects;
use an explicit acquisition to observe changes.
[criteria-parser]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/QueryCriteria.cs
[regexoptions-cultureinvariant]: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions#system-text-regularexpressions-regexoptions-cultureinvariant
[regexoptions-multiline]: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions#system-text-regularexpressions-regexoptions-multiline
[regexoptions-explicitcapture]: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions#system-text-regularexpressions-regexoptions-explicitcapture
[regexoptions-singleline]: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions#system-text-regularexpressions-regexoptions-singleline
[regexoptions-ignorepatternwhitespace]: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions#system-text-regularexpressions-regexoptions-ignorepatternwhitespace
[regexoptions-compiled]: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions#system-text-regularexpressions-regexoptions-compiled
[query-queryplan-requiredsnapshotdepth]: https://libtmux.org/en/csharp/latest/reference/libtmux-query-queryplan-requiredsnapshotdepth/
[queryselection]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/QuerySelection.cs
[regexoptions-ignorecase]: https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions#system-text-regularexpressions-regexoptions-ignorecase
---
# Inspect attached clients
Source: https://libtmux.org/en/powershell/latest/guides/clients/
> Inspect attached clients: LibTmux documentation.
Read the terminal and control clients already attached to a selected native
`$server`. A plain server handle does not attach a client or own its lifetime.
```powershell
$server | Get-TmuxClient
```
Results are native [`Client`]() objects with [`Name`][client-name],
[`Tty`][client-tty], [`IsControlClient`](), [`AttachedSessionId`]() and
[`Generation`][client-generation]. `-Name` selects an exact, case-sensitive
name; it does not interpret wildcards. No clients or no match produces no
objects. An unavailable server produces an error.
Captured fields stay unchanged when a client switches sessions. Refresh a
previously selected `$client` to obtain a new observation:
```powershell
$client | Update-TmuxClient
```
This reads current data; it does not redraw the terminal. Refreshing a client
that has detached writes the native missing-object error.
Resolve the client's current session, window and pane together:
```powershell
$client | Get-TmuxClientAttachment
```
The result is a native [`ClientAttachment`](). A detached client or missing
session produces no output; [`Window`]() or [`Pane`]() can be null. The operation
performs several tmux reads and does not promise an atomic observation.
Transport failures remain errors, not empty results.
These commands only inspect clients. Detachment, locking and suspension
remain available through explicit raw tmux commands. Closing or removing a
client must not be confused with removing its session or daemon.
[client-name]: https://libtmux.org/en/csharp/latest/reference/libtmux-client-name/
[client-tty]: https://libtmux.org/en/csharp/latest/reference/libtmux-client-tty/
[client-generation]: https://libtmux.org/en/csharp/latest/reference/libtmux-client-generation/
---
# Link and move windows between sessions
Source: https://libtmux.org/en/powershell/latest/guides/placement/
> Link and move windows between sessions: LibTmux documentation.
A tmux window can appear at different indices in several sessions. Read the
window through the session whose placement you intend to change; its native
[`Window`]() handle captures that session and index. Start from an
[explicit endpoint](https://libtmux.org/en/powershell/latest/guides/read/), then choose the source window and destination
session. The examples below use `$window` and `$session` from the same server.
Link the window into the destination session at index 5 while leaving that
session's selected window alone:
```powershell
$window |
New-TmuxWindowLink -Session $session -Index 5 -NoSelect -Confirm:$false
```
The command emits no placement handle. Read the destination session's windows
and select the new link by physical ID and destination index:
```powershell
$window = $session | Get-TmuxWindow |
Where-Object { $_.Id -eq $window.Id -and $_.Index -eq 5 }
```
`-ReplaceExisting` permits tmux to displace a window already at the index;
it may destroy that window when this was its last link.
Move the link from index 5 to index 6 in the same session. Keep the returned
replacement handle because the original still describes the old placement:
```powershell
$window = $window | Move-TmuxWindow -Index 6 -PassThru -Confirm:$false
```
Use `-DestinationSession $otherSession` to move a link to another session on
the same endpoint and daemon generation. Omit `-Index` to use the next free
index. `-Direction Before` or [`After`]() inserts relative to a destination;
`-NoSelect` keeps the destination's current selection.
Remove only this session's link to the window. Links in other sessions and
their panes remain:
```powershell
$window | Remove-TmuxWindowLink -Confirm:$false
```
Without `-KillIfLast`, tmux refuses to remove a window's final link. With it,
the final unlink destroys the physical window and its panes. To destroy the
window and every link deliberately, use [Remove-TmuxWindow](https://libtmux.org/en/powershell/latest/guides/remove/).
These three commands request confirmation by default. Use `-WhatIf` to
preview without contacting tmux. They reject a stale source placement in
tmux's native queue; link and cross-session move also reject destination
sessions from another endpoint or daemon generation before dispatch. A failed
move readback can follow a successful dispatch, so inspect current topology
before retrying. See the
[installed placement test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/Placement.Tests.ps1) and
[command reference](https://libtmux.org/en/powershell/latest/reference/libtmux-move-tmuxwindow/).
---
# Read and change options
Source: https://libtmux.org/en/powershell/latest/guides/options/
> Read and change options: LibTmux documentation.
Pass a native server, session, window or pane to select its option table.
Use `-Scope` to override the table and `-Global` to request global defaults.
tmux still selects pane-local options when pane scope is requested; `-Global`
does not make them global. A server handle with `-Scope Session -Global`
addresses global session defaults. Choose the endpoint explicitly with
[New-TmuxServer](https://libtmux.org/en/powershell/latest/reference/libtmux-new-tmuxserver/).
Read the effective key mode from a previously selected `$session`:
```powershell
$session | Get-TmuxOption -Name 'status-keys' -IncludeInherited
```
Each result is a native [`TmuxOption`](). Its [`Name`][tmuxoption-name],
[`Index`][tmuxoption-index], [`Inherited`]() and [`Value`][tmuxoption-value]
describe what tmux reported. Omit `-Name` to list a table. A normal read lists
local values; `-IncludeInherited` adds inherited values. `-Quiet` makes a
missing option produce no rows. [`Where-Object`]() filters returned rows locally.
Store a user option and return the value tmux actually stored:
```powershell
$session | Set-TmuxOption -Name '@project' -Value 'api' -PassThru
```
`-PassThru` emits a native [`TmuxOptionValue`](); its [`Raw`][tmuxoptionvalue-raw],
[`Boolean`][tmuxoptionvalue-boolean], [`Integer`]() and [`State`]() fields preserve
tmux's interpretation. Without it, setting emits no success output. `-Append`
and `-ExpandFormat` return the stored result, not just the supplied argument.
`-PreventOverwrite` asks tmux to refuse replacement and can produce an error.
Remove a previously stored user option:
```powershell
$session | Remove-TmuxOption -Name '@scratch'
```
Removing a built-in override restores inheritance. An empty string is a
stored value, so setting `''` does not remove an option. Indexed names such
as [`command-alias[40]`](https://libtmux.org/en/tmux/latest/catalog/options/command-alias/) read, set or remove that specific array entry;
listing the base name preserves sparse indices. tmux expands formats in
option names, so `#` is not guaranteed literal.
Set and Remove support `-WhatIf` and `-Confirm`; previews contact no server.
Errors retain the original core exception and owner. `-ErrorAction Continue`
permits later owners; [`Stop`][erroraction-stop] terminates the pipeline.
Cancellation cannot undo a dispatched mutation. Readback does not make a
mutation atomic with other clients.
[tmuxoption-name]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxoption-name/
[tmuxoption-index]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxoption-index/
[tmuxoption-value]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxoption-value/
[tmuxoptionvalue-raw]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxoptionvalue-raw/
[tmuxoptionvalue-boolean]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxoptionvalue-boolean/
[erroraction-stop]: https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.actionpreference#system-management-automation-actionpreference-stop
---
# Read tmux objects
Source: https://libtmux.org/en/powershell/latest/guides/read/
> Read tmux objects: LibTmux documentation.
The cmdlets return native objects from
[libtmux for .NET](https://github.com/libtmux/libtmux-dotnet). Inspect them with
[`Get-Member`](), select their properties and pass them directly to other cmdlets.
Create an endpoint with `New-TmuxServer -SocketPath` or `-SocketName`, then
pipe it to a read command. Constructing the endpoint performs no I/O.
With neither parameter the endpoint passes tmux no socket, and tmux picks the
server: the one `TMUX` names inside a tmux pane, otherwise its default socket.
`LIBTMUX_SOCKET_PATH` (`-S`) or `LIBTMUX_SOCKET` (`-L`) chooses a socket for
such an endpoint instead, the path first; a blank value counts as unset, and a
parameter beats both. The endpoint reads the variables when it is made.
[`Connect-TmuxServer`]() discovers an unmaterialized endpoint and returns its
connected replacement. An already connected handle is returned unchanged.
| Command | Typed owner accepted from the pipeline | Output |
| --- | --- | --- |
| [`Connect-TmuxServer`]() | [`LibTmux.Server`]() | [`LibTmux.Server`]() |
| [`Get-TmuxSnapshot`]() | [`LibTmux.Server`]() | Replacement [`LibTmux.Server`]() |
| [`Get-TmuxSession`]() | [`LibTmux.Server`]() | [`LibTmux.Session`]() objects |
| [`Get-TmuxWindow`]() | [`LibTmux.Server`]() or [`LibTmux.Session`]() | [`LibTmux.Window`]() objects |
| [`Get-TmuxPane`]() | [`LibTmux.Server`](), [`LibTmux.Session`](), or [`LibTmux.Window`]() | [`LibTmux.Pane`]() objects |
The acquisition commands above read tmux explicitly. `-Id` selects a literal tmux
identifier, such as `$0`, `@1`, or `%2`; use single quotes for a session ID.
Session and window commands also accept `-Name`. Selectors compare ordinally
and distinguish case. They do not expand wildcards. Combining selectors
requires both to match. An unmatched selector emits no objects; it is not an
error. Wrap a pipeline in `@(...)` when its count matters.
For `-Name` and `-Id`, Tab offers values from an explicitly supplied captured
server, session or window. Capture first with [`Get-TmuxSnapshot`](). Completion
does not contact tmux, refresh a handle or guess an endpoint. An uncaptured
owner offers no tmux values. The suggestion comes from the earlier observation;
the read command still checks current tmux state when you run it.
Owners bind by their native type. Property names on an arbitrary object do
not provide pipeline binding. Use [`Where-Object`]() after
acquisition for further local filtering. For reusable criteria, use
[New-TmuxQuery](https://libtmux.org/en/powershell/latest/reference/libtmux-new-tmuxquery/) and the local
[Select-TmuxPane](https://libtmux.org/en/powershell/latest/reference/libtmux-select-tmuxpane/),
[Select-TmuxWindow](https://libtmux.org/en/powershell/latest/reference/libtmux-select-tmuxwindow/) or
[Select-TmuxSession](https://libtmux.org/en/powershell/latest/reference/libtmux-select-tmuxsession/) commands.
[Get-TmuxQueryField](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxqueryfield/) discovers the
shared query catalog locally.
For a fresh query, pass an explicit endpoint and a query document to
[Invoke-TmuxQuery](https://libtmux.org/en/powershell/latest/reference/libtmux-invoke-tmuxquery/). It emits matching
native objects; `-AsResult` retains the result and its complete captured graph,
including an empty selection. Use
[Get-TmuxQueryPlan](https://libtmux.org/en/powershell/latest/reference/libtmux-get-tmuxqueryplan/) with a known daemon
version to inspect source evaluation, local residuals and fallback reasons
before execution. Planning performs no I/O. The [query guide](https://libtmux.org/en/powershell/latest/guides/query/) walks
through native filtering, reusable criteria, relationships and source plans.
[`Get-TmuxSnapshot`]() defaults to `-Depth Panes`. Shallower depths are
[`Server`][snapshotdepth-server], [`Sessions`][snapshotdepth-sessions], and
[`Windows`][snapshotdepth-windows]. It returns a replacement graph and leaves
the input handle and earlier snapshots unchanged. [`SnapshotMetadata`]() records the
depth, daemon generation, UTC start/end readings and monotonic
[`Elapsed`][snapshotmetadata-elapsed] time. UTC can move backwards if the clock
is adjusted; use [`Elapsed`][snapshotmetadata-elapsed] for duration. Even
`-Depth Server` performs a fresh generation-guarded read.
Snapshot acquisition spans several tmux commands; it does not promise an
atomic view. Contradictory parent, child-count or active-child observations
fail with [`InconsistentSnapshotException`]() and emit no graph. Equal-count
changes can escape detection. The command never retries automatically. Uncaptured
relations report `IsCaptured = false` and throw when enumerated. Property
access never reads tmux. Captured panes expose [`CurrentCommand`]() and
[`CurrentPath`](), which remain readable after the daemon exits. A field that was
not captured raises [`IncompleteSnapshotException`](); a captured empty string
or null retains that value.
Captured children retain their root through [`Server`](). Parent properties return
the captured instances when that depth is available. [`Session.ActiveWindow`](),
[`Session.ActivePane`][session-activepane] and
[`Window.ActivePane`][window-activepane] return `CapturedValue`: inspect
[`IsCaptured`][capturedvalue-iscaptured], then read
[`Value`][capturedvalue-value] for the captured object. Reading an unavailable
[`Value`][capturedvalue-value] raises [`IncompleteSnapshotException`](); [`OrNull()`]()
explicitly opts into null instead. A pane's [`Window`]() retains its session/index
placement, including repeated links to the same window. [`Window.LinkedSessions`]()
contains each related session once. Filtering a collection changes only selected
membership; traversing its parents still reaches their complete captured
children. Active properties use the IDs from their own parent's row, so separate
reads can record different selection states.
[`Update-TmuxPane`]() refreshes one pane's fields. Its parent navigation does not
borrow captured data from an older graph, even when its [`Server`]() names an older
captured root. Acquire another snapshot for a new graph.
Default tables show native identifiers, captured names or titles, and owner
context. Handles resolved only by identifier show blank columns for fields
they have not captured. The views distinguish that specific missing-field
condition from other failures. Formatting and [`Get-Member`]() use local data and
remain usable after the daemon exits. They do not refresh objects.
Read failures write an error for the affected owner, including an endpoint with
no running server, then allow later pipeline owners to continue. Use
`-ErrorAction Stop` to terminate instead. Error IDs are
[`Tmux.ConnectFailed`][connecttmuxservercommand],
[`Tmux.SnapshotFailed`][gettmuxsnapshotcommand],
[`Tmux.SessionReadFailed`][gettmuxsessioncommand],
[`Tmux.WindowReadFailed`][gettmuxwindowcommand], and
[`Tmux.PaneReadFailed`][gettmuxpanecommand]. The error record retains the core
exception and its dispatch metadata when the exception supplies it. Pipeline
cancellation cancels the pending core operation; borrowed server handles do not
own daemon lifetime.
The [installed-module integration test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/Read.Tests.ps1) executes
typed pipelines, exact selection, shallow and replacement snapshots, and
strict errors against its own tmux server. The fixture owns teardown.
The [snapshot integration test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/Snapshot.Tests.ps1) checks provenance,
repeated placements, parent navigation after teardown and contradictory reads.
The [formatting integration test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/Formatting.Tests.ps1) checks
captured objects and identity-only handles after daemon shutdown, including
that formatting and member discovery start no tmux processes.
The [completion integration test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/Completion.Tests.ps1) checks Tab
suggestions after teardown and verifies that completion starts no tmux client.
[snapshotdepth-sessions]: https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-sessions/
[snapshotdepth-windows]: https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-windows/
[snapshotmetadata-elapsed]: https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotmetadata-elapsed/
[capturedvalue-iscaptured]: https://libtmux.org/en/csharp/latest/reference/libtmux-capturedvalue-iscaptured/
[capturedvalue-value]: https://libtmux.org/en/csharp/latest/reference/libtmux-capturedvalue-value/
[connecttmuxservercommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/ConnectTmuxServerCommand.cs
[gettmuxsnapshotcommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/GetTmuxSnapshotCommand.cs
[gettmuxsessioncommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/GetTmuxSessionCommand.cs
[gettmuxwindowcommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/GetTmuxWindowCommand.cs
[gettmuxpanecommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/GetTmuxPaneCommand.cs
[snapshotdepth-server]: https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-server/
[session-activepane]: https://libtmux.org/en/csharp/latest/reference/libtmux-session-activepane/
[window-activepane]: https://libtmux.org/en/csharp/latest/reference/libtmux-window-activepane/
---
# Remove sessions, windows and panes
Source: https://libtmux.org/en/powershell/latest/guides/remove/
> Remove sessions, windows and panes: LibTmux documentation.
[`Remove-TmuxSession`](), [`Remove-TmuxWindow`]() and [`Remove-TmuxPane`]() accept native
core handles directly or through the pipeline. Each removes its target and
emits no success output. Select the target using the
[explicit endpoint and read commands](https://libtmux.org/en/powershell/latest/guides/read/).
These commands have high confirmation impact. The default PowerShell
confirmation preference prompts before removal. Review the endpoint and ID
in that prompt; use `-Confirm:$false` when an unattended caller has already
chosen the target. `-WhatIf` describes the removal without contacting tmux:
```powershell
$session | Remove-TmuxSession -WhatIf
```
Remove an owned session after its work finishes:
```powershell
$session | Remove-TmuxSession -Confirm:$false
```
An empty pipeline does nothing. A pipeline with several targets processes
them in input order. A successful removal emits no handles, Boolean values
or task objects, so `@($pane | Remove-TmuxPane -Confirm:$false)` is empty.
Captured fields on an old handle remain an observation of the removed
object; removal does not rewrite that snapshot.
## Linked windows and cascading removal
**Removing a window destroys the physical window, every pane in it, and all
its links in every session.** It does not merely unlink the placement through
which the window was selected. Repeated placements of that physical window
are removed together:
```powershell
$window | Remove-TmuxWindow -Confirm:$false
```
To remove one session placement while preserving other links, use
[Remove-TmuxWindowLink](https://libtmux.org/en/powershell/latest/guides/placement/).
Removing a session destroys windows that are no longer linked elsewhere. A
window still linked to another session survives with its panes.
Removing the last pane destroys its window. Removing the last window from a
session also removes that session; tmux may exit when no sessions remain.
These commands do not give the module ownership of the daemon or arrange
cleanup for other resources.
```powershell
$pane | Remove-TmuxPane -Confirm:$false
```
## Errors and cancellation
Failures retain the native owner and original core exception in the PowerShell
error record. The stable error IDs are
[`Tmux.SessionRemoveFailed`][removetmuxsessioncommand],
[`Tmux.WindowRemoveFailed`][removetmuxwindowcommand] and
[`Tmux.PaneRemoveFailed`][removetmuxpanecommand]. Core exceptions retain their
available dispatch metadata. A missing target remains an error;
`-ErrorAction Continue` permits later pipeline targets to run, while
`-ErrorAction Stop` stops before the next target.
Handles belong to a specific endpoint and daemon generation. The core
rejects an old-generation handle after daemon replacement instead of resolving
the same numeric ID against the replacement. Removal is never retried.
Stopping the pipeline cancels the active client operation; a removal already
accepted by tmux is not rolled back.
The [installed removal test](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/Remove.Tests.ps1) checks previews,
zero-output pipelines, per-owner errors, linked-window destruction, session
sharing, [last-pane](https://libtmux.org/en/tmux/latest/manual/last-pane/) cascades, isolated endpoints and real daemon replacement
on owned tmux servers.
[removetmuxsessioncommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/RemoveTmuxSessionCommand.cs
[removetmuxwindowcommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/RemoveTmuxWindowCommand.cs
[removetmuxpanecommand]: https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/src/LibTmux.PowerShell/RemoveTmuxPaneCommand.cs
---
# Send input to a pane
Source: https://libtmux.org/en/powershell/latest/guides/input/
> Send input to a pane: LibTmux documentation.
Select a native pane using [`Get-TmuxPane`]() on the endpoint you intend to
change. Input commands use that pane's endpoint and daemon generation.
Pipeline input must be a native [`LibTmux.Pane`](); an object with similarly
named properties does not bind as an owner.
| Command | Input | Enter behavior |
| --- | --- | --- |
| [Send-TmuxText](https://libtmux.org/en/powershell/latest/reference/libtmux-send-tmuxtext/) | Literal text, including spaces, dashes and tmux format markers | Appends one Enter only with `-Enter` |
| [Send-TmuxKey](https://libtmux.org/en/powershell/latest/reference/libtmux-send-tmuxkey/) | An ordered string array of tmux key tokens | Send [`Enter`]() explicitly as a token |
The [literal text example](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/docs/reference/LibTmux/Send-TmuxText.md#example-1)
types the characters in a key name. The
[key sequence example](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/docs/reference/LibTmux/Send-TmuxKey.md#example-1) sends
the corresponding control keys. Both examples run against an owned byte
receiver in the installed-help suite.
[`Send-TmuxText`]() accepts empty text. NUL is rejected before dispatch; newlines
and other control characters are delivered. Newlines already in the text
can execute commands even when `-Enter` is omitted. Literal sending does
not quote text for the receiving shell or application.
[`Send-TmuxKey`]() owns a snapshot of its input array and sends tokens in order.
It rejects null, empty and NUL-containing tokens. tmux interprets recognized
names such as `C-a`; unrecognized names follow tmux's character-sending
behavior. One string is not split into multiple tokens on whitespace.
Both commands support `-WhatIf` and `-Confirm`. A preview performs no
acquisition or input operation. Confirmation identifies the endpoint and
pane without displaying the supplied content. Successful commands emit no
objects; an empty owner pipeline performs no work.
Sending input confirms acceptance by tmux. Use
[Invoke-TmuxPaneCommand](https://libtmux.org/en/powershell/latest/reference/libtmux-invoke-tmuxpanecommand/) when a
shell command needs a verified exit status, or an explicit signal from the
receiving application before asserting completion or
[capturing its output](https://libtmux.org/en/powershell/latest/guides/capture/). Use
[Wait-TmuxChannel](https://libtmux.org/en/powershell/latest/reference/libtmux-wait-tmuxchannel/) for a cooperative
[`tmux wait-for -S`](https://libtmux.org/en/tmux/latest/manual/wait-for/) signal. Give each operation a unique channel with one waiter;
its timeout and cancellation cleanup withdraw the registration so it cannot
consume a later signal. A successful send is not a command result
or shell exit status.
Failures retain the original core exception, dispatch information and target
pane. `-ErrorAction Continue` permits later owners to run;
`-ErrorAction Stop` stops on the first failure. Cancellation stops pending
work but cannot undo input already delivered. A failed key sequence can leave
earlier keys applied. If literal text was sent but the following Enter fails,
the core reports unknown partial dispatch. Retrying can repeat effects;
the commands never retry automatically.
## Run a command to completion
[`Invoke-TmuxPaneCommand`]() runs a shell command in a writable POSIX shell pane.
It needs tmux 3.4 or newer, because it stages a temporary buffer that older
releases cannot delete safely; an older daemon is refused before any buffer
exists.
It returns a native [`LibTmux.PaneRunResult`]() with an authenticated exit
status. A nonzero status remains a result; a timeout returns `TimedOut = True`
and a null status because the command may still be running. The command runs
in a subshell, so `cd` and `export` do not change the pane's parent shell.
Completion uses a cooperative tmux [`wait-for`](https://libtmux.org/en/tmux/latest/manual/wait-for/) channel. While waiting, the
runner also checks authenticated run status and pane liveness, starting after
250 ms and backing off to five seconds. These checks detect a pane that exits
without signalling; they are separate from event-backed pane text waits.
With an endpoint in `$server`, create a shell pane and check the status rather
than guessing from a prompt or screen capture. The example removes only its
session:
```powershell
& {
$ErrorActionPreference = 'Stop'
$name = 'pane-run-' + [Guid]::NewGuid().ToString('N')
$session = $server | New-TmuxSession -Name $name -Command 'exec /bin/sh'
try {
$pane = $session | Get-TmuxPane
$pane |
Invoke-TmuxPaneCommand -Command 'exit 7' -Timeout 5 -Confirm:$false
} finally {
$session | Remove-TmuxSession -Confirm:$false
}
}
```
The result's [`ExitStatus`]() is 7 and [`TimedOut`][panerunresult-timedout] is
False. [`Output`]() contains bounded rendered command output, which can include both
stdout and stderr. It is not a byte-exact stream. The default view omits output
text; inspect [`Output`](), [`LinesMissed`][panerunresult-linesmissed],
[`AnchorLost`][panerunresult-anchorlost] and omission counts when needed.
[`Get-TmuxPaneContent`]() reads the current pane screen separately. On timeout or
cancellation after dispatch, inspect the pane before retrying. The
[cmdlet reference](https://libtmux.org/en/powershell/latest/reference/libtmux-invoke-tmuxpanecommand/) describes
history suppression, validation and confirmation.
## Wait for an application's readiness line
Use [Wait-TmuxPaneText](https://libtmux.org/en/powershell/latest/reference/libtmux-wait-tmuxpanetext/) when an
application reports readiness in its terminal output. On tmux 3.7 or newer,
it observes rendered text through a temporary control client, checks text
already visible at entry, then wakes on output or layout changes. On earlier
supported releases it polls without attaching a control client. It returns a
native [`LibTmux.PaneWaitResult`](); it does not require a cooperative tmux channel.
With Python 3 on `PATH` and the selected endpoint in `$server`, start a local
HTTP server on an available loopback port. Wait for its readiness line, then
make an HTTP request to verify that the server responds. The `finally` block
removes the session and stops the server process:
```powershell
& {
$ErrorActionPreference = 'Stop'
$session = $server | New-TmuxSession `
-Name ('http-' + [Guid]::NewGuid().ToString('N')) `
-Command 'exec python3 -u -m http.server 0 --bind 127.0.0.1'
try {
$pane = $session | Get-TmuxPane
$ready = $pane | Wait-TmuxPaneText `
-Pattern '^Serving HTTP on 127\.0\.0\.1 port [0-9]+' `
-CaseSensitive -Timeout 10 -TailLines 4 -Confirm:$false
if ($ready.Outcome -notin 'PresentAtEntry', 'Matched') {
throw "HTTP readiness ended with $($ready.Outcome)."
}
$tail = $ready.Tail -join "`n"
$port = [regex]::Match($tail, 'port ([0-9]+)').Groups[1].Value
$uri = "http://127.0.0.1:$port/"
$response = Invoke-WebRequest -Uri $uri -TimeoutSec 5 -NoProxy
$ready
$response.StatusCode
} finally {
$session | Remove-TmuxSession -Confirm:$false
}
}
```
The observation is [`PresentAtEntry`]() or [`Matched`](), followed by HTTP status 200.
The wait owns and closes any control client it creates; it leaves the pane and
daemon running. The example separately owns its session and removes it.
Patterns use bounded .NET regular expressions and ignore case by default. Use
`-SimpleMatch` for literal text, `-CaseSensitive` for case-sensitive matching,
and `-StopPattern` for a terminal failure line. Stop patterns take priority over
wanted patterns. Without `-Pattern`, the wait returns on new output.
[`TimedOut`][panewaitoutcome-timedout] and
[`PaneExited`][panewaitoutcome-paneexited] are result outcomes; transport
failures and invalid patterns are errors. Ctrl+C cancels observation, not the
application. On tmux 3.7 and newer, `-AllowPollingFallback` explicitly permits
polling if control observation fails; older releases attach no control client
and always poll. Either way a pattern matches a line that wraps across rows
as one line. A wait whose server is killed ends as `PaneExited` with the
output read so far, without an error. [`PollingFallback`]() and [`EventsDropped`]()
disclose degradation.
Rendered text can include echoed input and can disappear on repaint or
scrollback eviction. A match proves the text condition, not an exit status or
continuing service health. The HTTP request above checks service behavior
separately. Inspect [`LinesMissed`][panewaitresult-linesmissed],
[`AnchorLost`][panewaitresult-anchorlost], [`OmittedTailLines`]() and
[`OmittedTailBytes`]() before treating the bounded tail as complete output. Use
[command completion](https://libtmux.org/en/powershell/latest/guides/input/#run-a-command-to-completion) for an authenticated exit
status and [event streams](https://libtmux.org/en/powershell/latest/guides/watch/) for individual notifications.
## Send a command and wait for its output
With an endpoint in `$server`, send literal text to a shell and use `-Enter`
to submit it. See [endpoint selection](https://libtmux.org/en/powershell/latest/guides/read/) for setup. The shell signals
a unique channel after printing, so capture waits for completed output. The
signal uses the endpoint's tmux executable and socket, with paths quoted for
the shell. A successful send alone means tmux accepted the input; it does not
establish that the receiving program finished.
```powershell
& {
$ErrorActionPreference = 'Stop'
$ready = 'libtmux-demo-' + [Guid]::NewGuid().ToString('N')
$binary = $server.ConnectionOptions.TmuxBinaryPath
$tmux = (Get-Command $binary -CommandType Application |
Select-Object -First 1).Source
$selector = if ($server.ConnectionOptions.SocketPath) {
"-S '{0}'" -f $server.ConnectionOptions.SocketPath.Replace("'", "'\''")
} elseif ($server.ConnectionOptions.SocketName) {
"-L '{0}'" -f $server.ConnectionOptions.SocketName.Replace("'", "'\''")
} else { '' }
$quoted = $tmux.Replace("'", "'\''")
$signal = "'{0}' {1} wait-for -S '{2}'" -f $quoted, $selector, $ready
$session = $server |
New-TmuxSession -Name 'input-demo' -Command 'exec /bin/sh'
try {
$pane = $session | Get-TmuxPane
$text = 'printf "\nhello from PowerShell\n"; ' + $signal
$pane | Send-TmuxText -Text $text -Enter
$null = $server | Wait-TmuxChannel -Channel $ready -Timeout 10
$pane | Get-TmuxPaneContent
} finally {
$session | Remove-TmuxSession -Confirm:$false
}
}
```
The captured screen includes `hello from PowerShell`. [`Wait-TmuxChannel`]()
accepts a signal that arrived before the wait, reports a timeout if no signal
arrives, and withdraws its waiter on timeout or Ctrl+C. Use one waiter per
unique channel: tmux withdrawal also wakes other waiters on that channel.
The example removes its `input-demo` session in `finally`.
[`Send-TmuxKey`]() sends key tokens such as `C-c` or [`Enter`](); [`Send-TmuxText`]()
sends those characters literally. Mutation commands also support `-WhatIf`
and `-Confirm`. See [capturing output](https://libtmux.org/en/powershell/latest/guides/capture/).
[panerunresult-timedout]: https://libtmux.org/en/csharp/latest/reference/libtmux-panerunresult-timedout/
[panerunresult-linesmissed]: https://libtmux.org/en/csharp/latest/reference/libtmux-panerunresult-linesmissed/
[panerunresult-anchorlost]: https://libtmux.org/en/csharp/latest/reference/libtmux-panerunresult-anchorlost/
[panewaitoutcome-timedout]: https://libtmux.org/en/csharp/latest/reference/libtmux-panewaitoutcome-timedout/
[panewaitoutcome-paneexited]: https://libtmux.org/en/csharp/latest/reference/libtmux-panewaitoutcome-paneexited/
[panewaitresult-linesmissed]: https://libtmux.org/en/csharp/latest/reference/libtmux-panewaitresult-linesmissed/
[panewaitresult-anchorlost]: https://libtmux.org/en/csharp/latest/reference/libtmux-panewaitresult-anchorlost/
---
# Set the environment for new panes
Source: https://libtmux.org/en/powershell/latest/guides/environment/
> Set the environment for new panes: LibTmux documentation.
A native server selects tmux's global environment; a native session selects
its local environment. Reads return that table's entries without merging
inherited values. Changes affect future processes. They do not change the
environment of a process already running in a pane.
Read a stored value from a previously selected `$session`:
```powershell
$session | Get-TmuxEnvironment -Name 'APP_MODE'
```
Omit `-Name` to list visible entries. Results are native [`TmuxEnvironmentEntry`]()
objects with [`Name`][tmuxenvironmententry-name],
[`Value`][tmuxenvironmententry-value] and [`IsRemoved`](). A missing variable
produces no object.
Set a value for future panes and inspect the stored result:
```powershell
$session | Set-TmuxEnvironment -Name 'APP_MODE' -Value 'development' -PassThru
```
An empty string remains a present value. Without `-PassThru`, setting emits
no success output. `-ExpandFormats` asks tmux to expand the value as a format
before storage.
Forget the local entry so a global value can apply again:
```powershell
$session | Remove-TmuxEnvironment -Name 'APP_MODE'
```
Suppress inherited values in new pane processes instead:
```powershell
$session | Remove-TmuxEnvironment -Name 'APP_MODE' -MarkRemoved
```
`-MarkRemoved` retains an entry with `IsRemoved = true` and `Value = null`.
Unsetting, marking removed and setting an empty string are distinct tmux
operations.
`Set-TmuxEnvironment -Hidden` keeps a variable available to tmux formats
but excludes it from new child environments and ordinary reads. Its native
`-PassThru` result has `Value = null` and `IsRemoved = false`; the null value
means readback is unavailable, not that the variable is empty or removed.
Set and Remove support `-WhatIf` and `-Confirm`; previews contact no server.
Errors retain the original core exception and owner. `-ErrorAction Continue`
permits later owners; [`Stop`][erroraction-stop] terminates the pipeline.
Cancellation cannot undo a dispatched mutation.
[tmuxenvironmententry-name]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxenvironmententry-name/
[tmuxenvironmententry-value]: https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxenvironmententry-value/
[erroraction-stop]: https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.actionpreference#system-management-automation-actionpreference-stop
---
# Troubleshooting
Source: https://libtmux.org/en/powershell/latest/guides/troubleshooting/
> Troubleshooting: LibTmux documentation.
Start with the endpoint and operation that failed. The cmdlets keep native
objects and errors, so an empty result, a failed tmux command and a cancelled
wait have different meanings. Use `-ErrorAction Stop` when one failure should
stop a script.
| Symptom | Check and next action |
| --- | --- |
| `Import-Module LibTmux` cannot find a dependency | Follow [installation](https://libtmux.org/en/powershell/latest/guides/getting-started/#quick-start) to install from PowerShell Gallery with dependency resolution. Install both PowerShell modules at the same version; importing mixed core assemblies is rejected. For a checkout, use the [source build](https://libtmux.org/en/powershell/latest/guides/getting-started/#install-from-source) and import the staged manifests. For local shared-source changes, retain the exact inspected archives described in [review package builds](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/.github/CONTRIBUTING.md#review-package-builds). |
| A server handle exists, but reads cannot reach tmux | [`New-TmuxServer`]() constructs a local handle. Use [Connect-TmuxServer](https://libtmux.org/en/powershell/latest/guides/read/) to discover an existing daemon, or [New-TmuxSession](https://libtmux.org/en/powershell/latest/guides/create/) to create one on that explicit endpoint. Check the selected socket and executable before retrying. |
| A handle with no socket reaches a server you did not choose | A handle that names no socket passes tmux none, so tmux uses the server `TMUX` names inside a pane, otherwise its default. Pass `-SocketName` or `-SocketPath`, or set `LIBTMUX_SOCKET_PATH` or `LIBTMUX_SOCKET` before the handle is made; the path wins, a blank value is ignored and `LIBTMUX_SOCKET_NAME` selects nothing. See [read](https://libtmux.org/en/powershell/latest/guides/read/). |
| A command targets the wrong session or window | Read the object from the intended server and session. [Window placements](https://libtmux.org/en/powershell/latest/guides/placement/) carry a session-relative index; a physical window can be linked more than once. Raw tmux targets are strings and do not inherit a captured placement guard. |
| A move, input or raw mutation failed after dispatch | Read current topology or screen state before deciding whether to retry. A failed readback or cancelled wait can follow a successful tmux mutation. [Placement](https://libtmux.org/en/powershell/latest/guides/placement/) and [literal input](https://libtmux.org/en/powershell/latest/guides/input/) describe the uncertain cases. |
| Sent text has no captured output yet | [Sending text](https://libtmux.org/en/powershell/latest/guides/input/) acknowledges input, not program completion. Wait on a cooperative channel or a program-specific result, then [capture](https://libtmux.org/en/powershell/latest/guides/capture/) the pane. A sleep does not establish readiness. |
| A watcher reports dropped events | The [event stream](https://libtmux.org/en/powershell/latest/guides/watch/) bounds count and text bytes. A loss marker means history is incomplete; acquire a fresh snapshot when current topology matters. Rendered capture is a screen view, not a reconstruction of missed events. |
| Interactive attach fails from a script or CI job | [Enter-TmuxSession](https://libtmux.org/en/powershell/latest/reference/libtmux-enter-tmuxsession/) needs a foreground terminal with stdin and must run outside another tmux client. Workspace apply is detached; pass its successful native [`Session`]() to the attach command in a terminal. |
| Workspace apply stops partway through | Inspect the native [`WorkspaceBuildException`][workspacebuildexception] journal and partial result described in the [workspace guide](https://libtmux.org/en/powershell/latest/workspace/source-guide/#startup-host-effects-and-failures). Review the original plan and live server before another apply; host scripts and sent pane commands are not rolled back. |
| MCP tools or waits are unavailable | The [MCP server](https://libtmux.org/en/powershell/latest/guides/mcp/) is an independently installed .NET tool. Check the configured executable, socket and `LIBTMUX_TOOLSETS`, then initialize the client and read `tools/list` and `tmux://capabilities`. A cursor or task from an earlier process is not durable. |
For repeatable failures, record the command, PowerShell and tmux versions,
selected socket kind, error ID and original exception. Avoid including pane
contents, secrets or private socket paths in a public report. The
[contributor guide](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/.github/CONTRIBUTING.md#testing-tmux-behavior) runs
integration checks on owned sockets without touching your default server.
[workspacebuildexception]: https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacebuildexception/
---
# Using the .NET MCP server
Source: https://libtmux.org/en/powershell/latest/guides/mcp/
> Using the .NET MCP server: LibTmux documentation.
Use the separate [LibTmux.Mcp .NET tool](https://www.nuget.org/packages/LibTmux.Mcp)
to let an MCP client inspect panes, wait for output and run commands in tmux.
It uses the same .NET library as libtmux for PowerShell. It does not import
the PowerShell modules or require a PowerShell launcher. Tool names link to the
[.NET MCP tool reference](https://libtmux.org/en/csharp/latest/mcp/tools/),
which documents this server.
## Install and select a server
Install the published 0.1.1 tool on the Unix host running tmux:
```console
$ dotnet tool install LibTmux.Mcp \
--tool-path build/mcp \
--version 0.1.1 \
--framework net8.0
```
For shared .NET source changes, use the optional
[MCP development setup](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/.github/CONTRIBUTING.md#mcp-discovery).
A desktop-launched client may need `DOTNET_ROOT` in its server environment
when .NET comes from a version manager.
For clients using an `mcpServers` configuration, replace these absolute paths
with the installed tool, tmux executable and an existing server socket:
```json
{
"mcpServers": {
"tmux": {
"command": "/absolute/tool-directory/libtmux-mcp",
"env": {
"LIBTMUX_TMUX": "/absolute/path/to/tmux",
"LIBTMUX_SOCKET_PATH": "/absolute/path/to/tmux/socket",
"LIBTMUX_TOOLSETS": "inspect"
}
}
}
}
```
Claude Code takes the same settings as `-e` flags and the executable after
`--`:
```console
$ claude mcp add tmux \
-e LIBTMUX_TMUX=/absolute/path/to/tmux \
-e LIBTMUX_SOCKET_PATH=/absolute/path/to/tmux/socket \
-e LIBTMUX_TOOLSETS=inspect \
-- /absolute/tool-directory/libtmux-mcp
```
Other clients use different configuration formats; see the
[.NET MCP client setup](https://libtmux.org/en/csharp/latest/mcp/#install).
Launch the executable directly: standard input and output carry MCP messages.
To name a socket instead of giving its path, replace `LIBTMUX_SOCKET_PATH` with
`LIBTMUX_SOCKET`:
```console
$ claude mcp add tmux \
-e LIBTMUX_SOCKET=work \
-e LIBTMUX_TOOLSETS=inspect \
-- /absolute/tool-directory/libtmux-mcp
```
- To choose a socket, set `LIBTMUX_SOCKET`, a name, or `LIBTMUX_SOCKET_PATH`,
an absolute path. With both, including when one is inherited, the path wins.
A blank value stops the server, where a PowerShell handle ignores it.
`LIBTMUX_SOCKET_NAME` selects nothing, and the server refuses to start with
it alone.
- With neither, the server drives the server tmux picks: the one `TMUX` names,
otherwise your default socket. A client started from a tmux pane therefore
works on the panes you are using. The server starts no server of its own and
leaves `teardown` off, and `tmux://capabilities` reports the selector
`default`. Set `LIBTMUX_SOCKET` to keep an assistant on a server of its own.
- The choice is fixed at startup; calls cannot switch sockets.
- Shut down the client connection when finished. The server leaves a borrowed
tmux daemon running.
## Discover before calling
After initialization:
- Read the server instructions.
- Call `tools/list` for schemas, descriptions and annotations. Each advertised
tool also carries its capability row in
`_meta["com.git-pull.libtmux-mcp/capability"]`.
- Read the [`tmux://capabilities` resource][capabilities]. It identifies the
selected socket, the effective tools and the observation policy.
Choose the tools your client sees:
- The example selects `inspect`. Add `manage`, `execute` or `teardown` only for
the operations your client needs, then restart it to change the selection.
- Toolsets shape the interface; they are not an authorization boundary.
Commands execute with the tmux user's authority.
- [Tool selection][tool-selection] has the full contract.
| Task | Start with |
| --- | --- |
| Find a session, window or pane | [`list_sessions`][list_sessions], [`list_windows`][list_windows], [`list_panes`][list_panes] |
| Read terminal text | [`capture_pane`][capture_pane]; [`snapshot_pane`][snapshot_pane] for structured state |
| Find text across panes | [`search_panes`][search_panes] |
| Wait for text that has not appeared | [`wait_for_text`][wait_for_text] with a finite timeout |
| Read changes across later calls | [`capture_since`][capture_since], retaining its returned cursor |
| Run your own command and observe its completion | [`run_shell_command`][run_shell_command] from the `execute` toolset |
| Combine independent reads in one request | [`call_read_tools_batch`][call_read_tools_batch]; its operations run serially |
Know when a command is done:
- Input acknowledgement does not prove a shell command finished.
- Use the completion result of [`run_shell_command`][run_shell_command] for a
command you start. Cancellation or timeout can leave that command running in
its pane.
- For a program already running, wait for its output rather than repeatedly
capturing the screen.
Read output without losing it:
- On tmux 3.7 and newer, pane text waits require control observation by
default. Older releases attach no control client and poll.
- Setting `LIBTMUX_MCP_ALLOW_POLLING_FALLBACK=true` allows repeated captures if
control observation fails. Capabilities disclose the policy and affected
results report `pollingFallback`.
- Give text waits a finite timeout. The server bounds their returned tail.
- For captures, select `maxLines`. Check `eventsDropped` and the truncation
fields before treating observed output as complete.
- A [`capture_since`][capture_since] cursor tracks observation between calls;
it is not a background job.
- Progress notifications and optional MCP Tasks are separate protocol features,
available only where the discovered tool declares them.
- [Waits and captured output][waits] has the full contract.
To allow the polling fallback, add it to the server's environment:
```console
$ claude mcp add tmux \
-e LIBTMUX_SOCKET=work \
-e LIBTMUX_MCP_ALLOW_POLLING_FALLBACK=true \
-- /absolute/tool-directory/libtmux-mcp
```
## Inspect a pane and wait for readiness
After discovery, select a session from [`list_sessions`][list_sessions]. These
are `tools/call` parameter objects: replace `$0` and `%0` with IDs returned by
your server. The inspect toolset includes all three calls.
List the selected session's panes with [`list_panes`][list_panes]:
```json
{
"name": "list_panes",
"arguments": { "session": "$0" }
}
```
The response's [`structuredContent.result`][result] contains pane records with
`paneId`, `windowId`, `sessionId`, dimensions and the current command. Select
one pane and read its rendered screen with [`capture_pane`][capture_pane]:
```json
{
"name": "capture_pane",
"arguments": { "paneId": "%0", "maxLines": 64 }
}
```
For this object result:
- Read [`structuredContent.content.lines`][lines] directly.
- [`content.truncated`][truncated], [`content.droppedLines`][droppedlines] and
[`content.droppedBytes`][droppedbytes] disclose output omitted to fit the
budget.
- A list result has the `result` wrapper; object results do not.
- Check `isError` before interpreting either shape.
If the application prints `Service ready`, wait for that whole line with
[`wait_for_text`][wait_for_text]:
```json
{
"name": "wait_for_text",
"arguments": {
"paneId": "%0",
"patterns": ["^Service ready$"],
"timeoutSeconds": 1,
"ignoreCase": false
}
}
```
The result:
- An existing line returns `structuredContent.outcome = "PresentAtEntry"`; a
later line returns `"Matched"`.
- `matchedPattern` identifies the condition, and `tail` contains bounded
rendered text.
- Stop-pattern, timeout and pane-death outcomes remain distinct.
- A ready-line match is an application-specific condition; it does not
establish shell exit status or continuing health.
The [official SDK client](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/support/McpDiscovery/Program.cs) reads these
three request examples, substitutes discovered IDs and executes them against
an installed tool. Its owned fixture prints the ready line before the calls,
then checks capture, [`PresentAtEntry`](), an untruncated tail, no event drops,
polling only on tmux before 3.7, stdio shutdown and preservation of the
borrowed tmux state.
Cancel with care:
- Use a finite server timeout even when your client can cancel.
- With the pinned SDK 2.2.0, cancelling a local token does not reliably send
`notifications/cancelled`; it can leave the remote wait running until its
timeout. A client that knows its request ID can send that notification
itself.
- For negotiated MCP Tasks, cancel the task with `tasks/cancel` using its
returned task ID. Task records are temporary and disappear on expiry or
restart.
- Neither cancellation stops the application in the pane.
## Check the client workflow from this checkout
After [building the discovery probe](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/.github/CONTRIBUTING.md#mcp-discovery),
set `MCP_COMMAND` to the installed executable's absolute path and
`MCP_VERSION` to its exact version. Select the desired tmux on `PATH`, then run:
```console
$ pwsh -NoLogo -NoProfile -File eng/Test.ps1 \
-Suite Mcp \
-McpCommand "$MCP_COMMAND" \
-McpVersion "$MCP_VERSION"
```
The [official SDK client source](https://github.com/libtmux/libtmux-powershell/blob/fa5e60c48b312eb0d957d02aad9edcfc50cff359/tests/support/McpDiscovery/Program.cs)
initializes the installed tool, compares discovery with capabilities, then
executes [`list_sessions`][list_sessions] and the three request examples above.
The suite also:
- starts the tool with every `LIBTMUX_` setting that the `claude mcp add`
commands and JSON configuration on this page and in the repository README
show, and checks that capabilities report each setting;
- checks that both socket variables together are refused;
- checks that every tool name on those pages is a link to its tool page and
that every linked tool exists on the installed server;
- checks that the session and pane survive MCP shutdown, then removes the
owned fixture.
It neither imports the PowerShell modules nor builds, installs or downloads
anything during the test. Broader task, cancellation, loss and concurrent-wait
acceptance belongs to the .NET protocol suite.
[capabilities]: https://libtmux.org/en/csharp/latest/mcp/resources/tmux_capabilities/
[tool-selection]: https://libtmux.org/en/csharp/latest/mcp/topics/tool-selection/
[waits]: https://libtmux.org/en/csharp/latest/mcp/topics/waits-and-output/
[list_sessions]: https://libtmux.org/en/csharp/latest/mcp/tools/list_sessions/
[list_windows]: https://libtmux.org/en/csharp/latest/mcp/tools/list_windows/
[list_panes]: https://libtmux.org/en/csharp/latest/mcp/tools/list_panes/
[capture_pane]: https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/
[snapshot_pane]: https://libtmux.org/en/csharp/latest/mcp/tools/snapshot_pane/
[search_panes]: https://libtmux.org/en/csharp/latest/mcp/tools/search_panes/
[wait_for_text]: https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_text/
[capture_since]: https://libtmux.org/en/csharp/latest/mcp/tools/capture_since/
[run_shell_command]: https://libtmux.org/en/csharp/latest/mcp/tools/run_shell_command/
[call_read_tools_batch]: https://libtmux.org/en/csharp/latest/mcp/tools/call_read_tools_batch/
[result]: https://libtmux.org/en/csharp/latest/mcp/tools/list_panes/#mcp.tool.list_panes.output/properties/result
[lines]: https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/#mcp.tool.capture_pane.output/properties/content/properties/lines
[truncated]: https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/#mcp.tool.capture_pane.output/properties/content/properties/truncated
[droppedlines]: https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/#mcp.tool.capture_pane.output/properties/content/properties/droppedLines
[droppedbytes]: https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/#mcp.tool.capture_pane.output/properties/content/properties/droppedBytes
---
# Watch events and use runspaces
Source: https://libtmux.org/en/powershell/latest/guides/watch/
> Watch events and use runspaces: LibTmux documentation.
[`Watch-TmuxEvent`]() emits native notifications and pane output fragments as they
arrive. One application write may span several events, and one event may
contain multiple lines. Use [rendered capture](https://libtmux.org/en/powershell/latest/guides/capture/) when you need the
pane's current screen.
The stream is not a durable or byte-exact log.
Supply a control connection to borrow it, or a server and raw `-Target` to let
the watcher own a temporary client. Stop, early pipeline exit and module removal
end the reader; only an internally created client is disposed. The tmux daemon
and sessions remain running. Removing the module cancels active watchers only
in that runspace, and does not close handles returned by [`Connect-TmuxControl`]().
One connection has one event consumer. The package rejects competing watchers;
callers must also avoid directly enumerating the same native [`Events`]() stream.
Each event is delivered on the pipeline callback before another is fetched.
Downstream code may synchronously send a control command on that connection:
reply processing does not wait for notification delivery.
## Observe one owned change
[`Watch-TmuxEvent`]() attaches a control client, which needs tmux 3.7 or newer.
With a server it is refused on an older daemon before anything attaches.
After [installing libtmux for PowerShell](https://libtmux.org/en/powershell/latest/guides/getting-started/#install-from-source),
paste this script into PowerShell. It creates one session on a socket in a
private temporary directory. It connects a control client before renaming the
window, so tmux queues the notification even if the job reads it later. The job
emits that native event. An event limit, byte budget and five-second deadline
bound the observation. The finally block removes the job, client, session and
socket directory. If session removal fails, the directory remains so the
server is reachable. The default tmux server is untouched.
```powershell
& {
$ErrorActionPreference = 'Stop'
Import-Module LibTmux
$name = 'libtmux-watch-' + $PID + '-' + [Guid]::NewGuid().ToString('N')
$socketDirectory = Join-Path ([IO.Path]::GetTempPath()) $name
$null = New-Item $socketDirectory -ItemType Directory -ErrorAction Stop
$ownerOnly = [IO.UnixFileMode]::UserRead -bor
[IO.UnixFileMode]::UserWrite -bor
[IO.UnixFileMode]::UserExecute
[IO.File]::SetUnixFileMode($socketDirectory, $ownerOnly)
$socketPath = Join-Path $socketDirectory 'socket'
$options = @{ SocketPath = $socketPath; ConfigurationFile = '/dev/null' }
$server = New-TmuxServer @options
$session = $control = $job = $null
try {
$session = $server | New-TmuxSession `
-Name watch-demo -WindowName before -Command 'exec /bin/cat'
$control = $server |
Connect-TmuxControl -Target $session.Name -ErrorAction Stop
$job = Start-ThreadJob -ScriptBlock {
Import-Module LibTmux
$using:control |
Watch-TmuxEvent -MaxEvents 16 -MaxOutputBytes 1MB |
Where-Object {
$_ -is [LibTmux.TmuxNotificationEvent] -and
$_.Name -ceq 'window-renamed' -and
$_.Arguments -ccontains 'after'
} |
Select-Object -First 1
}
$null = $server | Invoke-TmuxCommand -Arguments @(
'rename-window', '-t', 'watch-demo:0', 'after'
)
if (-not ($job | Wait-Job -Timeout 5)) {
throw 'The rename notification did not arrive within five seconds.'
}
$notification = $job | Receive-Job -ErrorAction Stop
if ($null -eq $notification) {
throw 'The watcher ended without the rename notification.'
}
$notification
} finally {
try {
if ($job) {
$job | Stop-Job
$job | Remove-Job
}
} finally {
try {
if ($control) {
$control | Disconnect-TmuxControl -Confirm:$false
}
} finally {
if ($session) { $session | Remove-TmuxSession -Confirm:$false }
if ($session -or -not (Test-Path -LiteralPath $socketPath)) {
Remove-Item -LiteralPath $socketDirectory -Recurse -Force
}
}
}
}
}
```
## Bound background output
A foreground watcher occupies its pipeline until it ends or you press Ctrl+C.
[`Start-ThreadJob`]() returns a job immediately and runs the watcher in another
runspace. Select `$server` with an absolute socket path and an executable path
available to that runspace; the following example watches an existing session
named `fixture`. It creates its client inside the job.
Retained Job output needs both a count and a text-byte budget, even if nobody
calls [`Receive-Job`](). Budgets reset for each input connection or server;
piping N owners can emit N times `-MaxEvents`. This example uses one client
and retains at most one event and 1048576 UTF-8
text bytes. The job completes after the initial notification; increase both
limits deliberately for a longer observation.
```powershell
$job = & {
$path = $server.ConnectionOptions.SocketPath
$binary = $server.ConnectionOptions.TmuxBinaryPath
Start-ThreadJob -ScriptBlock {
Import-Module LibTmux
New-TmuxServer -SocketPath $using:path -TmuxBinaryPath $using:binary |
Watch-TmuxEvent -Target 'fixture' -MaxEvents 1 -MaxOutputBytes 1MB
}
}
```
Collect the result when needed. Always stop and remove the job in cleanup,
including after a failed receive. Thread jobs preserve native objects in this
process; process jobs serialize results and do not preserve live handles.
```powershell
& {
try {
$job | Receive-Job -Wait -ErrorAction Stop
} finally {
$job | Stop-Job
$job | Remove-Job
}
}
```
`-MaxEventBytes` defaults to 1048576 and bounds the single event held by the
handoff. `-MaxOutputBytes` counts decoded UTF-8 text in output data, pane IDs,
notification names and arguments, and exit reasons. Numeric loss counts carry
no text bytes. These limits bound text payload, not object overhead or the
size of serialized Job data. An event that cannot fit produces an explicit
error before output; earlier events remain valid.
The native upstream queue separately defaults to 512 events and 4 MiB of
decoded UTF-8 payload. [`ServerConnectionOptions.ControlModeEventBufferCapacity`]()
and [`ControlModeEventBufferMaxBytes`]() configure those positive limits before
connecting. Its byte accounting includes output data, notification names and
arguments, and exit reasons; it excludes pane IDs and object overhead.
Under count pressure, the queue discards the oldest output from the pane with
the most queued output events. Under byte pressure, it selects the pane with
the most queued output bytes. If no output remains, it discards the oldest
notification. An oversized
event is dropped; an oversized exit reason is omitted while the exit event
is retained. [`TmuxEventsDroppedEvent`]() reports each loss without blocking
command replies. Use a fresh snapshot when current topology matters after
loss. Stopping may consume a record that has not reached the pipeline.
## Run independent commands concurrently
`ForEach-Object -Parallel` creates worker runspaces. Create and close each
client in the worker that uses it. This finite example emits two short replies,
and `-ThrottleLimit 2` bounds concurrent workers. Results arrive in completion
order; include an identifier in your real workload if input order matters.
```powershell
& {
$path = $server.ConnectionOptions.SocketPath
$binary = $server.ConnectionOptions.TmuxBinaryPath
'first', 'second' | ForEach-Object -ThrottleLimit 2 -Parallel {
Import-Module LibTmux
$options = @{ SocketPath = $using:path; TmuxBinaryPath = $using:binary }
$endpoint = New-TmuxServer @options
$control = $endpoint |
Connect-TmuxControl -Target 'fixture' -ErrorAction Stop
try {
$command = New-TmuxCommand -Name 'display-message' -Arguments @(
'-p', $_
)
$control |
Invoke-TmuxControlCommand -Command $command -ErrorAction Stop
} finally {
$control | Disconnect-TmuxControl -Confirm:$false
}
}
}
```
---
# Linking and consuming our docs
Source: https://libtmux.org/en/powershell/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/powershell/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`:
`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/powershell/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`:
`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` 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/powershell/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.