Getting started
Drive tmux from PowerShell. Create sessions, arrange panes, send input, and read terminal output through native cmdlets. Snapshots return typed objects that you can traverse and filter with ordinary PowerShell pipelines.
Built on libtmux for .NET, in the
same libtmux organization and with the same main
author. The cmdlets return its native objects and add PowerShell parameter
binding, help, formatting and -WhatIf / -Confirm.
Install · Object graph · Run to completion · Service readiness · Execution modes · Guides · MCP · Compatibility · Troubleshooting · Cmdlet reference · License
Alpha. APIs may change. Both modules are available on PowerShell Gallery: LibTmux and LibTmux.Workspace.
Install¶
Use PowerShell 7.4 or later with tmux on the same Linux host. On Windows, run both inside WSL. PowerShell 7.4 includes the PSResourceGet commands below; see compatibility for the support contract.
Run these commands in PowerShell. Install the core module for sessions, windows, panes, snapshots, input and capture:
$ Install-PSResource -Name LibTmux ` -Version 0.1.0-alpha2 ` -Prerelease ` -Repository PSGallery ` -Scope CurrentUser ` -TrustRepositoryFor YAML/JSON workspace declarations, install the matching workspace module. It also installs its exact core dependency, so this command alone installs both modules:
$ Install-PSResource -Name LibTmux.Workspace ` -Version 0.1.0-alpha2 ` -Prerelease ` -Repository PSGallery ` -Scope CurrentUser ` -TrustRepositoryPowerShellGet is an alternative. Install the core module:
$ Install-Module -Name LibTmux -AllowPrereleaseOr install the workspace module with its matching core dependency:
$ Install-Module -Name LibTmux.Workspace -AllowPrereleaseChoose one installer. The prerelease flag includes the alpha releases; without it, the installers look for stable releases. 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 in compatibility.
Import both modules to run all the examples on this page:
$ Import-Module -Name LibTmux, LibTmux.Workspace ` -RequiredVersion 0.1.0 ` -ErrorAction StopPowerShell imports use the numeric module version, 0.1.0; Gallery packages
carry the alpha2 prerelease label. Browse cmdlets with
Get-Command -Module LibTmux and examples with
Get-Help LibTmux\New-TmuxSession -Examples. The MCP server is a separate
.NET tool; see MCP setup.
Build from source for development. The walkthrough below runs directly from the installed modules.
Create and read an object graph¶
Choose a unique socket and a clean tmux configuration. New-TmuxServer
creates a handle without contacting tmux. The example does not touch your
default server.
$server = LibTmux\New-TmuxServer ` -SocketName ('libtmux-readme-' + [Guid]::NewGuid().ToString('N')) ` -ConfigurationFile /dev/nullCreate a session with an editor window, split it, add a logs window, and take
one snapshot. cat keeps the three panes open without shell setup. The
finally block removes only the session this example created.
$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 native LibTmux.Session. Its Windows
contain native LibTmux.Window objects; each window’s Panes
contain native LibTmux.Pane objects. The graph is still readable after
cleanup:
| Expression | Captured result |
|---|---|
$captured¶ | A Session named demo |
$captured.Windows¶ | Two Window objects: editor and logs |
$captured.Windows[0].Panes¶ | Two Pane objects in editor; logs has one |
Walk it and filter locally:
$captured.Windows | Where-Object { $_.Panes.Count -gt 1 } | Select-Object Name, @{ Name = 'PaneCount'; Expression = { $_.Panes.Count } }The result is editor with two panes; logs has one. Where-Object,
navigation, formatting, and property access use captured data and start no
tmux client. Get-TmuxSnapshot explicitly reads fresh state. A linked window
can have several session placements; its index belongs to the placement.
See snapshots and linked windows for IDs, active children and
captured versus unavailable fields.
The structured equivalent selects the one window with at least two captured
panes. -ExactlyOne reports zero or multiple matches:
$captured.Windows | Select-TmuxWindow -Criteria @{ 'Panes.Count' = @{ Ge = 2 } } -ExactlyOneThis query also performs no I/O. The query guide shows native predicates, Boolean and relationship criteria, and explicit fresh source queries.
Run a command to completion¶
When the shell’s exit status matters, run the command in a pane and inspect its
native result. This example uses the private $server above and removes only
the session it creates:
& { $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 shell exit is
a result, not a tmux error. On timeout, the command may still be running, so
the result has no exit status. See command completion
for concurrency and output behavior.
Wait for service readiness¶
With Python 3 on PATH, start an HTTP server on an available loopback port.
Use the private $server above, wait for the application’s readiness line,
then make an HTTP request to check that it responds. The session’s cleanup
also stops the server process:
& { $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 native PaneWaitResult has outcome PresentAtEntry or Matched,
followed by HTTP status 200. The wait closes its temporary control client;
the example removes only its session. A text match proves the readiness
condition, and the HTTP request checks service behavior separately.
See pane-text waits
for stop patterns, bounded tails, cancellation and disclosed event loss.
Use a cooperative channel
when the application can signal completion itself.
Choose how to run¶
| Task | Use | Example |
|---|---|---|
| Read or change tmux state¶ | Typed cmdlets and pipelines | Create sessions and panes |
| Run a shell command and check its exit status¶ | Invoke-TmuxPaneCommand | Run to completion |
| Wait for a running application’s readiness line¶ | Wait-TmuxPaneText | Readiness and an HTTP health check |
| Enter a session interactively¶ | Enter-TmuxSession | Attach your foreground terminal |
| Run an ordered batch¶ | New-TmuxCommand → Invoke-TmuxChain | Compose commands |
| Reuse a connected client¶ | Connect-TmuxControl → Invoke-TmuxControlCommand | Control commands and cleanup |
| React to output and notifications¶ | Watch-TmuxEvent | Bounded event streams |
| Keep the prompt available¶ | Start-ThreadJob | Bounded background jobs |
| Run commands concurrently¶ | ForEach-Object -Parallel | Independent clients |
Connect once to send a command through tmux control mode. This example uses the private endpoint from above, reads a session name, then disconnects and removes the session it created:
& { $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; use the control guide
for multiple commands and cancellation behavior.
Foreground cmdlets and ForEach-Object -Parallel occupy their calling pipeline.
Thread jobs return the prompt while they run; control mode keeps one client
connected for repeated commands. Watchers accept event-count and text-byte
limits. Choose a mode by its ownership and failure behavior, not a timing claim;
the mode guide explains when chains merge failure attribution.
Modules and MCP¶
| Product | Use it for |
|---|---|
| LibTmux¶ | Typed cmdlets, snapshots, input, capture, control clients and event streams |
| LibTmux.Workspace¶ | Discover YAML/JSON declarations, resolve directories, review plans and create workspaces |
| LibTmux.Mcp¶ | Give an assistant tmux tools through the separately installed .NET MCP server |
Describe a two-pane workspace. Importing it parses YAML without contacting tmux or running its commands:
$workspace = LibTmux.Workspace\Import-TmuxWorkspace -Yaml @'session_name: readme-workspace-previewwindows: - window_name: editor panes: - shell_command: exec /bin/sh - shell_command: exec /bin/sh'@Plan on the same private endpoint. Planning may read tmux state; it does not create the workspace:
$workspacePlan = $workspace | LibTmux.Workspace\Get-TmuxWorkspacePlan ` -Server $server -ServerStartup CreateOrJoin -ExistingSession ErrorReview 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:
$workspacePlan.ActionsPreview without applying the plan:
$workspacePlan | LibTmux.Workspace\Invoke-TmuxWorkspace -WhatIfApply that exact plan, then remove only the session it created. The captured result remains readable after cleanup:
$workspaceResult = & { $result = $workspacePlan | LibTmux.Workspace\Invoke-TmuxWorkspace -Confirm:$false -ErrorAction Stop try { $result } finally { $result.Session | Remove-TmuxSession -Confirm:$false }}$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. For an MCP client, start with
the client configuration, then read
tools/list and tmux://capabilities before calling
list_sessions or capture_pane.
Install both PowerShell modules at the same version. The MCP server is an independent .NET tool and does not require PowerShell.
Guides¶
- Read: snapshots and filtering, structured queries, pane contents and scrollback, attached clients.
- Automate: create, send text and keys, arrange and resize, link and move windows, remove.
- Configure: options, hooks, environment for new panes.
- Coordinate: chains and control clients, event streams, jobs and parallel workers.
- Assistants: install and configure the MCP server.
- Workspaces: load, review and apply, export a starting declaration, edit a declaration.
The marked README blocks run together in the installed workflow test. The executable guides run against real tmux through the installed modules. See contributing for the runners and development checks.
The benchmark guide explains installed-package workloads, correctness checks, raw samples and reproduction commands.
Install from source¶
For development, install the pinned PowerShell and .NET SDK from .tool-versions with mise:
$ mise installInstall tmux with your operating system’s package manager and check that it
is on PATH:
$ tmux -VFrom the checkout root, restore the published .NET alpha.20 packages and build both PowerShell modules:
$ pwsh -NoLogo -NoProfile -File eng/Build.ps1 \ -RestoreRestore 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:
$ LIBTMUX_REVIEW_MODULE_ROOT="$PWD/build/Modules" \ pwsh \ -NoLogo \ -NoProfileImport the exact staged manifests so an older installed module cannot shadow the new build:
$modules = $env:LIBTMUX_REVIEW_MODULE_ROOTImport-Module -Name @( "$modules/LibTmux/0.1.0/LibTmux.psd1", "$modules/LibTmux.Workspace/0.1.0/LibTmux.Workspace.psd1") -ErrorAction StopRun the quick start from the checkout root. It
creates a private server, splits the editor window, adds logs, and returns
a captured native LibTmux.Session. Show each window’s pane IDs:
(./examples/QuickStart.ps1).Windows | Select-Object Name, @{ Name = 'PaneIds' Expression = { $_.Panes.Id -join ', ' }}Output from the private server:
Name PaneIds---- -------editor %0, %1logs %2Assign ./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 and leaves your
default tmux server alone.
License¶
MIT. See third-party notices for bundled dependencies.