tmuxtmuxTopics

Choose documentation 1

latest

tmux manual version

Latest (3.7c) 3.7c 3.2a
English

Prerelease This site documents an alpha of libtmux. Its structure, URLs and APIs are subject to change.

Edit this page on GitHub

Ownership and cleanup

A tmux session, window, or pane normally remains until you kill it. Scope-based cleanup can kill it when your code leaves a block, including after an exception. See Workspaces for a temporary layout example.

Python provides context managers for tmux objects. C# provides ownership scopes for servers, sessions, and windows. Other ports require explicit cleanup or offer guards for test servers:

PortServerSessionWindowPane
Pythonyesyesyesyes
C#yesyesyes-
Javacloses conn.---
Rusttest-only---
C++test-only---
TypeScript----
Go----
Swift----
"test-only" means a guard owns an entire disposable test server. Java's
AutoCloseable server releases its transport but leaves tmux running. A dash
means no built-in cleanup scope is listed for that object; use an explicit kill
call with the cleanup mechanism appropriate to your language.

Nested context managers

Python's Server, Session, Window, and Pane support context managers. Entry returns the existing object; exit kills it, including when the block raises:

with Server() as server:
with server.new_session() as session:
with session.new_window() as window:
with window.split() as pane:
pane.send_keys('echo "Hello"')
# everything above is killed on the way out, in reverse order

Nested scopes exit in reverse order: pane, window, session, then server.

Owned sessions and windows

C#'s OwnedSessionScope and OwnedWindowScope wrap the created object and implement IAsyncDisposable. The Session and Window handles themselves are not disposable:

await using OwnedSessionScope session = await server.CreateOwnedSessionAsync();
await using OwnedWindowScope window = await session.Value.CreateOwnedWindowAsync();
await window.Value.SendTextAsync("echo hello");
// window, then session, killed on the way out

For tests that need an owned pane, TmuxTestFactory.CreateHierarchyAsync() returns a TemporaryHierarchyScope containing a private server, session, window, and pane. Disposing it kills the server.

Closing a server connection

Java's Server implements AutoCloseable. Exiting try (Server server = Server.open(config)) releases the owned transport while tmux and its sessions remain running. Kill sessions, windows, panes, or the server explicitly when your program owns their cleanup.

ServerConfig config = ServerConfig.builder()
.endpoint(ServerEndpoint.socketPath(socket))
.build();
try (Server server = Server.open(config)) {
Session session = server.newSession("demo");
Window window = session.newWindow("build");
Pane pane = window.split();
pane.sendLine("echo hello from libtmux");
// session, window, and pane all outlive this block: only the
// connection this `server` handle held is released on the way out.
}

Explicit asynchronous cleanup

Rust's Drop is synchronous and cannot await an async tmux kill. Use explicit shutdown when you need to observe cleanup failures:

  • kill(self) consumes the handle. Session, window, and pane kill methods take self by value, preventing subsequent use of that handle.
  • libtmux::test::TestServer provides a test guard. Call TestServer.shutdown to handle cleanup errors. Its Drop implementation makes a synchronous cleanup attempt.
use libtmux::test::TestServer;
let guard = TestServer::new().await?;
let server = guard.server();
let session = server.new_session("work").await?;
session.new_window("editor").await?;
// Await shutdown to handle cleanup errors.
guard.shutdown().await?;

Owning a test server

C++'s Session, Window, and Pane are non-owning values; destroying a handle does not kill its tmux object. libtmux::test::ScopedTmuxServer, in the separate testing CMake component, owns a private test server and its temporary socket directory:

auto fixture = libtmux::test::ScopedTmuxServer::start(
{.socket_namespace = libtmux::test::SocketNamespace::consumer("my-suite")});
// fixture killed, and its tree removed, when this scope ends:
// even if the test that follows fails

Release connections and kill owned sessions

Control connections and notification streams implement [Symbol.asyncDispose]. await using releases those handles; it leaves the watched session and panes running. Use finally to kill a session your program owns:

const session = await server.newSession({ name: "work" });
try {
const window = await session.newWindow({ name: "editor" });
await window.panes.at(0)?.sendKeys("echo hi");
} finally {
await session.kill();
}

Defer cleanup with a fresh context

A Session, Window, or Pane handle does not own its tmux object. Dropping the value leaves tmux running. Register cleanup after successful creation and use a separate, bounded context so cancellation of the work cannot prevent cleanup. Return cleanup failures along with any work failure:

func temporarySession(ctx context.Context, server tmux.Server) (err error) {
session, err := server.NewSession(ctx, tmux.NewSessionRequest{})
if err != nil {
return err
}
defer func() {
cleanup, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
err = errors.Join(err, session.Kill(cleanup))
}()
_, err = session.SearchWindows(ctx, nil)
return err
}

This function uses context, errors, time, and the tmux package. It owns only the session it creates. Do not kill a shared server as session cleanup.

ControlClient, PaneObservation, and NotificationStream implement io.Closer. Close those resources separately from killing tmux objects. For tests, tmuxtest.NewServer registers isolated server cleanup with the Go test runner.

Kill objects your program owns

Session, window, and pane values are non-owning. Call try await server.kill(session) or the corresponding window or pane overload when cleanup is required. Perform cleanup on both success and failure paths; Swift's synchronous defer cannot await a tmux command.

Testing cleanup

Use explicit cleanup for objects whose handles have no disposal hook. For an entire disposable test server, prefer your port's test fixture or server guard; see Testing with libtmux.

Esc

Type to search.