tmux client library for C#
Control tmux, connect to and create servers, navigate sessions, windows, and panes, send keys, watch for changes via control mode, capture pane contents.
Quickstart
Install the package and run a complete program.
Guides
Task guides for C#.
Topics
Subject-by-subject, with C# in every code block.
Examples
Complete programs, sourced from the code each port tests.
API reference
Types and functions of the C# API.
Testing
Test code that uses tmux with an isolated server.
Install
dotnet add package LibTmuxLibTmux 0.1.0 is pre-1.0 and can change between minor versions. Pin to a range:
<PackageReference Include="LibTmux" Version="[0.1.0,0.2)" />At a glance
Server → Session → Window → Pane. Each level of the tmux hierarchy has its own entry in the C# API, with the tmux object it wraps.
| Type | Wraps |
|---|---|
LibTmux.Server | A tmux server |
LibTmux.Session | A session, ID $n |
LibTmux.Window | A window in a session, ID @n |
LibTmux.Pane | A pane in a window, ID %n |
What it does
Start with C#
using System;using System.Linq;using System.Threading;using System.Runtime.Versioning;using LibTmux;
[assembly: UnsupportedOSPlatform("windows")]
if (OperatingSystem.IsWindows()){ throw new PlatformNotSupportedException( "This example requires tmux on Unix.");}
using var deadline = new CancellationTokenSource( TimeSpan.FromSeconds(30));var token = deadline.Token;var options = new ServerConnectionOptions{ SocketName = "quickstart-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = Environment.GetEnvironmentVariable("LIBTMUX_TMUX") ?? "tmux",};
var owned = await Server.CreateOwnedAsync(options, token);Server server = owned.Value;
Session session = await server.CreateSessionAsync( new NewSessionRequest { Name = "build", Command = "/bin/sh" }, token);
Window window = await session.CreateWindowAsync( new NewWindowRequest { Name = "tests", Command = "/bin/sh" }, token);Pane pane = (await window.GetPanesAsync(token))[0];
await pane.SendTextAsync( "printf 'hello-from-%s\\n' libtmux", enter: false, cancellationToken: token);await pane.EnterAsync(token);
var lines = await TmuxWait.UntilAsync( async cancellation => await pane.CaptureAsync( cancellationToken: cancellation), output => output.Any(line => line.TrimEnd() == "hello-from-libtmux"), TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(20), token);
Console.WriteLine("hello-from-libtmux");using System;using System.Linq;using System.Threading;using System.Runtime.Versioning;using LibTmux;
[assembly: UnsupportedOSPlatform("windows")]
if (OperatingSystem.IsWindows()){ throw new PlatformNotSupportedException( "This example requires tmux on Unix.");}
using var deadline = new CancellationTokenSource( TimeSpan.FromSeconds(30));var token = deadline.Token;var options = new ServerConnectionOptions{ SocketName = "quickstart-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = Environment.GetEnvironmentVariable("LIBTMUX_TMUX") ?? "tmux",};
var owned = await Server.CreateOwnedAsync(options, token);Server server = owned.Value;
try{ Session session = await server.CreateSessionAsync( new NewSessionRequest { Name = "build", Command = "/bin/sh" }, token);
Window window = await session.CreateWindowAsync( new NewWindowRequest { Name = "tests", Command = "/bin/sh" }, token); Pane pane = (await window.GetPanesAsync(token))[0];
await pane.SendTextAsync( "printf 'hello-from-%s\\n' libtmux", enter: false, cancellationToken: token); await pane.EnterAsync(token);
var lines = await TmuxWait.UntilAsync( async cancellation => await pane.CaptureAsync( cancellationToken: cancellation), output => output.Any(line => line.TrimEnd() == "hello-from-libtmux"), TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(20), token);
Console.WriteLine("hello-from-libtmux");}catch (Exception error){ throw new InvalidOperationException( "tmux quickstart failed", error);}using System;using System.Linq;using System.Threading;using System.Runtime.Versioning;using LibTmux;
[assembly: UnsupportedOSPlatform("windows")]
if (OperatingSystem.IsWindows()){ throw new PlatformNotSupportedException( "This example requires tmux on Unix.");}
using var deadline = new CancellationTokenSource( TimeSpan.FromSeconds(30));var token = deadline.Token;var options = new ServerConnectionOptions{ SocketName = "quickstart-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = Environment.GetEnvironmentVariable("LIBTMUX_TMUX") ?? "tmux",};
await using var owned = await Server.CreateOwnedAsync(options, token);Server server = owned.Value;
Session session = await server.CreateSessionAsync( new NewSessionRequest { Name = "build", Command = "/bin/sh" }, token);
Window window = await session.CreateWindowAsync( new NewWindowRequest { Name = "tests", Command = "/bin/sh" }, token);Pane pane = (await window.GetPanesAsync(token))[0];
await pane.SendTextAsync( "printf 'hello-from-%s\\n' libtmux", enter: false, cancellationToken: token);await pane.EnterAsync(token);
var lines = await TmuxWait.UntilAsync( async cancellation => await pane.CaptureAsync( cancellationToken: cancellation), output => output.Any(line => line.TrimEnd() == "hello-from-libtmux"), TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(20), token);
Console.WriteLine("hello-from-libtmux");using System;using System.Linq;using System.Threading;using System.Runtime.Versioning;using LibTmux;
[assembly: UnsupportedOSPlatform("windows")]
if (OperatingSystem.IsWindows()){ throw new PlatformNotSupportedException( "This example requires tmux on Unix.");}
using var deadline = new CancellationTokenSource( TimeSpan.FromSeconds(30));var token = deadline.Token;var options = new ServerConnectionOptions{ SocketName = "quickstart-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = Environment.GetEnvironmentVariable("LIBTMUX_TMUX") ?? "tmux",};
await using var owned = await Server.CreateOwnedAsync(options, token);Server server = owned.Value;
try{ Session session = await server.CreateSessionAsync( new NewSessionRequest { Name = "build", Command = "/bin/sh" }, token);
Window window = await session.CreateWindowAsync( new NewWindowRequest { Name = "tests", Command = "/bin/sh" }, token); Pane pane = (await window.GetPanesAsync(token))[0];
await pane.SendTextAsync( "printf 'hello-from-%s\\n' libtmux", enter: false, cancellationToken: token); await pane.EnterAsync(token);
var lines = await TmuxWait.UntilAsync( async cancellation => await pane.CaptureAsync( cancellationToken: cancellation), output => output.Any(line => line.TrimEnd() == "hello-from-libtmux"), TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(20), token);
Console.WriteLine("hello-from-libtmux");}catch (Exception error){ throw new InvalidOperationException( "tmux quickstart failed", error);}Run this example
.NET SDK 10.0.303, .NET 8 and 10 runtimes, tmux on Linux/macOS
Save the program above as app/Program.cs 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.
app/Example.csproj
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFrameworks>net8.0;net10.0</TargetFrameworks> <LangVersion>12.0</LangVersion> <Nullable>enable</Nullable> <ImplicitUsings>disable</ImplicitUsings> <EnableDefaultCompileItems>false</EnableDefaultCompileItems> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> <AnalysisLevel>10-recommended</AnalysisLevel> </PropertyGroup> <ItemGroup> <Compile Include="Program.cs" /> <PackageReference Include="LibTmux" Version="[0.1.0]" /> </ItemGroup></Project>app/global.json
{ "sdk": { "version": "10.0.303", "rollForward": "disable", "allowPrerelease": false }, "test": { "runner": "Microsoft.Testing.Platform" }}Setup and run
# Save the files above at their displayed relative paths.cd appdotnet restore Example.csprojdotnet build Example.csproj -c Release --no-restore --warnaserrorexport TMUX_TMPDIR=/tmp/libtmux-dotnet-devmkdir -p "$TMUX_TMPDIR"unset TMUX TMUX_PANEdotnet bin/Release/net8.0/Example.dlldotnet bin/Release/net10.0/Example.dllExpected output
hello-from-libtmuxLibrary revision: 472c2bcfbda6.
Typed API
- Typed objects instead of parsed format strings:
LibTmux.Pane - Addressing by tmux ID:
LibTmux.PaneId - Filtering and queries over tmux objects:
LibTmux.Query.QueryExtensions - Typed errors instead of exit codes and stderr:
LibTmux.LibTmuxException
What you get over the tmux CLI
- Connect to or start a tmux server:
LibTmux.Server.ConnectAsync - Traversal from a server down to its panes:
LibTmux.Server.GetPanesAsync - Send keys to a pane:
LibTmux.Pane.SendKeysAsync - Watch for changes through tmux control mode:
LibTmux.IControlModeSession - Capture pane contents:
LibTmux.Pane.CaptureAsync - Arguments passed as a list, with no shell quoting:
LibTmux.TmuxCommand - A typed error when the running tmux lacks a feature:
LibTmux.TmuxUnsupportedOnReleaseException - Async operations:
LibTmux.Pane.RunAsync
Know where you're running
Inside tmux, find the pane your program runs in from TMUX and TMUX_PANE: LibTmux.Pane.FromEnvironmentAsync.
Testing
Run tests against an isolated tmux server: LibTmux.Testing.TemporaryServerScope.