libtmux Reference MCP Search

Workspaces

Edit this page on GitHub

A workspace is a window carved into panes, each running something specific — an editor in one, a dev server in another, a log tail in a third. Every port’s object API can build one imperatively: open a window, split it, arrange the splits, send a command into each pane. Most also ship a declarative layer on top, shaped after tmuxp’s YAML/JSON workspace files, for the common case where the layout is data rather than logic.

Building one imperativelyLink to section

The pattern is the same shape everywhere: create a window, split it as many times as you need panes, apply a layout to tile them evenly, then drive each pane. Grounded in Python’s API (the most fully documented of the eight), a typical two-pane-plus-logs workspace looks like this:

const auto window = session.new_window({.name = "dev"});
if (!window.has_value()) return 1;
// `focus = true` makes the new pane active, so the next split divides it.
const auto terminal = window->split({.percentage = 30, .focus = true});
if (!terminal.has_value()) return 1;
const auto logs = window->split({.horizontal = true});
if (!logs.has_value()) return 1;
(void)window->select_layout("main-vertical");

Window.split() (or the equivalent Pane.split()) is the one method that turns a single-pane window into a workspace; direction (PaneDirection.Right for side-by-side, the default for stacked) and size control the split. select_layout() re-tiles everything afterward without touching what’s running in each pane — tmux ships five built-ins (even-horizontal, even-vertical, main-horizontal, main-vertical, tiled), and you can switch layouts as often as you like.

New windows default to created-in-the-background across the ports that document the choice explicitly (Python’s attach=False, C++‘s “created detached: a library call that stole the terminal would be a surprise, and attaching is a separate decision”) — building a workspace shouldn’t yank focus around as each piece comes up. Splitting and resizing are each a tmux round trip, same as any other mutation; see Control mode vs one-shot for what that costs at scale and how to fold several into one invocation.

Building one declarativelyLink to section

Describing a session as data and applying it is common enough that six of the eight ports ship a purpose-built package for it, each reading (or authoring) a tmuxp-shaped configuration:

PortPackageShape
Pythontmuxp itselfthe format this whole idea is named after
TypeScript@libtmux/workspaceapplyWorkspace(server, { session_name, windows: [...] })
Goworkspacetmuxp-shaped, per the port’s own module layout
Rusttmux-workspacetmuxp-shaped
Javalibtmux-workspace“enough of tmuxp’s format to describe a workspace”
C#LibTmux.Workspacereads tmuxp YAML directly
SwiftTmuxWorkspaceSwift, JSON, or YAML (YAML needs the YAMLWorkspaces trait)

TypeScript’s shape is representative of the idea across all of them — declare the session, apply it, and applying twice converges rather than duplicating:

C++ is the exception: rather than shipping its own builder, its README points straight at tmuxp — “you want a workspace from a config file, tmuxp already does that, and does it well” — and its examples/workspace/ is a worked example of driving tmuxp’s format from C++ rather than a package of its own:

// Not a package — this is the examples/workspace/ consumer, showing the
// shape a tmuxp document builds into rather than a library entry point.
const workspace::Workspace description{
.session_name = "dev",
.windows = {{.name = "editor", .panes = {{}, {}}}}};
const auto built = workspace::build(server, description);

Cleaning upLink to section

A workspace meant to live only for the span of a task — a test run, a scripted demo — doesn’t have to be torn down by hand. Python’s Window and Session are context managers: the object is created on entry and killed on exit, including when something inside the with block raises, so a workspace built for one purpose never outlives it as a stray window:

Whether another port’s window or session handle offers the same context-manager convenience is worth checking against that port’s own reference rather than assuming — kill methods (window.kill(), session.kill()) are the one thing verified across all of them.

Esc

Type to search.