libtmux for PowerShell
PowerShell-based tmux client
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
Start with PowerShell
$ErrorActionPreference = 'Stop'Import-Module "$PSScriptRoot/modules/LibTmux/0.1.0/LibTmux.psd1"
$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' } -ExactlyOneforeach ($window in $captured.Windows) { '{0}: {1}' -f $window.Name, ($window.Panes.Id -join ', ')}$ErrorActionPreference = 'Stop'Import-Module "$PSScriptRoot/modules/LibTmux/0.1.0/LibTmux.psd1"
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}$ErrorActionPreference = 'Stop'Import-Module "$PSScriptRoot/modules/LibTmux/0.1.0/LibTmux.psd1"
$session = $null$failure = $nulltry { $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 = $_.Exception throw} 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] } }}$ErrorActionPreference = 'Stop'Import-Module "$PSScriptRoot/modules/LibTmux/0.1.0/LibTmux.psd1"
$session = $null$failure = $nulltry { $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] } }}Run this example
PowerShell 7.4.20 with PSResourceGet 1.1.1, POSIX shell and tmux on Linux.
Save the program above as quickstart.ps1 in a new directory, along with the files below.
Cleanup is omitted; the private tmux server and its temporary files may remain. Select Cleanup to remove them when the program finishes. The program stops its private tmux server and removes any temporary files it created when it finishes. Error handling adds diagnostics; every version checks required results and deadlines.
Setup and run
pwsh -NoLogo -NoProfile -Command ' $ErrorActionPreference = "Stop" $null = New-Item -ItemType Directory -Path ./modules -Force Save-PSResource -Name LibTmux -Version 0.1.0 ` -Path ./modules -TrustRepository'unset TMUX TMUX_PANEexport ENV=/dev/null BASH_ENV=/dev/null SHELL=/bin/shpwsh -NoLogo -NoProfile -File quickstart.ps1Expected output
editor: %0, %1logs: %2Library revision: 2c30121b7733.
Core Library documentation →More PowerShell examples →
Install LibTmux
Install-Module -Name LibTmuxRequires PowerShell 7.4 or later and tmux on the same Unix host.
Install-PSResource -Name LibTmuxRequires PowerShell 7.4 or later and tmux on the same Unix host.
MCP
PowerShell has no MCP package of its own. It uses the C# port's LibTmux.Mcp.
The C# server lets an agent work with tmux through 45 tools, grouped as Inspect, Manage, Execute and Teardown.
Install LibTmux.Mcp
Choose your client and configuration scope, then run the command or paste the configuration.
$ claude mcp add tmux -- dnx LibTmux.Mcp --yesRuns the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: ~/.claude.json (this project)
$ claude mcp add tmux --scope user -- dnx LibTmux.Mcp --yesRuns the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: ~/.claude.json (all projects)
$ claude mcp add tmux --scope project -- dnx LibTmux.Mcp --yesRuns the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: .mcp.json (in repo, version-controlled)
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen register:
$ claude mcp add tmux -- libtmux-mcpInstalls the `libtmux-mcp` tool from NuGet.
Config file: ~/.claude.json (this project)
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen register:
$ claude mcp add tmux --scope user -- libtmux-mcpInstalls the `libtmux-mcp` tool from NuGet.
Config file: ~/.claude.json (all projects)
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen register:
$ claude mcp add tmux --scope project -- libtmux-mcpInstalls the `libtmux-mcp` tool from NuGet.
Config file: .mcp.json (in repo, version-controlled)
Runs the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: claude_desktop_config.json
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen use this config:
Installs the `libtmux-mcp` tool from NuGet.
Config file: claude_desktop_config.json
$ codex mcp add tmux -- dnx LibTmux.Mcp --yesRuns the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: ~/.codex/config.toml
Codex's CLI doesn't support project scope yet — paste this into .codex/config.toml at the repo root.
Runs the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: .codex/config.toml (in repo)
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen register:
$ codex mcp add tmux -- libtmux-mcpInstalls the `libtmux-mcp` tool from NuGet.
Config file: ~/.codex/config.toml
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen register:
Codex's CLI doesn't support project scope yet — paste this into .codex/config.toml at the repo root.
Installs the `libtmux-mcp` tool from NuGet.
Config file: .codex/config.toml (in repo)
$ gemini mcp add --scope user tmux dnx -- LibTmux.Mcp --yesRuns the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: ~/.gemini/settings.json
$ gemini mcp add --scope project tmux dnx -- LibTmux.Mcp --yesRuns the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: .gemini/settings.json (in repo)
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen register:
$ gemini mcp add --scope user tmux libtmux-mcpInstalls the `libtmux-mcp` tool from NuGet.
Config file: ~/.gemini/settings.json
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen register:
$ gemini mcp add --scope project tmux libtmux-mcpInstalls the `libtmux-mcp` tool from NuGet.
Config file: .gemini/settings.json (in repo)
Runs the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: .cursor/mcp.json (in repo)
Runs the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: ~/.cursor/mcp.json
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen use this config:
Installs the `libtmux-mcp` tool from NuGet.
Config file: .cursor/mcp.json (in repo)
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen use this config:
Installs the `libtmux-mcp` tool from NuGet.
Config file: ~/.cursor/mcp.json
$ grok mcp add --scope user tmux -- dnx LibTmux.Mcp --yesRuns the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: ~/.grok/config.toml
$ grok mcp add --scope project tmux -- dnx LibTmux.Mcp --yesRuns the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: ./.grok/config.toml (in repo)
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen register:
$ grok mcp add --scope user tmux -- libtmux-mcpInstalls the `libtmux-mcp` tool from NuGet.
Config file: ~/.grok/config.toml
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen register:
$ grok mcp add --scope project tmux -- libtmux-mcpInstalls the `libtmux-mcp` tool from NuGet.
Config file: ./.grok/config.toml (in repo)
Runs the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: ~/.gemini/config/mcp_config.json
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen use this config:
Installs the `libtmux-mcp` tool from NuGet.
Config file: ~/.gemini/config/mcp_config.json
$ opencode mcp add tmux -- dnx LibTmux.Mcp --yesRuns the server from NuGet without installing it; needs the .NET 10 SDK. Write LibTmux.Mcp@<version> to pin a version.
Config file: ~/.config/opencode/opencode.jsonc
Build or install the server first:
$ dotnet tool install --global LibTmux.McpThen register:
$ opencode mcp add tmux -- libtmux-mcpInstalls the `libtmux-mcp` tool from NuGet.
Config file: ~/.config/opencode/opencode.jsonc
Embed the server in a program
Dictionary<string, string?> environment = StdioClientTransportOptions.GetDefaultEnvironmentVariables();environment["LIBTMUX_SOCKET"] = server.ConnectionOptions.SocketName;environment["TMUX_TMPDIR"] = Environment.GetEnvironmentVariable("TMUX_TMPDIR");environment["DOTNET_ROOT"] = Environment.GetEnvironmentVariable("DOTNET_ROOT");environment["LIBTMUX_TOOLSETS"] = "inspect,manage,execute";environment["LIBTMUX_EXCLUDE_TOOLS"] = "run_shell_command";
var transport = new StdioClientTransport(new StdioClientTransportOptions{ Name = "tmux", Command = Environment.GetEnvironmentVariable("LIBTMUX_MCP_COMMAND") ?? "libtmux-mcp", InheritEnvironmentVariables = false, EnvironmentVariables = environment,});McpClient client = await McpClient.CreateAsync( transport, cancellationToken: ct);
Excerpt of examples/LibTmux.Examples/Snippets/Mcp.cs,
which dotnet test --project tests/LibTmux.ExampleTests/LibTmux.ExampleTests.csproj runs in the repository's CI
(.github/workflows/dotnet.yml).
Workspace Manager
Main-horizontal layout
The main-horizontal layout gives the first pane the top of the window and splits the rest below it.
session_name: test window optionsstart_directory: '~'windows:- layout: main-horizontal options: main-pane-height: 5 panes: - pane - pane - pane window_name: editor{ "session_name": "test window options", "start_directory": "~", "windows": [ { "layout": "main-horizontal", "options": { "main-pane-height": 5 }, "panes": [ "pane", "pane", "pane" ], "window_name": "editor" } ]}Converted from the YAML; the tests load the YAML.
Workspace file: tests/fixtures/workspace/tmuxp-v1.74.0-window_options.yaml.
Tested by window options fixture
(tests/WorkspaceCorpus.Tests.ps1; a test runs the command).
Install LibTmux.Workspace
The workspace package is separate from the core library.
Install-Module -Name LibTmux.WorkspaceInstalls the matching LibTmux core dependency. Run PowerShell and tmux on the same Unix host.
Install-PSResource -Name LibTmux.WorkspaceInstalls the matching LibTmux core dependency. Run PowerShell and tmux on the same Unix host.
Build the workspace from a program
$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'@
Excerpt of examples/Guides.ps1,
which eng/Test.ps1 -Suite Documentation runs in the repository's CI
(.github/workflows/ci.yml).
Topics
Subject-by-subject, with PowerShell in every code block.
Guides
Task guides for PowerShell.
Examples
Complete programs, sourced from the code each port tests.
Concepts
The domain model every port shares.