Core Library0.xGuides

Choose documentation 2

latest

Current version

latest
English

Early release libtmux is released, and its APIs may still change between releases. This site's structure and URLs may change too.

Getting started

powershell LibTmux libtmux.org license

Drive tmux from PowerShell with native cmdlets. Sessions, windows and panes come back as typed objects that an ordinary pipeline can filter.

Run a command and read its exit status with Invoke-TmuxPaneCommand, find what a server holds with Get-TmuxSnapshot, wait for output with Wait-TmuxPaneText, and apply a reviewed workspace file with 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 and LibTmux.Workspace.

It needs PowerShell 7.4 or later and tmux 3.3a or newer on the same Linux host, including WSL. 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.

Contents — Quick start · Find things · Service readiness · Choose how to run · Workspaces · Packages · From source · Leaves out · Support · Documentation

Reference — Cmdlet reference · Compatibility · Troubleshooting · MCP · 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.

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:

Terminal window
$ Install-PSResource -Name LibTmux

Import it:

Terminal window
$ Import-Module -Name LibTmux -ErrorAction Stop

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:

Terminal window
$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.

Invoke-TmuxPaneCommand runs a command in a pane and returns a LibTmux.PaneRunResult. New-TmuxSession starts the shell, and the finally block removes only that session with Remove-TmuxSession:

Terminal window
& {
$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 covers concurrency and output behavior.

Every PowerShell block on this page is a copy of a tested source. The guide test fails when a copy drifts, and the installed workflow test runs the blocks in order on an owned tmux server. Later sections reuse $server.

Find sessions, windows, and panes

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, Split-TmuxPane and New-TmuxWindow, reads it, and removes it with Remove-TmuxSession. cat keeps the panes open:

Terminal window
$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 that stays readable after cleanup. Its Windows hold LibTmux.Window objects, and each window’s Panes hold LibTmux.Pane objects:

ExpressionCaptured result
$capturedA Session named demo
$captured.WindowsTwo Window objects: editor and logs
$captured.Windows[0].PanesTwo Pane objects in editor; logs has one

A captured object keeps what tmux reported when you read it. Call Get-TmuxSnapshot again to see a later change. Snapshots and linked windows 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:

Terminal window
$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:

Name PaneCount
---- ---------
editor 2

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:

Terminal window
$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 shows native predicates, Boolean and relationship criteria, and explicit fresh source queries.

Wait for service readiness

Wait-TmuxPaneText: wait for a readiness line

It watches a pane’s rendered text and returns a LibTmux.PaneWaitResult. On tmux 3.7 or newer it uses a temporary control client; on earlier supported releases it polls instead.

Send-TmuxText and Send-TmuxKey type into the pane first, and Get-TmuxPaneContent reads its screen. When the application can signal completion itself, use Wait-TmuxChannel with a cooperative channel.

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:

Terminal window
& {
$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 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:

TaskUseExample
Read or change tmux stateTyped cmdlets and pipelinesCreate sessions and panes
Run a shell command and check its exit statusInvoke-TmuxPaneCommandRun to completion
Wait for a running application’s readiness lineWait-TmuxPaneTextReadiness and an HTTP health check
Enter a session interactivelyEnter-TmuxSessionAttach your foreground terminal
Run an ordered batchNew-TmuxCommand → Invoke-TmuxChainCompose commands
Reuse a connected clientConnect-TmuxControl → Invoke-TmuxControlCommandControl commands and cleanup
React to output and notificationsWatch-TmuxEventBounded event streams
Keep the prompt availableStart-ThreadJobBounded background jobs
Run commands concurrentlyForEach-Object -ParallelIndependent clients

An older daemon refuses these before anything changes: Invoke-TmuxPaneCommand needs tmux 3.4, and Connect-TmuxControl and Watch-TmuxEvent with a server need 3.7.

Other commands are refused on the releases they harm. The optional features table lists each one, and capabilities.json holds the same list for an assistant or a script to read.

The raw-command cmdlets Invoke-TmuxCommand, Invoke-TmuxChain and Invoke-TmuxControlCommand check the command they are given and nothing nested in it, such as an if-shell string, a bind-key command or a brace block.

On exactly tmux 3.7, name every 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 lists the other failures.

Connect-TmuxControl: one client for repeated commands

It connects one control client. New-TmuxCommand builds a command, Invoke-TmuxControlCommand sends it through the client, and Disconnect-TmuxControl ends it. 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:

Terminal window
& {
$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 covers multiple commands and cancellation.

The other modes in short:

  • 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 accepts event-count and text-byte limits.

The mode guide 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:

Terminal window
$ Install-PSResource -Name LibTmux.Workspace

Import both modules:

Terminal window
$ Import-Module -Name LibTmux, LibTmux.Workspace -ErrorAction Stop

Import-TmuxWorkspace: read a declaration

It parses YAML or JSON without contacting tmux or running the commands in it.

Get-TmuxWorkspace finds declaration files, Resolve-TmuxWorkspace expands directories and Test-TmuxWorkspace validates one. This declaration has two panes in one window:

Terminal window
$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 and prints nothing.

Get-TmuxWorkspacePlan: review before anything runs

It plans on the same private endpoint. Planning may read tmux state and creates nothing:

Terminal window
$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 only in a trusted terminal:

Terminal window
$workspacePlan.Actions

It lists the actions in order, from CreateSession to CaptureResult, with command text shown as [redacted].

Invoke-TmuxWorkspace: preview, then apply

-WhatIf previews the plan without applying it:

Terminal window
$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:

Terminal window
$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. Read its windows:

Terminal window
$workspaceResult.Windows |
Select-Object Name, @{ Name = 'PaneCount'; Expression = { $_.Panes.Count } }

This returns editor with two panes. The workspace guide covers failure recovery, attaching and exporting a declaration; ConvertTo-TmuxWorkspace turns a captured session into a starting declaration.

Packages

ProductUse it for
LibTmuxTyped cmdlets, snapshots, input, capture, control clients and event streams
LibTmux.Workspace LibTmux.WorkspaceDiscover YAML/JSON declarations, resolve directories, review plans and create workspaces
LibTmux.McpGive an assistant tmux tools through the separately installed .NET MCP server

LibTmux: 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:

Reference: every LibTmux cmdlet and the PowerShell Gallery page.

LibTmux.Workspace: workspaces from YAML or JSON

Describe a session once, review the plan, then apply it. The commands below run in this order:

Install it with the core module, at the same version. Reference: every LibTmux.Workspace cmdlet and the PowerShell Gallery page.

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, the tool reference and NuGet.

Install the tool on the Unix host that runs tmux:

Terminal window
$ 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:

Terminal window
$ 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:

{
"mcpServers": {
"tmux": {
"command": "libtmux-mcp",
"env": { "LIBTMUX_SOCKET": "work", "LIBTMUX_TOOLSETS": "inspect" }
}
}
}

The MCP guide covers client configuration, discovery before calling, finite waits and the other toolsets. Its test 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 with mise:

Terminal window
$ mise install

Install tmux with your operating system’s package manager and check that it is on PATH:

Terminal window
$ tmux -V

From the checkout root, restore the published .NET 0.1.1 packages and build both PowerShell modules:

Terminal window
$ 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. Start PowerShell with the staged module path:

Terminal window
$ 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:

Terminal window
$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: a private server and three panes

Run the quick start from the checkout root. It creates a private server, splits the editor window, adds logs, and returns a captured LibTmux.Session. Show each window’s pane IDs:

Terminal window
(./examples/QuickStart.ps1).Windows | Select-Object Name, @{
Name = 'PaneIds'
Expression = { $_.Panes.Id -join ', ' }
}

It prints the pane IDs from the private server:

Name PaneIds
---- -------
editor %0, %1
logs %2

Assign ./examples/QuickStart.ps1 to a variable to keep the session object. Its Windows and 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 reads again, and snapshots and linked windows list what a capture cannot know.
  • An implicit server. A handle from 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).
  • Shell quoting. Send-TmuxText sends its text literally and does not quote it for the shell that receives it (send input).
  • Native Windows. Run PowerShell and tmux inside WSL, in one Linux environment. Native Windows and psmux are outside this port (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).

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 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. It lives in the same libtmux organization with the same main author. The cmdlets return its native objects and add PowerShell parameter binding, help, formatting and -WhatIf / -Confirm.

Documentation

Browse cmdlets with Get-Command -Module LibTmux and examples with Get-Help LibTmux\New-TmuxSession -Examples. Further reading:

License

MIT. See third-party notices for bundled dependencies.

Esc

Type to search.

Reference previewOpen reference