# libtmux > Typed tmux control libraries for Python, Ruby, Lua, TypeScript, Rust, Go, Java, Kotlin, Scala, C#, F#, C++, Swift. This site includes shared concepts and language-specific guides, examples and API references. - [tmux manual](https://libtmux.org/en/tmux/latest/manual/): versioned command syntax and the tmux manual. - [tmux C source reference](https://libtmux.org/en/tmux/latest/reference/): internal C declarations, members and source links by tmux version. --- # tmux MCP for C# Source: https://libtmux.org/en/csharp/latest/mcp/ > Run LibTmux.Mcp as a .NET tool with bounded results and a selectable tool catalog. [`LibTmux.Mcp`]() is a .NET tool package whose executable is `libtmux-mcp`. It serves tmux tools and a static capability resource over standard input and output. The tool targets .NET 8 and .NET 10 and requires a POSIX host with tmux. Its registered operations include `capture_pane`, `run_shell_command`, and `capture_since`. ## Toolsets Use `LIBTMUX_TOOLSETS=inspect` for discovery and terminal reads. Additional toolsets enable changes, execution, and teardown. The [tool-selection topic](https://libtmux.org/en/csharp/latest/mcp/topics/tool-selection/) explains exact-name filters, defaults, and the capability resource. The [complete examples](https://libtmux.org/en/csharp/latest/mcp/examples/) include project files and cleanup for their owned tmux servers. [Workspace Manager](https://libtmux.org/en/csharp/latest/workspace/) is the separately packaged [`LibTmux.Workspace`]() library. The MCP catalog does not include a workspace-file operation. [Package contract](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/README.md). - [Tools](https://libtmux.org/en/csharp/latest/mcp/tools/): Every MCP operation, with its arguments and results. - [Guides](https://libtmux.org/en/csharp/latest/mcp/guides/): Install the tool, choose a socket, and verify the client's connection. - [Topics](https://libtmux.org/en/csharp/latest/mcp/topics/): Tool selection, command waits, capture limits, and cancellation. - [Examples](https://libtmux.org/en/csharp/latest/mcp/examples/): Complete clients for session inspection and bounded command execution. - [Language API](https://libtmux.org/en/csharp/latest/mcp/reference/): Embedding and implementation types. --- # C# MCP API Source: https://libtmux.org/en/csharp/latest/mcp/reference/ > Find the C# server composition API and current MCP protocol catalog. For MCP client requests, use the [tool reference](https://libtmux.org/en/csharp/latest/mcp/tools/). This page covers language APIs for embedding or extending the server. [`LibTmux.Mcp`]() is distributed as a .NET tool package. Installing its executable does not provide a NuGet library reference for embedding. ## Source API [`McpServerComposition.Add`]() registers the server in a service collection and returns the MCP builder for transport composition. It accepts the connection options, caller pane ID, and a [`ServerPolicy`]() containing wait and output limits. The public overload selects tools without teardown. Tool handlers are internal implementation details. [Composition source](https://github.com/libtmux/libtmux-dotnet/blob/320dc64f4b8b7815842471327a5e6b84a1499bf8/src/LibTmux.Mcp/McpServerComposition.cs). ## Protocol API The [tool reference](https://libtmux.org/en/csharp/latest/mcp/tools/) uses names such as `capture_pane` and `run_shell_command`. Results provide structured content and bounded text. Read `tmux://capabilities` for the startup-frozen selection. The current surface has no workflow prompts or dynamic resource templates. For the separately published configuration library, see [Workspace builder API](https://libtmux.org/en/csharp/latest/workspace/reference/). ## API declarations - [LibTmux.Mcp.ActionResult](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-actionresult/) - [LibTmux.Mcp.BoundedText](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-boundedtext/) - [LibTmux.Mcp.CaptureResult](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-captureresult/) - [LibTmux.Mcp.ChannelWaitResult](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-channelwaitresult/) - [LibTmux.Mcp.EnvironmentEntry](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-environmententry/) - [LibTmux.Mcp.HookEntry](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-hookentry/) - [LibTmux.Mcp.KeyStep](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-keystep/) - [LibTmux.Mcp.LibTmuxMcp](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-libtmuxmcp/) - [LibTmux.Mcp.MatchedLine](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-matchedline/) - [LibTmux.Mcp.McpServerComposition](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-mcpservercomposition/) - [LibTmux.Mcp.OptionEntry](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-optionentry/) - [LibTmux.Mcp.PaneInfo](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-paneinfo/) - [LibTmux.Mcp.PaneInputResult](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-paneinputresult/) - [LibTmux.Mcp.PaneMatch](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-panematch/) - [LibTmux.Mcp.PaneSnapshot](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-panesnapshot/) - [LibTmux.Mcp.RunResult](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-runresult/) - [LibTmux.Mcp.SearchResult](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-searchresult/) - [LibTmux.Mcp.ServerInstructions](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-serverinstructions/) - [LibTmux.Mcp.ServerPolicy](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-serverpolicy/) - [LibTmux.Mcp.SessionInfo](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-sessioninfo/) - [LibTmux.Mcp.TailResult](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-tailresult/) - [LibTmux.Mcp.TmuxConnectionAccessor](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-tmuxconnectionaccessor/) - [LibTmux.Mcp.TmuxServerInfo](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-tmuxserverinfo/) - [LibTmux.Mcp.WaitOutcome](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-waitoutcome/) - [LibTmux.Mcp.WaitResult](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-waitresult/) - [LibTmux.Mcp.WindowInfo](https://libtmux.org/en/csharp/latest/mcp/reference/libtmux-mcp-windowinfo/) [Protocol catalog](https://libtmux.org/en/csharp/latest/mcp/tools.json) --- # C# workspace manager Source: https://libtmux.org/en/csharp/latest/workspace/ > Describe a tmux session in a file, then load, inspect and capture it. **Workspace Manager for C# is in development.** The `tmux-workspace` CLI is published to NuGet as a prerelease. Pin its version when automation depends on its output. `tmux-workspace` creates tmux sessions from YAML or JSON. A file describes windows, panes, commands, directories and environment. Load it from a terminal or request machine output for automation. ## Load a workspace from the terminal 1. [Install the command and load a workspace](https://libtmux.org/en/csharp/latest/workspace/guides/installation/). 2. [Configure windows and panes](https://libtmux.org/en/csharp/latest/workspace/configuration/). 3. [Capture and reload a session](https://libtmux.org/en/csharp/latest/workspace/guides/export-session/). The [CLI manual](https://libtmux.org/en/csharp/latest/workspace/cli/) covers discovery, search, editing, loading, capture, conversion and import. [Examples](https://libtmux.org/en/csharp/latest/workspace/examples/gallery/) provide complete configurations with their prerequisites. ## Automate and inspect Use `load -d` when the caller should return without attaching. `--json` returns a result, and `--ndjson` supports a stream of records. Read [automation](https://libtmux.org/en/csharp/latest/workspace/guides/automation/) for retry and cleanup decisions and [errors](https://libtmux.org/en/csharp/latest/workspace/reference/exit-codes/) for failure handling. Loaded workspaces are ordinary tmux sessions. Select the same socket when inspecting them from tmux or the [MCP server](https://libtmux.org/en/csharp/latest/mcp/). ## Build from application code The [workspace library](https://libtmux.org/en/csharp/latest/workspace/internals/) has its own API and configuration contract. Use it when a program needs direct control over construction. The CLI task guides here describe the `tmux-workspace` executable and link to its documented source revision. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). - [CLI Manual](https://libtmux.org/en/csharp/latest/workspace/cli/): Commands, options and machine output. - [Configuration](https://libtmux.org/en/csharp/latest/workspace/configuration/): Workspace fields, normalization and execution. - [Install and load](https://libtmux.org/en/csharp/latest/workspace/guides/installation/): Load a workspace on a private socket, then capture it. - [Example gallery](https://libtmux.org/en/csharp/latest/workspace/examples/gallery/): Workspace files to start from, with their prerequisites. - [Runtime support](https://libtmux.org/en/csharp/latest/workspace/reference/compatibility/): Runtime requirements and supported behavior. - [Internals](https://libtmux.org/en/csharp/latest/workspace/internals/): The workspace library, for building sessions from code. --- # tmux MCP for C++ Source: https://libtmux.org/en/cxx/latest/mcp/ > Build the native C++ MCP executable and use its platform-specific tmux tool catalog. `libtmux-mcp-server` is a native executable that exposes tmux through MCP over standard input and output. It is an optional consumer of the C++ library, enabled separately in the CMake build. The catalog exposes discovery, creation, capture, input, search, and bounded text waits. Native Windows advertises the same catalog, with unsupported psmux operations failing explicitly at dispatch. ## Start here - [Install](https://libtmux.org/en/cxx/latest/mcp/#install) points an MCP client at this server. - [Tools](https://libtmux.org/en/cxx/latest/mcp/tools/) lists the MCP operations, arguments, and results. - [Guides](https://libtmux.org/en/cxx/latest/mcp/guides/) build the executable and select an endpoint. - [Topics](https://libtmux.org/en/cxx/latest/mcp/topics/) explain platform coverage, identifiers, and failures. - [Examples](https://libtmux.org/en/cxx/latest/mcp/examples/) call a tool, then explore server internals. - [Language API](https://libtmux.org/en/cxx/latest/mcp/reference/) documents embedding and implementation types. Toolsets and exact tool names select the startup surface. The static `tmux://capabilities` resource reports it; workflow prompts and dynamic resource templates are absent. The [Workspace Manager](https://libtmux.org/en/cxx/latest/workspace/) is another source consumer. Its configuration types are not part of the installed core API, and the MCP server does not include a workspace-file operation. [Executable and platform contract](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/apps/mcp/README.md). --- # C++ MCP topics Source: https://libtmux.org/en/cxx/latest/mcp/topics/ > Select toolsets, inspect the pinned endpoint, and observe bounded commands. The server selects one tmux endpoint and freezes its offered tools at startup. Read `tmux://capabilities` to inspect that endpoint's provenance and the effective tool selection. ## Select tools `LIBTMUX_TOOLSETS` selects any combination of [`inspect`](), [`manage`](), [`execute`](), and [`teardown`](). `LIBTMUX_TOOLS` adds exact names; `LIBTMUX_EXCLUDE_TOOLS` removes names last. Unknown names and malformed lists fail startup. Use [`inspect`]() for discovery and terminal reads. Add [`manage`]() for topology changes and [`execute`]() for input and process creation. Select [`teardown`]() explicitly when removal is needed on an existing or explicitly selected server. A default dedicated daemon can receive teardown tools when the launcher verifies its own minimal-configuration provenance. Tool selection shapes the callable interface. Execute tools act with the tmux user's authority; selecting a socket does not confine shell effects. ## Observe a command Use [`run_shell_command`](https://libtmux.org/en/cxx/latest/mcp/tools/run_shell_command/) for a bounded command and its exit status. A deadline ends the wait; the pane command may still be running. Inspect it before submitting another command. Use [`capture_since`](https://libtmux.org/en/cxx/latest/mcp/tools/capture_since/) to collect subsequent output and [`wait_for_text`](https://libtmux.org/en/cxx/latest/mcp/tools/wait_for_text/) for an expected terminal condition. Their schemas and result limits are in the [tool reference](https://libtmux.org/en/cxx/latest/mcp/tools/). The current catalog has no detached job-handle API. ## Resources and prompts The server exposes the static `tmux://capabilities` resource. Read live hierarchy and terminal state through tools. The current surface has no workflow prompts or dynamic resource templates. [Configuration and lifecycle contract](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/apps/mcp/README.md). --- # Connect a C++ MCP client Source: https://libtmux.org/en/cxx/latest/mcp/guides/ > Build the optional native executable and launch it against an explicit POSIX tmux socket. Build the optional MCP executable from the C++ repository, then configure the client to launch it. This guide targets POSIX tmux. Native Windows has separate psmux prerequisites and command-dependent support. ## Build the executable Use a toolchain supported by the repository's C++23 or C++20 build. Enable the server and its JSON dependency: ```console $ cmake \ -S . \ -B build/mcp \ -DLIBTMUX_BUILD_MCP_SERVER=ON \ -DLIBTMUX_FETCH_DEPS=ON \ -DLIBTMUX_BUILD_TESTS=OFF \ -DLIBTMUX_BUILD_EXAMPLES=OFF ``` Build it: ```console $ cmake --build build/mcp ``` Install into the user's local prefix: ```console $ cmake --install build/mcp \ --prefix ~/.local ``` ## Select the endpoint Make the installed binary directory available to the MCP client. For clients using `mcpServers`: ```json { "mcpServers": { "tmux-cpp": { "command": "libtmux-mcp-server", "args": ["--socket-name", "docs-agent"] } } } ``` Use `--socket-path` for an explicit POSIX socket path. Without a selector, the executable uses the dedicated `libtmux-mcp` socket and minimal configuration. Use `--socket inherit` to select an inherited `TMUX` route. ## Verify the catalog Have the client list tools, then call `list_sessions`. Retain the returned session, window, and pane identities for later calls. Use `LIBTMUX_TOOLSETS=inspect` for discovery and reads. Read `tmux://capabilities` to inspect the startup selection; see [Topics](https://libtmux.org/en/cxx/latest/mcp/topics/) for exact tool inclusions and exclusions. [Build instructions](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/apps/mcp/README.md) and [selector implementation](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/apps/mcp/src/cli.cpp). --- # C++ MCP examples Source: https://libtmux.org/en/cxx/latest/mcp/examples/ > List sessions through the C++ MCP server and inspect implementation examples. Connect the server using the [setup guide](https://libtmux.org/en/cxx/latest/mcp/guides/), then call [`list_sessions`](https://libtmux.org/en/cxx/latest/mcp/tools/list_sessions/) from your MCP client. ## List sessions This is the `params` object for an MCP `tools/call` request. Send it through the connected client: ```json { "name": "list_sessions", "arguments": {} } ``` Use the returned session IDs when choosing a window or pane. The [tool reference](https://libtmux.org/en/cxx/latest/mcp/tools/list_sessions/) describes this port's result and optional arguments. ## Internals The following examples are for applications that embed or extend the server. Installing and connecting an MCP client does not require this code. The MCP consumer separates its tool model from JSON-RPC encoding. Source applications can inspect that model without starting a tmux server. ### Inspect the consumer catalog This program uses the declarations in the [consumer header](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/apps/mcp/include/libtmux_consumers/mcp.hpp): ```cpp #include #include "libtmux_consumers/mcp.hpp" int main() { const auto catalog = libtmux::mcp::default_tools(); if (!catalog) { std::cerr << catalog.error() << '\n'; return 1; } for (const auto& tool : catalog->tools()) { std::cout << tool.name << '\n'; } } ``` Build this within an application that includes the repository's `mcp_tools` CMake target. The header and target belong to the source consumer; the installed core package does not export them. The [consumer tests](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/apps/mcp/tests/mcp_test.cpp) exercise the same catalog and direct calls. This small listing program is a source-derived example, not one of those collected tests. ### Drive the executable After connecting an MCP client using the [guide](https://libtmux.org/en/cxx/latest/mcp/guides/), start with `list_sessions`, then `list_windows` and `list_panes`. Preserve returned object identities for subsequent calls. On POSIX, use `capture_pane` to inspect a discovered pane, then `wait_for_text` for a bounded wait. Read its match/timeout result and final capture before choosing another operation. The [protocol tests](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/apps/mcp/tests/protocol_test.cpp) cover client lifecycle, validation, concurrency, and cancellation. Native Windows advertises the same catalog; unsupported psmux operations fail explicitly when called. --- # C++ MCP API Source: https://libtmux.org/en/cxx/latest/mcp/reference/ > Distinguish installed protocol tools from the C++ source consumer's tool-model API. For MCP client requests, use the [tool reference](https://libtmux.org/en/cxx/latest/mcp/tools/). This page covers language APIs for embedding or extending the server. The installed product is `libtmux-mcp-server`. Its public MCP operations are available through the protocol. The C++ tool model lives in a source consumer and is not exported by the installed core package. ## Consumer API [`libtmux::mcp::default_tools()`]() returns an expected value containing a [`ToolRegistry`]() or an error. [`tools()`]() enumerates definitions, [`find()`]() looks up a name, and [`call()`]() invokes a handler against a [`Server`]() with named arguments and an optional [`CallContext`](). [`ToolResult`]() is an expected value containing structured output or a [`ToolError`](). [`CallContext`]() provides cooperative cancellation and progress callbacks. [`ToolDefinition`]() describes parameters, output shape, and effect annotations independently of a JSON library. [Consumer declarations](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/apps/mcp/include/libtmux_consumers/mcp.hpp) and [build target](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/apps/mcp/CMakeLists.txt). ## Protocol API The [tool reference](https://libtmux.org/en/cxx/latest/mcp/tools/) covers registered names and schemas. Toolsets and exact names filter the catalog at startup. The static `tmux://capabilities` resource reports that selection. The server has no workflow prompts or dynamic resource templates. Successful tool calls return matching structured content and serialized JSON text. Strict argument validation precedes tmux execution. [Protocol tests](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/apps/mcp/tests/protocol_test.cpp) cover supported lifecycle revisions and result shapes. [Workspace builder API](https://libtmux.org/en/cxx/latest/workspace/reference/) documents a separate source consumer; it is not a workspace operation in this MCP catalog. ## API declarations - [libtmux::mcp::ArgumentMap](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-argumentmap/) - [libtmux::mcp::Arguments](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-arguments/) - [libtmux::mcp::ArgumentType](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-argumenttype/) - [libtmux::mcp::CallContext](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-callcontext/) - [libtmux::mcp::configured_tools](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-configured_tools/) - [libtmux::mcp::default_tools](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-default_tools/) - [libtmux::mcp::Effect](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-effect/) - [libtmux::mcp::FlatArguments](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-flatarguments/) - [libtmux::json_wire::from_json](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-json_wire-from_json/) - [libtmux::mcp::Handler](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-handler/) - [libtmux::mcp::InputControl](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-inputcontrol/) - [libtmux::mcp::InputSink](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-inputsink/) - [libtmux::json_wire::is_known_field](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-json_wire-is_known_field/) - [libtmux::mcp::kConservativeAnnotations](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-kconservativeannotations/) - [libtmux::json_wire::kind_from](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-json_wire-kind_from/) - [libtmux::json_wire::kSchemaVersion](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-json_wire-kschemaversion/) - [libtmux::json_wire::name_of](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-json_wire-name_of/) - [libtmux::mcp::NestedAuthority](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-nestedauthority/) - [libtmux::mcp::OutputClass](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-outputclass/) - [libtmux::mcp::OutputShape](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-outputshape/) - [libtmux::mcp::Parameter](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-parameter/) - [libtmux::mcp::parse_tool_selection](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-parse_tool_selection/) - [libtmux::mcp::ProcessReach](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-processreach/) - [libtmux::mcp::ReadToolCall](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-readtoolcall/) - [libtmux::mcp::Sink](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-sink/) - [libtmux::mcp::StructuredValue](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-structuredvalue/) - [libtmux::json_wire::to_json](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-json_wire-to_json/) - [libtmux::mcp::ToolAnnotations](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-toolannotations/) - [libtmux::mcp::ToolAuthority](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-toolauthority/) - [libtmux::mcp::ToolDefinition](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-tooldefinition/) - [libtmux::mcp::ToolError](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-toolerror/) - [libtmux::mcp::ToolOutput](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-tooloutput/) - [libtmux::mcp::ToolRegistry](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-toolregistry/) - [libtmux::mcp::ToolResult](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-toolresult/) - [libtmux::mcp::ToolSchema](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-toolschema/) - [libtmux::mcp::ToolSelection](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-toolselection/) - [libtmux::mcp::Toolset](https://libtmux.org/en/cxx/latest/mcp/reference/libtmux-mcp-toolset/) [Protocol catalog](https://libtmux.org/en/cxx/latest/mcp/tools.json) --- # C++ workspace manager Source: https://libtmux.org/en/cxx/latest/workspace/ > Describe a tmux session in a file, then load, inspect and capture it. **Workspace Manager for C++ is in development.** Build `tmux-workspace` from the source revision in the installation guide. Its CLI and workspace library have separate installation and configuration contracts. `tmux-workspace` creates tmux sessions from YAML or JSON. A file describes windows, panes, commands, directories and environment. Load it from a terminal or request machine output for automation. ## Load a workspace from the terminal 1. [Install the command and load a workspace](https://libtmux.org/en/cxx/latest/workspace/guides/installation/). 2. [Configure windows and panes](https://libtmux.org/en/cxx/latest/workspace/configuration/). 3. [Capture and reload a session](https://libtmux.org/en/cxx/latest/workspace/guides/export-session/). The [CLI manual](https://libtmux.org/en/cxx/latest/workspace/cli/) covers discovery, search, editing, loading, capture, conversion and import. [Examples](https://libtmux.org/en/cxx/latest/workspace/examples/gallery/) provide complete configurations with their prerequisites. ## Automate and inspect Use `load -d` when the caller should return without attaching. `--json` returns a result, and `--ndjson` supports a stream of records. Read [automation](https://libtmux.org/en/cxx/latest/workspace/guides/automation/) for retry and cleanup decisions and [errors](https://libtmux.org/en/cxx/latest/workspace/reference/exit-codes/) for failure handling. Loaded workspaces are ordinary tmux sessions. Select the same socket when inspecting them from tmux or the [MCP server](https://libtmux.org/en/cxx/latest/mcp/). ## Build from application code The [workspace library](https://libtmux.org/en/cxx/latest/workspace/internals/) has its own API and configuration contract. Use it when a program needs direct control over construction. The CLI task guides here describe the `tmux-workspace` executable and link to its documented source revision. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). - [CLI Manual](https://libtmux.org/en/cxx/latest/workspace/cli/): Commands, options and machine output. - [Configuration](https://libtmux.org/en/cxx/latest/workspace/configuration/): Workspace fields, normalization and execution. - [Install and load](https://libtmux.org/en/cxx/latest/workspace/guides/installation/): Load a workspace on a private socket, then capture it. - [Example gallery](https://libtmux.org/en/cxx/latest/workspace/examples/gallery/): Workspace files to start from, with their prerequisites. - [Runtime support](https://libtmux.org/en/cxx/latest/workspace/reference/compatibility/): Runtime requirements and supported behavior. - [Internals](https://libtmux.org/en/cxx/latest/workspace/internals/): The workspace library, for building sessions from code. --- # libtmux-workspace CLI manual Source: https://libtmux.org/en/ruby/latest/workspace/cli/ > Commands, options and exit statuses for the Ruby workspace CLI. `libtmux-workspace` validates a YAML or JSON configuration, shows its creation plan, and applies it to an explicitly selected tmux server. Install the workspace gem using the [workspace installation instructions](https://libtmux.org/en/ruby/latest/). ## Commands
validate
Check the configuration without contacting tmux or running commands.
plan
Inspect ordered creation operations, optionally using a live snapshot.
load
Create a new session on an existing server selected by socket path.
## Input and common options Pass one configuration file after the options. If you omit the file, discovery requires exactly one of [`.tmuxp.yaml`](https://libtmux.org/en/ruby/latest/workspace/cli/validate/), [`.tmuxp.yml`](https://libtmux.org/en/ruby/latest/workspace/cli/validate/), or [`.tmuxp.json`](https://libtmux.org/en/ruby/latest/workspace/cli/validate/) in the current directory. Missing or ambiguous input exits with status `2`. | Option | Behavior | | --- | --- | | `--json` | Write one JSON result or error to stdout. | | `--expand-environment` | Expand `${NAME}` in configured paths and environment values using explicit `--env` values. Shell command text stays unchanged. | | `--env NAME=VALUE` | Supply an expansion value. Repeat for different names; duplicate names are invalid. Ambient environment variables are not the expansion map. | | `-h`, `--help` | Show commands and options without reading a file or contacting tmux. | | `--version` | Show the installed gem version without reading a file or contacting tmux. | Show the installed command's options: ```console $ libtmux-workspace --help ``` Check the installed version: ```console $ libtmux-workspace --version ``` The command pages explain `--socket`, `--live`, `--timeout`, `--compensate`, `--attach`, and `--switch`, including which commands accept them. ## Output and exit statuses Successful human-readable results go to stdout. Human-readable errors go to stderr; an application failure can also include its partial creation ledger there. With `--json`, both results and errors go to stdout as JSON. Check the exit status as well as the output. | Status | Meaning | | --- | --- | | `0` | The requested operation succeeded. | | `1` | Execution failed before recorded application effects. | | `2` | Arguments or configuration are invalid. | | `3` | Application effects are partial or uncertain, or a post-load attach or switch failed. | | `130` | The operation was interrupted or cancelled. | A successful load confirms that the creation operations completed and shell commands were dispatched. It does not establish that the programs in those panes have completed. A failed load can leave a session behind; inspect its result before retrying. [CLI parser and implementation](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-workspace/lib/libtmux/workspace/cli.rb). --- # validate Source: https://libtmux.org/en/ruby/latest/workspace/cli/validate/ > Check a Ruby workspace configuration without contacting tmux. `validate` reads and checks a YAML or JSON workspace without starting tmux, opening a socket, creating a session, or running configured shell commands. Use it before inspecting or applying a plan. ## Check a workspace Save the [complete example configuration](https://libtmux.org/en/ruby/latest/workspace/examples/) as [`workspace.yaml`](), then validate it: ```console $ libtmux-workspace validate workspace.yaml ``` Success prints `Workspace configuration is valid.` and exits with status `0`. To request a JSON result: ```console $ libtmux-workspace validate \ --json \ workspace.yaml ``` The result contains `valid`, `profile`, and `version`. Invalid configuration exits with status `2`. In JSON mode, the error object is written to stdout; otherwise diagnostics go to stderr. ## Options and limits The [common options](https://libtmux.org/en/ruby/latest/workspace/cli/#input-and-common-options) control output and explicit environment expansion. Omit the filename only when the current directory contains exactly one discoverable configuration. `--socket`, `--live`, `--attach`, `--switch`, and `--compensate` are invalid for validation. Validation checks the [supported configuration format](https://libtmux.org/en/ruby/latest/workspace/topics/). It does not prove that a session name is free on a server, a shell command will succeed, or a program is installed. Use [live planning](https://libtmux.org/en/ruby/latest/workspace/cli/plan/#inspect-a-live-server) to inspect the chosen server, and check [load results](https://libtmux.org/en/ruby/latest/workspace/cli/load/#results-and-failures) when applying the workspace. [CLI parser and implementation](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-workspace/lib/libtmux/workspace/cli.rb). --- # plan Source: https://libtmux.org/en/ruby/latest/workspace/cli/plan/ > Inspect the ordered operations needed to create a Ruby workspace. [`plan`]() lists the ordered creation operations without applying them. By default it reads only the configuration. It does not contact tmux or execute the workspace's shell commands. ## Inspect an offline plan Save the [complete example configuration](https://libtmux.org/en/ruby/latest/workspace/examples/) as [`workspace.yaml`](), then inspect its plan: ```console $ libtmux-workspace plan \ --json \ workspace.yaml ``` The JSON result includes configured command text and paths. Treat it as application data, not a redacted diagnostic. Without `--json`, the output lists the mode, step count, and each step's operation, target, and effect. ## Inspect a live server `--live` acquires a snapshot from an existing server before planning. It requires `--socket PATH`; passing a socket without `--live` is invalid. Use the private server prepared in the [load walkthrough](https://libtmux.org/en/ruby/latest/workspace/cli/load/#create-a-workspace): ```console $ libtmux-workspace plan \ --live \ --socket "$WORKSPACE_TMP/tmux.sock" \ --json \ workspace.yaml ``` Run this before loading the workspace. The manager creates new sessions; it does not reconcile an existing session with the file. A live snapshot describes the server when captured, so inspect the later load result rather than assuming the server stayed unchanged. ## Options and failures `--timeout SECONDS` bounds the live snapshot operation. It defaults to `5` and must be finite and positive. The [common options](https://libtmux.org/en/ruby/latest/workspace/cli/#input-and-common-options) control file discovery, JSON output, and explicit environment expansion. `--attach`, `--switch`, and `--compensate` are invalid for planning. Invalid arguments or configuration return status `2`. An unavailable live server returns an execution error. See [exit statuses](https://libtmux.org/en/ruby/latest/workspace/cli/#output-and-exit-statuses) before using a plan in automation. [CLI parser and implementation](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-workspace/lib/libtmux/workspace/cli.rb). --- # load Source: https://libtmux.org/en/ruby/latest/workspace/cli/load/ > Create a Ruby workspace on an explicitly selected existing tmux server. [`load`]() applies a creation plan to an existing server selected by `--socket`. It creates a new session and leaves it detached by default. It does not reconcile, replace, or delete a preexisting workspace. ## Create a workspace Install tmux and the workspace gem using the [installation instructions](https://libtmux.org/en/ruby/latest/), then save the [complete example configuration](https://libtmux.org/en/ruby/latest/workspace/examples/) as [`workspace.yaml`](). Run these commands in the same POSIX shell. Create a temporary directory for this example's private socket: ```console $ WORKSPACE_TMP=$(mktemp -d) ``` Start a private server with a keepalive session and no user configuration: ```console $ tmux \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ new-session -d -s manual-keepalive ``` Load the workspace on that socket: ```console $ libtmux-workspace load \ --socket "$WORKSPACE_TMP/tmux.sock" \ --json \ workspace.yaml ``` The result records completed steps, effects, and created references. Inspect the example's `work` session: ```console $ tmux \ -S "$WORKSPACE_TMP/tmux.sock" \ list-windows -t work ``` This lists the `editor` window. When finished, stop only the private server: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-server ``` Remove the private socket and temporary directory after stopping the server: ```console $ rm -rf "$WORKSPACE_TMP" ``` ## Options | Option | Behavior | | --- | --- | | `--socket PATH` | Required path to an existing server's socket. Relative paths resolve from the current directory. | | `--timeout SECONDS` | Finite positive time budget shared by preflight and all creation steps; defaults to `5`. A post-load client switch receives a separate budget of the same length. This option does not bound terminal attachment. | | `--compensate` | Attempt guarded cleanup of positively identified created resources after application failure. It cannot undo shell effects. | | `--attach` | Attach this CLI's terminal after loading. Requires `/dev/tty` and a valid `TERM`. | | `--switch CLIENT` | Switch the explicitly named current client to the created session after loading. There is no fallback client selection. | `--attach` and `--switch` are mutually exclusive. `--live` belongs to [`plan`]() and is invalid for [`load`](). The [common options](https://libtmux.org/en/ruby/latest/workspace/cli/#input-and-common-options) cover JSON output, file discovery, and explicit environment expansion. ## Results and failures Success means that the creation operations completed and configured shell commands were dispatched. It does not mean those programs finished or became ready. Inspect their output or use an application-specific readiness signal. A failed operation can leave completed steps in place. The result retains created references and effects for inspection; do not retry blindly. The default preserves partial state. `--compensate` attempts cleanup only when ownership can be established. If post-load attachment or switching fails, the created session and its ledger remain available and the command returns status `3`. Read the [exit statuses](https://libtmux.org/en/ruby/latest/workspace/cli/#output-and-exit-statuses) when using JSON output in a script. [CLI parser and implementation](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-workspace/lib/libtmux/workspace/cli.rb). [Apply deadline](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-workspace/lib/libtmux/workspace/apply.rb). --- # Load a workspace Source: https://libtmux.org/en/csharp/latest/workspace/cli/load/ > Create or reuse a session from a workspace file, with explicit attachment and output choices. Load a saved configuration into tmux. Use `-d` for scripts so the command returns after construction without attaching a terminal. Command delivery does not mean the programs running in those panes have finished or become ready. ## Load without attaching Continue the [installation walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/) with its [`workspace.yaml`](https://libtmux.org/en/csharp/latest/workspace/guides/installation/#create-the-input) and private socket: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-S` selects the socket path; `-L` selects a socket name. `-f` supplies tmux's configuration when starting a server. Keep the same endpoint for later capture, inspection and cleanup. Pass `-s another-name` to override the final input's session name. ## Existing sessions and append A session with the requested name is reused. Loading is not a reconciliation operation that removes extra windows. Inspect a failed result before retrying: earlier inputs and changes to a borrowed session can remain. Inside tmux, `--append` adds windows to the invoking pane's session. It needs valid `TMUX` and `TMUX_PANE` values for the selected daemon. Use `-d` when loading onto a different server. Multiple inputs are processed in their supplied order. ## Attachment and output Human loading can attach a terminal or switch a tmux client. For automation, choose `-d` or an authenticated append explicitly; machine output does not answer interactive questions. `--yes` accepts supported confirmations. `--json` returns a result; `--ndjson` emits records as work proceeds. Read [output](https://libtmux.org/en/csharp/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/csharp/latest/workspace/reference/exit-codes/) before consuming those records. `--no-progress` disables the terminal display; it does not disable errors. `-2` requests 256-color handling from tmux. Use [configuration](https://libtmux.org/en/csharp/latest/workspace/configuration/) for fields and [hooks](https://libtmux.org/en/csharp/latest/workspace/configuration/hooks/) for bootstrap scripts and extensions. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Load a workspace Source: https://libtmux.org/en/cxx/latest/workspace/cli/load/ > Create or reuse a session from a workspace file, with explicit attachment and output choices. Load a saved configuration into tmux. Use `-d` for scripts so the command returns after construction without attaching a terminal. Command delivery does not mean the programs running in those panes have finished or become ready. ## Load without attaching Continue the [installation walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/) with its [`workspace.yaml`](https://libtmux.org/en/cxx/latest/workspace/guides/installation/#create-the-input) and private socket: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-S` selects the socket path; `-L` selects a socket name. `-f` supplies tmux's configuration when starting a server. Keep the same endpoint for later capture, inspection and cleanup. Pass `-s another-name` to override the final input's session name. ## Existing sessions and append A session with the requested name is reused. Loading is not a reconciliation operation that removes extra windows. Inspect a failed result before retrying: earlier inputs and changes to a borrowed session can remain. Inside tmux, `--append` adds windows to the invoking pane's session. It needs valid `TMUX` and `TMUX_PANE` values for the selected daemon. Use `-d` when loading onto a different server. Multiple inputs are processed in their supplied order. ## Attachment and output Human loading can attach a terminal or switch a tmux client. For automation, choose `-d` or an authenticated append explicitly; machine output does not answer interactive questions. `--yes` accepts supported confirmations. `--json` returns a result; `--ndjson` emits records as work proceeds. Read [output](https://libtmux.org/en/cxx/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/cxx/latest/workspace/reference/exit-codes/) before consuming those records. `--no-progress` disables the terminal display; it does not disable errors. `-2` requests 256-color handling from tmux. Use [configuration](https://libtmux.org/en/cxx/latest/workspace/configuration/) for fields and [hooks](https://libtmux.org/en/cxx/latest/workspace/configuration/hooks/) for bootstrap scripts and extensions. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Load a workspace Source: https://libtmux.org/en/go/latest/workspace/cli/load/ > Create or reuse a session from a workspace file, with explicit attachment and output choices. Load a saved configuration into tmux. Use `-d` for scripts so the command returns after construction without attaching a terminal. Command delivery does not mean the programs running in those panes have finished or become ready. ## Load without attaching Continue the [installation walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/) with its [`workspace.yaml`](https://libtmux.org/en/go/latest/workspace/guides/installation/#create-the-input) and private socket: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-S` selects the socket path; `-L` selects a socket name. `-f` supplies tmux's configuration when starting a server. Keep the same endpoint for later capture, inspection and cleanup. Pass `-s another-name` to override the final input's session name. ## Existing sessions and append A session with the requested name is reused. Loading is not a reconciliation operation that removes extra windows. Inspect a failed result before retrying: earlier inputs and changes to a borrowed session can remain. Inside tmux, `--append` adds windows to the invoking pane's session. It needs valid `TMUX` and `TMUX_PANE` values for the selected daemon. Use `-d` when loading onto a different server. Multiple inputs are processed in their supplied order. ## Attachment and output Human loading can attach a terminal or switch a tmux client. For automation, choose `-d` or an authenticated append explicitly; machine output does not answer interactive questions. `--yes` accepts supported confirmations. `--json` returns a result; `--ndjson` emits records as work proceeds. Read [output](https://libtmux.org/en/go/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/go/latest/workspace/reference/exit-codes/) before consuming those records. `--no-progress` disables the terminal display; it does not disable errors. `-2` requests 256-color handling from tmux. Use [configuration](https://libtmux.org/en/go/latest/workspace/configuration/) for fields and [hooks](https://libtmux.org/en/go/latest/workspace/configuration/hooks/) for bootstrap scripts and extensions. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Load a workspace Source: https://libtmux.org/en/java/latest/workspace/cli/load/ > Create or reuse a session from a workspace file, with explicit attachment and output choices. Load a saved configuration into tmux. Use `-d` for scripts so the command returns after construction without attaching a terminal. Command delivery does not mean the programs running in those panes have finished or become ready. ## Load without attaching Continue the [installation walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/) with its [`workspace.yaml`](https://libtmux.org/en/java/latest/workspace/guides/installation/#create-the-input) and private socket: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-S` selects the socket path; `-L` selects a socket name. `-f` supplies tmux's configuration when starting a server. Keep the same endpoint for later capture, inspection and cleanup. Pass `-s another-name` to override the final input's session name. ## Existing sessions and append A session with the requested name is reused. Loading is not a reconciliation operation that removes extra windows. Inspect a failed result before retrying: earlier inputs and changes to a borrowed session can remain. Inside tmux, `--append` adds windows to the invoking pane's session. It needs valid `TMUX` and `TMUX_PANE` values for the selected daemon. Use `-d` when loading onto a different server. Multiple inputs are processed in their supplied order. ## Attachment and output Human loading can attach a terminal or switch a tmux client. For automation, choose `-d` or an authenticated append explicitly; machine output does not answer interactive questions. `--yes` accepts supported confirmations. `--json` returns a result; `--ndjson` emits records as work proceeds. Read [output](https://libtmux.org/en/java/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/java/latest/workspace/reference/exit-codes/) before consuming those records. `--no-progress` disables the terminal display; it does not disable errors. `-2` requests 256-color handling from tmux. Use [configuration](https://libtmux.org/en/java/latest/workspace/configuration/) for fields and [hooks](https://libtmux.org/en/java/latest/workspace/configuration/hooks/) for bootstrap scripts and extensions. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Load a workspace Source: https://libtmux.org/en/py/latest/workspace/cli/load/ > Create or reuse a session from a workspace file, with explicit attachment and output choices. Load a workspace file, saved workspace name, or project directory. Multiple inputs build in order; without `-d`, the final session is attached or selected through the current-client flow. ## Loading and attachment Create [`workspace.yaml`](https://libtmux.org/en/py/latest/workspace/guides/installation/#create-the-input) using the [installation walkthrough](https://libtmux.org/en/py/latest/workspace/guides/installation/), then load it on that walkthrough's dedicated socket: ```console $ tmuxp load \ -L workspace-guide \ -d \ workspace.yaml ``` `-d` avoids attachment. Inside an existing tmux client, the normal interactive flow can switch to the new session, append windows, or stay detached. `--append` explicitly selects the append flow and needs a current target session. An existing session is handled through tmuxp's load policy; loading is not a declarative reconciliation operation that removes surplus windows. Put flags before the complete group of filenames. The reference accepts flags before or after that group, but a flag between two filenames can cause an argument error. `-s` overrides the final input's session name when several files are loaded. tmuxp parses `-2` and `-8` as mutually exclusive flags, separate from the CLI text's `--color` setting. Legacy `-8` is unsupported; [tmux removed 88-color support](https://raw.githubusercontent.com/tmux/tmux/3.2a/CHANGES). ## Progress and script output `--progress-format` accepts [`default`](), `minimal`, `"window"`, `"pane"`, `verbose`, or a custom format. Available tokens include `{session}`, `{window}`, `{window_index}`, `{window_total}`, `{window_progress}`, `{window_progress_rel}`, `{windows_done}`, `{windows_remaining}`, `{pane_index}`, `{pane_total}`, `{pane_progress}`, `{progress}`, `{session_pane_progress}`, `{overall_percent}`, `{bar}`, `{pane_bar}`, `{window_bar}`, and `{status_icon}`. The output panel defaults to three lines. `--progress-lines 0` hides the panel and sends script output to stdout; `-1` permits all available lines up to terminal height. `--no-progress` disables animation. See [environment settings](https://libtmux.org/en/py/latest/workspace/configuration/environment/) for environment bindings and [command ordering](https://libtmux.org/en/py/latest/workspace/configuration/commands/) for what is executed. ## Arguments and flags | Argument or flags | Arity / default | Choices or meaning | | --- | --- | --- | | `"workspace_files"` | one or more | filepath to session or filename of session in tmuxp workspace directory | | `-L` | value; None | passthru to tmux(1) -L | | `-S` | value; None | passthru to tmux(1) -S | | `-f` | value; None | passthru to tmux(1) -f | | `-s` | value; None | start new session with new session name | | `--yes`, `-y` | flag; False | always answer yes | | `-d` | flag; False | load the session without attaching it | | `-a`, `--append` | flag; False | load workspace, appending windows to the current session | | `-2` | flag; None | force tmux to assume the terminal supports 256 colours. | | `-8` | flag; None | legacy 88-colour flag; unsupported by tmux 3.2a+ | | `--log-file` | value; None | file to log errors/output to | | `--progress-format` | value; None | Spinner line format: preset name (default, minimal, window, pane, verbose) or a format string with tokens {session}, {window}, {progress}, {window_progress}, {pane_progress}, etc. Env: TMUXP_PROGRESS_FORMAT | | `--progress-lines` | value; None | Number of script-output lines shown in the spinner panel (default: 3). 0 hides the panel entirely (script output goes to stdout). -1 shows unlimited lines (capped to terminal height). Env: TMUXP_PROGRESS_LINES | | `--no-progress` | flag; False | Disable the animated progress spinner. Env: TMUXP_PROGRESS=0 | All commands accept `-h` / `--help`. Root options precede the command; see the [CLI overview](https://libtmux.org/en/py/latest/workspace/cli/). The [output reference](https://libtmux.org/en/py/latest/workspace/reference/output/) describes the formats supported by each command. [Parser and implementation source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/load.py). [tmuxp reference source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Load a workspace Source: https://libtmux.org/en/rs/latest/workspace/cli/load/ > Create or reuse a session from a workspace file, with explicit attachment and output choices. Load a saved configuration into tmux. Use `-d` for scripts so the command returns after construction without attaching a terminal. Command delivery does not mean the programs running in those panes have finished or become ready. ## Load without attaching Continue the [installation walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/) with its [`workspace.yaml`](https://libtmux.org/en/rs/latest/workspace/guides/installation/#create-the-input) and private socket: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-S` selects the socket path; `-L` selects a socket name. `-f` supplies tmux's configuration when starting a server. Keep the same endpoint for later capture, inspection and cleanup. Pass `-s another-name` to override the final input's session name. ## Existing sessions and append A session with the requested name is reused. Loading is not a reconciliation operation that removes extra windows. Inspect a failed result before retrying: earlier inputs and changes to a borrowed session can remain. Inside tmux, `--append` adds windows to the invoking pane's session. It needs valid `TMUX` and `TMUX_PANE` values for the selected daemon. Use `-d` when loading onto a different server. Multiple inputs are processed in their supplied order. ## Attachment and output Human loading can attach a terminal or switch a tmux client. For automation, choose `-d` or an authenticated append explicitly; machine output does not answer interactive questions. `--yes` accepts supported confirmations. `--json` returns a result; `--ndjson` emits records as work proceeds. Read [output](https://libtmux.org/en/rs/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/rs/latest/workspace/reference/exit-codes/) before consuming those records. `--no-progress` disables the terminal display; it does not disable errors. `-2` requests 256-color handling from tmux. Use [configuration](https://libtmux.org/en/rs/latest/workspace/configuration/) for fields and [hooks](https://libtmux.org/en/rs/latest/workspace/configuration/hooks/) for bootstrap scripts and extensions. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Load a workspace Source: https://libtmux.org/en/swift/latest/workspace/cli/load/ > Create or reuse a session from a workspace file, with explicit attachment and output choices. Load a saved configuration into tmux. Use `-d` for scripts so the command returns after construction without attaching a terminal. Command delivery does not mean the programs running in those panes have finished or become ready. ## Load without attaching Continue the [installation walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/) with its [`workspace.yaml`](https://libtmux.org/en/swift/latest/workspace/guides/installation/#create-the-input) and private socket: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-S` selects the socket path; `-L` selects a socket name. `-f` supplies tmux's configuration when starting a server. Keep the same endpoint for later capture, inspection and cleanup. Pass `-s another-name` to override the final input's session name. ## Existing sessions and append A session with the requested name is reused. Loading is not a reconciliation operation that removes extra windows. Inspect a failed result before retrying: earlier inputs and changes to a borrowed session can remain. Inside tmux, `--append` adds windows to the invoking pane's session. It needs valid `TMUX` and `TMUX_PANE` values for the selected daemon. Use `-d` when loading onto a different server. Multiple inputs are processed in their supplied order. ## Attachment and output Human loading can attach a terminal or switch a tmux client. For automation, choose `-d` or an authenticated append explicitly; machine output does not answer interactive questions. `--yes` accepts supported confirmations. `--json` returns a result; `--ndjson` emits records as work proceeds. Read [output](https://libtmux.org/en/swift/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/swift/latest/workspace/reference/exit-codes/) before consuming those records. `--no-progress` disables the terminal display; it does not disable errors. `-2` requests 256-color handling from tmux. Use [configuration](https://libtmux.org/en/swift/latest/workspace/configuration/) for fields and [hooks](https://libtmux.org/en/swift/latest/workspace/configuration/hooks/) for bootstrap scripts and extensions. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Load a workspace Source: https://libtmux.org/en/ts/latest/workspace/cli/load/ > Create or reuse a session from a workspace file, with explicit attachment and output choices. Load a saved configuration into tmux. Use `-d` for scripts so the command returns after construction without attaching a terminal. Command delivery does not mean the programs running in those panes have finished or become ready. ## Load without attaching Continue the [installation walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/) with its [`workspace.yaml`](https://libtmux.org/en/ts/latest/workspace/guides/installation/#create-the-input) and private socket: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-S` selects the socket path; `-L` selects a socket name. `-f` supplies tmux's configuration when starting a server. Keep the same endpoint for later capture, inspection and cleanup. Pass `-s another-name` to override the final input's session name. ## Existing sessions and append A session with the requested name is reused. Loading is not a reconciliation operation that removes extra windows. Inspect a failed result before retrying: earlier inputs and changes to a borrowed session can remain. Inside tmux, `--append` adds windows to the invoking pane's session. It needs valid `TMUX` and `TMUX_PANE` values for the selected daemon. Use `-d` when loading onto a different server. Multiple inputs are processed in their supplied order. ## Attachment and output Human loading can attach a terminal or switch a tmux client. For automation, choose `-d` or an authenticated append explicitly; machine output does not answer interactive questions. `--yes` accepts supported confirmations. `--json` returns a result; `--ndjson` emits records as work proceeds. Read [output](https://libtmux.org/en/ts/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/ts/latest/workspace/reference/exit-codes/) before consuming those records. `--no-progress` disables the terminal display; it does not disable errors. `-2` requests 256-color handling from tmux. Use [configuration](https://libtmux.org/en/ts/latest/workspace/configuration/) for fields and [hooks](https://libtmux.org/en/ts/latest/workspace/configuration/hooks/) for bootstrap scripts and extensions. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Capture a workspace Source: https://libtmux.org/en/csharp/latest/workspace/cli/freeze/ > Capture a running tmux session as a starting point for a workspace file. Capture a running tmux session as a starting point for a workspace file. Capture reads live state. It cannot recover original command arguments, command history, script definitions or plugin intent. ## Inspect a session After the [installation walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/) creates `workspace-guide`, request a machine result from its private socket: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ workspace-guide ``` ## Save the captured document Name the destination and format explicitly: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to captured-workspace.yaml \ workspace-guide ``` Use a new destination, or pass `--force` to authorize replacement. Review captured commands and directories before loading the file on another machine. The saved document encoding is separate from the CLI result format selected by `--json` or `--ndjson`. See [export and reload](https://libtmux.org/en/csharp/latest/workspace/guides/export-session/) for the complete workflow. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Capture a workspace Source: https://libtmux.org/en/cxx/latest/workspace/cli/freeze/ > Capture a running tmux session as a starting point for a workspace file. Capture a running tmux session as a starting point for a workspace file. Capture reads live state. It cannot recover original command arguments, command history, script definitions or plugin intent. ## Inspect a session After the [installation walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/) creates `workspace-guide`, request a machine result from its private socket: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ workspace-guide ``` ## Save the captured document Name the destination and format explicitly: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to captured-workspace.yaml \ workspace-guide ``` Use a new destination, or pass `--force` to authorize replacement. Review captured commands and directories before loading the file on another machine. The saved document encoding is separate from the CLI result format selected by `--json` or `--ndjson`. See [export and reload](https://libtmux.org/en/cxx/latest/workspace/guides/export-session/) for the complete workflow. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Capture a workspace Source: https://libtmux.org/en/go/latest/workspace/cli/freeze/ > Capture a running tmux session as a starting point for a workspace file. Capture a running tmux session as a starting point for a workspace file. Capture reads live state. It cannot recover original command arguments, command history, script definitions or plugin intent. ## Inspect a session After the [installation walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/) creates `workspace-guide`, request a machine result from its private socket: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ workspace-guide ``` ## Save the captured document Name the destination and format explicitly: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to captured-workspace.yaml \ workspace-guide ``` Use a new destination, or pass `--force` to authorize replacement. Review captured commands and directories before loading the file on another machine. The saved document encoding is separate from the CLI result format selected by `--json` or `--ndjson`. See [export and reload](https://libtmux.org/en/go/latest/workspace/guides/export-session/) for the complete workflow. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Capture a workspace Source: https://libtmux.org/en/java/latest/workspace/cli/freeze/ > Capture a running tmux session as a starting point for a workspace file. Capture a running tmux session as a starting point for a workspace file. Capture reads live state. It cannot recover original command arguments, command history, script definitions or plugin intent. ## Inspect a session After the [installation walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/) creates `workspace-guide`, request a machine result from its private socket: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ workspace-guide ``` ## Save the captured document Name the destination and format explicitly: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to captured-workspace.yaml \ workspace-guide ``` Use a new destination, or pass `--force` to authorize replacement. Review captured commands and directories before loading the file on another machine. The saved document encoding is separate from the CLI result format selected by `--json` or `--ndjson`. See [export and reload](https://libtmux.org/en/java/latest/workspace/guides/export-session/) for the complete workflow. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Capture a workspace Source: https://libtmux.org/en/py/latest/workspace/cli/freeze/ > Capture a running tmux session as a starting point for a workspace file. Capture a running tmux session as a starting workspace file. A capture cannot recover original scripts, plugin intent, comments or every application state. ## Export a named session After the [installation walkthrough](https://libtmux.org/en/py/latest/workspace/guides/installation/) creates `workspace-guide`, choose a new destination: ```console $ tmuxp freeze \ -L workspace-guide \ --workspace-format yaml \ --save-to captured-workspace.yaml \ --yes \ workspace-guide ``` Without a session, format or destination, the command can ask for missing choices. `--yes` answers yes/no questions; it does not supply every choice. `--quiet` suppresses explanatory status but can still allow prompts. An explicit `--save-to` path bypasses the overwrite confirmation used by the prompted path. Select a new path deliberately. A successful export writes a file; declining a confirmation can return without saving. Inspect the captured commands and paths before following [export and reload](https://libtmux.org/en/py/latest/workspace/guides/export-session/). [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/freeze.py). --- # Capture a workspace Source: https://libtmux.org/en/rs/latest/workspace/cli/freeze/ > Capture a running tmux session as a starting point for a workspace file. Capture a running tmux session as a starting point for a workspace file. Capture reads live state. It cannot recover original command arguments, command history, script definitions or plugin intent. ## Inspect a session After the [installation walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/) creates `workspace-guide`, request a machine result from its private socket: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ workspace-guide ``` ## Save the captured document Name the destination and format explicitly: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to captured-workspace.yaml \ workspace-guide ``` Use a new destination, or pass `--force` to authorize replacement. Review captured commands and directories before loading the file on another machine. The saved document encoding is separate from the CLI result format selected by `--json` or `--ndjson`. See [export and reload](https://libtmux.org/en/rs/latest/workspace/guides/export-session/) for the complete workflow. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Capture a workspace Source: https://libtmux.org/en/swift/latest/workspace/cli/freeze/ > Capture a running tmux session as a starting point for a workspace file. Capture a running tmux session as a starting point for a workspace file. Capture reads live state. It cannot recover original command arguments, command history, script definitions or plugin intent. ## Inspect a session After the [installation walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/) creates `workspace-guide`, request a machine result from its private socket: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ workspace-guide ``` ## Save the captured document Name the destination and format explicitly: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to captured-workspace.yaml \ workspace-guide ``` Use a new destination, or pass `--force` to authorize replacement. Review captured commands and directories before loading the file on another machine. The saved document encoding is separate from the CLI result format selected by `--json` or `--ndjson`. See [export and reload](https://libtmux.org/en/swift/latest/workspace/guides/export-session/) for the complete workflow. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Capture a workspace Source: https://libtmux.org/en/ts/latest/workspace/cli/freeze/ > Capture a running tmux session as a starting point for a workspace file. Capture a running tmux session as a starting point for a workspace file. Capture reads live state. It cannot recover original command arguments, command history, script definitions or plugin intent. ## Inspect a session After the [installation walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/) creates `workspace-guide`, request a machine result from its private socket: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ workspace-guide ``` ## Save the captured document Name the destination and format explicitly: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to captured-workspace.yaml \ workspace-guide ``` Use a new destination, or pass `--force` to authorize replacement. Review captured commands and directories before loading the file on another machine. The saved document encoding is separate from the CLI result format selected by `--json` or `--ndjson`. See [export and reload](https://libtmux.org/en/ts/latest/workspace/guides/export-session/) for the complete workflow. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Convert workspace files Source: https://libtmux.org/en/csharp/latest/workspace/cli/convert/ > Convert a complete workspace document between YAML and JSON. Convert a complete workspace document between YAML and JSON. Conversion preserves mapping fields; it does not establish that every field can be loaded. ## Inspect the result Start with [`workspace.yaml`](https://libtmux.org/en/csharp/latest/workspace/guides/installation/#create-the-input) from the [installation walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/): ```console $ tmux-workspace convert --json workspace.yaml ``` Without a destination, machine mode returns the converted document in its result. YAML comments and textual formatting do not survive conversion to JSON. ## Save a file Choose an explicit destination and encoding: ```console $ tmux-workspace convert \ --json \ --workspace-format json \ --save-to workspace.json \ workspace.yaml ``` Replacing an existing destination requires `--force`. Keep that choice separate from `--yes`, which answers prompts. Review the result before [loading it](https://libtmux.org/en/csharp/latest/workspace/cli/load/). [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Convert workspace files Source: https://libtmux.org/en/cxx/latest/workspace/cli/convert/ > Convert a complete workspace document between YAML and JSON. Convert a complete workspace document between YAML and JSON. Conversion preserves mapping fields; it does not establish that every field can be loaded. ## Inspect the result Start with [`workspace.yaml`](https://libtmux.org/en/cxx/latest/workspace/guides/installation/#create-the-input) from the [installation walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/): ```console $ tmux-workspace convert --json workspace.yaml ``` Without a destination, machine mode returns the converted document in its result. YAML comments and textual formatting do not survive conversion to JSON. ## Save a file Choose an explicit destination and encoding: ```console $ tmux-workspace convert \ --json \ --workspace-format json \ --save-to workspace.json \ workspace.yaml ``` Replacing an existing destination requires `--force`. Keep that choice separate from `--yes`, which answers prompts. Review the result before [loading it](https://libtmux.org/en/cxx/latest/workspace/cli/load/). [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Convert workspace files Source: https://libtmux.org/en/go/latest/workspace/cli/convert/ > Convert a complete workspace document between YAML and JSON. Convert a complete workspace document between YAML and JSON. Conversion preserves mapping fields; it does not establish that every field can be loaded. ## Inspect the result Start with [`workspace.yaml`](https://libtmux.org/en/go/latest/workspace/guides/installation/#create-the-input) from the [installation walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/): ```console $ tmux-workspace convert --json workspace.yaml ``` Without a destination, machine mode returns the converted document in its result. YAML comments and textual formatting do not survive conversion to JSON. ## Save a file Choose an explicit destination and encoding: ```console $ tmux-workspace convert \ --json \ --workspace-format json \ --save-to workspace.json \ workspace.yaml ``` Replacing an existing destination requires `--force`. Keep that choice separate from `--yes`, which answers prompts. Review the result before [loading it](https://libtmux.org/en/go/latest/workspace/cli/load/). [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Convert workspace files Source: https://libtmux.org/en/java/latest/workspace/cli/convert/ > Convert a complete workspace document between YAML and JSON. Convert a complete workspace document between YAML and JSON. Conversion preserves mapping fields; it does not establish that every field can be loaded. ## Inspect the result Start with [`workspace.yaml`](https://libtmux.org/en/java/latest/workspace/guides/installation/#create-the-input) from the [installation walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/): ```console $ tmux-workspace convert --json workspace.yaml ``` Without a destination, machine mode returns the converted document in its result. YAML comments and textual formatting do not survive conversion to JSON. ## Save a file Choose an explicit destination and encoding: ```console $ tmux-workspace convert \ --json \ --workspace-format json \ --save-to workspace.json \ workspace.yaml ``` Replacing an existing destination requires `--force`. Keep that choice separate from `--yes`, which answers prompts. Review the result before [loading it](https://libtmux.org/en/java/latest/workspace/cli/load/). [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Convert workspace files Source: https://libtmux.org/en/py/latest/workspace/cli/convert/ > Convert a complete workspace document between YAML and JSON. Convert a workspace document between YAML and JSON while retaining its mapping keys. ## Change the file format Given [`workspace.yaml`](https://libtmux.org/en/py/latest/workspace/guides/installation/#create-the-input) from the [installation walkthrough](https://libtmux.org/en/py/latest/workspace/guides/installation/): ```console $ tmuxp convert \ --yes \ workspace.yaml ``` The destination has the same stem and opposite extension. `--yes` permits replacement of an existing destination. The original input remains. YAML comments and textual formatting do not round-trip through JSON. The command resolves a file or saved workspace name. [Discovery](https://libtmux.org/en/py/latest/workspace/guides/discovery/) describes that lookup. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/convert.py). --- # Convert workspace files Source: https://libtmux.org/en/rs/latest/workspace/cli/convert/ > Convert a complete workspace document between YAML and JSON. Convert a complete workspace document between YAML and JSON. Conversion preserves mapping fields; it does not establish that every field can be loaded. ## Inspect the result Start with [`workspace.yaml`](https://libtmux.org/en/rs/latest/workspace/guides/installation/#create-the-input) from the [installation walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/): ```console $ tmux-workspace convert --json workspace.yaml ``` Without a destination, machine mode returns the converted document in its result. YAML comments and textual formatting do not survive conversion to JSON. ## Save a file Choose an explicit destination and encoding: ```console $ tmux-workspace convert \ --json \ --workspace-format json \ --save-to workspace.json \ workspace.yaml ``` Replacing an existing destination requires `--force`. Keep that choice separate from `--yes`, which answers prompts. Review the result before [loading it](https://libtmux.org/en/rs/latest/workspace/cli/load/). [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Convert workspace files Source: https://libtmux.org/en/swift/latest/workspace/cli/convert/ > Convert a complete workspace document between YAML and JSON. Convert a complete workspace document between YAML and JSON. Conversion preserves mapping fields; it does not establish that every field can be loaded. ## Inspect the result Start with [`workspace.yaml`](https://libtmux.org/en/swift/latest/workspace/guides/installation/#create-the-input) from the [installation walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/): ```console $ tmux-workspace convert --json workspace.yaml ``` Without a destination, machine mode returns the converted document in its result. YAML comments and textual formatting do not survive conversion to JSON. ## Save a file Choose an explicit destination and encoding: ```console $ tmux-workspace convert \ --json \ --workspace-format json \ --save-to workspace.json \ workspace.yaml ``` Replacing an existing destination requires `--force`. Keep that choice separate from `--yes`, which answers prompts. Review the result before [loading it](https://libtmux.org/en/swift/latest/workspace/cli/load/). [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Convert workspace files Source: https://libtmux.org/en/ts/latest/workspace/cli/convert/ > Convert a complete workspace document between YAML and JSON. Convert a complete workspace document between YAML and JSON. Conversion preserves mapping fields; it does not establish that every field can be loaded. ## Inspect the result Start with [`workspace.yaml`](https://libtmux.org/en/ts/latest/workspace/guides/installation/#create-the-input) from the [installation walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/): ```console $ tmux-workspace convert --json workspace.yaml ``` Without a destination, machine mode returns the converted document in its result. YAML comments and textual formatting do not survive conversion to JSON. ## Save a file Choose an explicit destination and encoding: ```console $ tmux-workspace convert \ --json \ --workspace-format json \ --save-to workspace.json \ workspace.yaml ``` Replacing an existing destination requires `--force`. Keep that choice separate from `--yes`, which answers prompts. Review the result before [loading it](https://libtmux.org/en/ts/latest/workspace/cli/load/). [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Edit a workspace Source: https://libtmux.org/en/csharp/latest/workspace/cli/edit/ > Resolve a workspace file or saved name and open it in an editor. Resolve a workspace file or saved name and open it in an editor. Use an explicit path when editing a particular file. ## Open the file With `vi` installed and [`workspace.yaml`](https://libtmux.org/en/csharp/latest/workspace/guides/installation/#create-the-input) saved: ```console $ EDITOR=vi tmux-workspace edit workspace.yaml ``` The CLI waits for the editor and reports a failed child through its exit status. Editor values can contain quoted arguments. They are parsed as an argument list; shell pipelines and redirection require an explicit shell or wrapper. [Discovery](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/) explains saved workspace names. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Edit a workspace Source: https://libtmux.org/en/cxx/latest/workspace/cli/edit/ > Resolve a workspace file or saved name and open it in an editor. Resolve a workspace file or saved name and open it in an editor. Use an explicit path when editing a particular file. ## Open the file With `vi` installed and [`workspace.yaml`](https://libtmux.org/en/cxx/latest/workspace/guides/installation/#create-the-input) saved: ```console $ EDITOR=vi tmux-workspace edit workspace.yaml ``` `VISUAL` takes precedence over `EDITOR`. Unset it or select the same editor there when using the command above. The CLI waits for the editor and reports a failed child through its exit status. Editor values can contain quoted arguments. They are parsed as an argument list; shell pipelines and redirection require an explicit shell or wrapper. [Discovery](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/) explains saved workspace names. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Edit a workspace Source: https://libtmux.org/en/go/latest/workspace/cli/edit/ > Resolve a workspace file or saved name and open it in an editor. Resolve a workspace file or saved name and open it in an editor. Use an explicit path when editing a particular file. ## Open the file With `vi` installed and [`workspace.yaml`](https://libtmux.org/en/go/latest/workspace/guides/installation/#create-the-input) saved: ```console $ EDITOR=vi tmux-workspace edit workspace.yaml ``` The CLI waits for the editor and reports a failed child through its exit status. Editor values can contain quoted arguments. They are parsed as an argument list; shell pipelines and redirection require an explicit shell or wrapper. [Discovery](https://libtmux.org/en/go/latest/workspace/guides/discovery/) explains saved workspace names. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Edit a workspace Source: https://libtmux.org/en/java/latest/workspace/cli/edit/ > Resolve a workspace file or saved name and open it in an editor. Resolve a workspace file or saved name and open it in an editor. Use an explicit path when editing a particular file. ## Open the file With `vi` installed and [`workspace.yaml`](https://libtmux.org/en/java/latest/workspace/guides/installation/#create-the-input) saved: ```console $ EDITOR=vi tmux-workspace edit workspace.yaml ``` The CLI waits for the editor and reports a failed child through its exit status. Editor values can contain quoted arguments. They are parsed as an argument list; shell pipelines and redirection require an explicit shell or wrapper. [Discovery](https://libtmux.org/en/java/latest/workspace/guides/discovery/) explains saved workspace names. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Edit a workspace Source: https://libtmux.org/en/py/latest/workspace/cli/edit/ > Resolve a workspace file or saved name and open it in an editor. Resolve a saved workspace or file and open it in the configured editor. ## Open a workspace With [`workspace.yaml`](https://libtmux.org/en/py/latest/workspace/guides/installation/#create-the-input) saved and `vi` installed: ```console $ EDITOR=vi tmuxp edit workspace.yaml ``` The command passes the entire `EDITOR` value as one executable name followed by the file path. It does not split editor arguments. Use a wrapper executable when arguments are needed. The command waits for the editor but does not propagate its exit status. Inspect the edited file before loading it. [Discovery](https://libtmux.org/en/py/latest/workspace/guides/discovery/) explains saved workspace names. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/edit.py). --- # Edit a workspace Source: https://libtmux.org/en/rs/latest/workspace/cli/edit/ > Resolve a workspace file or saved name and open it in an editor. Resolve a workspace file or saved name and open it in an editor. Use an explicit path when editing a particular file. ## Open the file With `vi` installed and [`workspace.yaml`](https://libtmux.org/en/rs/latest/workspace/guides/installation/#create-the-input) saved: ```console $ EDITOR=vi tmux-workspace edit workspace.yaml ``` The CLI waits for the editor and reports a failed child through its exit status. Editor values can contain quoted arguments. They are parsed as an argument list; shell pipelines and redirection require an explicit shell or wrapper. [Discovery](https://libtmux.org/en/rs/latest/workspace/guides/discovery/) explains saved workspace names. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Edit a workspace Source: https://libtmux.org/en/swift/latest/workspace/cli/edit/ > Resolve a workspace file or saved name and open it in an editor. Resolve a workspace file or saved name and open it in an editor. Use an explicit path when editing a particular file. ## Open the file With `vi` installed and [`workspace.yaml`](https://libtmux.org/en/swift/latest/workspace/guides/installation/#create-the-input) saved: ```console $ EDITOR=vi tmux-workspace edit workspace.yaml ``` The CLI waits for the editor and reports a failed child through its exit status. Editor values can contain quoted arguments. They are parsed as an argument list; shell pipelines and redirection require an explicit shell or wrapper. [Discovery](https://libtmux.org/en/swift/latest/workspace/guides/discovery/) explains saved workspace names. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Edit a workspace Source: https://libtmux.org/en/ts/latest/workspace/cli/edit/ > Resolve a workspace file or saved name and open it in an editor. Resolve a workspace file or saved name and open it in an editor. Use an explicit path when editing a particular file. ## Open the file With `vi` installed and [`workspace.yaml`](https://libtmux.org/en/ts/latest/workspace/guides/installation/#create-the-input) saved: ```console $ EDITOR=vi tmux-workspace edit workspace.yaml ``` The CLI waits for the editor and reports a failed child through its exit status. Editor values can contain quoted arguments. They are parsed as an argument list; shell pipelines and redirection require an explicit shell or wrapper. [Discovery](https://libtmux.org/en/ts/latest/workspace/guides/discovery/) explains saved workspace names. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Inspect runtime diagnostics Source: https://libtmux.org/en/csharp/latest/workspace/cli/debug-info/ > Collect the workspace CLI runtime, configuration and tmux diagnostics.. Collect the workspace CLI runtime, configuration and tmux diagnostics. ## Collect a report ```console $ tmux-workspace debug-info --json ``` Review the report before sharing it. Paths, session names and raw tmux values can describe your environment even when home-directory prefixes are redacted. Use the failed command exit status and stderr to diagnose its actual failure. See [troubleshooting](https://libtmux.org/en/csharp/latest/workspace/guides/troubleshooting/) and the [machine output reference](https://libtmux.org/en/csharp/latest/workspace/reference/output/). [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Inspect runtime diagnostics Source: https://libtmux.org/en/cxx/latest/workspace/cli/debug-info/ > Collect the workspace CLI runtime, configuration and tmux diagnostics.. Collect the workspace CLI runtime, configuration and tmux diagnostics. ## Collect a report ```console $ tmux-workspace debug-info --json ``` Review the report before sharing it. Paths, session names and raw tmux values can describe your environment even when home-directory prefixes are redacted. Use the failed command exit status and stderr to diagnose its actual failure. See [troubleshooting](https://libtmux.org/en/cxx/latest/workspace/guides/troubleshooting/) and the [machine output reference](https://libtmux.org/en/cxx/latest/workspace/reference/output/). [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Inspect runtime diagnostics Source: https://libtmux.org/en/go/latest/workspace/cli/debug-info/ > Collect the workspace CLI runtime, configuration and tmux diagnostics.. Collect the workspace CLI runtime, configuration and tmux diagnostics. ## Collect a report ```console $ tmux-workspace debug-info --json ``` Review the report before sharing it. Paths, session names and raw tmux values can describe your environment even when home-directory prefixes are redacted. Use the failed command exit status and stderr to diagnose its actual failure. See [troubleshooting](https://libtmux.org/en/go/latest/workspace/guides/troubleshooting/) and the [machine output reference](https://libtmux.org/en/go/latest/workspace/reference/output/). [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Inspect runtime diagnostics Source: https://libtmux.org/en/java/latest/workspace/cli/debug-info/ > Collect the workspace CLI runtime, configuration and tmux diagnostics.. Collect the workspace CLI runtime, configuration and tmux diagnostics. ## Collect a report ```console $ tmux-workspace debug-info --json ``` Review the report before sharing it. Paths, session names and raw tmux values can describe your environment even when home-directory prefixes are redacted. Use the failed command exit status and stderr to diagnose its actual failure. See [troubleshooting](https://libtmux.org/en/java/latest/workspace/guides/troubleshooting/) and the [machine output reference](https://libtmux.org/en/java/latest/workspace/reference/output/). [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Inspect runtime diagnostics Source: https://libtmux.org/en/py/latest/workspace/cli/debug-info/ > Collect the workspace CLI runtime, configuration and tmux diagnostics.. Collect tmuxp, Python, tmux, configuration and environment diagnostics. ## Collect a report ```console $ tmuxp debug-info --json ``` The command writes one JSON object. Named path fields mask the home directory, but raw tmux output arrays are preserved. Review diagnostics before sharing them because names, commands and raw values may describe your environment. See [troubleshooting](https://libtmux.org/en/py/latest/workspace/guides/troubleshooting/) for connection and configuration failures. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/debug_info.py). --- # Inspect runtime diagnostics Source: https://libtmux.org/en/rs/latest/workspace/cli/debug-info/ > Collect the workspace CLI runtime, configuration and tmux diagnostics.. Collect the workspace CLI runtime, configuration and tmux diagnostics. ## Collect a report ```console $ tmux-workspace debug-info --json ``` Review the report before sharing it. Paths, session names and raw tmux values can describe your environment even when home-directory prefixes are redacted. Use the failed command exit status and stderr to diagnose its actual failure. See [troubleshooting](https://libtmux.org/en/rs/latest/workspace/guides/troubleshooting/) and the [machine output reference](https://libtmux.org/en/rs/latest/workspace/reference/output/). [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Inspect runtime diagnostics Source: https://libtmux.org/en/swift/latest/workspace/cli/debug-info/ > Collect the workspace CLI runtime, configuration and tmux diagnostics.. Collect the workspace CLI runtime, configuration and tmux diagnostics. ## Collect a report ```console $ tmux-workspace debug-info --json ``` Review the report before sharing it. Paths, session names and raw tmux values can describe your environment even when home-directory prefixes are redacted. Use the failed command exit status and stderr to diagnose its actual failure. See [troubleshooting](https://libtmux.org/en/swift/latest/workspace/guides/troubleshooting/) and the [machine output reference](https://libtmux.org/en/swift/latest/workspace/reference/output/). [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Inspect runtime diagnostics Source: https://libtmux.org/en/ts/latest/workspace/cli/debug-info/ > Collect the workspace CLI runtime, configuration and tmux diagnostics.. Collect the workspace CLI runtime, configuration and tmux diagnostics. ## Collect a report ```console $ tmux-workspace debug-info --json ``` Review the report before sharing it. Paths, session names and raw tmux values can describe your environment even when home-directory prefixes are redacted. Use the failed command exit status and stderr to diagnose its actual failure. See [troubleshooting](https://libtmux.org/en/ts/latest/workspace/guides/troubleshooting/) and the [machine output reference](https://libtmux.org/en/ts/latest/workspace/reference/output/). [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # List saved workspaces Source: https://libtmux.org/en/csharp/latest/workspace/cli/ls/ > List the workspace files found in project and global configuration locations. List the workspace files found in project and global configuration locations. Listing does not load sessions or run pane commands. ## List records ```console $ tmux-workspace ls --json ``` Include each document configuration: ```console $ tmux-workspace ls --full --json ``` For a human display grouped by directory, use `--tree`: ```console $ tmux-workspace ls --tree ``` Machine output preserves record values and has its own structure; do not parse the human tree. See [discovery](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/) for the locations searched and [output](https://libtmux.org/en/csharp/latest/workspace/reference/output/) for the result format. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # List saved workspaces Source: https://libtmux.org/en/cxx/latest/workspace/cli/ls/ > List the workspace files found in project and global configuration locations. List the workspace files found in project and global configuration locations. Listing does not load sessions or run pane commands. ## List records ```console $ tmux-workspace ls --json ``` Include each document configuration: ```console $ tmux-workspace ls --full --json ``` For a human display grouped by directory, use `--tree`: ```console $ tmux-workspace ls --tree ``` Machine output preserves record values and has its own structure; do not parse the human tree. See [discovery](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/) for the locations searched and [output](https://libtmux.org/en/cxx/latest/workspace/reference/output/) for the result format. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # List saved workspaces Source: https://libtmux.org/en/go/latest/workspace/cli/ls/ > List the workspace files found in project and global configuration locations. List the workspace files found in project and global configuration locations. Listing does not load sessions or run pane commands. ## List records ```console $ tmux-workspace ls --json ``` Include each document configuration: ```console $ tmux-workspace ls --full --json ``` For a human display grouped by directory, use `--tree`: ```console $ tmux-workspace ls --tree ``` Machine output preserves record values and has its own structure; do not parse the human tree. See [discovery](https://libtmux.org/en/go/latest/workspace/guides/discovery/) for the locations searched and [output](https://libtmux.org/en/go/latest/workspace/reference/output/) for the result format. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # List saved workspaces Source: https://libtmux.org/en/java/latest/workspace/cli/ls/ > List the workspace files found in project and global configuration locations. List the workspace files found in project and global configuration locations. Listing does not load sessions or run pane commands. ## List records ```console $ tmux-workspace ls --json ``` Include each document configuration: ```console $ tmux-workspace ls --full --json ``` For a human display grouped by directory, use `--tree`: ```console $ tmux-workspace ls --tree ``` Machine output preserves record values and has its own structure; do not parse the human tree. See [discovery](https://libtmux.org/en/java/latest/workspace/guides/discovery/) for the locations searched and [output](https://libtmux.org/en/java/latest/workspace/reference/output/) for the result format. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # List saved workspaces Source: https://libtmux.org/en/py/latest/workspace/cli/ls/ > List the workspace files found in project and global configuration locations. List discovered project and saved workspace files, with optional grouping and configuration content. ## List records ```console $ tmuxp ls --json ``` JSON output is an object with `workspaces` and `global_workspace_dirs`. No workspaces produces an empty `workspaces` array. `--ndjson` emits one record per line and zero lines for an empty result; it takes precedence when both output flags are present. `--full` includes configuration content. `--tree` groups human output by directory. [Discovery](https://libtmux.org/en/py/latest/workspace/guides/discovery/) explains the locations searched. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/ls.py). --- # List saved workspaces Source: https://libtmux.org/en/rs/latest/workspace/cli/ls/ > List the workspace files found in project and global configuration locations. List the workspace files found in project and global configuration locations. Listing does not load sessions or run pane commands. ## List records ```console $ tmux-workspace ls --json ``` Include each document configuration: ```console $ tmux-workspace ls --full --json ``` For a human display grouped by directory, use `--tree`: ```console $ tmux-workspace ls --tree ``` Machine output preserves record values and has its own structure; do not parse the human tree. See [discovery](https://libtmux.org/en/rs/latest/workspace/guides/discovery/) for the locations searched and [output](https://libtmux.org/en/rs/latest/workspace/reference/output/) for the result format. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # List saved workspaces Source: https://libtmux.org/en/swift/latest/workspace/cli/ls/ > List the workspace files found in project and global configuration locations. List the workspace files found in project and global configuration locations. Listing does not load sessions or run pane commands. ## List records ```console $ tmux-workspace ls --json ``` Include each document configuration: ```console $ tmux-workspace ls --full --json ``` For a human display grouped by directory, use `--tree`: ```console $ tmux-workspace ls --tree ``` Machine output preserves record values and has its own structure; do not parse the human tree. See [discovery](https://libtmux.org/en/swift/latest/workspace/guides/discovery/) for the locations searched and [output](https://libtmux.org/en/swift/latest/workspace/reference/output/) for the result format. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # List saved workspaces Source: https://libtmux.org/en/ts/latest/workspace/cli/ls/ > List the workspace files found in project and global configuration locations. List the workspace files found in project and global configuration locations. Listing does not load sessions or run pane commands. ## List records ```console $ tmux-workspace ls --json ``` Include each document configuration: ```console $ tmux-workspace ls --full --json ``` For a human display grouped by directory, use `--tree`: ```console $ tmux-workspace ls --tree ``` Machine output preserves record values and has its own structure; do not parse the human tree. See [discovery](https://libtmux.org/en/ts/latest/workspace/guides/discovery/) for the locations searched and [output](https://libtmux.org/en/ts/latest/workspace/reference/output/) for the result format. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Search workspaces Source: https://libtmux.org/en/csharp/latest/workspace/cli/search/ > Search the fields of discovered workspace documents. Search the fields of discovered workspace documents. Use literal matching when the input should be treated as text rather than a regular expression. ## Find a session name ```console $ tmux-workspace search \ --json \ --fixed-strings \ --field session \ workspace ``` Repeat `--field` to restrict additional fields. Query terms combine with AND; `--any` selects OR. `--ignore-case`, `--smart-case`, `--word-regexp`, and `--invert-match` control matching. Inspect the installed `search --help` for supported field names and aliases. Check both the exit status and [machine result](https://libtmux.org/en/csharp/latest/workspace/reference/output/). An empty successful search and a failed pattern are different outcomes. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Search workspaces Source: https://libtmux.org/en/cxx/latest/workspace/cli/search/ > Search the fields of discovered workspace documents. Search the fields of discovered workspace documents. Use literal matching when the input should be treated as text rather than a regular expression. ## Find a session name ```console $ tmux-workspace search \ --json \ --fixed-strings \ --field session \ workspace ``` Repeat `--field` to restrict additional fields. Query terms combine with AND; `--any` selects OR. `--ignore-case`, `--smart-case`, `--word-regexp`, and `--invert-match` control matching. Inspect the installed `search --help` for supported field names and aliases. Check both the exit status and [machine result](https://libtmux.org/en/cxx/latest/workspace/reference/output/). An empty successful search and a failed pattern are different outcomes. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Search workspaces Source: https://libtmux.org/en/go/latest/workspace/cli/search/ > Search the fields of discovered workspace documents. Search the fields of discovered workspace documents. Use literal matching when the input should be treated as text rather than a regular expression. ## Find a session name ```console $ tmux-workspace search \ --json \ --fixed-strings \ --field session \ workspace ``` Repeat `--field` to restrict additional fields. Query terms combine with AND; `--any` selects OR. `--ignore-case`, `--smart-case`, `--word-regexp`, and `--invert-match` control matching. Inspect the installed `search --help` for supported field names and aliases. ## Regular expressions The default engine uses Go regular expressions and ASCII word boundaries. Structured pane commands are searched as JSON text. Unsupported regex syntax fails; it does not start another runtime automatically. `--regex-engine python` explicitly enables lookaround, backreferences and Unicode word boundaries through an installed Python 3.10 or newer interpreter. Ordinary searches do not need that optional runtime. Check both the exit status and [machine result](https://libtmux.org/en/go/latest/workspace/reference/output/). An empty successful search and a failed pattern are different outcomes. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Search workspaces Source: https://libtmux.org/en/java/latest/workspace/cli/search/ > Search the fields of discovered workspace documents. Search the fields of discovered workspace documents. Use literal matching when the input should be treated as text rather than a regular expression. ## Find a session name ```console $ tmux-workspace search \ --json \ --fixed-strings \ --field session \ workspace ``` Repeat `--field` to restrict additional fields. Query terms combine with AND; `--any` selects OR. `--ignore-case`, `--smart-case`, `--word-regexp`, and `--invert-match` control matching. Inspect the installed `search --help` for supported field names and aliases. Check both the exit status and [machine result](https://libtmux.org/en/java/latest/workspace/reference/output/). An empty successful search and a failed pattern are different outcomes. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Search workspaces Source: https://libtmux.org/en/py/latest/workspace/cli/search/ > Search the fields of discovered workspace documents. Search discovered workspace fields with regular expressions or literal strings. Query terms combine with AND unless `--any` selects OR. ## Find a session name ```console $ tmuxp search \ --json \ --fixed-strings \ --field session \ workspace ``` Field prefixes and repeated `--field` restrictions select name, session (`s`), path ([`p`]()), window (`w`) or pane data. `--ignore-case` ignores case; `--smart-case` does so only when a pattern has no uppercase. `--word-regexp` requires whole words and `--invert-match` selects nonmatches. ## Empty and invalid queries The documented implementation emits no bytes for an empty search result, including with `--json`. With no query, machine search can print human help and return normally. An invalid regular expression can also produce no machine output. Account for these outcomes before parsing stdout as JSON. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/search.py). --- # Search workspaces Source: https://libtmux.org/en/rs/latest/workspace/cli/search/ > Search the fields of discovered workspace documents. Search the fields of discovered workspace documents. Use literal matching when the input should be treated as text rather than a regular expression. ## Find a session name ```console $ tmux-workspace search \ --json \ --fixed-strings \ --field session \ workspace ``` Repeat `--field` to restrict additional fields. Query terms combine with AND; `--any` selects OR. `--ignore-case`, `--smart-case`, `--word-regexp`, and `--invert-match` control matching. Inspect the installed `search --help` for supported field names and aliases. Check both the exit status and [machine result](https://libtmux.org/en/rs/latest/workspace/reference/output/). An empty successful search and a failed pattern are different outcomes. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Search workspaces Source: https://libtmux.org/en/swift/latest/workspace/cli/search/ > Search the fields of discovered workspace documents. Search the fields of discovered workspace documents. Use literal matching when the input should be treated as text rather than a regular expression. ## Find a session name ```console $ tmux-workspace search \ --json \ --fixed-strings \ --field session \ workspace ``` Repeat `--field` to restrict additional fields. Query terms combine with AND; `--any` selects OR. `--ignore-case`, `--smart-case`, `--word-regexp`, and `--invert-match` control matching. Inspect the installed `search --help` for supported field names and aliases. Check both the exit status and [machine result](https://libtmux.org/en/swift/latest/workspace/reference/output/). An empty successful search and a failed pattern are different outcomes. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Search workspaces Source: https://libtmux.org/en/ts/latest/workspace/cli/search/ > Search the fields of discovered workspace documents. Search the fields of discovered workspace documents. Use literal matching when the input should be treated as text rather than a regular expression. ## Find a session name ```console $ tmux-workspace search \ --json \ --fixed-strings \ --field session \ workspace ``` Repeat `--field` to restrict additional fields. Query terms combine with AND; `--any` selects OR. `--ignore-case`, `--smart-case`, `--word-regexp`, and `--invert-match` control matching. Inspect the installed `search --help` for supported field names and aliases. Check both the exit status and [machine result](https://libtmux.org/en/ts/latest/workspace/reference/output/). An empty successful search and a failed pattern are different outcomes. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Evaluate in a workspace Source: https://libtmux.org/en/csharp/latest/workspace/cli/shell/ > Use the optional Python runtime to inspect a workspace through the native command. `tmux-workspace shell` opens the optional Python inspection environment for a loaded session. Code passed to `-c` executes in that environment, with tmux objects such as `server`, `session`, `window` and `pane` available. ## Runtime requirement Install tmuxp 1.74.0 in a separate Python environment and set `TMUX_WORKSPACE_PYTHON` to that environment's Python executable. The native CLI checks the runtime before evaluating code. Ordinary workspace loading does not require this inspection runtime. ## Evaluate with a selected server Continue the [installation walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/) through its detached load. Select its socket, session and window: ```console $ tmux-workspace shell \ -S "$WORKSPACE_TMP/tmux.sock" \ -c 'print(pane.pane_id)' \ --json \ workspace-guide editor ``` The result includes captured output and child status. Check the command's exit status before consuming it. An interactive shell needs a terminal; use `-c` when stdout belongs to automation. `shell --help` lists backend and startup choices. Optional shell backends must be installed in the selected Python environment. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Evaluate in a workspace Source: https://libtmux.org/en/cxx/latest/workspace/cli/shell/ > Use the optional Python runtime to inspect a workspace through the native command. `tmux-workspace shell` opens the optional Python inspection environment for a loaded session. Code passed to `-c` executes in that environment, with tmux objects such as [`server`](), `session`, `window` and `pane` available. ## Runtime requirement Install tmuxp 1.74.0 in a separate Python environment and set `TMUX_WORKSPACE_PYTHON` to that environment's Python executable. The native CLI checks the runtime before evaluating code. Ordinary workspace loading does not require this inspection runtime. ## Evaluate with a selected server Continue the [installation walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/) through its detached load. Select its socket, session and window: ```console $ tmux-workspace shell \ -S "$WORKSPACE_TMP/tmux.sock" \ -c 'print(pane.pane_id)' \ --json \ workspace-guide editor ``` The result includes captured output and child status. Check the command's exit status before consuming it. An interactive shell needs a terminal; use `-c` when stdout belongs to automation. `shell --help` lists backend and startup choices. Optional shell backends must be installed in the selected Python environment. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Evaluate in a workspace Source: https://libtmux.org/en/go/latest/workspace/cli/shell/ > Use the optional Python runtime to inspect a workspace through the native command. `tmux-workspace shell` opens the optional Python inspection environment for a loaded session. Code passed to `-c` executes in that environment, with tmux objects such as `server`, `session`, `window` and `pane` available. ## Runtime requirement Install tmuxp 1.74.0 in a separate Python environment and set `TMUX_WORKSPACE_PYTHON` to that environment's Python executable. The native CLI checks the runtime before evaluating code. Ordinary workspace loading does not require this inspection runtime. ## Evaluate with a selected server Continue the [installation walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/) through its detached load. Select its socket, session and window: ```console $ tmux-workspace shell \ -S "$WORKSPACE_TMP/tmux.sock" \ -c 'print(pane.pane_id)' \ --json \ workspace-guide editor ``` The result includes captured output and child status. Check the command's exit status before consuming it. An interactive shell needs a terminal; use `-c` when stdout belongs to automation. `shell --help` lists backend and startup choices. Optional shell backends must be installed in the selected Python environment. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Evaluate in a workspace Source: https://libtmux.org/en/java/latest/workspace/cli/shell/ > Use the optional Python runtime to inspect a workspace through the native command. `tmux-workspace shell` opens the optional Python inspection environment for a loaded session. Code passed to `-c` executes in that environment, with tmux objects such as `server`, `session`, `window` and `pane` available. ## Runtime requirement Install tmuxp 1.74.0 in a separate Python environment and set `TMUX_WORKSPACE_PYTHON` to that environment's Python executable. The native CLI checks the runtime before evaluating code. Ordinary workspace loading does not require this inspection runtime. ## Evaluate with a selected server Continue the [installation walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/) through its detached load. Select its socket, session and window: ```console $ tmux-workspace shell \ -S "$WORKSPACE_TMP/tmux.sock" \ -c 'print(pane.pane_id)' \ --json \ workspace-guide editor ``` The result includes captured output and child status. Check the command's exit status before consuming it. An interactive shell needs a terminal; use `-c` when stdout belongs to automation. `shell --help` lists backend and startup choices. Optional shell backends must be installed in the selected Python environment. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Evaluate in a workspace Source: https://libtmux.org/en/py/latest/workspace/cli/shell/ > Use the optional Python runtime to inspect a workspace through the native command. Open a Python shell with tmux objects available, or pass `-c` to evaluate a Python expression and exit. After the [installation walkthrough](https://libtmux.org/en/py/latest/workspace/guides/installation/) creates its dedicated server: ```console $ tmuxp shell \ -L workspace-guide \ -c 'print(server.sessions)' ``` Optional session and window arguments select a narrower context. `--best` chooses an available backend; explicit backends such as `--ipython` need their packages installed in the same Python environment. `--use-pythonrc` and `--no-startup` control startup loading. The last occurrence wins. `--use-vi-mode` and `--no-vi-mode` follow the same ordering rule. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/shell.py). --- # Evaluate in a workspace Source: https://libtmux.org/en/rs/latest/workspace/cli/shell/ > Use the optional Python runtime to inspect a workspace through the native command. `tmux-workspace shell` opens the optional Python inspection environment for a loaded session. Code passed to `-c` executes in that environment, with tmux objects such as [`server`](), [`session`](), [`window`]() and [`pane`]() available. ## Runtime requirement Install tmuxp 1.74.0 in a separate Python environment and set `TMUX_WORKSPACE_PYTHON` to that environment's Python executable. The native CLI checks the runtime before evaluating code. Ordinary workspace loading does not require this inspection runtime. ## Evaluate with a selected server Continue the [installation walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/) through its detached load. Select its socket, session and window: ```console $ tmux-workspace shell \ -S "$WORKSPACE_TMP/tmux.sock" \ -c 'print(pane.pane_id)' \ --json \ workspace-guide editor ``` The result includes captured output and child status. Check the command's exit status before consuming it. An interactive shell needs a terminal; use `-c` when stdout belongs to automation. `shell --help` lists backend and startup choices. Optional shell backends must be installed in the selected Python environment. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Evaluate in a workspace Source: https://libtmux.org/en/swift/latest/workspace/cli/shell/ > Use the optional Python runtime to inspect a workspace through the native command. `tmux-workspace shell` opens the optional Python inspection environment for a loaded session. Code passed to `-c` executes in that environment, with tmux objects such as `server`, `session`, `window` and `pane` available. ## Runtime requirement Install tmuxp 1.74.0 in a separate Python environment and set `TMUX_WORKSPACE_PYTHON` to that environment's Python executable. The native CLI checks the runtime before evaluating code. Ordinary workspace loading does not require this inspection runtime. ## Evaluate with a selected server Continue the [installation walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/) through its detached load. Select its socket, session and window: ```console $ tmux-workspace shell \ -S "$WORKSPACE_TMP/tmux.sock" \ -c 'print(pane.pane_id)' \ --json \ workspace-guide editor ``` The result includes captured output and child status. Check the command's exit status before consuming it. An interactive shell needs a terminal; use `-c` when stdout belongs to automation. `shell --help` lists backend and startup choices. Optional shell backends must be installed in the selected Python environment. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Evaluate in a workspace Source: https://libtmux.org/en/ts/latest/workspace/cli/shell/ > Use the optional Python runtime to inspect a workspace through the native command. `tmux-workspace shell` opens the optional Python inspection environment for a loaded session. Code passed to `-c` executes in that environment, with tmux objects such as [`server`](), [`session`](), [`window`]() and [`pane`]() available. ## Runtime requirement Install tmuxp 1.74.0 in a separate Python environment and set `TMUX_WORKSPACE_PYTHON` to that environment's Python executable. The native CLI checks the runtime before evaluating code. Ordinary workspace loading does not require this inspection runtime. ## Evaluate with a selected server Continue the [installation walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/) through its detached load. Select its socket, session and window: ```console $ tmux-workspace shell \ -S "$WORKSPACE_TMP/tmux.sock" \ -c 'print(pane.pane_id)' \ --json \ workspace-guide editor ``` The result includes captured output and child status. Check the command's exit status before consuming it. An interactive shell needs a terminal; use `-c` when stdout belongs to automation. `shell --help` lists backend and startup choices. Optional shell backends must be installed in the selected Python environment. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Import a workspace Source: https://libtmux.org/en/csharp/latest/workspace/cli/import/ > Choose a source format and translate it into a workspace document. Translate a saved Teamocil or tmuxinator configuration into a native workspace document. Import reads and translates the file without creating tmux sessions or running its pane commands. - [Teamocil](https://libtmux.org/en/csharp/latest/workspace/cli/import-teamocil/) translates a session with named windows and panes. - [tmuxinator](https://libtmux.org/en/csharp/latest/workspace/cli/import-tmuxinator/) translates a project with ordered windows. ```console $ tmux-workspace import --help ``` Select a child command and an explicit source path. Preview with `--json` before choosing `--save-to`. An existing destination requires `--force`. Review commands, directories and layout in the translated document before loading it. Source features the importer cannot preserve fail visibly. Use [convert](https://libtmux.org/en/csharp/latest/workspace/cli/convert/) to change YAML/JSON encoding without translating fields. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Import a workspace Source: https://libtmux.org/en/cxx/latest/workspace/cli/import/ > Choose a source format and translate it into a workspace document. Translate a saved Teamocil or tmuxinator configuration into a native workspace document. Import reads and translates the file without creating tmux sessions or running its pane commands. - [Teamocil](https://libtmux.org/en/cxx/latest/workspace/cli/import-teamocil/) translates a session with named windows and panes. - [tmuxinator](https://libtmux.org/en/cxx/latest/workspace/cli/import-tmuxinator/) translates a project with ordered windows. ```console $ tmux-workspace import --help ``` Select a child command and an explicit source path. Preview with `--json` before choosing `--save-to`. An existing destination requires `--force`. Review commands, directories and layout in the translated document before loading it. Source features the importer cannot preserve fail visibly. Use [convert](https://libtmux.org/en/cxx/latest/workspace/cli/convert/) to change YAML/JSON encoding without translating fields. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Import a workspace Source: https://libtmux.org/en/go/latest/workspace/cli/import/ > Choose a source format and translate it into a workspace document. Translate a saved Teamocil or tmuxinator configuration into a native workspace document. Import reads and translates the file without creating tmux sessions or running its pane commands. - [Teamocil](https://libtmux.org/en/go/latest/workspace/cli/import-teamocil/) translates a session with named windows and panes. - [tmuxinator](https://libtmux.org/en/go/latest/workspace/cli/import-tmuxinator/) translates a project with ordered windows. ```console $ tmux-workspace import --help ``` Select a child command and an explicit source path. Preview with `--json` before choosing `--save-to`. An existing destination requires `--force`. Review commands, directories and layout in the translated document before loading it. Source features the importer cannot preserve fail visibly. Use [convert](https://libtmux.org/en/go/latest/workspace/cli/convert/) to change YAML/JSON encoding without translating fields. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Import a workspace Source: https://libtmux.org/en/java/latest/workspace/cli/import/ > Choose a source format and translate it into a workspace document. Translate a saved Teamocil or tmuxinator configuration into a native workspace document. Import reads and translates the file without creating tmux sessions or running its pane commands. - [Teamocil](https://libtmux.org/en/java/latest/workspace/cli/import-teamocil/) translates a session with named windows and panes. - [tmuxinator](https://libtmux.org/en/java/latest/workspace/cli/import-tmuxinator/) translates a project with ordered windows. ```console $ tmux-workspace import --help ``` Select a child command and an explicit source path. Preview with `--json` before choosing `--save-to`. An existing destination requires `--force`. Review commands, directories and layout in the translated document before loading it. Source features the importer cannot preserve fail visibly. Use [convert](https://libtmux.org/en/java/latest/workspace/cli/convert/) to change YAML/JSON encoding without translating fields. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Import a workspace Source: https://libtmux.org/en/py/latest/workspace/cli/import/ > Choose a source format and translate it into a workspace document. Use `tmuxp import teamocil` or `tmuxp import tmuxinator` to translate a saved workspace. Each child command requires a source. The parent groups the importers and accepts `--help`. - [Teamocil](https://libtmux.org/en/py/latest/workspace/cli/import-teamocil/) imports its session and window structure. - [tmuxinator](https://libtmux.org/en/py/latest/workspace/cli/import-tmuxinator/) imports its project structure. Review the converted commands and directories before loading the result. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/import_config.py). --- # Import a workspace Source: https://libtmux.org/en/rs/latest/workspace/cli/import/ > Choose a source format and translate it into a workspace document. Translate a saved Teamocil or tmuxinator configuration into a native workspace document. Import reads and translates the file without creating tmux sessions or running its pane commands. - [Teamocil](https://libtmux.org/en/rs/latest/workspace/cli/import-teamocil/) translates a session with named windows and panes. - [tmuxinator](https://libtmux.org/en/rs/latest/workspace/cli/import-tmuxinator/) translates a project with ordered windows. ```console $ tmux-workspace import --help ``` Select a child command and an explicit source path. Preview with `--json` before choosing `--save-to`. An existing destination requires `--force`. Review commands, directories and layout in the translated document before loading it. Source features the importer cannot preserve fail visibly. Use [convert](https://libtmux.org/en/rs/latest/workspace/cli/convert/) to change YAML/JSON encoding without translating fields. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Import a workspace Source: https://libtmux.org/en/swift/latest/workspace/cli/import/ > Choose a source format and translate it into a workspace document. Translate a saved Teamocil or tmuxinator configuration into a native workspace document. Import reads and translates the file without creating tmux sessions or running its pane commands. - [Teamocil](https://libtmux.org/en/swift/latest/workspace/cli/import-teamocil/) translates a session with named windows and panes. - [tmuxinator](https://libtmux.org/en/swift/latest/workspace/cli/import-tmuxinator/) translates a project with ordered windows. ```console $ tmux-workspace import --help ``` Select a child command and an explicit source path. Preview with `--json` before choosing `--save-to`. An existing destination requires `--force`. Review commands, directories and layout in the translated document before loading it. Source features the importer cannot preserve fail visibly. Use [convert](https://libtmux.org/en/swift/latest/workspace/cli/convert/) to change YAML/JSON encoding without translating fields. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Import a workspace Source: https://libtmux.org/en/ts/latest/workspace/cli/import/ > Choose a source format and translate it into a workspace document. Translate a saved Teamocil or tmuxinator configuration into a native workspace document. Import reads and translates the file without creating tmux sessions or running its pane commands. - [Teamocil](https://libtmux.org/en/ts/latest/workspace/cli/import-teamocil/) translates a session with named windows and panes. - [tmuxinator](https://libtmux.org/en/ts/latest/workspace/cli/import-tmuxinator/) translates a project with ordered windows. ```console $ tmux-workspace import --help ``` Select a child command and an explicit source path. Preview with `--json` before choosing `--save-to`. An existing destination requires `--force`. Review commands, directories and layout in the translated document before loading it. Source features the importer cannot preserve fail visibly. Use [convert](https://libtmux.org/en/ts/latest/workspace/cli/convert/) to change YAML/JSON encoding without translating fields. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Import from Teamocil Source: https://libtmux.org/en/csharp/latest/workspace/cli/import-teamocil/ > Translate Teamocil windows and pane commands into a workspace document. Import a Teamocil file without starting tmux. Save this source as `teamocil.yaml`: ```yaml title="teamocil.yaml" session: name: imported-team windows: - name: editor layout: even-horizontal panes: - commands: [printf ready] - commands: [printf second] ``` ## Preview the translation ```console $ tmux-workspace import teamocil --json ./teamocil.yaml ``` The translated document preserves window and pane order. Several commands in one Teamocil `commands` list become one semicolon-separated shell input in that pane. Review the absolute working directories selected by the import. ## Save the workspace ```console $ tmux-workspace import teamocil \ --json \ --workspace-format yaml \ --save-to imported-teamocil.yaml \ ./teamocil.yaml ``` Use `--force` only to replace an existing destination deliberately. Unsupported fields, such as pane widths and filters, fail before saving. Conversion does not prove that a command or directory will be available when you [load](https://libtmux.org/en/csharp/latest/workspace/cli/load/) the result. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Import from Teamocil Source: https://libtmux.org/en/cxx/latest/workspace/cli/import-teamocil/ > Translate Teamocil windows and pane commands into a workspace document. Import a Teamocil file without starting tmux. Save this source as `teamocil.yaml`: ```yaml title="teamocil.yaml" session: name: imported-team windows: - name: editor layout: even-horizontal panes: - commands: [printf ready] - commands: [printf second] ``` ## Preview the translation ```console $ tmux-workspace import teamocil --json ./teamocil.yaml ``` The translated document preserves window and pane order. Several commands in one Teamocil `commands` list become one semicolon-separated shell input in that pane. Review the absolute working directories selected by the import. ## Save the workspace ```console $ tmux-workspace import teamocil \ --json \ --workspace-format yaml \ --save-to imported-teamocil.yaml \ ./teamocil.yaml ``` Use `--force` only to replace an existing destination deliberately. Unsupported fields, such as pane widths and filters, fail before saving. Conversion does not prove that a command or directory will be available when you [load](https://libtmux.org/en/cxx/latest/workspace/cli/load/) the result. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Import from Teamocil Source: https://libtmux.org/en/go/latest/workspace/cli/import-teamocil/ > Translate Teamocil windows and pane commands into a workspace document. Import a Teamocil file without starting tmux. Save this source as `teamocil.yaml`: ```yaml title="teamocil.yaml" session: name: imported-team windows: - name: editor layout: even-horizontal panes: - commands: [printf ready] - commands: [printf second] ``` ## Preview the translation ```console $ tmux-workspace import teamocil --json ./teamocil.yaml ``` The translated document preserves window and pane order. Several commands in one Teamocil `commands` list become one semicolon-separated shell input in that pane. Review the absolute working directories selected by the import. ## Save the workspace ```console $ tmux-workspace import teamocil \ --json \ --workspace-format yaml \ --save-to imported-teamocil.yaml \ ./teamocil.yaml ``` Use `--force` only to replace an existing destination deliberately. Unsupported fields, such as pane widths and filters, fail before saving. Conversion does not prove that a command or directory will be available when you [load](https://libtmux.org/en/go/latest/workspace/cli/load/) the result. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Import from Teamocil Source: https://libtmux.org/en/java/latest/workspace/cli/import-teamocil/ > Translate Teamocil windows and pane commands into a workspace document. Import a Teamocil file without starting tmux. Save this source as `teamocil.yaml`: ```yaml title="teamocil.yaml" session: name: imported-team windows: - name: editor layout: even-horizontal panes: - commands: [printf ready] - commands: [printf second] ``` ## Preview the translation ```console $ tmux-workspace import teamocil --json ./teamocil.yaml ``` The translated document preserves window and pane order. Several commands in one Teamocil [`commands`]() list become one semicolon-separated shell input in that pane. Review the absolute working directories selected by the import. ## Save the workspace ```console $ tmux-workspace import teamocil \ --json \ --workspace-format yaml \ --save-to imported-teamocil.yaml \ ./teamocil.yaml ``` Use `--force` only to replace an existing destination deliberately. Unsupported fields, such as pane widths and filters, fail before saving. Conversion does not prove that a command or directory will be available when you [load](https://libtmux.org/en/java/latest/workspace/cli/load/) the result. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Import from Teamocil Source: https://libtmux.org/en/py/latest/workspace/cli/import-teamocil/ > Translate Teamocil windows and pane commands into a workspace document. Translate a Teamocil workspace into tmuxp configuration, review the result, and select its saved representation. ## Select an existing source With [`project.yml`](https://libtmux.org/en/py/latest/workspace/guides/discovery/) already present in the Teamocil configuration directory: ```console $ tmuxp import teamocil project ``` The source lookup uses [`~/.teamocil`](https://libtmux.org/en/py/latest/workspace/cli/import-teamocil/). A source argument is effectively required: although its positional action has optional arity, it belongs to a required exclusive group, and omission exits 2. The reference previews and saves the transformed document interactively. Inspect translated commands and directories before loading the result. See [output](https://libtmux.org/en/py/latest/workspace/reference/output/) for the command's formats. An extensionless name searches the configured source directory. A filename with an extension is resolved relative to the current directory unless you provide an explicit path. ## Arguments and flags | Argument or flags | Arity / default | Choices or meaning | | --- | --- | --- | | `workspace_file` | effectively required | `nargs="?"` belongs to a required exclusive group; omission exits 2. Source lookup uses [`~/.teamocil`](https://libtmux.org/en/py/latest/workspace/cli/import-teamocil/). | All commands accept `-h` / `--help`. Root options precede the command; see the [CLI overview](https://libtmux.org/en/py/latest/workspace/cli/). The [output reference](https://libtmux.org/en/py/latest/workspace/reference/output/) describes the formats supported by each command. [Parser and implementation source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/import_config.py). [tmuxp reference source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Import from Teamocil Source: https://libtmux.org/en/rs/latest/workspace/cli/import-teamocil/ > Translate Teamocil windows and pane commands into a workspace document. Import a Teamocil file without starting tmux. Save this source as `teamocil.yaml`: ```yaml title="teamocil.yaml" session: name: imported-team windows: - name: editor layout: even-horizontal panes: - commands: [printf ready] - commands: [printf second] ``` ## Preview the translation ```console $ tmux-workspace import teamocil --json ./teamocil.yaml ``` The translated document preserves window and pane order. Several commands in one Teamocil `commands` list become one semicolon-separated shell input in that pane. Review the absolute working directories selected by the import. ## Save the workspace ```console $ tmux-workspace import teamocil \ --json \ --workspace-format yaml \ --save-to imported-teamocil.yaml \ ./teamocil.yaml ``` Use `--force` only to replace an existing destination deliberately. Unsupported fields, such as pane widths and filters, fail before saving. Conversion does not prove that a command or directory will be available when you [load](https://libtmux.org/en/rs/latest/workspace/cli/load/) the result. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Import from Teamocil Source: https://libtmux.org/en/swift/latest/workspace/cli/import-teamocil/ > Translate Teamocil windows and pane commands into a workspace document. Import a Teamocil file without starting tmux. Save this source as `teamocil.yaml`: ```yaml title="teamocil.yaml" session: name: imported-team windows: - name: editor layout: even-horizontal panes: - commands: [printf ready] - commands: [printf second] ``` ## Preview the translation ```console $ tmux-workspace import teamocil --json ./teamocil.yaml ``` The translated document preserves window and pane order. Several commands in one Teamocil [`commands`]() list become one semicolon-separated shell input in that pane. Review the absolute working directories selected by the import. ## Save the workspace ```console $ tmux-workspace import teamocil \ --json \ --workspace-format yaml \ --save-to imported-teamocil.yaml \ ./teamocil.yaml ``` Use `--force` only to replace an existing destination deliberately. Unsupported fields, such as pane widths and filters, fail before saving. Conversion does not prove that a command or directory will be available when you [load](https://libtmux.org/en/swift/latest/workspace/cli/load/) the result. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Import from Teamocil Source: https://libtmux.org/en/ts/latest/workspace/cli/import-teamocil/ > Translate Teamocil windows and pane commands into a workspace document. Import a Teamocil file without starting tmux. Save this source as `teamocil.yaml`: ```yaml title="teamocil.yaml" session: name: imported-team windows: - name: editor layout: even-horizontal panes: - commands: [printf ready] - commands: [printf second] ``` ## Preview the translation ```console $ tmux-workspace import teamocil --json ./teamocil.yaml ``` The translated document preserves window and pane order. Several commands in one Teamocil [`commands`]() list become one semicolon-separated shell input in that pane. Review the absolute working directories selected by the import. ## Save the workspace ```console $ tmux-workspace import teamocil \ --json \ --workspace-format yaml \ --save-to imported-teamocil.yaml \ ./teamocil.yaml ``` Use `--force` only to replace an existing destination deliberately. Unsupported fields, such as pane widths and filters, fail before saving. Conversion does not prove that a command or directory will be available when you [load](https://libtmux.org/en/ts/latest/workspace/cli/load/) the result. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Import from tmuxinator Source: https://libtmux.org/en/csharp/latest/workspace/cli/import-tmuxinator/ > Translate a tmuxinator project into a workspace document. Import a saved tmuxinator project without starting tmux. Save this source as `tmuxinator.yaml`: ```yaml title="tmuxinator.yaml" name: imported-project windows: - editor: - printf ready - printf second ``` ## Preview the translation ```console $ tmux-workspace import tmuxinator --json ./tmuxinator.yaml ``` The window's command list remains sequential commands in one pane. Use an explicit source `panes` list when the project needs separate panes. ## Save the workspace ```console $ tmux-workspace import tmuxinator \ --json \ --workspace-format yaml \ --save-to imported-tmuxinator.yaml \ ./tmuxinator.yaml ``` Existing destinations require `--force`. The importer rejects unexpanded ERB templates and unsupported lifecycle or runtime fields before writing. It does not evaluate Ruby. Review the translated commands and absolute directories before [loading](https://libtmux.org/en/csharp/latest/workspace/cli/load/) the file. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Import from tmuxinator Source: https://libtmux.org/en/cxx/latest/workspace/cli/import-tmuxinator/ > Translate a tmuxinator project into a workspace document. Import a saved tmuxinator project without starting tmux. Save this source as `tmuxinator.yaml`: ```yaml title="tmuxinator.yaml" name: imported-project windows: - editor: - printf ready - printf second ``` ## Preview the translation ```console $ tmux-workspace import tmuxinator --json ./tmuxinator.yaml ``` The window's command list remains sequential commands in one pane. Use an explicit source [`panes`]() list when the project needs separate panes. ## Save the workspace ```console $ tmux-workspace import tmuxinator \ --json \ --workspace-format yaml \ --save-to imported-tmuxinator.yaml \ ./tmuxinator.yaml ``` Existing destinations require `--force`. The importer rejects unexpanded ERB templates and unsupported lifecycle or runtime fields before writing. It does not evaluate Ruby. Review the translated commands and absolute directories before [loading](https://libtmux.org/en/cxx/latest/workspace/cli/load/) the file. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Import from tmuxinator Source: https://libtmux.org/en/go/latest/workspace/cli/import-tmuxinator/ > Translate a tmuxinator project into a workspace document. Import a saved tmuxinator project without starting tmux. Save this source as `tmuxinator.yaml`: ```yaml title="tmuxinator.yaml" name: imported-project windows: - editor: - printf ready - printf second ``` ## Preview the translation ```console $ tmux-workspace import tmuxinator --json ./tmuxinator.yaml ``` The window's command list remains sequential commands in one pane. Use an explicit source `panes` list when the project needs separate panes. ## Save the workspace ```console $ tmux-workspace import tmuxinator \ --json \ --workspace-format yaml \ --save-to imported-tmuxinator.yaml \ ./tmuxinator.yaml ``` Existing destinations require `--force`. The importer rejects unexpanded ERB templates and unsupported lifecycle or runtime fields before writing. It does not evaluate Ruby. Review the translated commands and absolute directories before [loading](https://libtmux.org/en/go/latest/workspace/cli/load/) the file. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Import from tmuxinator Source: https://libtmux.org/en/java/latest/workspace/cli/import-tmuxinator/ > Translate a tmuxinator project into a workspace document. Import a saved tmuxinator project without starting tmux. Save this source as `tmuxinator.yaml`: ```yaml title="tmuxinator.yaml" name: imported-project windows: - editor: - printf ready - printf second ``` ## Preview the translation ```console $ tmux-workspace import tmuxinator --json ./tmuxinator.yaml ``` The window's command list remains sequential commands in one pane. Use an explicit source `panes` list when the project needs separate panes. ## Save the workspace ```console $ tmux-workspace import tmuxinator \ --json \ --workspace-format yaml \ --save-to imported-tmuxinator.yaml \ ./tmuxinator.yaml ``` Existing destinations require `--force`. The importer rejects unexpanded ERB templates and unsupported lifecycle or runtime fields before writing. It does not evaluate Ruby. Review the translated commands and absolute directories before [loading](https://libtmux.org/en/java/latest/workspace/cli/load/) the file. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Import from tmuxinator Source: https://libtmux.org/en/py/latest/workspace/cli/import-tmuxinator/ > Translate a tmuxinator project into a workspace document. Translate a tmuxinator workspace into tmuxp configuration, preserving an explicit boundary around dynamic Ruby configuration. ## Select an existing source With [`project.yml`](https://libtmux.org/en/py/latest/workspace/guides/discovery/) already present in the configured tmuxinator directory: ```console $ tmuxp import tmuxinator project ``` `TMUXINATOR_CONFIG` overrides the source directory and expands a leading tilde. A source argument is effectively required, and omission exits 2 despite optional-looking help. The reference previews and saves the transformed document interactively. Do not interpret successful YAML parsing as support for ERB templates or arbitrary Ruby execution. Inspect the resulting commands and directories before loading. See [environment](https://libtmux.org/en/py/latest/workspace/configuration/environment/) and [output](https://libtmux.org/en/py/latest/workspace/reference/output/). An extensionless name searches the configured source directory. A filename with an extension is resolved relative to the current directory unless you provide an explicit path. ## Arguments and flags | Argument or flags | Arity / default | Choices or meaning | | --- | --- | --- | | `workspace_file` | effectively required | `nargs="?"` belongs to a required exclusive group; omission exits 2. Source lookup honors `TMUXINATOR_CONFIG`. | All commands accept `-h` / `--help`. Root options precede the command; see the [CLI overview](https://libtmux.org/en/py/latest/workspace/cli/). The [output reference](https://libtmux.org/en/py/latest/workspace/reference/output/) describes the formats supported by each command. [Parser and implementation source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/import_config.py). [tmuxp reference source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Import from tmuxinator Source: https://libtmux.org/en/rs/latest/workspace/cli/import-tmuxinator/ > Translate a tmuxinator project into a workspace document. Import a saved tmuxinator project without starting tmux. Save this source as `tmuxinator.yaml`: ```yaml title="tmuxinator.yaml" name: imported-project windows: - editor: - printf ready - printf second ``` ## Preview the translation ```console $ tmux-workspace import tmuxinator --json ./tmuxinator.yaml ``` The window's command list remains sequential commands in one pane. Use an explicit source [`panes`]() list when the project needs separate panes. ## Save the workspace ```console $ tmux-workspace import tmuxinator \ --json \ --workspace-format yaml \ --save-to imported-tmuxinator.yaml \ ./tmuxinator.yaml ``` Existing destinations require `--force`. The importer rejects unexpanded ERB templates and unsupported lifecycle or runtime fields before writing. It does not evaluate Ruby. Review the translated commands and absolute directories before [loading](https://libtmux.org/en/rs/latest/workspace/cli/load/) the file. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Import from tmuxinator Source: https://libtmux.org/en/swift/latest/workspace/cli/import-tmuxinator/ > Translate a tmuxinator project into a workspace document. Import a saved tmuxinator project without starting tmux. Save this source as `tmuxinator.yaml`: ```yaml title="tmuxinator.yaml" name: imported-project windows: - editor: - printf ready - printf second ``` ## Preview the translation ```console $ tmux-workspace import tmuxinator --json ./tmuxinator.yaml ``` The window's command list remains sequential commands in one pane. Use an explicit source [`panes`]() list when the project needs separate panes. ## Save the workspace ```console $ tmux-workspace import tmuxinator \ --json \ --workspace-format yaml \ --save-to imported-tmuxinator.yaml \ ./tmuxinator.yaml ``` Existing destinations require `--force`. The importer rejects unexpanded ERB templates and unsupported lifecycle or runtime fields before writing. It does not evaluate Ruby. Review the translated commands and absolute directories before [loading](https://libtmux.org/en/swift/latest/workspace/cli/load/) the file. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Import from tmuxinator Source: https://libtmux.org/en/ts/latest/workspace/cli/import-tmuxinator/ > Translate a tmuxinator project into a workspace document. Import a saved tmuxinator project without starting tmux. Save this source as `tmuxinator.yaml`: ```yaml title="tmuxinator.yaml" name: imported-project windows: - editor: - printf ready - printf second ``` ## Preview the translation ```console $ tmux-workspace import tmuxinator --json ./tmuxinator.yaml ``` The window's command list remains sequential commands in one pane. Use an explicit source `panes` list when the project needs separate panes. ## Save the workspace ```console $ tmux-workspace import tmuxinator \ --json \ --workspace-format yaml \ --save-to imported-tmuxinator.yaml \ ./tmuxinator.yaml ``` Existing destinations require `--force`. The importer rejects unexpanded ERB templates and unsupported lifecycle or runtime fields before writing. It does not evaluate Ruby. Review the translated commands and absolute directories before [loading](https://libtmux.org/en/ts/latest/workspace/cli/load/) the file. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # tmux-workspace CLI manual Source: https://libtmux.org/en/csharp/latest/workspace/cli/ > Use `tmux-workspace` to load, inspect and save workspace files. Use `tmux-workspace` to load, inspect and save workspace files. Complete [installation](https://libtmux.org/en/csharp/latest/workspace/guides/installation/) and put the executable on `PATH` before using these commands. ## Sessions
load
Create a session from a workspace file.
freeze
Capture a running session into a workspace document.
## Workspace files
ls
List saved configurations.
search
Find saved configurations.
edit
Open a configuration in your editor.
convert
Change a document between YAML and JSON.
import
Translate Teamocil or tmuxinator configuration.
## Diagnostics and completion
debug-info
Report runtime and tmux information.
completion
Generate completion for your shell.
## Command options Show the options accepted by the installed command: ```console $ tmux-workspace load --help ``` ## Machine output `--json` requests one JSON result. `--ndjson` requests a stream of records and takes precedence when both are present. Select detached loading with `-d` when automating session creation. Check the exit status as well as the result; a failed load can leave completed tmux operations in place. The [output reference](https://libtmux.org/en/csharp/latest/workspace/reference/output/) describes the result records, and [automation](https://libtmux.org/en/csharp/latest/workspace/guides/automation/) covers scripts. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # tmux-workspace CLI manual Source: https://libtmux.org/en/cxx/latest/workspace/cli/ > Use `tmux-workspace` to load, inspect and save workspace files. Use `tmux-workspace` to load, inspect and save workspace files. Complete [installation](https://libtmux.org/en/cxx/latest/workspace/guides/installation/) and put the executable on `PATH` before using these commands. ## Sessions
load
Create a session from a workspace file.
freeze
Capture a running session into a workspace document.
## Workspace files
ls
List saved configurations.
search
Find saved configurations.
edit
Open a configuration in your editor.
convert
Change a document between YAML and JSON.
import
Translate Teamocil or tmuxinator configuration.
## Diagnostics and completion
debug-info
Report runtime and tmux information.
completion
Generate completion for your shell.
## Command options Show the options accepted by the installed command: ```console $ tmux-workspace load --help ``` ## Machine output `--json` requests one JSON result. `--ndjson` requests a stream of records and takes precedence when both are present. Select detached loading with `-d` when automating session creation. Check the exit status as well as the result; a failed load can leave completed tmux operations in place. The [output reference](https://libtmux.org/en/cxx/latest/workspace/reference/output/) describes the result records, and [automation](https://libtmux.org/en/cxx/latest/workspace/guides/automation/) covers scripts. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # tmux-workspace CLI manual Source: https://libtmux.org/en/go/latest/workspace/cli/ > Use `tmux-workspace` to load, inspect and save workspace files. Use `tmux-workspace` to load, inspect and save workspace files. Complete [installation](https://libtmux.org/en/go/latest/workspace/guides/installation/) and put the executable on `PATH` before using these commands. ## Sessions
load
Create a session from a workspace file.
freeze
Capture a running session into a workspace document.
## Workspace files
ls
List saved configurations.
search
Find saved configurations.
edit
Open a configuration in your editor.
convert
Change a document between YAML and JSON.
import
Translate Teamocil or tmuxinator configuration.
## Diagnostics and completion
debug-info
Report runtime and tmux information.
completion
Generate completion for your shell.
## Command options Show the options accepted by the installed command: ```console $ tmux-workspace load --help ``` ## Machine output `--json` requests one JSON result. `--ndjson` requests a stream of records and takes precedence when both are present. Select detached loading with `-d` when automating session creation. Check the exit status as well as the result; a failed load can leave completed tmux operations in place. The [output reference](https://libtmux.org/en/go/latest/workspace/reference/output/) describes the result records, and [automation](https://libtmux.org/en/go/latest/workspace/guides/automation/) covers scripts. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # tmux-workspace CLI manual Source: https://libtmux.org/en/java/latest/workspace/cli/ > Use `tmux-workspace` to load, inspect and save workspace files. Use `tmux-workspace` to load, inspect and save workspace files. Complete [installation](https://libtmux.org/en/java/latest/workspace/guides/installation/) and put the executable on `PATH` before using these commands. ## Sessions
load
Create a session from a workspace file.
freeze
Capture a running session into a workspace document.
## Workspace files
ls
List saved configurations.
search
Find saved configurations.
edit
Open a configuration in your editor.
convert
Change a document between YAML and JSON.
import
Translate Teamocil or tmuxinator configuration.
## Diagnostics and completion
debug-info
Report runtime and tmux information.
completion
Generate completion for your shell.
## Command options Show the options accepted by the installed command: ```console $ tmux-workspace load --help ``` ## Machine output `--json` requests one JSON result. `--ndjson` requests a stream of records and takes precedence when both are present. Select detached loading with `-d` when automating session creation. Check the exit status as well as the result; a failed load can leave completed tmux operations in place. The [output reference](https://libtmux.org/en/java/latest/workspace/reference/output/) describes the result records, and [automation](https://libtmux.org/en/java/latest/workspace/guides/automation/) covers scripts. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # tmux-workspace CLI manual Source: https://libtmux.org/en/rs/latest/workspace/cli/ > Use `tmux-workspace` to load, inspect and save workspace files. Use `tmux-workspace` to load, inspect and save workspace files. Complete [installation](https://libtmux.org/en/rs/latest/workspace/guides/installation/) and put the executable on `PATH` before using these commands. ## Sessions
load
Create a session from a workspace file.
freeze
Capture a running session into a workspace document.
## Workspace files
ls
List saved configurations.
search
Find saved configurations.
edit
Open a configuration in your editor.
convert
Change a document between YAML and JSON.
import
Translate Teamocil or tmuxinator configuration.
## Diagnostics and completion
debug-info
Report runtime and tmux information.
completion
Generate completion for your shell.
## Command options Show the options accepted by the installed command: ```console $ tmux-workspace load --help ``` ## Machine output `--json` requests one JSON result. `--ndjson` requests a stream of records and takes precedence when both are present. Select detached loading with `-d` when automating session creation. Check the exit status as well as the result; a failed load can leave completed tmux operations in place. The [output reference](https://libtmux.org/en/rs/latest/workspace/reference/output/) describes the result records, and [automation](https://libtmux.org/en/rs/latest/workspace/guides/automation/) covers scripts. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # tmux-workspace CLI manual Source: https://libtmux.org/en/swift/latest/workspace/cli/ > Use `tmux-workspace` to load, inspect and save workspace files. Use `tmux-workspace` to load, inspect and save workspace files. Complete [installation](https://libtmux.org/en/swift/latest/workspace/guides/installation/) and put the executable on `PATH` before using these commands. ## Sessions
load
Create a session from a workspace file.
freeze
Capture a running session into a workspace document.
## Workspace files
ls
List saved configurations.
search
Find saved configurations.
edit
Open a configuration in your editor.
convert
Change a document between YAML and JSON.
import
Translate Teamocil or tmuxinator configuration.
## Diagnostics and completion
debug-info
Report runtime and tmux information.
completion
Generate completion for your shell.
## Command options Show the options accepted by the installed command: ```console $ tmux-workspace load --help ``` ## Machine output `--json` requests one JSON result. `--ndjson` requests a stream of records and takes precedence when both are present. Select detached loading with `-d` when automating session creation. Check the exit status as well as the result; a failed load can leave completed tmux operations in place. The [output reference](https://libtmux.org/en/swift/latest/workspace/reference/output/) describes the result records, and [automation](https://libtmux.org/en/swift/latest/workspace/guides/automation/) covers scripts. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # tmux-workspace CLI manual Source: https://libtmux.org/en/ts/latest/workspace/cli/ > Use `tmux-workspace` to load, inspect and save workspace files. Use `tmux-workspace` to load, inspect and save workspace files. Complete [installation](https://libtmux.org/en/ts/latest/workspace/guides/installation/) and put the executable on `PATH` before using these commands. ## Sessions
load
Create a session from a workspace file.
freeze
Capture a running session into a workspace document.
## Workspace files
ls
List saved configurations.
search
Find saved configurations.
edit
Open a configuration in your editor.
convert
Change a document between YAML and JSON.
import
Translate Teamocil or tmuxinator configuration.
## Diagnostics and completion
debug-info
Report runtime and tmux information.
completion
Generate completion for your shell.
## Command options Show the options accepted by the installed command: ```console $ tmux-workspace load --help ``` ## Machine output `--json` requests one JSON result. `--ndjson` requests a stream of records and takes precedence when both are present. Select detached loading with `-d` when automating session creation. Check the exit status as well as the result; a failed load can leave completed tmux operations in place. The [output reference](https://libtmux.org/en/ts/latest/workspace/reference/output/) describes the result records, and [automation](https://libtmux.org/en/ts/latest/workspace/guides/automation/) covers scripts. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # tmuxp CLI manual Source: https://libtmux.org/en/py/latest/workspace/cli/ > Use tmuxp to load, inspect and save workspace configurations. Use `tmuxp` to load, inspect and save workspace configurations. [Install tmuxp](https://libtmux.org/en/py/latest/workspace/guides/installation/) separately from the core [`libtmux`]() package. ## Sessions
load
Build a session from files or saved workspace names.
freeze
Export a running session to a workspace configuration.
## Workspace files
ls
List saved configurations.
search
Find configurations by name or content.
edit
Open a workspace in an editor.
convert
Change a workspace between YAML and JSON representation.
import
Translate Teamocil or tmuxinator configuration.
## Diagnostics and shell
debug-info
Report runtime and tmux information.
shell
Evaluate Python with tmux context.
## Command options Root options precede the subcommand: ```console $ tmuxp --color never ls ``` Short flags belong to their command: `search -S` selects smart-case matching, while `load -S` selects a socket path. Show the installed command options before using a flag: ```console $ tmuxp load --help ``` Machine output is command-specific. Read each command reference for its supported formats and empty-result behavior. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Shell completion Source: https://libtmux.org/en/csharp/latest/workspace/cli/completion/ > Generate completion for the installed workspace command. Generate completion using the installed `tmux-workspace` command. The script matches that executable's command definitions. ## Enable Bash completion ```console $ tmux-workspace --generate bash > tmux-workspace.bash ``` Check the generated script before loading it in your current Bash session: ```console $ bash -n tmux-workspace.bash ``` ```bash source ./tmux-workspace.bash ``` Keep the script in your shell's completion directory to load it in later sessions. Regenerate it after upgrading the CLI. ## Other shells `--generate zsh` and `--generate fish` generate the other supported shells. Follow the selected shell's completion setup before sourcing its script. Generating a script does not start tmux or load workspace files. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Shell completion Source: https://libtmux.org/en/cxx/latest/workspace/cli/completion/ > Generate completion for the installed workspace command. Generate completion using the installed `tmux-workspace` command. The script matches that executable's command definitions. ## Enable Bash completion ```console $ tmux-workspace --generate-completion bash > tmux-workspace.bash ``` Check the generated script before loading it in your current Bash session: ```console $ bash -n tmux-workspace.bash ``` ```bash source ./tmux-workspace.bash ``` Keep the script in your shell's completion directory to load it in later sessions. Regenerate it after upgrading the CLI. ## Other shells `--generate-completion` also accepts `zsh` and `fish`. Follow the selected shell's completion setup before sourcing its script. Generating a script does not start tmux or load workspace files. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Shell completion Source: https://libtmux.org/en/go/latest/workspace/cli/completion/ > Generate completion for the installed workspace command. Generate completion using the installed `tmux-workspace` command. The script matches that executable's command definitions. ## Enable Bash completion ```console $ tmux-workspace --generate-completion bash > tmux-workspace.bash ``` Check the generated script before loading it in your current Bash session: ```console $ bash -n tmux-workspace.bash ``` ```bash source ./tmux-workspace.bash ``` Keep the script in your shell's completion directory to load it in later sessions. Regenerate it after upgrading the CLI. ## Other shells `--generate-completion` also accepts `zsh`, `fish` and `powershell`. Follow the selected shell's completion setup before sourcing its script. Generating a script does not start tmux or load workspace files. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Shell completion Source: https://libtmux.org/en/java/latest/workspace/cli/completion/ > Generate completion for the installed workspace command. Generate completion using the installed `tmux-workspace` command. The script matches that executable's command definitions. ## Enable Bash completion ```console $ tmux-workspace --generate bash > tmux-workspace.bash ``` Check the generated script before loading it in your current Bash session: ```console $ bash -n tmux-workspace.bash ``` ```bash source ./tmux-workspace.bash ``` Keep the script in your shell's completion directory to load it in later sessions. Regenerate it after upgrading the CLI. ## Other shells The CLI provides Bash completion. Follow the selected shell's completion setup before sourcing its script. Generating a script does not start tmux or load workspace files. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Shell completion Source: https://libtmux.org/en/py/latest/workspace/cli/completion/ > Generate completion for the installed workspace command. tmuxp uses the optional `shtab` package to generate experimental shell completion from its argparse definitions. Install it in the same Python environment as tmuxp, then follow the [completion setup](https://tmuxp.git-pull.com/cli/completion/) for your shell. Generate the script again after upgrading tmuxp so it matches the installed parser. The parser is available through [`tmuxp.cli.create_parser`](). [Parser source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Shell completion Source: https://libtmux.org/en/rs/latest/workspace/cli/completion/ > Generate completion for the installed workspace command. Generate completion using the installed `tmux-workspace` command. The script matches that executable's command definitions. ## Enable Bash completion ```console $ tmux-workspace --generate bash > tmux-workspace.bash ``` Check the generated script before loading it in your current Bash session: ```console $ bash -n tmux-workspace.bash ``` ```bash source ./tmux-workspace.bash ``` Keep the script in your shell's completion directory to load it in later sessions. Regenerate it after upgrading the CLI. ## Other shells `--generate` also accepts `zsh`, `fish`, `powershell` and `elvish`. Follow the selected shell's completion setup before sourcing its script. Generating a script does not start tmux or load workspace files. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Shell completion Source: https://libtmux.org/en/swift/latest/workspace/cli/completion/ > Generate completion for the installed workspace command. Generate completion using the installed `tmux-workspace` command. The script matches that executable's command definitions. ## Enable Bash completion ```console $ tmux-workspace --generate-completion-script bash > tmux-workspace.bash ``` Check the generated script before loading it in your current Bash session: ```console $ bash -n tmux-workspace.bash ``` ```bash source ./tmux-workspace.bash ``` Keep the script in your shell's completion directory to load it in later sessions. Regenerate it after upgrading the CLI. ## Other shells `--generate-completion-script` also accepts `zsh` and `fish`. Follow the selected shell's completion setup before sourcing its script. Generating a script does not start tmux or load workspace files. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Shell completion Source: https://libtmux.org/en/ts/latest/workspace/cli/completion/ > Generate completion for the installed workspace command. Generate completion using the installed `tmux-workspace` command. The script matches that executable's command definitions. ## Enable Bash completion ```console $ tmux-workspace completion bash > tmux-workspace.bash ``` Check the generated script before loading it in your current Bash session: ```console $ bash -n tmux-workspace.bash ``` ```bash source ./tmux-workspace.bash ``` Keep the script in your shell's completion directory to load it in later sessions. Regenerate it after upgrading the CLI. ## Other shells `completion zsh` and `completion fish` generate the other supported shells. Follow the selected shell's completion setup before sourcing its script. Generating a script does not start tmux or load workspace files. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Async Source: https://libtmux.org/en/ruby/latest/guides/async/ > Run concurrent commands within an owned Async scope. Run libtmux operations inside an application-owned Async task. This gem provides a subprocess facade, ordered mapping, control replies and event subscriptions. Imports start no scheduler, tmux server or background task. Install the alpha with `gem install libtmux-async --pre`. The [complete program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/async_cancel.rb) owns an isolated server and its cleanup. This excerpt uses that server and creates the Async root: ```ruby Async do |parent| LibTmux::Async.open(parent: parent, server: server) do |scope| waiting = parent.async do scope.server.run(["wait-for", "-S", "ready", ";", "wait-for", "held"], timeout: 0.5) rescue LibTmux::Cancelled => error error end scope.server.wait_for("ready", timeout: 0.5) Example.check(scope.diagnostics.fetch(:active_process_slots) == 1, "waiting client lost its slot") captures = scope.map(scope.server.list_panes.map(&:ref), concurrency: 2) do |ref| scope.server.pane(ref).capture end Example.check(captures.all?(&:success?), "sibling captures stalled") waiting.cancel failure = waiting.wait Example.check(failure.is_a?(LibTmux::Cancelled), "cancellation lost") Example.check(failure.delivery == :possibly_sent, "cancelled dispatch claimed no effects") Example.raises(Errno::ECHILD) { Process.waitpid(failure.pid, Process::WNOHANG) } Example.check(scope.server.diagnostics.fetch(:admitted_requests).zero?, "cancelled client remains admitted") end end.wait ``` Omitting `parent:` uses the existing current Async task. The source server must outlive the scope. References keep their source binding identity. Scope exit retires its clients and joins its owned tasks; it leaves the borrowed daemon alive. A scope rejects use from another thread, process or scheduler. Create a separate scope for each scheduler thread. Interactive terminal attachment stays on the blocking core facade and raises [`UnsupportedFeatureError`]() on this facade. [`scope.server.run`]() returns the same binary [`CommandResult`]() as core. Its stdin, stdout and stderr are owned by scheduler tasks. A bounded native helper observes and reaps each child only after its final signalling handoff. Cancelling the calling task retires its client and raises [`Cancelled`]() with `:not_sent` or `:possibly_sent` delivery. An already observed exit completes its bounded drain. Repeated cancellation does not restart cleanup deadlines or replace an earlier operation failure. Deadlines cannot undo tmux effects. [`scope.map`]() returns a frozen Array in input order; independent requests may complete out of order. It caps retained items at 1024 and accounts payload bytes in strings, primitive values, [`CommandResult`](), Arrays and Hashes. Cycles and excessive nesting are refused. Application-defined results require an explicit `result_bytes:` callable returning a nonnegative Integer. Keep measured values unchanged until the map returns. These payload limits complement item counts; they are not exact Ruby heap measurements. | Scope limit | Default | | --- | --- | | Active subprocess clients | 4 | | Admitted subprocess requests, including unconsumed results | 32 | | Queued request payload | 4 MiB | | Retained process and map output payload | 8 MiB | | Per-command stdout / stderr | 1 MiB / 256 KiB | | Control connections | 4 | | Ordinary command deadline | 5 seconds | Control connections use their own request, reply and subscriber limits. Obtain one with [`scope.server.open_control(session: ref)`](). `exchange` returns guarded [`GuardedReply`]() blocks with `:boundary_window` attribution. It makes no claim of final command completion. Outside-block events arrive through [`events.next`]() or an explicit `subscribe`; consumer callbacks run outside the parser. Reliable subscriptions raise on overflow. Tail subscriptions report dropped ranges. Cancelling a dispatched, undrained exchange closes that connection. `pause_output(pane_id:)` and `resume_output(pane_id:)` retain guarded evidence and report possible output loss through gap events. A requested-action gap does not prove that the action took effect. Close a connection before passing it as `reconnect:` to [`scope.server.open_control`](); the replacement stays owned by that scope and reports a new generation plus a gap with unknown loss. Subscriptions expose their `generation`; prior subscriptions stay closed. Reconnect and resume never replay requests or missed output. The development bundle pins Async 2.46 and io-event 1.22. The [compatibility workflow](https://github.com/libtmux/libtmux-ruby/actions/workflows/compatibility.yml) exercises the selected Ruby/tmux versions on Linux and macOS and retains per-revision results. Package builds and tests do not publish this gem. --- # Concepts Source: https://libtmux.org/en/tmux/concepts/ > tmux objects, command transports, queries, and workspaces. libtmux lets you create sessions, arrange windows and panes, send commands, and read output from tmux. Start with the object hierarchy, then read about the transport, query, or workspace behavior your program needs. Use the API reference for signatures, defaults, and failure conditions. - [Server, session, window, pane](https://libtmux.org/en/tmux/concepts/server-session-window-pane/): Understand the tmux object hierarchy and attached clients. - [Control mode vs one-shot](https://libtmux.org/en/tmux/concepts/transports/): Choose subprocess commands, persistent connections, and batching. - [Filtering and queries](https://libtmux.org/en/tmux/concepts/queries/): Find objects and handle absent or ambiguous matches. - [Workspaces](https://libtmux.org/en/tmux/concepts/workspaces/): Build pane layouts from code or configuration files. --- # Concepts Source: https://libtmux.org/en/fsharp/latest/concepts/ > Understand F# handles, filters, transports and layout ownership. Use these concepts to reason about F# handles, selection and command execution. Each page includes complete programs with imports, project files, run commands and cleanup. For individual types and operations, open the [API reference](https://libtmux.org/en/fsharp/latest/reference/). For a first connection, start with [attaching to tmux](https://libtmux.org/en/fsharp/latest/guides/attaching-to-tmux/). - [Server, session, window, pane](https://libtmux.org/en/fsharp/latest/concepts/server-session-window-pane/): Navigate captured sessions, windows, and panes, and refresh their state. - [Filtering and queries](https://libtmux.org/en/fsharp/latest/concepts/queries/): Combine predicates, handle result counts, and match related windows. - [Commands and control mode](https://libtmux.org/en/fsharp/latest/concepts/transports/): Run bounded commands and manage a persistent control client. - [Layouts and repeated setup](https://libtmux.org/en/fsharp/latest/concepts/workspaces/): Create a split window and reuse a named window safely. --- # Concepts Source: https://libtmux.org/en/kotlin/latest/concepts/ > Understand Kotlin handles, filters, transports and layout ownership. Use these concepts to reason about Kotlin handles, selection and command execution. Each page includes complete programs with imports, project files, run commands and cleanup. For individual types and operations, open the [API reference](https://libtmux.org/en/kotlin/latest/reference/). For a first connection, start with [attaching to tmux](https://libtmux.org/en/kotlin/latest/guides/attaching-to-tmux/). - [Server, session, window, pane](https://libtmux.org/en/kotlin/latest/concepts/server-session-window-pane/): Navigate captured sessions, windows, and panes, and refresh their state. - [Filtering and queries](https://libtmux.org/en/kotlin/latest/concepts/queries/): Combine predicates, handle result counts, and match related windows. - [Commands and control mode](https://libtmux.org/en/kotlin/latest/concepts/transports/): Run bounded commands and manage a persistent control client. - [Layouts and repeated setup](https://libtmux.org/en/kotlin/latest/concepts/workspaces/): Create a split window and reuse a named window safely. --- # Concepts Source: https://libtmux.org/en/scala/latest/concepts/ > Understand Scala handles, filters, transports and layout ownership. Use these concepts to reason about Scala handles, selection and command execution. Each page includes complete programs with imports, project files, run commands and cleanup. For individual types and operations, open the [API reference](https://libtmux.org/en/scala/latest/reference/). For a first connection, start with [attaching to tmux](https://libtmux.org/en/scala/latest/guides/attaching-to-tmux/). - [Server, session, window, pane](https://libtmux.org/en/scala/latest/concepts/server-session-window-pane/): Navigate captured sessions, windows, and panes, and refresh their state. - [Filtering and queries](https://libtmux.org/en/scala/latest/concepts/queries/): Combine predicates, handle result counts, and match related windows. - [Commands and control mode](https://libtmux.org/en/scala/latest/concepts/transports/): Run bounded commands and manage a persistent control client. - [Layouts and repeated setup](https://libtmux.org/en/scala/latest/concepts/workspaces/): Create a split window and reuse a named window safely. --- # Server, session, window, pane Source: https://libtmux.org/en/tmux/concepts/server-session-window-pane/ > How tmux servers, sessions, windows, panes and attached clients relate to each other. libtmux models tmux's server, session, window, and pane objects: ``` Server ├── Session │ └── Window │ └── Pane └── Client (attached view) ``` A `Server` contains sessions. Each `Session` contains links to windows, and each `Window` contains panes. Commands run inside a `Pane`, where you send input and capture output. A window can be linked to more than one session. ## Stable identity, not name or index tmux assigns a unique ID to each session, window, and pane at creation. The ID remains stable for that object's lifetime even if its name or index changes: | Object | ID prefix | Example | |--------|-----------|---------| | Session | `$` | `$13` | | Window | `@` | `@3243` | | Pane | `%` | `%5433` | | Server | - | identified by socket name or path instead | Use stable IDs to identify the same tmux object across reads. Names and indexes can change while a program is running. Read the hierarchy: ```python for session in server.sessions: print(session.session_name) for window in session.windows: print(" ", window.window_index, window.window_name) for pane in window.panes: print(" ", pane.pane_id, pane.pane_current_command) ``` ```typescript for (const session of await server.sessions()) { console.log(session.name); for (const window of session.windows) { console.log(" ", window.index, window.name); for (const pane of window.panes) { console.log(" ", pane.id, pane.currentCommand); } } } ``` ```rust // Three tmux commands total, not one per object: walking down would cost a // command per session and per window. for branch in server.hierarchy().await? { let session = &branch.session; println!("{session} {} ({} windows)", session.name().to_string_lossy(), session.window_count()); for built in &branch.windows { let window = &built.window; println!(" {window} {}", window.name().to_string_lossy()); for pane in &built.panes { println!(" {pane}"); } } } ``` ```go // A snapshot reads sessions, windows, and panes in one pass; relations // resolve against it without another tmux command. snapshot, err := server.Snapshot(ctx) if err != nil { return err } for _, session := range snapshot.Sessions() { name, _ := session.Name() fmt.Printf("%s %q\n", session.ID(), name) windows, _ := session.Windows() for _, window := range windows { fmt.Printf(" %s:%d\n", window.ID(), window.Index()) panes, _ := window.Panes() for _, pane := range panes { command, _ := pane.CurrentCommand() fmt.Printf(" %s %q\n", pane.ID(), command) } } } ``` ```java for (Session session : server.sessions()) { System.out.println(session.name()); for (Window window : session.windows()) { System.out.println(" " + window.index() + " " + window.name()); for (Pane pane : window.panes()) { System.out.println(" " + pane.id().value() + " " + pane.currentCommand()); } } } ``` ```csharp foreach (Session session in await server.GetSessionsAsync()) { Console.WriteLine(session.Name); foreach (Window window in await session.GetWindowsAsync()) { Console.WriteLine($" {window.Index} {window.Name}"); foreach (Pane pane in await window.GetPanesAsync()) { Console.WriteLine($" {pane.Index} {pane.Width}x{pane.Height}"); } } } ``` ```cpp const auto sessions = server.sessions(); if (!sessions.has_value()) return 1; for (const libtmux::Session& session : *sessions) { std::printf("%s (%lld windows)\n", std::string{session.name()}.c_str(), session.window_count()); const auto windows = session.windows(); if (!windows.has_value()) continue; for (const libtmux::Window& window : *windows) { std::printf(" %s\n", std::string{window.name()}.c_str()); const auto panes = window.panes(); if (!panes.has_value()) continue; for (const libtmux::Pane& pane : *panes) { std::printf(" %s\n", std::string{pane.id()}.c_str()); } } } ``` ```swift // A snapshot reads sessions, windows, and panes in one pass; the relations // below resolve against it without another tmux command. let snapshot = try await server.snapshot() for session in snapshot.sessions { print(session.name) for window in snapshot.windows(of: session) { print(" ", window.name) for pane in snapshot.panes(of: window) { print(" ", pane.id, pane.currentCommand) } } } ``` ## Client: a view, not a child A `Client` represents a terminal attached to a session. Several clients can view the same server, and each can switch sessions or windows independently. Client fields describe the view at the time of the read. A [control-mode connection](https://libtmux.org/en/tmux/concepts/transports/) is also a client. It appears in `list-clients`, counts toward `session_attached`, and affects attachment-dependent behavior such as `destroy-unattached`. Closing the last attached client can therefore destroy a session configured with that option. ## What differs between ports Ports differ in how they read state and report failures: - **Refreshing state.** Python objects reflect their last read until you call `.refresh()`. TypeScript, Swift, and Go also provide snapshots whose relationships can be queried without another tmux command. - **Blocking and async calls.** Python and Java use blocking calls. Rust, TypeScript, C#, and Swift provide async APIs. Go uses ordinary calls with contexts for cancellation and deadlines. - **Failure handling.** Python and C# raise exceptions. C++ returns `expected`. Some commands have an expected negative answer, such as `has-session` when a session is absent; check the method's result contract before treating that answer as a failure. See [Control mode vs one-shot](https://libtmux.org/en/tmux/concepts/transports/) for command costs and connection behavior. ## Snapshots and live commands [`Server.Snapshot(ctx)`]() reads the hierarchy. The resulting relationship methods read that captured data without another tmux command. A boolean return value reports whether a relationship was captured. Use [`Session.SearchWindows`]() or [`Server.SearchPanes`]() for current live state, and check the returned error. Calls that contact tmux accept a context for cancellation and deadlines. Cancelling a mutation does not prove that tmux never received it; check the resulting state before retrying. [Errors and exceptions](https://libtmux.org/en/go/latest/topics/errors-and-exceptions/) covers failure handling. ## tmux command reference Read the tmux command references for [list-sessions](https://libtmux.org/en/tmux/latest/manual/list-sessions/), [list-windows](https://libtmux.org/en/tmux/latest/manual/list-windows/), and [list-panes](https://libtmux.org/en/tmux/latest/manual/list-panes/). The [target syntax](https://libtmux.org/en/tmux/latest/manual/full/#COMMANDS) explains IDs, names, and indexes. --- # Server, session, window, pane Source: https://libtmux.org/en/fsharp/latest/concepts/server-session-window-pane/ > Traverse captured F# handles, retain IDs and refresh after changes. Capture a hierarchy, then read its sessions, windows and panes locally. Handles retain the state they captured; a rename does not rewrite an older handle. Use a new capture to observe later changes. [`Server`](https://libtmux.org/en/fsharp/latest/reference/libtmux-fsharp-server/) is the F# helper module. It operates on the underlying [`LibTmux.Server`](https://libtmux.org/en/csharp/latest/reference/libtmux-server/) object. Choose a snapshot depth before traversal: sessions, windows or panes. A relation that was not captured is unavailable, rather than an empty collection. A session holds window placements; a window holds panes. A linked window can appear in several sessions, so traversal counts placements rather than necessarily distinct physical windows. Names can change; retain IDs when identifying a target. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and .NET SDK 10.0.302. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. ```xml title="Query.fsproj" Exe net10.0 Local ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-dotnet-dev directory=$(mktemp -d /tmp/libtmux-dotnet-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-dotnet libtmux-source && git -C libtmux-source checkout 2d99ead5aba8d968e85dcac8c9a9a518452e6ba6 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Walk sessions, windows and panes Flatten the captured children and verify the fixture contains two of each. The program also prints each session and its window. ```fsharp title="Hierarchy.fs" open System open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let run () = task { let socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") if String.IsNullOrEmpty(socket) then invalidOp "Set LIBTMUX_SOCKET_PATH to an existing socket" use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5.0)) let token = timeout.Token let! server = LibTmux.Server.ConnectAsync( ServerConnectionOptions(SocketPath = socket), token) let! captured = server |> Server.capture token SnapshotDepth.Panes let sessions = captured.Sessions let windows = sessions |> Seq.collect (fun session -> session.Windows) |> Seq.toList let panes = windows |> Seq.collect (fun window -> window.Panes) |> Seq.toList if sessions.Count <> 2 || windows.Length <> 2 || panes.Length <> 2 then failwith "Unexpected hierarchy" for session in sessions do printfn "%s: %s" session.Name session.Windows[0].Name printfn "2 sessions, 2 windows, 2 panes" } [] let main _ = try run().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ```console $ dotnet build Query.fsproj --maxcpucount:1 -p:Example=Hierarchy \ -p:DisableImplicitLibraryPacksFolder=true -p:RestorePackagesPath="$PWD/.packages" && sh run.sh dotnet run --project Query.fsproj --no-build -p:Example=Hierarchy ``` Expected program output: ```text work-one: editor work-two: logs 2 sessions, 2 windows, 2 panes ``` ## Observe a rename with a fresh read Rename the editor window. The old handle still says `editor`; the returned handle and a new server read say `renamed`. This distinction matters when a UI, another client or your own code changes tmux after a capture. ```fsharp title="Refresh.fs" open System open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let run () = task { let socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") if String.IsNullOrEmpty(socket) then invalidOp "Set LIBTMUX_SOCKET_PATH to an existing socket" use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5.0)) let token = timeout.Token let! server = LibTmux.Server.ConnectAsync( ServerConnectionOptions(SocketPath = socket), token) let! captured = server |> Server.capture token SnapshotDepth.Windows let session = captured.Sessions |> Seq.find (fun session -> session.Name = "work-one") let before = session.Windows[0] let! after = before.RenameAsync("renamed", token) if before.Name <> "editor" || after.Name <> "renamed" then failwith "Unexpected rename state" let! refreshed = server |> Server.capture token SnapshotDepth.Windows let session = refreshed.Sessions |> Seq.find (fun s -> s.Name = "work-one") let window = session.Windows[0] if window.Name <> "renamed" then failwith "Fresh read did not see the rename" printfn "%s -> %s" before.Name window.Name } [] let main _ = try run().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ```console $ dotnet build Query.fsproj --maxcpucount:1 -p:Example=Refresh \ -p:DisableImplicitLibraryPacksFolder=true -p:RestorePackagesPath="$PWD/.packages" && sh run.sh dotnet run --project Query.fsproj --no-build -p:Example=Refresh ``` Expected program output: ```text editor -> renamed ``` ## Select a target before changing it A successful lookup does not reserve a tmux object. Another client can remove it before your next command. Handle a command failure at the mutation, and refresh before deciding what to do next. See [filtering and queries](https://libtmux.org/en/fsharp/latest/concepts/queries/) for missing and ambiguous selections, and [layouts](https://libtmux.org/en/fsharp/latest/concepts/workspaces/) for creation. --- # Server, session, window, pane Source: https://libtmux.org/en/go/latest/concepts/server-session-window-pane/ > Create Go tmux objects, list the hierarchy, and distinguish captured relations from fresh reads. A [`Server`](https://libtmux.org/en/go/latest/reference/tmux-server/) addresses a tmux server through its socket. Its sessions hold window placements, and its windows hold panes. [`NewServer`](https://libtmux.org/en/go/latest/reference/tmux-newserver/) validates configuration without starting tmux. Creating a session starts tmux when the selected socket has no server. The zero Go [`Server`]() value is invalid. Use [`Server.Snapshot`](https://libtmux.org/en/go/latest/reference/tmux-server-snapshot/) to capture the hierarchy once, then traverse it locally. A snapshot performs sequential tmux listings, so it is an observation rather than an atomic transaction. Its records do not change when another command renames or removes an object. ## Setup and run Use an empty directory on Linux or macOS with Git, Go 1.26 or newer, and tmux 3.2a or newer. Save these two files and any complete Go program below. Each program includes its imports and entry point; run it by filename so other examples in the directory do not introduce duplicate `main` functions. ```text title="go.mod" module example.com/concepts go 1.26.0 require github.com/libtmux/libtmux-go v0.0.0 replace github.com/libtmux/libtmux-go => ./libtmux-source ``` The launcher starts two sessions on a private socket: `work-one` with an `editor` window and `work-two` with a `logs` window. Each pane runs `cat` to keep it alive. Every run gets a fresh fixture. The launcher stops only that server on success or failure, and retains its directory if shutdown fails. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d /tmp/libtmux-go-concepts.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the documented library revision and resolve this module's dependencies: ```console $ git clone https://github.com/libtmux/libtmux-go libtmux-source && git -C libtmux-source checkout bb06e26e116e941813ca40bf45e7e3a47d38f52a && GOWORK=off go mod tidy ``` The programs use a five-second context for tmux operations. Errors reach `main`, which reports the error and exits unsuccessfully. The launcher's cleanup runs independently of that context. A cancelled mutation can already have reached tmux; inspect the current state before retrying it. ## Create and list sessions, windows and panes [`Server.NewSession`](https://libtmux.org/en/go/latest/reference/tmux-server-newsession/) creates a detached `tools` session. [`Session.NewWindow`](https://libtmux.org/en/go/latest/reference/tmux-session-newwindow/) adds `logs` beside its initial `editor` window, and [`Window.SplitPane`](https://libtmux.org/en/go/latest/reference/tmux-window-splitpane/) adds a second pane below the first. The 100-by-30 terminal leaves enough space for the split. `cat` keeps these demonstration panes alive without shell configuration. The program checks the complete server through [`Server.Sessions`](https://libtmux.org/en/go/latest/reference/tmux-server-sessions/), [`Server.Windows`](https://libtmux.org/en/go/latest/reference/tmux-server-windows/) and [`Server.Panes`](https://libtmux.org/en/go/latest/reference/tmux-server-panes/). Each call reads fresh state. When several collections should come from the same observation, use one snapshot and its local accessors instead. A creation result does not promise captured children: check the boolean from [`Session.Windows()`](). The program captures again and uses the stable session ID to find the created session and verify its descendants. ```go title="Create.go" package main import ( "context" "errors" "fmt" "log" "os" "time" "github.com/libtmux/libtmux-go/tmux" ) func main() { if err := run(); err != nil { log.Fatal(err) } } func run() error { socket := os.Getenv("LIBTMUX_SOCKET_PATH") if socket == "" { return errors.New("run this program with run.sh") } server, err := tmux.NewServer(tmux.ServerOptions{SocketPath: socket, ConfigFile: "/dev/null"}) if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() session, err := server.NewSession(ctx, tmux.NewSessionRequest{ Name: "tools", WindowName: "editor", Command: "/bin/cat", Width: 100, Height: 30, }) if err != nil { return fmt.Errorf("create tools session: %w", err) } if _, captured := session.Windows(); captured { return errors.New("a newly created session unexpectedly includes window relations") } window, err := session.NewWindow(ctx, tmux.NewWindowRequest{ Name: tmux.Ptr("logs"), Command: "/bin/cat", }) if err != nil { return fmt.Errorf("create logs window: %w", err) } if _, err := window.SplitPane(ctx, tmux.SplitPaneRequest{Command: "/bin/cat"}); err != nil { return fmt.Errorf("split logs window: %w", err) } sessions, err := server.Sessions(ctx) if err != nil { return err } windows, err := server.Windows(ctx) if err != nil { return err } panes, err := server.Panes(ctx) if err != nil { return err } if len(sessions) != 3 || len(windows) != 4 || len(panes) != 5 { return fmt.Errorf("unexpected counts: %d sessions, %d windows, %d panes", len(sessions), len(windows), len(panes)) } fmt.Println("server: 3 sessions, 4 windows, 5 panes") snapshot, err := server.Snapshot(ctx) if err != nil { return err } captured, err := snapshot.SessionByID(session.ID()) if err != nil { return err } children, ok := captured.Windows() if !ok || len(children) != 2 { return errors.New("tools should have 2 captured windows") } descendants, ok := captured.Panes() if !ok || len(descendants) != 3 { return errors.New("tools should have 3 captured panes") } fmt.Println("tools: 2 windows, 3 panes") return nil } ``` ```console $ sh run.sh env GOWORK=off go run Create.go ``` Expected program output: ```text server: 3 sessions, 4 windows, 5 panes tools: 2 windows, 3 panes ``` ## Walk a capture and observe a rename A fresh launcher contains two sessions, one window and one pane in each. [`Session.Windows`](https://libtmux.org/en/go/latest/reference/tmux-session-windows/) and [`Window.Panes`](https://libtmux.org/en/go/latest/reference/tmux-window-panes/) read the captured relations without issuing another tmux command. Their boolean distinguishes an available empty relation from one that was never captured. Renaming `editor` returns a new record. The original window still says `editor`; a new snapshot sees `renamed`. Retain IDs across reads rather than using mutable names as identity. ```go title="Snapshot.go" package main import ( "context" "errors" "fmt" "log" "os" "time" "github.com/libtmux/libtmux-go/tmux" ) func main() { if err := run(); err != nil { log.Fatal(err) } } func run() error { socket := os.Getenv("LIBTMUX_SOCKET_PATH") if socket == "" { return errors.New("run this program with run.sh") } server, err := tmux.NewServer(tmux.ServerOptions{SocketPath: socket, ConfigFile: "/dev/null"}) if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() before, err := server.Snapshot(ctx) if err != nil { return err } if len(before.Sessions()) != 2 || len(before.Windows()) != 2 || len(before.Panes()) != 2 { return errors.New("expected the initial two-session fixture") } var editor tmux.Window found := false for _, session := range before.Sessions() { name, ok := session.Name() if !ok { return errors.New("session name was not captured") } windows, ok := session.Windows() if !ok || len(windows) != 1 { return errors.New("expected one captured window") } window := windows[0] windowName, ok := window.Name() if !ok { return errors.New("window name was not captured") } panes, ok := window.Panes() if !ok || len(panes) != 1 { return errors.New("expected one captured pane") } fmt.Printf("%s: %s, %d pane\n", name, windowName, len(panes)) if name == "work-one" { editor, found = window, true } } if !found { return errors.New("work-one is missing") } renamed, err := editor.Rename(ctx, "renamed") if err != nil { return err } oldName, oldOK := editor.Name() newName, newOK := renamed.Name() if !oldOK || !newOK || oldName != "editor" || newName != "renamed" { return errors.New("rename should return a new record without changing the old one") } after, err := server.Snapshot(ctx) if err != nil { return err } current, err := after.WindowByID(editor.ID()) if err != nil { return err } currentName, ok := current.Name() if !ok || currentName != "renamed" { return errors.New("fresh snapshot missed the rename") } fmt.Printf("captured: %s; returned: %s; fresh: %s\n", oldName, newName, currentName) return nil } ``` ```console $ sh run.sh env GOWORK=off go run Snapshot.go ``` Expected program output: ```text work-one: editor, 1 pane work-two: logs, 1 pane captured: editor; returned: renamed; fresh: renamed ``` ## Window placements and attached clients A window linked into several sessions appears once per placement in [`Snapshot.Windows()`](). Pane views also repeat for each placement. These collection lengths count views, not necessarily distinct window or pane IDs. [`Snapshot.WindowByID`]() reports [`ErrSnapshotAmbiguous`]() if an ID has several views; [`Snapshot.WindowsByID`]() returns all of them. A client is an attached terminal view, not a child pane. [`Snapshot.Clients()`]() returns the captured clients. The subprocess calls here do not attach a client. An application that opens a control connection owns that connection's cleanup; stopping a tmux server is a separate action. [Filtering and queries](https://libtmux.org/en/go/latest/concepts/queries/) covers result counts and related-object filters. [Sending keys](https://libtmux.org/en/go/latest/guides/sending-keys/) and the [complete capture program](https://libtmux.org/en/go/latest/examples/capture-pane-output/) cover input and waiting for output. The launcher owns this demonstration server; code connecting to a user's server should leave it running. --- # Server, session, window, pane Source: https://libtmux.org/en/kotlin/latest/concepts/server-session-window-pane/ > Traverse captured Kotlin handles, retain IDs and refresh after changes. Capture a hierarchy, then read its sessions, windows and panes locally. Handles retain the state they captured; a rename does not rewrite an older handle. Use a new capture to observe later changes. [`Server`](https://libtmux.org/en/kotlin/latest/reference/io-github-libtmux-kotlin-server/) selects the socket and owns client resources. [`Session`](https://libtmux.org/en/kotlin/latest/reference/io-github-libtmux-kotlin-session/), [`Window`](https://libtmux.org/en/kotlin/latest/reference/io-github-libtmux-kotlin-window/) and [`Pane`](https://libtmux.org/en/kotlin/latest/reference/io-github-libtmux-kotlin-pane/) hold captured state and send mutations through that server. The session list captures the hierarchy; walking its children reads that capture. A session holds window placements; a window holds panes. A linked window can appear in several sessions, so traversal counts placements rather than necessarily distinct physical windows. Names can change; retain IDs when identifying a target. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and JDK 25. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. The pinned source checkout supplies the Gradle wrapper and the library dependency. ```kotlin title="settings.gradle.kts" rootProject.name = "connect" includeBuild("libtmux-source") ``` ```kotlin title="build.gradle.kts" val example = providers.gradleProperty("example").getOrElse("Local") plugins { application kotlin("jvm") version "2.4.10" } repositories { mavenCentral() } dependencies { implementation("io.github.libtmux:libtmux-kotlin:0.0.1-alpha.17-SNAPSHOT") } kotlin { jvmToolchain(25) sourceSets.main { kotlin.srcDir("."); kotlin.include("${example}.kt") } } application { mainClass.set("${example}Kt") } ``` ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-java-dev directory=$(mktemp -d /tmp/libtmux-java-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Walk sessions, windows and panes Flatten the captured children and verify the fixture contains two of each. The program also prints each session and its window. ```kotlin title="Hierarchy.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.* import io.github.libtmux.kotlin.query.* import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.runBlocking fun main() = runBlocking { val socket = requireNotNull(System.getenv("LIBTMUX_SOCKET_PATH")) { "Set LIBTMUX_SOCKET_PATH to an existing socket" } val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() withServer(config) { server -> val sessions = server.sessions() val windows = sessions.flatMap { it.windows } val panes = windows.flatMap { it.panes } check(sessions.size == 2 && windows.size == 2 && panes.size == 2) for (session in sessions) { println("${session.name}: ${session.windows.single().name}") } println("2 sessions, 2 windows, 2 panes") } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Hierarchy --console=plain --max-workers=2 ``` Expected program output: ```text work-one: editor work-two: logs 2 sessions, 2 windows, 2 panes ``` ## Observe a rename with a fresh read Rename the editor window. The old handle still says `editor`; the returned handle and a new server read say `renamed`. This distinction matters when a UI, another client or your own code changes tmux after a capture. ```kotlin title="Refresh.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.* import io.github.libtmux.kotlin.query.* import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.runBlocking fun main() = runBlocking { val socket = requireNotNull(System.getenv("LIBTMUX_SOCKET_PATH")) { "Set LIBTMUX_SOCKET_PATH to an existing socket" } val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() withServer(config) { server -> val session = server.sessions().single { it.name == "work-one" } val before = session.windows.single() val after = before.rename("renamed") check(before.name == "editor") check(after.name == "renamed") val readAgain = server.sessions().single { it.name == "work-one" }.windows.single() check(readAgain.name == "renamed") println("${before.name} -> ${readAgain.name}") } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Refresh --console=plain --max-workers=2 ``` Expected program output: ```text editor -> renamed ``` ## Select a target before changing it A successful lookup does not reserve a tmux object. Another client can remove it before your next command. Handle a command failure at the mutation, and refresh before deciding what to do next. See [filtering and queries](https://libtmux.org/en/kotlin/latest/concepts/queries/) for missing and ambiguous selections, and [layouts](https://libtmux.org/en/kotlin/latest/concepts/workspaces/) for creation. --- # Server, session, window, pane Source: https://libtmux.org/en/scala/latest/concepts/server-session-window-pane/ > Traverse captured Scala handles, retain IDs and refresh after changes. Capture a hierarchy, then read its sessions, windows and panes locally. Handles retain the state they captured; a rename does not rewrite an older handle. Use a new capture to observe later changes. [`Server`](https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-server/) selects the socket and owns client resources. [`Session`](https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-session/), [`Window`](https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-window/) and [`Pane`](https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-pane/) hold captured state and send mutations through that server. The session list captures the hierarchy; walking its children reads that capture. A session holds window placements; a window holds panes. A linked window can appear in several sessions, so traversal counts placements rather than necessarily distinct physical windows. Names can change; retain IDs when identifying a target. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and JDK 25. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. The pinned source checkout supplies the Gradle wrapper and the library dependency. ```kotlin title="settings.gradle.kts" rootProject.name = "connect" includeBuild("libtmux-source") { dependencySubstitution { substitute(module("io.github.libtmux:libtmux-scala_3")) .using(project(":libtmux-scala")) } } ``` ```kotlin title="build.gradle.kts" val example = providers.gradleProperty("example").getOrElse("Local") plugins { application scala } repositories { mavenCentral() } dependencies { implementation("org.scala-lang:scala3-library_3:3.9.0") implementation("io.github.libtmux:libtmux-scala_3:0.0.1-alpha.17-SNAPSHOT") } java { toolchain { languageVersion.set(JavaLanguageVersion.of(25)) } } sourceSets.main { scala.srcDir("."); scala.include("${example}.scala") } application { mainClass.set(example) } ``` ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-java-dev directory=$(mktemp -d /tmp/libtmux-java-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Walk sessions, windows and panes Flatten the captured children and verify the fixture contains two of each. The program also prints each session and its window. ```scala title="Hierarchy.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint} import io.github.libtmux.scaladsl.* import io.github.libtmux.scaladsl.query.* import java.nio.file.Path import java.time.Duration import scala.util.Using import scala.jdk.CollectionConverters.* object Hierarchy { def main(args: Array[String]): Unit = { val socket = sys.env.getOrElse("LIBTMUX_SOCKET_PATH", throw new IllegalArgumentException("Set LIBTMUX_SOCKET_PATH to an existing socket")) val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() Using.resource(Server.open(config)) { server => val sessions = server.sessions() val windows = sessions.flatMap(_.windows) val panes = windows.flatMap(_.panes) assert(sessions.size == 2 && windows.size == 2 && panes.size == 2) for (session <- sessions) { println(s"${session.name}: ${session.windows.head.name}") } println("2 sessions, 2 windows, 2 panes") } } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Hierarchy --console=plain --max-workers=2 ``` Expected program output: ```text work-one: editor work-two: logs 2 sessions, 2 windows, 2 panes ``` ## Observe a rename with a fresh read Rename the editor window. The old handle still says `editor`; the returned handle and a new server read say `renamed`. This distinction matters when a UI, another client or your own code changes tmux after a capture. ```scala title="Refresh.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint} import io.github.libtmux.scaladsl.* import io.github.libtmux.scaladsl.query.* import java.nio.file.Path import java.time.Duration import scala.util.Using import scala.jdk.CollectionConverters.* object Refresh { def main(args: Array[String]): Unit = { val socket = sys.env.getOrElse("LIBTMUX_SOCKET_PATH", throw new IllegalArgumentException("Set LIBTMUX_SOCKET_PATH to an existing socket")) val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() Using.resource(Server.open(config)) { server => val session = server.sessions().find(_.name == "work-one").get val before = session.windows.head val after = before.rename("renamed") assert(before.name == "editor") assert(after.name == "renamed") val readAgain = server.sessions().find(_.name == "work-one").get.windows.head assert(readAgain.name == "renamed") println(s"${before.name} -> ${readAgain.name}") } } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Refresh --console=plain --max-workers=2 ``` Expected program output: ```text editor -> renamed ``` ## Select a target before changing it A successful lookup does not reserve a tmux object. Another client can remove it before your next command. Handle a command failure at the mutation, and refresh before deciding what to do next. See [filtering and queries](https://libtmux.org/en/scala/latest/concepts/queries/) for missing and ambiguous selections, and [layouts](https://libtmux.org/en/scala/latest/concepts/workspaces/) for creation. --- # Control mode vs one-shot Source: https://libtmux.org/en/tmux/concepts/transports/ > Choose subprocesses, command batches, or persistent connections to send commands and receive events. libtmux sends commands to tmux through subprocesses or persistent control-mode connections. tmux also accepts several commands in one invocation: 1. **One-shot subprocess.** Each command spawns a fresh `tmux` process, which sends the request to the server, prints the result, and exits. 2. **A persistent control-mode client.** `tmux -C attach-session` starts one long-lived tmux process that stays attached and speaks a line-oriented protocol over its stdout: commands go in, replies and asynchronous notifications (`%window-add`, `%output`, ...) come out, without starting a process per call. 3. **One invocation, several commands.** tmux accepts more than one command per invocation (`;`-joined, or one `-F`-tagged `list-*` per line). Grouping operations this way reduces process starts without opening a control-mode connection. ## Available transports ### Python Each library call starts a tmux subprocess. [`ControlMode`]() in `libtmux._internal` is an internal test helper, not a public command transport. ### TypeScript Commands use a subprocess by default. [`pipeline()`]() and [`batch()`]() group operations. [`connect()`]() and [`watch()`]() keep a connection for notifications; ordinary commands still use separate processes. ### Go The process transport starts a tmux subprocess for each call. [`Plan.Run`]() groups commands into fewer invocations. Use [`Session.OpenControl`]() for a persistent command connection and [`Session.OpenNotifications`]() for a notification stream. ### Rust Commands use subprocesses by default. [`CommandChain`]() and the planning API group commands; the `control-mode` feature enables persistent connections. ### C# The default one-shot mode runs commands through subprocesses. [`Server.Chain`]() groups commands, and [`EnterControlModeAsync`]() opens a persistent command connection. ### C++ The default transport uses bounded subprocesses. [`Chain`]() groups commands into an invocation. [`Server::control()`]() opens a persistent [`Connection`](). ### Java Ordinary calls run through tmux subprocesses. [`Batch`]() groups commands, and [`ControlClient`]() provides a persistent connection for commands and events. ### Swift Ordinary calls use subprocesses. [`Server.connected(attachingTo:_:)`]() provides a persistent connection, and [`ControlConnection.watch(_:)`]() receives events. Choose based on whether you need command results, notifications, or a batch of changes. ## Notifications and commands are separable TypeScript's [`connect()`]() adds an event observer while commands such as [`session.newWindow(...)`]() and [`pane.sendKeys(...)`]() continue to run as separate tmux processes. A dedicated process provides a completion boundary for output from alias-expanded or waiting commands. [`Session.OpenControl`]() opens a persistent command connection. [`Session.OpenNotifications`]() opens a notification stream. Close each handle when finished. Starting an observer does not change the transport used by an existing server handle. Use [`EnterControlModeAsync`]() for commands on a persistent connection. [`ControlClient.send`]() sends commands through the persistent connection. Enable the `control-mode` feature to send commands through a persistent connection. ## A control client is a real client A persistent control connection attaches a tmux client. It appears in `list-clients`, increments `session_attached`, and affects `destroy-unattached`, client hooks, and idle-client accounting. Each connection counts separately. Python's internal [`ControlMode`]() test helper uses this behavior for commands that require an attached client, such as `display-popup` and `detach-client`. ## Why fold several commands into one invocation Creating an object can require a second command to read its resulting state. Batching can reduce repeated reads and process starts. [`batch()`]() resolves planned mutations from one final snapshot. A [`Plan`]() groups operations without attaching a control client. A `Chain` groups operations without attaching a control client. ## What this costs in practice A persistent connection avoids starting a client for each command. A chain groups a known sequence into one invocation. For occasional commands, use the default subprocess transport; measure your workload before changing transports for performance. Use a notification stream when your program needs tmux events. ## Sending a command The example uses the subprocess API. See the reference for batching and control-mode setup. ```python import libtmux # One-shot: every call underneath this handle spawns a `tmux` process. server = libtmux.Server() session = server.new_session(session_name="work") session.active_window.active_pane.send_keys("echo hello") ``` ```typescript import { Server } from "libtmux"; // Each awaited command uses a tmux subprocess. const server = new Server(); const session = await server.newSession({ name: "work" }); const editor = await session.newWindow({ name: "editor" }); await editor.panes.at(0)?.sendKeys("echo hello"); ``` ```rust use libtmux::Server; #[tokio::main] async fn main() -> Result<(), Box> { // One-shot: every call underneath this handle spawns a `tmux` process. let server = Server::new()?; let session = server.new_session("work").await?; let window = session.active_window().await?.expect("a session has a window"); let pane = window.active_pane().await?.expect("a window has a pane"); pane.send_line("echo hello").await?; Ok(()) } ``` ```go ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // One-shot: every call underneath this handle spawns a `tmux` process. server, err := tmux.NewServer(tmux.ServerOptions{}) if err != nil { return err } session, err := server.NewSession(ctx, tmux.NewSessionRequest{Name: "work"}) if err != nil { return err } window, err := session.ResolveActiveWindow(ctx) if err != nil { return err } pane, err := window.ResolveActivePane(ctx) if err != nil { return err } command := "echo hello" return pane.SendKeys(ctx, tmux.SendKeysRequest{Command: &command, Literal: true}) ``` ```java ServerConfig config = ServerConfig.builder() .endpoint(ServerEndpoint.defaultSocket()) .build(); // One-shot: every call underneath this handle spawns a `tmux` process. try (Server server = Server.open(config)) { Session session = server.newSession("work"); Pane pane = session.windows().get(0).panes().get(0); pane.sendLine("echo hello"); } ``` ```csharp using LibTmux; // One-shot: every call underneath this handle spawns a `tmux` process. Server server = await Server.ConnectAsync(); Session session = await server.CreateSessionAsync(new NewSessionRequest(name: "work")); Window window = (await session.GetWindowsAsync())[0]; Pane pane = (await window.GetPanesAsync())[0]; await pane.SendTextAsync("echo hello"); ``` ```cpp #include // One-shot: every call answers with a value; no tmux failure is thrown. const auto server = libtmux::Server::at_default(); if (!server.has_value()) { return 1; } const auto session = server->new_session("work"); if (!session.has_value()) { return 1; } const auto pane = session->active_pane(); if (pane.has_value()) { (void)pane->send_text("echo hello"); (void)pane->send_key("Enter"); } ``` ```swift import LibTmux // One-shot: every call underneath this handle spawns a `tmux` process. let server = try Server(socketName: "default") let session = try await server.newSession(named: "work", windowName: "editor") let window = try await server.newWindow(in: session, named: "logs").window let pane = try await server.splitWindow(window, direction: .right) try await server.run("echo hello", in: pane) ``` To inspect tmux's control protocol, attach a control client: ```console $ tmux -C attach-session -t work ``` --- # Execution modes Source: https://libtmux.org/en/ruby/latest/concepts/transports/ > Choose blocking commands, captured queries, control mode, or Async tasks. | Mode | Wait and ownership | Result evidence | | --- | --- | --- | | Core command | Calling thread blocks; server binding owns each client and its pipes | [`CommandResult`]() has binary stdout/stderr and final client status | | Captured query | Snapshot acquisition performs explicit I/O; [`Selection`]() filtering is local | Stable captured membership with acquisition interval and coverage | | Command group | One client submits an ordered, nontransactional group | Aggregate final status; individual steps remain `unknown` | | Core control | One owned reader thread drains the connection; each subscriber has limits | Guarded blocks between boundaries; hooks can share the interval | | Async | Caller supplies an Async parent task; pipe I/O yields on its scheduler | Same command evidence, with bounded request admission and cancellation | | MCP | Caller supplies transport streams, Async scope and tool policy | Versioned protocol envelopes and structured tool responses | | Workspace | Parsing and planning are inert; apply performs ordered commands | Created-reference ledger, observed effects and explicit uncertainty | Use `Server.open(socket_path: ...)` to borrow a daemon through a pinned binding. `Server.start` creates an owned daemon on a unique socket and closes it with the block. No API in these recipes chooses the default server. `CommandResult#success?` means the client exited successfully. Sending input does not establish shell completion. A [`GuardedReply`]() has no `success?`: `%end` terminates a guard, while WAIT commands, aliases and hooks can change what finishes when. Its `boundary_window` attribution is deliberately weaker than per-command ownership. Concurrent control calls pipeline complete wire requests on one connection. The writer can submit a later request while an earlier reply waits; the reader assigns boundaries in the same order. Admission limits include all pending and completed but unconsumed requests. Cancellation after any request bytes are written closes the connection: other written requests have `possibly_sent` delivery, and requests with no written bytes have `not_sent`. No uncertain request is replayed. Sequential calls still wait for each reply. Reliable control subscriptions raise [`SubscriptionOverflow`]() when they cannot retain the stream. Tail subscriptions emit a gap containing lost sequence and byte evidence. Neither mode blocks the command reader behind a slow consumer. Limits apply to connection-owned buffers; callers own the replies they retain after return. Captured queries evaluate the whole criteria tree before selecting rows, including inactive OR branches. Explain methods perform no I/O. Current source plans use explicit capture and local evaluation; unsupported required pushdown fails rather than silently changing semantics. See [the recipes](https://libtmux.org/en/ruby/latest/examples/recipes/) for event-based WAIT release, cancellation, overflow and group-failure examples. No throughput comparison is claimed. --- # Subprocesses, plans, and control mode Source: https://libtmux.org/en/rs/latest/concepts/transports/ > Choose how Rust commands reach tmux and understand completion, failures, cancellation, and connection ownership. Ordinary [`Server`](https://libtmux.org/en/rs/latest/reference/server-server/) calls use tmux subprocesses. No optional Cargo feature is required for that route. Add [plan][plan-feature] to record and group commands, or `control-mode` to use a persistent connection for commands and notifications. ## Available transports | Your task | Rust API | Cargo feature | | --- | --- | --- | | List objects, create a session, send keys, or capture a pane | Ordinary [`Server`](), [`Session`](), [`Window`](), and [`Pane`]() methods | None | | Send a known command sequence in one invocation | [`Server::chain(CommandChain)`]() | None | | Describe operations, validate dependencies, and choose how to group them | [`Plan`]() with [`Planner::Sequential`](), [`Folding`](), or [`Marked`]() | [plan][plan-feature] | | Attach a persistent command and event connection | [`ControlMode::attach`]() | `control-mode` | | Route typed object methods through that connection | [`Server::over_control_mode`]() | `control-mode` | Choose based on whether your application needs occasional command results, a known batch of changes, or an ongoing connection. Start with ordinary calls unless another route solves a measured problem. Fewer process starts alone do not establish an end-to-end latency improvement. ## Ordinary calls and command results A [`Server`]() is a handle to a tmux endpoint. Constructing it does not start a daemon; creating the first session does. A typed call can dispatch more than one command, for example to read the state of an object it just created. Do not equate one Rust method call with exactly one subprocess. Typed operations report their documented failures through [`Result`](). The lower level [`Server::cmd`](https://libtmux.org/en/rs/latest/reference/server-server-cmd/) instead returns a [`CommandResult`](https://libtmux.org/en/rs/latest/reference/command-commandresult/): reaching tmux and tmux accepting the command are separate outcomes. Check [`success()`]() or the exit status before treating its output as a successful operation. The complete program below lists its session, then asks whether a missing session exists. `cmd()` returns [`Ok`](https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok) with an unsuccessful command result for the refused `has-session`; a missing executable, timeout, or capture failure would return [`Err`](https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err) instead. ## Setup and run Use an empty directory with Git, rustup with the 1.97.1 toolchain installed, tmux 3.2a or newer, and a Unix environment. The program creates a private socket under `/tmp/libtmux-rs-dev`, starts `cat` in its panes, and stops only the server it created. No existing session, socket, or environment variable is required. Save this file as `Cargo.toml`: ```toml title="Cargo.toml" [package] name = "libtmux-subprocess-example" version = "0.0.0" edition = "2024" publish = false [workspace] exclude = ["libtmux-source"] [dependencies] libtmux = { path = "libtmux-source/crates/libtmux", default-features = false } tempfile = "=3.27.0" tokio = { version = "=1.53.1", features = ["macros", "rt", "time"] } [[bin]] name = "subprocess" path = "subprocess.rs" ``` Fetch the library revision used by the example: ```console $ git clone https://github.com/libtmux/libtmux-rs libtmux-source && git -C libtmux-source checkout e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4 ``` This dependency disables all default features to show that subprocess calls do not depend on [`query`](), [plan][plan-feature], or `control-mode`. Save the complete program as `subprocess.rs`: ```rust title="subprocess.rs" use std::error::Error; use std::time::Duration; use libtmux::{Command, NewSessionOptions, Server}; type ExampleError = Box; async fn demonstrate(server: &Server) -> Result<(), ExampleError> { server .new_session(NewSessionOptions::new("work").command("cat")) .await?; let sessions = server.sessions().await?; if sessions.len() != 1 || sessions[0].name().as_bytes() != b"work" { return Err("expected only the work session".into()); } println!("sessions: work"); // Transport success and a successful tmux command are separate results. let missing = server .cmd(Command::new("has-session").arg("-t").arg("missing")) .await?; if missing.success() { return Err("the missing session unexpectedly exists".into()); } println!("missing session: tmux refused the command"); Ok(()) } #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), ExampleError> { let root = std::path::Path::new("/tmp/libtmux-rs-dev"); std::fs::create_dir_all(root)?; let directory = tempfile::Builder::new() .prefix("docs-subprocess-") .tempdir_in(root)?; std::fs::write( directory.path().join("owner"), std::process::id().to_string(), )?; let server = Server::builder() .socket_path(directory.path().join("tmux.sock")) .config_file("/dev/null") .default_timeout(Duration::from_secs(5)) .build()?; let outcome = tokio::time::timeout(Duration::from_secs(10), demonstrate(&server)).await; // Stop the owned daemon before closing the client executor. let killed = server.kill().await; let closed = server.shutdown().await; let cleanup_failed = killed.is_err() || closed.is_err(); let mut failures = Vec::new(); match outcome { Ok(Ok(())) => {} Ok(Err(error)) => failures.push(format!("example failed: {error}")), Err(error) => failures.push(format!("example deadline: {error}")), } if let Err(error) = killed { failures.push(format!("daemon cleanup: {error}")); } if let Err(error) = closed { failures.push(format!("executor cleanup: {error}")); } if cleanup_failed { let retained = directory.keep(); failures.push(format!("inspect retained directory {}", retained.display())); } else if let Err(error) = directory.close() { failures.push(format!("directory cleanup: {error}")); } if failures.is_empty() { Ok(()) } else { Err(failures.join("; ").into()) } } ``` ```console $ cargo +1.97.1 run --quiet --bin subprocess ``` Expected output: ```text sessions: work missing session: tmux refused the command ``` ## Group a known sequence [`Server::chain`](https://libtmux.org/en/rs/latest/reference/server-server-chain/) sends a [`CommandChain`]() as one invocation. It gives the group one exit status and merged output. tmux stops at the first refused command; it does not undo earlier commands. A [`Plan`](https://libtmux.org/en/rs/latest/reference/plan-plan/) adds recorded operations, typed references to objects created earlier in the plan, validation, and per-operation reports. The planner can retain separate invocations or combine compatible neighbors. A failed combined invocation may leave individual outcomes `Unknown`. [`Ok(PlanResult)`](https://libtmux.org/en/rs/latest/reference/plan-run-planresult/) therefore does not mean every operation succeeded. [Batch commands with a plan](https://libtmux.org/en/rs/latest/guides/batching-commands/) runs one workload with each planner, checks the resulting pane output, and handles a refused operation. It explains which counts and failure details the result can prove. ## Notifications and commands are separable Attaching [`ControlMode`](https://libtmux.org/en/rs/latest/reference/control-controlmode/) opens another real tmux client. It appears in `list-clients` and affects attachment counts, client hooks, and options such as `destroy-unattached`. The original [`Server`]() continues to use subprocesses. Calling [`over_control_mode()`](https://libtmux.org/en/rs/latest/reference/server-server-over_control_mode/) returns another handle; typed objects obtained through that handle inherit its route. The sender must address the same endpoint. Setup may probe the tmux version through the process route; later routed calls use the connection. [Send commands over control mode](https://libtmux.org/en/rs/latest/guides/control-mode/) provides a complete program that sends input, captures output, drains notifications, and closes the connection while keeping the daemon alive until final cleanup. ## Deadlines, partial effects, and cleanup [`ServerBuilder::default_timeout`]() bounds ordinary subprocess commands and the opening control handshake. A connected sender has its own [`reply_timeout`](https://libtmux.org/en/rs/latest/reference/control-controlsender-reply_timeout/), initially copied from that server limit. The control guide sets it explicitly. A timeout or cancelled future does not roll back an accepted mutation. Inspect the server before repeating a creation or another operation that is unsafe to run twice. A plan can be partly applied, and dropping its future also loses the returned report of which steps completed. [`Server::shutdown`](https://libtmux.org/en/rs/latest/reference/server-server-shutdown/) closes the client executor and its connections; it does not kill the daemon. Use [`Server::kill`](https://libtmux.org/en/rs/latest/reference/server-server-kill/) only when your application owns that daemon. The example bounds each command to five seconds and its work to ten seconds, then attempts both daemon and executor cleanup. A cleanup failure reports and retains the private directory for inspection. ## Read the implementation contract These examples use the public APIs at [`libtmux@0.1.0-alpha.15`](https://github.com/libtmux/libtmux-rs/tree/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4). The pinned [Server contract](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/libtmux/src/server.rs) describes command outcomes, shutdown, and routing. The guides above explain plans and persistent connections as separate application workflows. [plan-feature]: https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/libtmux/Cargo.toml#L115 --- # Filtering and queries Source: https://libtmux.org/en/tmux/concepts/queries/ > How you get from every session on the server to the one pane you mean, and what happens when zero or several match. Use a collection filter to find matching sessions, windows, or panes. Use an exactly-one lookup when your next operation requires a single target. - **Filtering returns a collection; exactly-one lookup checks the result count.** A filter returns zero or more matches. An exactly-one operation returns one object or reports a missing or ambiguous match. - **Choose where to filter.** Filter a snapshot in your program when you need several queries over the same data. A tmux format filter can reduce the rows returned by a live read. The cost depends on the data and queries you need. ## Filter collections and select one object [`server.sessions`](), [`session.windows`](), and [`window.panes`]() are [`QueryList`]() collections. Call [`.filter()`]() with field names and optional lookup suffixes: ```python >>> session.windows.filter(window_name__startswith='api') [Window(@... ...:api-server, Session($... ...))] >>> session.windows.filter(window_name__iregex=r'n?vim') ``` Lookups include `exact`, `contains`, `startswith`, `endswith`, [`regex`](), and their case-insensitive `i`-prefixed variants. Multiple keywords and chained [`.filter()`]() calls combine with AND. `.get()` requires exactly one match. Its [`default`]() argument handles an absent result; multiple matches still raise [`MultipleObjectsReturned`](). Server-wide collections ([`server.windows`](), [`server.panes`]()) enumerate window links. A window linked to two sessions appears once per session, so a lookup can be ambiguous even when the window ID is unique. Use [`Window.linked_sessions`]() to find its sessions. For a known ID, use [`Pane.from_pane_id()`]() or [`Window.from_window_id()`]() to resolve the object directly. For servers with hundreds or thousands of panes, [`.filter()`]() still builds every object before you discard the ones that don't match. [`search_sessions`](), `search_windows`, and `search_panes` push a tmux `-f` filter expression down to the server instead, so libtmux builds objects only for the matches: ```python >>> server.search_sessions(filter='#{==:#{session_name},alpha-1}') ``` Python-side lookups work with the library's supported tmux versions. The tmux filter grammar requires tmux 3.2 or newer. An unknown format token expands to an empty value, so a malformed filter can look like a valid filter with no matches. If `search_*()` unexpectedly returns no results, try `#{m:*,#{session_name}}` to check that the session data is available. ## TypeScript criteria The [TypeScript filtering guide](https://libtmux.org/en/ts/latest/concepts/queries/) includes complete programs for matching names, handling result counts, traversing linked windows, refreshing snapshots, validating query documents, and filtering live tmux rows. ## Typed and local filters Typed field operations let the compiler reject incompatible comparisons: [`tmux.PaneFilter`]() describes a typed predicate over captured values. Use [`tmuxq.Matching`]() or compile its [`PaneFilter.Predicate()`]() for local queries. To filter a live tmux listing, pass a [`TmuxFilter`]() expression to [`Server.SearchPanes`](). Typed fields reject invalid comparisons: `fields.pane_active.eq(true)` is valid, while `.gt(...)` on a boolean field fails to compile. Compose expressions with [`.and()`](). The `serde` feature supports versioned query JSON for configuration or MCP. [`Pane_`](), [`Window_`](), and [`Session_`]() expose typed field accessors for stream predicates. A numeric field has no [`startsWith`]() operation. Use [`Selections.exactlyOne`]() to reject absent or ambiguous matches. Compose [`FilterExpr`]() values with `&&`, `||`, and `!`. For example, [`pane::command.starts_with("nv") && pane::active`]() is valid, while `pane::active.starts_with("x")` fails to compile. Examples of typed and local filters: ```rust use libtmux::query::{Filterable as _, QueryIteratorExt as _}; let fields = libtmux::Pane::filter_fields(); // `pane_active` is a flag, so `.eq(true)` compiles; `.gt(..)` would not. let active = fields .pane_current_command .starts_with("sh") .and(fields.pane_active.eq(true)); let panes = server.panes().await?; let matched: Vec<_> = panes.iter().matching(&active).collect(); ``` ```go // Read once, filter in Go: several answers from one read. snapshot, err := server.Snapshot(ctx) if err != nil { return err } predicate, err := tmux.PaneActiveIs(true).Predicate() if err != nil { return err } active := tmuxq.Where(snapshot.Panes(), predicate) fmt.Println("active panes:", len(active)) // Or push the filter down: tmux returns only the matches. filter := tmux.TmuxFilter("#{==:#{pane_active},1}") panes, err := server.SearchPanes(ctx, &filter) if err != nil { return err } fmt.Println("live matches:", len(panes)) ``` ```java List editors = server.windows().stream() .filter(Window_.name().startsWith("edit")) .toList(); // Selections.exactlyOne() is the `.get()`-shaped call. Session build = Selections.exactlyOne( server.sessions().stream().filter(Session_.name().is("build")).toList()); ``` ```csharp IReadOnlyList windows = await session.GetWindowsAsync(ct); IEnumerable building = windows.Where( each => each.Name.StartsWith("build", StringComparison.Ordinal)); // A declarative query is a document, not just a lambda run in place. IReadOnlyList sessions = await server.GetSessionsAsync(ct); IReadOnlyList matched = sessions.Matching( session => session.Name.StartsWith("build", StringComparison.Ordinal)); ``` ```cpp // A filter is a value built from typed fields; `window::active.starts_with(...)` // would not compile: a flag has no string operations. const auto interesting = libtmux::window::name.starts_with("e") || libtmux::window::name == "logs"; auto matched = *windows | libtmux::matching(interesting); // "Exactly one, or say why not" is a question the library answers directly. auto logs = *windows | libtmux::matching(libtmux::window::name == "logs"); if (const auto only = libtmux::exactly_one(logs); only.has_value()) { std::printf("exactly one: %s\n", std::string{only->get().id()}.c_str()); } ``` ```swift // Filter locally with the standard library: let editors = try await server.panes().filter { $0.currentCommand == "nvim" } // Or build a filter that travels: stored, sent, replayed elsewhere: let expression = try FilterExpr.where(\.currentCommand, .isIn(["nvim", "vim"])) let matching = try await server.panes().filter(expression) ``` ## Result counts ### Python Use [`QueryList.filter`]() to keep matching objects and [`QueryList.get`]() when exactly one must match. An empty result raises [`ObjectDoesNotExist`]() unless you supply `default=`. Several matches raise [`MultipleObjectsReturned`](). ### TypeScript Use [`where()`]() or [`filter()`]() to select matches and [`one()`]() to require exactly one. No match raises [`NoMatchError`](); [`oneOrUndefined()`]() accepts that case. Several matches raise [`MultipleMatchesError`](). ### Java Filter with [`Stream.filter`]() and require one match with [`Selections.exactlyOne`](). Empty and multiple results raise [`CardinalityException.NoMatch`]() and [`CardinalityException.MultipleMatches`](), respectively. [Filtering and querying](https://libtmux.org/en/tmux/guides/querying-and-filtering/) shows exactly-one lookups and their error handling. Do not index the first result until the operation has established that a match exists. ## tmux command reference The tmux [list-panes](https://libtmux.org/en/tmux/latest/manual/list-panes/) and [list-windows](https://libtmux.org/en/tmux/latest/manual/list-windows/) references describe native format filters. See [formats](https://libtmux.org/en/tmux/latest/manual/full/#FORMATS) for expressions and available variables. --- # Filtering and queries Source: https://libtmux.org/en/fsharp/latest/concepts/queries/ > Compose F# filters, distinguish zero and several matches, and query captured relations. Filter captured objects in F#, handle result counts explicitly, and match sessions by their related windows. Local filters read captured values; they do not subscribe to changes or issue a fresh tmux query. [`Filter`](https://libtmux.org/en/fsharp/latest/reference/libtmux-fsharp-filter/) supplies equality, ordinal prefix matching and membership. Use [`allOf`](), [`anyOf`]() and [`negate`]() to compose conditions. [`Query.matching`](https://libtmux.org/en/fsharp/latest/reference/libtmux-fsharp-query-matching/) materializes the matching objects in source order. Use [`Seq.filter`]() for an application predicate that does not need a portable query. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and .NET SDK 10.0.302. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. ```xml title="Query.fsproj" Exe net10.0 Local ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-dotnet-dev directory=$(mktemp -d /tmp/libtmux-dotnet-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-dotnet libtmux-source && git -C libtmux-source checkout 2d99ead5aba8d968e85dcac8c9a9a518452e6ba6 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Match names and combine conditions Select the two names beginning with `work-`, then assert equality, AND, OR and exclusion against the same captured collection. Matching is case sensitive. The native collection predicate agrees with the typed prefix query. ```fsharp title="Local.fs" open System open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let run () = task { let socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") if String.IsNullOrEmpty(socket) then invalidOp "Set LIBTMUX_SOCKET_PATH to an existing socket" use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5.0)) let token = timeout.Token let! server = LibTmux.Server.ConnectAsync( ServerConnectionOptions(SocketPath = socket), token) let! captured = server |> Server.capture token SnapshotDepth.Sessions let prefix = Filter.startsWith "work-" SessionFields.name let matching = captured.Sessions |> Query.matching prefix let names = matching |> Seq.map (fun session -> session.Name) |> Seq.sort |> Seq.toList if names <> [ "work-one"; "work-two" ] then failwith "Unexpected sessions" printfn "%s" (String.concat ", " names) let native = captured.Sessions |> Seq.filter (fun session -> session.Name.StartsWith("work-")) if Seq.length native <> matching.Count then failwith "Local filters disagree" let onlyOne = Filter.allOf [ Filter.startsWith "work-" SessionFields.name Filter.eq "work-one" SessionFields.name ] let selected = captured.Sessions |> Query.matching onlyOne if selected.Count <> 1 || selected[0].Name <> "work-one" then failwith "Wrong AND result" let either = Filter.oneOf [ "work-one"; "work-two" ] SessionFields.name if (captured.Sessions |> Query.matching either).Count <> 2 then failwith "Wrong OR result" let excluded = Filter.eq "work-one" SessionFields.name |> Filter.negate let remaining = captured.Sessions |> Query.matching excluded if remaining.Count <> 1 || remaining[0].Name <> "work-two" then failwith "Wrong NOT result" } [] let main _ = try run().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ```console $ dotnet build Query.fsproj --maxcpucount:1 -p:Example=Local \ -p:DisableImplicitLibraryPacksFolder=true -p:RestorePackagesPath="$PWD/.packages" && sh run.sh dotnet run --project Query.fsproj --no-build -p:Example=Local ``` Expected program output: ```text work-one, work-two ``` ## Distinguish missing and ambiguous results [`Selection.exactlyOne`](https://libtmux.org/en/fsharp/latest/reference/libtmux-fsharp-selection-exactlyone/) returns a [`Result`](). Match [`NoMatches`]() and [`MultipleMatches`]() separately. A missing optional target and an ambiguous destructive target should not take the same path. ```fsharp title="Cardinality.fs" open System open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let run () = task { let socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") if String.IsNullOrEmpty(socket) then invalidOp "Set LIBTMUX_SOCKET_PATH to an existing socket" use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5.0)) let token = timeout.Token let! server = LibTmux.Server.ConnectAsync( ServerConnectionOptions(SocketPath = socket), token) let! captured = server |> Server.capture token SnapshotDepth.Sessions for name in [ "work-one"; "missing" ] do let matches = captured.Sessions |> Query.matching (Filter.eq name SessionFields.name) match matches |> Selection.exactlyOne with | Ok session -> printfn "%s: selected" session.Name | Error CardinalityError.NoMatches -> printfn "%s: absent" name | Error CardinalityError.MultipleMatches -> failwithf "Ambiguous session: %s" name let many = captured.Sessions |> Selection.exactlyOne match many with | Error CardinalityError.MultipleMatches -> printfn "work-: ambiguous" | _ -> failwith "Expected two sessions" } [] let main _ = try run().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ```console $ dotnet build Query.fsproj --maxcpucount:1 -p:Example=Cardinality \ -p:DisableImplicitLibraryPacksFolder=true -p:RestorePackagesPath="$PWD/.packages" && sh run.sh dotnet run --project Query.fsproj --no-build -p:Example=Cardinality ``` Expected program output: ```text work-one: selected missing: absent work-: ambiguous ``` ## Filter through related windows Match sessions with any window named `editor`, then match sessions with none. For an empty captured relation, [`any`]() is false and [`none`]() is true; [`all`]() is true. An uncaptured relation is a different condition and must be captured before filtering. This program derives the required snapshot depth from the query document. ```fsharp title="Relations.fs" open System open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let run () = task { let socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") if String.IsNullOrEmpty(socket) then invalidOp "Set LIBTMUX_SOCKET_PATH to an existing socket" use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5.0)) let token = timeout.Token let! server = LibTmux.Server.ConnectAsync( ServerConnectionOptions(SocketPath = socket), token) let editor = Filter.eq "editor" WindowFields.name let withEditor = editor |> Filter.any SessionFields.windows let withoutEditor = editor |> Filter.none SessionFields.windows let depth = (Filter.toDocument withEditor).RequiredSnapshotDepth let! captured = server |> Server.capture token depth let selected = captured.Sessions |> Query.matching withEditor let excluded = captured.Sessions |> Query.matching withoutEditor if selected.Count <> 1 || selected[0].Name <> "work-one" then failwith "Wrong editor session" if excluded.Count <> 1 || excluded[0].Name <> "work-two" then failwith "Wrong other session" printfn "editor: %s" selected[0].Name printfn "no editor: %s" excluded[0].Name } [] let main _ = try run().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ```console $ dotnet build Query.fsproj --maxcpucount:1 -p:Example=Relations \ -p:DisableImplicitLibraryPacksFolder=true -p:RestorePackagesPath="$PWD/.packages" && sh run.sh dotnet run --project Query.fsproj --no-build -p:Example=Relations ``` Expected program output: ```text editor: work-one no editor: work-two ``` ## Refresh before repeating a decision Reusing the same list repeats the same decision over old state. Capture again when you need to observe a rename, new window or closed pane. The [snapshot example](https://libtmux.org/en/fsharp/latest/concepts/server-session-window-pane/#observe-a-rename-with-a-fresh-read) shows the old and fresh values side by side. --- # Filtering and queries Source: https://libtmux.org/en/go/latest/concepts/queries/ > Filter captured Go tmux objects, handle missing and ambiguous results, and query related windows. Read a snapshot once when several questions concern the same captured state. [`tmuxq.Matching`](https://libtmux.org/en/go/latest/reference/tmuxq-matching/) applies typed filters in Go without another tmux call. [`tmuxq.ExactlyOne`](https://libtmux.org/en/go/latest/reference/tmuxq-exactlyone/) distinguishes an absent result from an ambiguous one. Neither reserves an object for a later mutation. [`SessionFilter`](https://libtmux.org/en/go/latest/reference/tmux-sessionfilter/) fields are ANDed. `AnyOf` adds an OR condition; `Not` excludes a match. Names and regular expressions are case sensitive unless the regular expression enables another mode. A nil field leaves the criterion unset; a pointer to an empty string still supplies a criterion. [`tmux.Ptr`]() is useful for these pointer fields. ## Setup and run Use an empty directory on Linux or macOS with Git, Go 1.26 or newer, and tmux 3.2a or newer. Save these two files and any complete Go program below. Each program includes its imports and entry point; run it by filename so other examples in the directory do not introduce duplicate `main` functions. ```text title="go.mod" module example.com/concepts go 1.26.0 require github.com/libtmux/libtmux-go v0.0.0 replace github.com/libtmux/libtmux-go => ./libtmux-source ``` The launcher starts two sessions on a private socket: `work-one` with an `editor` window and `work-two` with a `logs` window. Each pane runs `cat` to keep it alive. Every run gets a fresh fixture. The launcher stops only that server on success or failure, and retains its directory if shutdown fails. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d /tmp/libtmux-go-concepts.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the documented library revision and resolve this module's dependencies: ```console $ git clone https://github.com/libtmux/libtmux-go libtmux-source && git -C libtmux-source checkout bb06e26e116e941813ca40bf45e7e3a47d38f52a && GOWORK=off go mod tidy ``` The programs use a five-second context for tmux operations. Errors reach `main`, which reports the error and exits unsuccessfully. The launcher's cleanup runs independently of that context. A cancelled mutation can already have reached tmux; inspect the current state before retrying it. ## Match names and combine conditions Use `NameRegex` for a prefix, then combine it with exclusion. `AnyOf` accepts either exact name. These queries all reuse the same snapshot. The final check shows an invalid regular expression is an [`ErrInvalidFilter`]() error, rather than an empty result. ```go title="Local.go" package main import ( "context" "errors" "fmt" "log" "os" "slices" "strings" "time" "github.com/libtmux/libtmux-go/tmux" "github.com/libtmux/libtmux-go/tmuxq" ) func main() { if err := run(); err != nil { log.Fatal(err) } } func run() error { socket := os.Getenv("LIBTMUX_SOCKET_PATH") if socket == "" { return errors.New("run this program with run.sh") } server, err := tmux.NewServer(tmux.ServerOptions{SocketPath: socket, ConfigFile: "/dev/null"}) if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() snapshot, err := server.Snapshot(ctx) if err != nil { return err } cases := []struct { label string filter tmux.SessionFilter want string }{ {"prefix", tmux.SessionFilter{NameRegex: "^work-"}, "work-one, work-two"}, {"AND and NOT", tmux.SessionFilter{ NameRegex: "^work-", Not: tmux.Ptr(tmux.SessionNameIs("work-two")), }, "work-one"}, {"OR", tmux.SessionFilter{AnyOf: []tmux.SessionFilter{ tmux.SessionNameIs("work-one"), tmux.SessionNameIs("work-two"), }}, "work-one, work-two"}, {"case-sensitive", tmux.SessionFilter{NameRegex: "^WORK-"}, ""}, } for _, test := range cases { matches, err := tmuxq.Matching(snapshot.Sessions(), test.filter) if err != nil { return fmt.Errorf("%s: %w", test.label, err) } names := make([]string, 0, len(matches)) for _, session := range matches { name, ok := session.Name() if !ok { return errors.New("session name was not captured") } names = append(names, name) } slices.Sort(names) got := strings.Join(names, ", ") if got != test.want { return fmt.Errorf("%s: got %q, want %q", test.label, got, test.want) } if got == "" { got = "(no matches)" } fmt.Printf("%s: %s\n", test.label, got) } _, err = tmuxq.Matching(snapshot.Sessions(), tmux.SessionFilter{NameRegex: "["}) if !errors.Is(err, tmux.ErrInvalidFilter) { return fmt.Errorf("expected invalid filter, got %v", err) } fmt.Println("invalid regular expression: rejected") return nil } ``` ```console $ sh run.sh env GOWORK=off go run Local.go ``` Expected program output: ```text prefix: work-one, work-two AND and NOT: work-one OR: work-one, work-two case-sensitive: (no matches) invalid regular expression: rejected ``` ## Distinguish missing and ambiguous results Compile the typed filter, then use [`ExactlyOne`]() when a later operation needs one target. Check [`ErrNoMatch`]() and [`ErrMultipleMatches`]() with [`errors.Is`](), which also works after wrapping the error with `%w`. Use [`tmuxq.First`]() only when choosing the first match is intentional; it cannot report ambiguity. ```go title="Cardinality.go" package main import ( "context" "errors" "fmt" "log" "os" "time" "github.com/libtmux/libtmux-go/tmux" "github.com/libtmux/libtmux-go/tmuxq" ) func main() { if err := run(); err != nil { log.Fatal(err) } } func run() error { socket := os.Getenv("LIBTMUX_SOCKET_PATH") if socket == "" { return errors.New("run this program with run.sh") } server, err := tmux.NewServer(tmux.ServerOptions{SocketPath: socket, ConfigFile: "/dev/null"}) if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() sessions, err := server.Sessions(ctx) if err != nil { return err } cases := []struct { label string filter tmux.SessionFilter want error }{ {"work-one", tmux.SessionNameIs("work-one"), nil}, {"missing", tmux.SessionNameIs("missing"), tmuxq.ErrNoMatch}, {"work-", tmux.SessionFilter{NameRegex: "^work-"}, tmuxq.ErrMultipleMatches}, } for _, test := range cases { predicate, err := test.filter.Predicate() if err != nil { return err } selected, err := tmuxq.ExactlyOne(sessions, predicate) if !errors.Is(err, test.want) { return fmt.Errorf("%s: unexpected result: %v", test.label, err) } switch { case err == nil: name, ok := selected.Name() if !ok || name != test.label { return errors.New("selected the wrong session") } fmt.Printf("%s: selected\n", name) case errors.Is(err, tmuxq.ErrNoMatch): fmt.Printf("%s: absent\n", test.label) case errors.Is(err, tmuxq.ErrMultipleMatches): fmt.Printf("%s: ambiguous\n", test.label) } } return nil } ``` ```console $ sh run.sh env GOWORK=off go run Cardinality.go ``` Expected program output: ```text work-one: selected missing: absent work-: ambiguous ``` ## Filter related windows and compare a live listing [`WindowRel`](https://libtmux.org/en/go/latest/reference/tmux-windowrel/) supports `Some`, `Every` and `None`. For a captured empty relation, `Every` and `None` are true and `Some` is false. An uncaptured relation matches none of those quantifiers. Check [`Session.Windows()`]() when missing relations should be an application error. The program checks all three quantifiers against the captured hierarchy. It then sends a [`TmuxFilter`](https://libtmux.org/en/go/latest/reference/tmux-tmuxfilter/) to [`Server.SearchSessions`](https://libtmux.org/en/go/latest/reference/tmux-server-searchsessions/). That expression runs inside tmux and returns only session records. It does not capture their windows, so treating the result as a session with no `editor` window would be incorrect. ```go title="Relations.go" package main import ( "context" "errors" "fmt" "log" "os" "time" "github.com/libtmux/libtmux-go/tmux" "github.com/libtmux/libtmux-go/tmuxq" ) func main() { if err := run(); err != nil { log.Fatal(err) } } func run() error { socket := os.Getenv("LIBTMUX_SOCKET_PATH") if socket == "" { return errors.New("run this program with run.sh") } server, err := tmux.NewServer(tmux.ServerOptions{SocketPath: socket, ConfigFile: "/dev/null"}) if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() snapshot, err := server.Snapshot(ctx) if err != nil { return err } editor := tmux.WindowNameIs("editor") cases := []struct { label string relation tmux.WindowRel want string }{ {"some editor", tmux.WindowRel{Some: &editor}, "work-one"}, {"no editor", tmux.WindowRel{None: &editor}, "work-two"}, {"every window is editor", tmux.WindowRel{Every: &editor}, "work-one"}, } for _, test := range cases { matches, err := tmuxq.Matching(snapshot.Sessions(), tmux.SessionFilter{Windows: &test.relation}) if err != nil { return err } if len(matches) != 1 { return fmt.Errorf("%s: expected one match, got %d", test.label, len(matches)) } name, ok := matches[0].Name() if !ok || name != test.want { return fmt.Errorf("%s: unexpected session %q", test.label, name) } fmt.Printf("%s: %s\n", test.label, name) } filter := tmux.TmuxFilter("#{==:#{session_name},work-one}") live, err := server.SearchSessions(ctx, &filter) if err != nil { return err } if len(live) != 1 { return errors.New("live filter should return work-one") } if _, captured := live[0].Windows(); captured { return errors.New("a session-only listing should not contain window relations") } matches, err := tmuxq.Matching(live, tmux.SessionFilter{Windows: &tmux.WindowRel{None: &editor}}) if err != nil { return err } if len(matches) != 0 { return errors.New("an uncaptured relation is not an empty relation") } fmt.Println("live session listing: window relations not captured") return nil } ``` ```console $ sh run.sh env GOWORK=off go run Relations.go ``` Expected program output: ```text some editor: work-one no editor: work-two every window is editor: work-one live session listing: window relations not captured ``` ## Choose local or tmux-side filtering Typed [`SessionFilter`](), [`WindowFilter`](), [`PaneFilter`]() and [`ClientFilter`]() inspect materialized Go records. A [`TmuxFilter`]() is instead a tmux format expression passed to a live listing. It is not a serialized Go predicate. Do not build format expressions by interpolating arbitrary input; use a typed local filter for application-provided values. Use a new snapshot when repeating a decision must observe recent changes. The [rename example](https://libtmux.org/en/go/latest/concepts/server-session-window-pane/#walk-a-capture-and-observe-a-rename) shows the old and new values together. A successful lookup does not guarantee that the object still exists when a later command runs; check that command's error even after the query succeeds. --- # Filtering and queries Source: https://libtmux.org/en/kotlin/latest/concepts/queries/ > Compose Kotlin filters, distinguish zero and several matches, and query captured relations. Filter captured objects in Kotlin, handle result counts explicitly, and match sessions by their related windows. Local filters read captured values; they do not subscribe to changes or issue a fresh tmux query. [`TextField`](https://libtmux.org/en/kotlin/latest/reference/io-github-libtmux-kotlin-query-textfield/) builds typed expressions with `eq`, `ne`, [`startsWith`](), [`endsWith`](), [`contains`](), [`oneOf`]() and [`matches`](). Compose them with [`.and()`](), [`.or()`]() and `!`. Ordinary Kotlin predicates remain useful for application-specific conditions. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and JDK 25. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. The pinned source checkout supplies the Gradle wrapper and the library dependency. ```kotlin title="settings.gradle.kts" rootProject.name = "connect" includeBuild("libtmux-source") ``` ```kotlin title="build.gradle.kts" val example = providers.gradleProperty("example").getOrElse("Local") plugins { application kotlin("jvm") version "2.4.10" } repositories { mavenCentral() } dependencies { implementation("io.github.libtmux:libtmux-kotlin:0.0.1-alpha.17-SNAPSHOT") } kotlin { jvmToolchain(25) sourceSets.main { kotlin.srcDir("."); kotlin.include("${example}.kt") } } application { mainClass.set("${example}Kt") } ``` ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-java-dev directory=$(mktemp -d /tmp/libtmux-java-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Match names and combine conditions Select the two names beginning with `work-`, then assert equality, AND, OR and exclusion against the same captured collection. Matching is case sensitive. The native collection predicate agrees with the typed prefix query. ```kotlin title="Local.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.* import io.github.libtmux.kotlin.query.* import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.runBlocking fun main() = runBlocking { val socket = requireNotNull(System.getenv("LIBTMUX_SOCKET_PATH")) { "Set LIBTMUX_SOCKET_PATH to an existing socket" } val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() withServer(config) { server -> val sessions = server.sessions() val matching = sessions.filter(Session.name startsWith "work-") val names = matching.map { it.name }.sorted() check(names == listOf("work-one", "work-two")) println(names.joinToString(", ")) // Filtering the captured list makes no new tmux calls. check(sessions.filter { it.name.startsWith("work-") } == matching) val onlyOne = (Session.name startsWith "work-").and(Session.name endsWith "one") check(sessions.filter(onlyOne).single().name == "work-one") val either = (Session.name eq "work-one").or(Session.name eq "work-two") check(sessions.filter(either).size == 2) check(sessions.filter(!(Session.name eq "work-one")).single().name == "work-two") } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Local --console=plain --max-workers=2 ``` Expected program output: ```text work-one, work-two ``` ## Distinguish missing and ambiguous results The program distinguishes zero and one local result. The checked server lookup throws [`CardinalityException.MultipleMatches`]() for two matches. Do not use [`singleOrNull()`]() when zero and several matches need different handling. ```kotlin title="Cardinality.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.* import io.github.libtmux.kotlin.query.* import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.runBlocking fun main() = runBlocking { val socket = requireNotNull(System.getenv("LIBTMUX_SOCKET_PATH")) { "Set LIBTMUX_SOCKET_PATH to an existing socket" } val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() withServer(config) { server -> val sessions = server.sessions() for (name in listOf("work-one", "missing")) { val matches = sessions.filter(Session.name eq name) when (matches.size) { 0 -> println("$name: absent") 1 -> println("$name: selected") else -> error("More than one session named $name") } } val ambiguous = sessions.filter(Session.name startsWith "work-") check(ambiguous.size == 2) // singleOrNull() alone cannot distinguish zero from several matches. try { server.session(Session.name startsWith "work-") error("Expected an ambiguous selection") } catch (error: io.github.libtmux.exception.CardinalityException.MultipleMatches) { println("work-: ambiguous") } } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Cardinality --console=plain --max-workers=2 ``` Expected program output: ```text work-one: selected missing: absent work-: ambiguous ``` ## Filter through related windows Match sessions with any window named `editor`, then match sessions with none. For an empty captured relation, [`any`]() is false and [`none`]() is true; `all` is true. An uncaptured relation is a different condition and must be captured before filtering. ```kotlin title="Relations.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.* import io.github.libtmux.kotlin.query.* import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.runBlocking fun main() = runBlocking { val socket = requireNotNull(System.getenv("LIBTMUX_SOCKET_PATH")) { "Set LIBTMUX_SOCKET_PATH to an existing socket" } val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() withServer(config) { server -> val sessions = server.sessions() val editorWindow = Window.name eq "editor" val withEditor = sessions.filter(Session.windows any editorWindow) val withoutEditor = sessions.filter(Session.windows none editorWindow) check(withEditor.map { it.name } == listOf("work-one")) check(withoutEditor.map { it.name } == listOf("work-two")) println("editor: ${withEditor.single().name}") println("no editor: ${withoutEditor.single().name}") } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Relations --console=plain --max-workers=2 ``` Expected program output: ```text editor: work-one no editor: work-two ``` ## Refresh before repeating a decision Reusing the same list repeats the same decision over old state. Capture again when you need to observe a rename, new window or closed pane. The [snapshot example](https://libtmux.org/en/kotlin/latest/concepts/server-session-window-pane/#observe-a-rename-with-a-fresh-read) shows the old and fresh values side by side. --- # Filtering and queries Source: https://libtmux.org/en/rs/latest/concepts/queries/ > Filter captured Rust objects, handle missing and ambiguous results, and refresh snapshots when tmux changes. Read sessions, windows, or panes once, then filter their captured values in Rust. [`matching()`](https://libtmux.org/en/rs/latest/reference/query-queryiteratorext-matching/) evaluates a typed predicate locally; it does not ask tmux for another listing. Use [`exactly_one()`](https://libtmux.org/en/rs/latest/reference/query-queryiteratorext-exactly_one/) when the next operation needs one unambiguous target. ## Setup and run Use an empty directory with Git, rustup with the 1.97.1 toolchain installed, tmux 3.2a or newer, and a Unix environment. Each program below creates its own private server, uses `cat` to keep its panes alive, and stops that server before exiting. No existing session, socket, or environment variable is required. Save this file as `Cargo.toml`, then save the three programs below beside it. Each has its own entry point and can run independently. ```toml title="Cargo.toml" [package] name = "libtmux-query-examples" version = "0.0.0" edition = "2024" publish = false [workspace] exclude = ["libtmux-source"] [dependencies] libtmux = { path = "libtmux-source/crates/libtmux" } tempfile = "=3.27.0" tokio = { version = "=1.53.1", features = ["macros", "rt", "time"] } [[bin]] name = "matching" path = "matching.rs" [[bin]] name = "cardinality" path = "cardinality.rs" [[bin]] name = "refresh" path = "refresh.rs" ``` Fetch the library revision used by these programs: ```console $ git clone https://github.com/libtmux/libtmux-rs libtmux-source && git -C libtmux-source checkout e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4 ``` The [`query`]() feature is enabled by default. If your application disables default features, enable [`query`]() explicitly. These examples do not need `derive`, `serde`, or `test-support`. `derive` adds typed fields for your own data, while `serde` adds the versioned query-document format. Each tmux command has a five-second limit, and the main operation has a ten-second deadline. Cleanup still runs after an operation fails. A cleanup failure reports the private directory and retains it for inspection instead of hiding the error or removing the address of a possibly running server. ## Match names and combine conditions Import [`Filterable`](https://libtmux.org/en/rs/latest/reference/query-filterable/) to call [`Session::filter_fields()`]() or [`Pane::filter_fields()`](). The returned fields construct [`FilterExpr`](https://libtmux.org/en/rs/latest/reference/query-filterexpr/) values. Text fields support text operations; boolean fields support boolean equality and membership. A boolean field has no string-prefix or numeric-comparison operation. Text matching is case sensitive unless the method ends in `_ignore_case`. Compose expressions with [`and`](), [`or`](), and [`not`](). Use ordinary [`Iterator::filter`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter) for a local closure, such as a condition that uses other application state. | Need | Text-field operation | | --- | --- | | An exact name | `eq("prod-api")` | | Part of a name | [`contains("api")`]() | | A prefix or suffix | [`starts_with("prod-")`](), [`ends_with("api")`]() | | Case-insensitive equality | [`eq_ignore_case("PROD-API")`]() | | Membership in known names | `is_in(["prod-api", "dev-api"])` | | A regular expression | [`regex("^prod-")`]() | The program creates `prod-api` and `dev-api`. It combines a prefix and suffix, checks OR and case-insensitive matching, compares a native closure, and then filters panes by their boolean `pane_active` field. That flag describes the active pane in each window, so both one-pane windows have a match. ```rust title="matching.rs" //! Filter native snapshots with typed field expressions. use std::error::Error; use std::time::Duration; use libtmux::query::{Filterable as _, QueryIteratorExt as _}; use libtmux::{NewSessionOptions, Pane, Server, Session}; type ExampleError = Box; fn check(condition: bool, message: &str) -> Result<(), ExampleError> { if condition { Ok(()) } else { Err(message.into()) } } async fn demonstrate(server: &Server) -> Result<(), ExampleError> { server .new_session(NewSessionOptions::new("prod-api").command("cat")) .await?; server .new_session(NewSessionOptions::new("dev-api").command("cat")) .await?; let sessions = server.sessions().await?; let fields = Session::filter_fields(); let production = fields .session_name .starts_with("prod-") .and(fields.session_name.ends_with("api")); let selected = sessions.iter().matching(&production).exactly_one()?; check( selected.name().as_bytes() == b"prod-api", "wrong filtered session", )?; check(sessions.len() == 2, "filtering changed the source snapshot")?; let either = fields .session_name .eq("prod-api") .or(fields.session_name.eq("dev-api")); check( sessions.iter().matching(&either).count() == 2, "OR did not select both sessions", )?; let insensitive = fields.session_name.eq_ignore_case("PROD-API"); check( sessions.iter().matching(&insensitive).count() == 1, "case-insensitive equality did not match", )?; let native = sessions .iter() .filter(|session| session.name().as_bytes().starts_with(b"prod-")); check(native.count() == 1, "native predicate disagreed")?; let regex = fields.session_name.regex("^prod-")?; check( sessions.iter().matching(®ex).count() == 1, "regex did not match", )?; check( fields.session_name.regex("(").is_err(), "invalid regex was accepted", )?; println!("query: {}", selected.name().to_string_lossy()); let panes = server.panes().await?; let pane_fields = Pane::filter_fields(); let active = pane_fields.pane_active.eq(true); let count = panes.iter().matching(&active).count(); check(count == 2, "expected one active pane per window")?; println!("active panes: {count}"); Ok(()) } #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), ExampleError> { let root = std::path::Path::new("/tmp/libtmux-rs-dev"); std::fs::create_dir_all(root)?; let directory = tempfile::Builder::new() .prefix("api-query-") .tempdir_in(root)?; std::fs::write( directory.path().join("owner"), std::process::id().to_string(), )?; let server = Server::builder() .socket_path(directory.path().join("tmux.sock")) .config_file("/dev/null") .default_timeout(Duration::from_secs(5)) .build()?; let outcome = tokio::time::timeout(Duration::from_secs(10), demonstrate(&server)).await; // Stop the owned daemon before closing the client executor. let killed = server.kill().await; let closed = server.shutdown().await; let cleanup_failed = killed.is_err() || closed.is_err(); let mut failures = Vec::new(); match outcome { Ok(Ok(())) => {} Ok(Err(error)) => failures.push(format!("example failed: {error}")), Err(error) => failures.push(format!("example deadline: {error}")), } if let Err(error) = killed { failures.push(format!("daemon cleanup: {error}")); } if let Err(error) = closed { failures.push(format!("executor cleanup: {error}")); } if cleanup_failed { let retained = directory.keep(); failures.push(format!("inspect retained directory {}", retained.display())); } else if let Err(error) = directory.close() { failures.push(format!("directory cleanup: {error}")); } if failures.is_empty() { Ok(()) } else { Err(failures.join("; ").into()) } } ``` ```console $ cargo +1.97.1 run --quiet --bin matching ``` Expected output: ```text query: prod-api active panes: 2 ``` A regex is validated when the expression is constructed. [`regex("(")`]() returns an error; the program checks that refusal. Rust regex syntax excludes lookaround and backreferences. Text predicates require valid UTF-8 in the candidate; invalid bytes do not match a text predicate, although an outer [`not`]() can invert that result. Use [`TmuxText::as_bytes()`]() when your own predicate must inspect raw bytes without a lossy conversion. Calling [`matching()`](https://libtmux.org/en/rs/latest/reference/query-queryiteratorext-matching/) on a slice iterator borrows the source collection and yields references in its original order. It is lazy: consume it with a count, collection, or result helper. It neither changes the captured objects nor eagerly creates another vector. Use `into_iter().matching_owned(...)` when selected values should move out of the original collection. ## Result counts Choose the result contract before sending input or deleting an object. Taking [`next()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next) would silently accept the first match in an ambiguous collection. | Matches | [`exactly_one()`]() | [`one_or_none()`]() | | --- | --- | --- | | None | `Err(ExactlyOneError::NoItems)` | [`Ok(None)`](https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok) | | One | [`Ok(item)`](https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok) | [`Ok(Some(item))`](https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok) | | Several | `Err(ExactlyOneError::MultipleItems)` | [`Err(MultipleItemsError)`](https://libtmux.org/en/rs/latest/reference/query-multipleitemserror/) | Both helpers preserve the iterator's item type and pull at most two items. With a [slice iterator](https://doc.rust-lang.org/std/primitive.slice.html#method.iter), a successful lookup returns a borrowed object. Neither helper issues tmux commands or refreshes a stale snapshot. This independent program checks all three result counts. The missing optional session is a normal [`None`](https://doc.rust-lang.org/std/option/enum.Option.html#variant.None); multiple sessions still produce an error. ```rust title="cardinality.rs" //! Distinguish no match, one match and multiple matches. use std::error::Error; use std::time::Duration; use libtmux::query::{ExactlyOneError, Filterable as _, MultipleItemsError, QueryIteratorExt as _}; use libtmux::{NewSessionOptions, Server, Session}; type ExampleError = Box; fn check(condition: bool, message: &str) -> Result<(), ExampleError> { if condition { Ok(()) } else { Err(message.into()) } } async fn demonstrate(server: &Server) -> Result<(), ExampleError> { server .new_session(NewSessionOptions::new("work").command("cat")) .await?; server .new_session(NewSessionOptions::new("review").command("cat")) .await?; let sessions = server.sessions().await?; let fields = Session::filter_fields(); let work = fields.session_name.eq("work"); let missing = fields.session_name.eq("missing"); check( sessions .iter() .matching(&work) .exactly_one()? .name() .as_bytes() == b"work", "wrong single match", )?; check( sessions.iter().matching(&missing).one_or_none()?.is_none(), "missing match was present", )?; check( matches!( sessions.iter().matching(&missing).exactly_one(), Err(ExactlyOneError::NoItems) ), "missing match did not report NoItems", )?; check( matches!( sessions.iter().exactly_one(), Err(ExactlyOneError::MultipleItems) ), "ambiguous match was accepted", )?; check( matches!(sessions.iter().one_or_none(), Err(MultipleItemsError)), "optional lookup accepted multiple matches", )?; println!("cardinality: none, one, multiple"); Ok(()) } #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), ExampleError> { let root = std::path::Path::new("/tmp/libtmux-rs-dev"); std::fs::create_dir_all(root)?; let directory = tempfile::Builder::new() .prefix("api-cardinality-") .tempdir_in(root)?; std::fs::write( directory.path().join("owner"), std::process::id().to_string(), )?; let server = Server::builder() .socket_path(directory.path().join("tmux.sock")) .config_file("/dev/null") .default_timeout(Duration::from_secs(5)) .build()?; let outcome = tokio::time::timeout(Duration::from_secs(10), demonstrate(&server)).await; // Stop the owned daemon before closing the client executor. let killed = server.kill().await; let closed = server.shutdown().await; let cleanup_failed = killed.is_err() || closed.is_err(); let mut failures = Vec::new(); match outcome { Ok(Ok(())) => {} Ok(Err(error)) => failures.push(format!("example failed: {error}")), Err(error) => failures.push(format!("example deadline: {error}")), } if let Err(error) = killed { failures.push(format!("daemon cleanup: {error}")); } if let Err(error) = closed { failures.push(format!("executor cleanup: {error}")); } if cleanup_failed { let retained = directory.keep(); failures.push(format!("inspect retained directory {}", retained.display())); } else if let Err(error) = directory.close() { failures.push(format!("directory cleanup: {error}")); } if failures.is_empty() { Ok(()) } else { Err(failures.join("; ").into()) } } ``` ```console $ cargo +1.97.1 run --quiet --bin cardinality ``` Expected output: ```text cardinality: none, one, multiple ``` Propagate the error with `?` when absence or ambiguity should stop your task. Match [`ExactlyOneError`](https://libtmux.org/en/rs/latest/reference/query-exactlyoneerror/) when the two failure cases need different application behavior. An optional lookup only relaxes the absent-result case; it does not choose between several candidates. ## Refresh captured state A listing captures values at the time it runs. Renaming a session refreshes the handle used for the rename, but another handle obtained earlier keeps its old snapshot. A local filter over that earlier collection still sees the old name. [`refreshed()`](https://libtmux.org/en/rs/latest/reference/session-session-refreshed/) returns a new handle with current values and preserves the original. Use [`refresh()`](https://libtmux.org/en/rs/latest/reference/session-session-refresh/) with a mutable handle to replace its values in place. Both can fail if the session disappeared or its listing could not be read. The program selects `work`, renames it through another handle, and compares the captured name with a refreshed copy and a new server-wide listing. ```rust title="refresh.rs" //! Refresh captured values without replacing the original snapshot. use std::error::Error; use std::time::Duration; use libtmux::query::{Filterable as _, QueryIteratorExt as _}; use libtmux::{NewSessionOptions, Server, Session}; type ExampleError = Box; fn check(condition: bool, message: &str) -> Result<(), ExampleError> { if condition { Ok(()) } else { Err(message.into()) } } async fn demonstrate(server: &Server) -> Result<(), ExampleError> { let mut session = server .new_session(NewSessionOptions::new("work").command("cat")) .await?; let captured = server.sessions().await?; let fields = Session::filter_fields(); let old_name = fields.session_name.eq("work"); let selected = captured.iter().matching(&old_name).exactly_one()?; session.rename("renamed").await?; check( session.name().as_bytes() == b"renamed", "rename did not refresh its receiver", )?; check( selected.name().as_bytes() == b"work", "captured handle changed itself", )?; check( captured.iter().matching(&old_name).count() == 1, "snapshot query became live", )?; let fresh = selected.refreshed().await?; check( fresh.id() == selected.id(), "refresh changed the session identity", )?; check( fresh.name().as_bytes() == b"renamed", "refresh retained the old name", )?; check( selected.name().as_bytes() == b"work", "refreshed changed its original", )?; println!( "snapshot: {} -> {}", selected.name().to_string_lossy(), fresh.name().to_string_lossy() ); let current = server.sessions().await?; check( current.iter().matching(&old_name).count() == 0, "fresh listing kept the old name", )?; println!( "fresh listing: {}", current.iter().exactly_one()?.name().to_string_lossy() ); Ok(()) } #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), ExampleError> { let root = std::path::Path::new("/tmp/libtmux-rs-dev"); std::fs::create_dir_all(root)?; let directory = tempfile::Builder::new() .prefix("query-refresh-") .tempdir_in(root)?; std::fs::write( directory.path().join("owner"), std::process::id().to_string(), )?; let server = Server::builder() .socket_path(directory.path().join("tmux.sock")) .config_file("/dev/null") .default_timeout(Duration::from_secs(5)) .build()?; let outcome = tokio::time::timeout(Duration::from_secs(10), demonstrate(&server)).await; // Stop the owned daemon before closing the client executor. let killed = server.kill().await; let closed = server.shutdown().await; let cleanup_failed = killed.is_err() || closed.is_err(); let mut failures = Vec::new(); match outcome { Ok(Ok(())) => {} Ok(Err(error)) => failures.push(format!("example failed: {error}")), Err(error) => failures.push(format!("example deadline: {error}")), } if let Err(error) = killed { failures.push(format!("daemon cleanup: {error}")); } if let Err(error) = closed { failures.push(format!("executor cleanup: {error}")); } if cleanup_failed { let retained = directory.keep(); failures.push(format!("inspect retained directory {}", retained.display())); } else if let Err(error) = directory.close() { failures.push(format!("directory cleanup: {error}")); } if failures.is_empty() { Ok(()) } else { Err(failures.join("; ").into()) } } ``` ```console $ cargo +1.97.1 run --quiet --bin refresh ``` Expected output: ```text snapshot: work -> renamed fresh listing: renamed ``` A filter result is not a reservation on the tmux object. The session can change or disappear between the listing and a later operation; handle that operation's error even after a successful lookup. Use a fresh listing when you need a new set of objects, or refresh a selected handle when you need its current fields. ## Keep local queries separate from tmux commands Typed query expressions describe captured data. They do not turn into tmux format filters, subscribe to changes, or fetch related objects. Relation predicates inspect only relations already loaded in the candidate: an empty collection makes [`any`]() false and [`all`]() and [`none`]() true; an absent to-one relation makes [`is`]() false. Use [object listings](https://libtmux.org/en/rs/latest/concepts/server-session-window-pane/) to obtain the data your workflow needs, and [command transports](https://libtmux.org/en/rs/latest/concepts/transports/) to choose how later operations reach tmux. A serialized query remains a local expression; enabling `serde` does not make it a remote tmux query. The [query module](https://github.com/libtmux/libtmux-rs/blob/e9be0b6/crates/libtmux/src/query.rs) and [session refresh methods](https://github.com/libtmux/libtmux-rs/blob/e9be0b6/crates/libtmux/src/session.rs) record these contracts for the library revision used above. --- # Filtering and queries Source: https://libtmux.org/en/scala/latest/concepts/queries/ > Compose Scala filters, distinguish zero and several matches, and query captured relations. Filter captured objects in Scala, handle result counts explicitly, and match sessions by their related windows. Local filters read captured values; they do not subscribe to changes or issue a fresh tmux query. [`Expr`](https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-query-expr-zfkn/) supports `&&`, `||` and `!`. The field companions expose equality, prefix, suffix, substring and pattern matching. Use [`.matching(expression)`]() for a typed query or `.filter(predicate)` for an ordinary Scala condition. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and JDK 25. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. The pinned source checkout supplies the Gradle wrapper and the library dependency. ```kotlin title="settings.gradle.kts" rootProject.name = "connect" includeBuild("libtmux-source") { dependencySubstitution { substitute(module("io.github.libtmux:libtmux-scala_3")) .using(project(":libtmux-scala")) } } ``` ```kotlin title="build.gradle.kts" val example = providers.gradleProperty("example").getOrElse("Local") plugins { application scala } repositories { mavenCentral() } dependencies { implementation("org.scala-lang:scala3-library_3:3.9.0") implementation("io.github.libtmux:libtmux-scala_3:0.0.1-alpha.17-SNAPSHOT") } java { toolchain { languageVersion.set(JavaLanguageVersion.of(25)) } } sourceSets.main { scala.srcDir("."); scala.include("${example}.scala") } application { mainClass.set(example) } ``` ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-java-dev directory=$(mktemp -d /tmp/libtmux-java-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Match names and combine conditions Select the two names beginning with `work-`, then assert equality, AND, OR and exclusion against the same captured collection. Matching is case sensitive. The native collection predicate agrees with the typed prefix query. ```scala title="Local.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint} import io.github.libtmux.scaladsl.* import io.github.libtmux.scaladsl.query.* import java.nio.file.Path import java.time.Duration import scala.util.Using import scala.jdk.CollectionConverters.* object Local { def main(args: Array[String]): Unit = { val socket = sys.env.getOrElse("LIBTMUX_SOCKET_PATH", throw new IllegalArgumentException("Set LIBTMUX_SOCKET_PATH to an existing socket")) val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() Using.resource(Server.open(config)) { server => val sessions = server.sessions() val matching = sessions.matching(Session.name.startsWith("work-")) val names = matching.map(_.name).sorted assert(names == Vector("work-one", "work-two")) println(names.mkString(", ")) // Filtering the captured vector makes no new tmux calls. assert(sessions.filter(_.name.startsWith("work-")) == matching) val onlyOne = Session.name.startsWith("work-") && Session.name.endsWith("one") assert(sessions.matching(onlyOne).head.name == "work-one") val either = Session.name.is("work-one") || Session.name.is("work-two") assert(sessions.matching(either).size == 2) assert(sessions.matching(!Session.name.is("work-one")).head.name == "work-two") } } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Local --console=plain --max-workers=2 ``` Expected program output: ```text work-one, work-two ``` ## Distinguish missing and ambiguous results An exactly-one selection returns an [`Either`](): one handle on success, [`CardinalityError.NoMatch`]() for zero, or [`MultipleMatches`]() for several. An at-most-one selection also rejects ambiguity; it does not pick an arbitrary first result. ```scala title="Cardinality.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint} import io.github.libtmux.scaladsl.* import io.github.libtmux.scaladsl.query.* import java.nio.file.Path import java.time.Duration import scala.util.Using import scala.jdk.CollectionConverters.* object Cardinality { def main(args: Array[String]): Unit = { val socket = sys.env.getOrElse("LIBTMUX_SOCKET_PATH", throw new IllegalArgumentException("Set LIBTMUX_SOCKET_PATH to an existing socket")) val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() Using.resource(Server.open(config)) { server => val sessions = server.sessions() for (name <- Vector("work-one", "missing")) { sessions.matching(Session.name.is(name)).exactlyOne match { case Right(session) => println(s"${session.name}: selected") case Left(CardinalityError.NoMatch) => println(s"$name: absent") case Left(CardinalityError.MultipleMatches(count)) => throw new IllegalStateException(s"At least $count sessions named $name") } } val many = sessions.matching(Session.name.startsWith("work-")).atMostOne assert(many == Left(CardinalityError.MultipleMatches(2))) println("work-: ambiguous") } } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Cardinality --console=plain --max-workers=2 ``` Expected program output: ```text work-one: selected missing: absent work-: ambiguous ``` ## Filter through related windows Match sessions with any window named `editor`, then match sessions with none. For an empty captured relation, [`any`]() is false and [`none`]() is true; `all` is true. An uncaptured relation is a different condition and must be captured before filtering. ```scala title="Relations.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint} import io.github.libtmux.scaladsl.* import io.github.libtmux.scaladsl.query.* import java.nio.file.Path import java.time.Duration import scala.util.Using import scala.jdk.CollectionConverters.* object Relations { def main(args: Array[String]): Unit = { val socket = sys.env.getOrElse("LIBTMUX_SOCKET_PATH", throw new IllegalArgumentException("Set LIBTMUX_SOCKET_PATH to an existing socket")) val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() Using.resource(Server.open(config)) { server => val sessions = server.sessions() val editorWindow = Window.name.is("editor") val withEditor = sessions.matching(Session.windows.any(editorWindow)) val withoutEditor = sessions.matching(Session.windows.none(editorWindow)) assert(withEditor.map(_.name) == Vector("work-one")) assert(withoutEditor.map(_.name) == Vector("work-two")) println(s"editor: ${withEditor.head.name}") println(s"no editor: ${withoutEditor.head.name}") } } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Relations --console=plain --max-workers=2 ``` Expected program output: ```text editor: work-one no editor: work-two ``` ## Refresh before repeating a decision Reusing the same list repeats the same decision over old state. Capture again when you need to observe a rename, new window or closed pane. The [snapshot example](https://libtmux.org/en/scala/latest/concepts/server-session-window-pane/#observe-a-rename-with-a-fresh-read) shows the old and fresh values side by side. --- # Filtering and queries Source: https://libtmux.org/en/ts/latest/concepts/queries/ > Match names, handle missing and ambiguous results, traverse linked windows, refresh snapshots, and validate saved TypeScript queries. Read a snapshot once, then query its sessions, windows, panes, and clients in TypeScript. [`Selection.where()`](https://libtmux.org/en/ts/latest/reference/selection-selection-where/) filters that captured state without another tmux command. Use [`one()`](https://libtmux.org/en/ts/latest/reference/selection-selection-one/) when the next operation requires exactly one target. ## Setup and run These are independent programs with imports, assertions, and cleanup. Each creates a private tmux server, runs `cat` in its panes to keep them alive, and stops its server before exiting. They require Bun 1.4.2 or newer, tmux 3.2a or newer, and a Unix environment. You do not need an existing tmux session. In an empty directory, save this file as `package.json`: ```json title="package.json" {"type":"module","dependencies":{"libtmux":"file:./libtmux/packages/libtmux"}} ``` Install the library revision used to run the examples: ```console $ git clone https://github.com/libtmux/libtmux-ts libtmux && git -C libtmux checkout 3fe1ca654b81b8cbf4a13b777a001a3298c87a6f && bun install ``` Save any program below in that directory and run its command. Each program includes its own setup; none depends on another example's variables or server. A failed assertion or cleanup exits with an error. If cleanup fails, the error names the retained directory so the private server remains reachable. ## Match names and combine conditions A bare value means equality. Matching is case sensitive unless that field's criterion has `mode: "insensitive"`. Fields in one object and successive [`.where()`]() calls combine with AND; `AND`, `OR`, and `NOT` compose whole criteria. [`.filter()`]() accepts a JavaScript predicate when a condition needs application code, such as membership in an existing [`Set`](). | Task | Criterion for `name` | | --- | --- | | Equal | `"app-api"` or `{ equals: "app-api" }` | | Contain text | `{ contains: "api" }` | | Start or end with text | `{ startsWith: "app-" }`, `{ endsWith: "worker" }` | | Ignore case | `{ contains: "MYAPP", mode: "insensitive" }` | | Be in a list | `{ in: ["app-api", "app-worker"] }` | | Be outside a list | `{ notIn: ["shell"] }` | | Match a pattern | `{ regex: { pattern: "^app-v[0-9]+-0$", flags: "" } }` | Save as `matching.ts`. It selects exact names, composes conditions, and compares structured criteria with a local predicate. ```typescript title="matching.ts" import assert from "node:assert/strict"; import { mkdtemp, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Server } from "libtmux"; const directory = await mkdtemp(join(tmpdir(), "libtmux-query-")); const server = new Server({ socketPath: join(directory, "tmux.sock"), configFile: "/dev/null", timeoutMs: 5_000, }); const failures: unknown[] = []; try { const session = await server.newSession({ name: "work", windowName: "shell", shellCommand: "cat", }); for (const name of ["app-api", "app-worker", "MyApp-logs", "app-v1-0", "app-beta"]) { await session.newWindow({ name, shellCommand: "cat" }); } const { windows } = await server.snapshot(); const exact = windows.where({ name: "app-api" }); assert.equal(exact.one().name, "app-api"); console.log("exact:", exact.one().name); const worker = windows.where({ name: { startsWith: "app-" } }) .where({ name: { endsWith: "worker" } }); assert.equal(worker.one().name, "app-worker"); console.log("prefix AND suffix:", worker.one().name); const apiOrLogs = windows.where({ OR: [{ name: "app-api" }, { name: { contains: "logs" } }], NOT: [{ name: "shell" }], }).map((window) => window.name).sort(); assert.deepEqual(apiOrLogs, ["MyApp-logs", "app-api"]); console.log("OR and NOT:", apiOrLogs.join(", ")); const insensitive = windows.where({ name: { contains: "MYAPP", mode: "insensitive" }, }); assert.equal(insensitive.one().name, "MyApp-logs"); console.log("case insensitive:", insensitive.one().name); const versioned = windows.where({ name: { regex: { pattern: "^app-v[0-9]+-0$", flags: "" } }, }); assert.equal(versioned.one().name, "app-v1-0"); console.log("regex:", versioned.one().name); const selected = windows.where({ name: { in: ["app-api", "app-worker"] } }); assert.equal(selected.count(), 2); assert.equal(selected.where({ name: { notIn: ["app-worker"] } }).one().name, "app-api"); console.log("membership:", selected.map((window) => window.name).sort().join(", ")); const namesFromConfig = new Set(["shell", "app-beta"]); const local = windows.filter((window) => namesFromConfig.has(window.name)); assert.equal(local.count(), 2); console.log("predicate:", local.map((window) => window.name).sort().join(", ")); } catch (error) { failures.push(error); } finally { try { if ((await readdir(directory)).includes("tmux.sock")) await server.kill(); await rm(directory, { recursive: true }); } catch (error) { failures.push(new Error(`Cleanup failed; inspect ${directory}`, { cause: error })); } } if (failures.length > 0) throw new AggregateError(failures, "Query example failed"); ``` ```console $ bun run matching.ts ``` The output identifies `app-api`, `app-worker`, and `MyApp-logs`; the version pattern selects `app-v1-0`. Membership selects two application windows, while the predicate selects `app-beta` and `shell`. ### Regular expression limits Structured regex criteria use a restricted grammar. This revision accepts at most 512 UTF-16 code units and one repetition operator. A repeated pattern must start with `^`, cannot repeat a group, and cannot combine repetition with alternation or multiline mode. It rejects lookarounds, backreferences, and escapes such as `\d`; use `[0-9]` for digits. Accepted flags are `""`, `"m"`, `"s"`, and `"ms"`; use the field's `mode: "insensitive"` for case folding. A syntactically valid JavaScript pattern can therefore raise [`QueryValidationError`](https://libtmux.org/en/ts/latest/reference/errors-queryvalidationerror/) here. The saved-query example below checks that rejection. For a trusted pattern that needs the full JavaScript grammar, use a predicate with a [`RegExp`](); that predicate is local code and cannot be encoded as a query document. ## Handle zero, one, and several matches Choose the result contract before using a target: | Operation | Zero matches | One match | Several matches | | --- | --- | --- | --- | | [`.where()`]() | Empty selection | Selection | Selection | | [`.one()`]() | [`NoMatchError`]() | Object | [`MultipleMatchesError`]() | | [`.oneOrUndefined()`]() | [`undefined`]() | Object | [`MultipleMatchesError`]() | | [`.first()`]() | [`undefined`]() | Object | First object in tmux order | | [`.exists()`]() | `false` | `true` | `true` | | `.count()` | `0` | `1` | Match count | Use [`.first()`]() when any first result is acceptable. It does not establish that there is only one target. [`.oneOrUndefined()`]() relaxes only the missing case; it still reports ambiguity. Save as `single-result.ts`. This handles missing and ambiguous results separately and rethrows unexpected failures. ```typescript title="single-result.ts" import assert from "node:assert/strict"; import { mkdtemp, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Server, MultipleMatchesError, NoMatchError } from "libtmux"; const directory = await mkdtemp(join(tmpdir(), "libtmux-query-")); const server = new Server({ socketPath: join(directory, "tmux.sock"), configFile: "/dev/null", timeoutMs: 5_000, }); const failures: unknown[] = []; try { const session = await server.newSession({ name: "work", windowName: "editor", shellCommand: "cat", }); await session.newWindow({ name: "logs", shellCommand: "cat" }); const { windows } = await server.snapshot(); assert.equal(windows.one({ name: "logs" }).name, "logs"); assert.equal(windows.oneOrUndefined({ name: "missing" }), undefined); assert.equal(windows.exists({ name: "missing" }), false); console.log("optional missing:", windows.oneOrUndefined({ name: "missing" })); try { windows.one({ name: "missing" }); throw new Error("Expected the missing lookup to fail"); } catch (error) { if (!(error instanceof NoMatchError)) throw error; console.log("missing:", error.code); } for (const lookup of [() => windows.one(), () => windows.oneOrUndefined()]) { try { lookup(); throw new Error("Expected the ambiguous lookup to fail"); } catch (error) { if (!(error instanceof MultipleMatchesError)) throw error; assert.equal(error.count, 2); console.log("ambiguous:", error.code, error.count); } } assert.equal(windows.first()?.name, "editor"); console.log("first:", windows.first()?.name); } catch (error) { failures.push(error); } finally { try { if ((await readdir(directory)).includes("tmux.sock")) await server.kill(); await rm(directory, { recursive: true }); } catch (error) { failures.push(new Error(`Cleanup failed; inspect ${directory}`, { cause: error })); } } if (failures.length > 0) throw new AggregateError(failures, "Query example failed"); ``` ```console $ bun run single-result.ts ``` The program prints [`undefined`]() for an optional missing window, [`NoMatchError`]() for a required missing window, and `MultipleMatchesError 2` for both ambiguous lookups. [`first()`]() returns `editor` because it occupies the first window index. ## Query relations and linked windows A server-wide window selection contains placements: a window linked into two sessions appears twice with the same window ID. A pane reached through those placements also has session context. Add a [`session`]() criterion when the action needs a particular placement. Use [`linkedSessions`](https://libtmux.org/en/ts/latest/reference/window-window-linkedsessions/) to inspect the sessions holding the window. Collection relations accept `some`, `every`, and `none`. `every` and `none` are true for an empty collection; combine `some: {}` with `every` when you require at least one related object. Single-object relations use `is` and `isNot`; `is: null` matches an absent relation. Save as `relations.ts`. It links one logs window into a second session, selects its home placement, and queries sessions and panes through their relations. ```typescript title="relations.ts" import assert from "node:assert/strict"; import { mkdtemp, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Server, MultipleMatchesError } from "libtmux"; const directory = await mkdtemp(join(tmpdir(), "libtmux-query-")); const server = new Server({ socketPath: join(directory, "tmux.sock"), configFile: "/dev/null", timeoutMs: 5_000, }); const failures: unknown[] = []; try { const home = await server.newSession({ name: "home", windowName: "logs", shellCommand: "cat", }); const guest = await server.newSession({ name: "guest", windowName: "shell", shellCommand: "cat", }); const shared = home.windows.one({ name: "logs" }); await shared.link({ session: guest }); const snapshot = await server.snapshot(); const placements = snapshot.windows.where({ id: shared.id }); assert.equal(placements.count(), 2); console.log("placements:", placements.count()); try { placements.one(); throw new Error("Expected two placements to be ambiguous"); } catch (error) { if (!(error instanceof MultipleMatchesError)) throw error; console.log("same ID:", error.code); } const atHome = placements.one({ session: { is: { name: "home" } } }); assert.equal(atHome.session?.name, "home"); const owners = atHome.linkedSessions.map((session) => session.name).sort(); assert.deepEqual(owners, ["guest", "home"]); console.log("linked sessions:", owners.join(", ")); const hasLogs = snapshot.sessions.where({ windows: { some: { name: "logs" } } }); assert.equal(hasLogs.count(), 2); const onlyLogs = snapshot.sessions.where({ windows: { some: {}, every: { name: "logs" } }, }); assert.equal(onlyLogs.one().name, "home"); const noShell = snapshot.sessions.where({ windows: { none: { name: "shell" } } }); assert.equal(noShell.one().name, "home"); console.log("some logs:", hasLogs.map((session) => session.name).sort().join(", ")); console.log("every window is logs:", onlyLogs.one().name); console.log("no shell:", noShell.one().name); const guestPanes = snapshot.panes.where({ session: { is: { name: "guest" } } }); assert.equal(guestPanes.count(), 2); console.log("panes reached through guest:", guestPanes.count()); } catch (error) { failures.push(error); } finally { try { if ((await readdir(directory)).includes("tmux.sock")) await server.kill(); await rm(directory, { recursive: true }); } catch (error) { failures.push(new Error(`Cleanup failed; inspect ${directory}`, { cause: error })); } } if (failures.length > 0) throw new AggregateError(failures, "Query example failed"); ``` ```console $ bun run relations.ts ``` The logs window has two placements and two linked sessions. Both sessions have some logs window. Only `home` has every window named `logs` and no window named `shell`. The guest session contains two panes through its two windows. These relations come from the same snapshot. Traversing them does not refresh the server. A scalar window mutation such as `rename()` affects that window in every session that links it; selecting a placement does not create a copy. ## Refresh after a mutation [`Server.snapshot()`](https://libtmux.org/en/ts/latest/reference/server-server-snapshot/) acquires the state. Filtering and reading relations use it locally. A handle can issue a mutation, but its captured fields and earlier selections keep their old values. Acquire another snapshot to observe the result. Save as `refresh.ts`. It creates a window after a snapshot, then renames it and compares old and fresh reads. ```typescript title="refresh.ts" import assert from "node:assert/strict"; import { mkdtemp, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Server } from "libtmux"; const directory = await mkdtemp(join(tmpdir(), "libtmux-query-")); const server = new Server({ socketPath: join(directory, "tmux.sock"), configFile: "/dev/null", timeoutMs: 5_000, }); const failures: unknown[] = []; try { const session = await server.newSession({ name: "work", windowName: "editor", shellCommand: "cat", }); const before = await server.snapshot(); await session.newWindow({ name: "logs", shellCommand: "cat" }); assert.equal(before.windows.exists({ name: "logs" }), false); console.log("old snapshot sees logs:", before.windows.exists({ name: "logs" })); const after = await server.snapshot(); assert.equal(after.windows.exists({ name: "logs" }), true); console.log("fresh snapshot sees logs:", after.windows.exists({ name: "logs" })); const logs = after.windows.one({ name: "logs" }); await logs.rename("archive"); assert.equal(logs.name, "logs"); assert.equal(after.windows.one({ id: logs.id }).name, "logs"); console.log("captured name after rename:", logs.name); const renamed = await server.snapshot(); assert.equal(renamed.windows.one({ id: logs.id }).name, "archive"); console.log("refreshed name:", renamed.windows.one({ id: logs.id }).name); } catch (error) { failures.push(error); } finally { try { if ((await readdir(directory)).includes("tmux.sock")) await server.kill(); await rm(directory, { recursive: true }); } catch (error) { failures.push(new Error(`Cleanup failed; inspect ${directory}`, { cause: error })); } } if (failures.length > 0) throw new AggregateError(failures, "Query example failed"); ``` ```console $ bun run refresh.ts ``` The old snapshot reports no logs window. The fresh one finds it. After the rename, the existing handle still reports `logs`; another snapshot reports `archive` for the same ID. Prefer one snapshot when several queries should describe the same captured state. Calling [`server.sessions()`](), [`server.windows()`](), and [`server.panes()`]() separately takes a separate snapshot for each call. A snapshot also cannot prevent another process from removing a target before a later mutation; handle that command's error at the mutation boundary. ## Save and validate criteria [`encodeWhereDocument()`](https://libtmux.org/en/ts/latest/reference/selection-encodewheredocument/) serializes a versioned query. Parse its JSON and pass the value to [`decodeWhereDocument()`](https://libtmux.org/en/ts/latest/reference/selection-decodewheredocument/) before applying it. Check the document's model so session criteria go to the session selection. Use the encoder and decoder to preserve the wire format; do not cast unvalidated JSON to a criteria type. Save as `query-document.ts`. It round-trips a session query, rejects an unknown field, and catches a regex outside the supported grammar. ```typescript title="query-document.ts" import assert from "node:assert/strict"; import { mkdtemp, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Server, decodeWhereDocument, encodeWhereDocument, QueryValidationError, } from "libtmux"; const directory = await mkdtemp(join(tmpdir(), "libtmux-query-")); const server = new Server({ socketPath: join(directory, "tmux.sock"), configFile: "/dev/null", timeoutMs: 5_000, }); const failures: unknown[] = []; try { await server.newSession({ name: "prod-api", shellCommand: "cat" }); await server.newSession({ name: "dev-api", shellCommand: "cat" }); const encoded = encodeWhereDocument({ version: 1, model: "session", where: { name: { startsWith: "prod-" } }, }); const document = decodeWhereDocument(JSON.parse(encoded)); assert.equal(document.model, "session"); if (document.model !== "session") throw new Error("Expected session criteria"); const snapshot = await server.snapshot(); const selected = snapshot.sessions.where(document.where); assert.equal(selected.one().name, "prod-api"); console.log("decoded query:", selected.one().name); console.log("wire JSON:", encoded); try { decodeWhereDocument({ version: 1, model: "session", where: { session_naem: "prod-api" } }); throw new Error("Expected an unknown field to fail validation"); } catch (error) { if (!(error instanceof QueryValidationError)) throw error; assert.equal(error.reason, "invalid-query"); console.log("invalid document:", error.code, error.reason); } try { snapshot.sessions.where({ name: { regex: { pattern: "^prod-[a-z]+-[0-9]+$", flags: "" } }, }); throw new Error("Expected multiple repetitions to fail validation"); } catch (error) { if (!(error instanceof QueryValidationError)) throw error; console.log("unsupported regex:", error.code); } } catch (error) { failures.push(error); } finally { try { if ((await readdir(directory)).includes("tmux.sock")) await server.kill(); await rm(directory, { recursive: true }); } catch (error) { failures.push(new Error(`Cleanup failed; inspect ${directory}`, { cause: error })); } } if (failures.length > 0) throw new AggregateError(failures, "Query example failed"); ``` ```console $ bun run query-document.ts ``` The decoded query selects `prod-api`. Both invalid inputs raise [`QueryValidationError`](). Its `reason` distinguishes invalid IDs from invalid criteria; `path` identifies the failing field or nested condition. A valid criterion can still name a field introduced after the running tmux version. That raises [`VersionTooLowError`](https://libtmux.org/en/ts/latest/reference/errors-versiontoolowerror/), which carries [`criteriaName`](), [`serverVersion`](), and [`since`](). Treat a version error as an unsupported query, not as evidence that no objects match. ## Filter a live tmux listing Use snapshot selections when you need typed handles, relations, several local queries, or JavaScript predicates. To request only matching rows from tmux, call [`Server.cmd()`]() with a list command's `-f` option. This returns output lines; it does not return a [`Selection`]() or apply the TypeScript criteria grammar. Save as `tmux-filter.ts`. It lists production sessions with a tmux glob, then shows why an unknown format token can look like a valid empty result. ```typescript title="tmux-filter.ts" import assert from "node:assert/strict"; import { mkdtemp, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Server } from "libtmux"; const directory = await mkdtemp(join(tmpdir(), "libtmux-query-")); const server = new Server({ socketPath: join(directory, "tmux.sock"), configFile: "/dev/null", timeoutMs: 5_000, }); const failures: unknown[] = []; try { await server.newSession({ name: "prod-api", shellCommand: "cat" }); await server.newSession({ name: "dev-api", shellCommand: "cat" }); const expression = "#{m:prod-*,#{session_name}}"; const names = await server.cmd("list-sessions", [ "-f", expression, "-F", "#{session_name}", ]); assert.deepEqual(names, ["prod-api"]); console.log("tmux matches:", names.join(", ")); const unknown = "#{session_naem}"; const empty = await server.cmd("list-sessions", [ "-f", unknown, "-F", "#{session_name}", ]); assert.deepEqual(empty, []); console.log("unknown token matches:", empty.length); const expansion = await server.cmd("display-message", [ "-p", "-t", "=prod-api:", expression, ]); assert.deepEqual(expansion, ["1"]); const badExpansion = await server.cmd("display-message", [ "-p", "-t", "=prod-api:", `value=<${unknown}>`, ]); assert.deepEqual(badExpansion, ["value=<>"]); console.log("valid expression:", expansion[0]); console.log("unknown token:", badExpansion[0]); } catch (error) { failures.push(error); } finally { try { if ((await readdir(directory)).includes("tmux.sock")) await server.kill(); await rm(directory, { recursive: true }); } catch (error) { failures.push(new Error(`Cleanup failed; inspect ${directory}`, { cause: error })); } } if (failures.length > 0) throw new AggregateError(failures, "Query example failed"); ``` ```console $ bun run tmux-filter.ts ``` The glob returns `prod-api`. The misspelled `session_naem` returns zero rows without a command error. Expanding the valid expression prints `1`; expanding the unknown token between delimiters prints `value=<>`. When a live filter unexpectedly returns nothing, first run the same listing without `-f` to confirm the objects exist. Expand the expression with `display-message -p` against a known target, and check its token names against the running tmux version's manual. Keep each command argument separate as above; these strings go to tmux without shell interpolation. ## API and related tasks - [`Selection`](https://libtmux.org/en/ts/latest/reference/selection-selection/) defines iteration, criteria, predicates, counts, and exactly-one lookup. - [`Server`](https://libtmux.org/en/ts/latest/reference/server-server/) owns snapshot acquisition and command execution. - [Traversal](https://libtmux.org/en/ts/latest/topics/traversal/) explains object relationships and identity. - [Sending keys](https://libtmux.org/en/ts/latest/guides/sending-keys/) uses a selected pane as an input target. - [Capturing output](https://libtmux.org/en/ts/latest/guides/capturing-output/) reads a selected pane's screen. --- # Commands and control mode Source: https://libtmux.org/en/fsharp/latest/concepts/transports/ > Use F# command calls and persistent control connections with explicit cleanup. Choose command calls for bounded operations and a control connection when you need a persistent tmux client. Closing a client releases its resources; it does not mean the tmux server should be stopped. [`Server.capture`](https://libtmux.org/en/fsharp/latest/reference/libtmux-fsharp-server-capture/) returns a task and takes an explicit cancellation token. The default connection executes command requests through subprocesses. [`Control.withSession`](https://libtmux.org/en/fsharp/latest/reference/libtmux-fsharp-control-withsession/) brackets a persistent control session and closes it when the callback finishes. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and .NET SDK 10.0.302. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. ```xml title="Query.fsproj" Exe net10.0 Local ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-dotnet-dev directory=$(mktemp -d /tmp/libtmux-dotnet-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-dotnet libtmux-source && git -C libtmux-source checkout 2d99ead5aba8d968e85dcac8c9a9a518452e6ba6 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Run a bounded command and inspect its result Read the session list and filter it locally. The connection uses a five-second timeout so an unavailable server fails visibly. ```fsharp title="Local.fs" open System open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let run () = task { let socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") if String.IsNullOrEmpty(socket) then invalidOp "Set LIBTMUX_SOCKET_PATH to an existing socket" use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5.0)) let token = timeout.Token let! server = LibTmux.Server.ConnectAsync( ServerConnectionOptions(SocketPath = socket), token) let! captured = server |> Server.capture token SnapshotDepth.Sessions let prefix = Filter.startsWith "work-" SessionFields.name let matching = captured.Sessions |> Query.matching prefix let names = matching |> Seq.map (fun session -> session.Name) |> Seq.sort |> Seq.toList if names <> [ "work-one"; "work-two" ] then failwith "Unexpected sessions" printfn "%s" (String.concat ", " names) let native = captured.Sessions |> Seq.filter (fun session -> session.Name.StartsWith("work-")) if Seq.length native <> matching.Count then failwith "Local filters disagree" let onlyOne = Filter.allOf [ Filter.startsWith "work-" SessionFields.name Filter.eq "work-one" SessionFields.name ] let selected = captured.Sessions |> Query.matching onlyOne if selected.Count <> 1 || selected[0].Name <> "work-one" then failwith "Wrong AND result" let either = Filter.oneOf [ "work-one"; "work-two" ] SessionFields.name if (captured.Sessions |> Query.matching either).Count <> 2 then failwith "Wrong OR result" let excluded = Filter.eq "work-one" SessionFields.name |> Filter.negate let remaining = captured.Sessions |> Query.matching excluded if remaining.Count <> 1 || remaining[0].Name <> "work-two" then failwith "Wrong NOT result" } [] let main _ = try run().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ```console $ dotnet build Query.fsproj --maxcpucount:1 -p:Example=Local \ -p:DisableImplicitLibraryPacksFolder=true -p:RestorePackagesPath="$PWD/.packages" && sh run.sh dotnet run --project Query.fsproj --no-build -p:Example=Local ``` Expected program output: ```text work-one, work-two ``` ## Open and close a control client Send `list-sessions` over a persistent control connection, verify the response, then close the control client. A subsequent ordinary read verifies the tmux server still has both sessions. ```fsharp title="Control.fs" open System open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let run () = task { let socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") if String.IsNullOrEmpty(socket) then invalidOp "Set LIBTMUX_SOCKET_PATH to an existing socket" use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5.0)) let token = timeout.Token let! server = LibTmux.Server.ConnectAsync( ServerConnectionOptions(SocketPath = socket), token) do! server |> Control.withSession token (fun control -> task { let command = TmuxCommand.Create("list-sessions", "-F", "#{session_name}") let! lines = control.SendAsync(command, token) let names = lines |> Seq.sort |> Seq.toList if names <> [ "work-one"; "work-two" ] then failwith "Unexpected sessions" printfn "%s" (String.concat ", " names) }) let! captured = server |> Server.capture token SnapshotDepth.Sessions if captured.Sessions.Count <> 2 then failwith "Server lost its sessions" printfn "control client closed; server still running" } [] let main _ = try run().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ```console $ dotnet build Query.fsproj --maxcpucount:1 -p:Example=Control \ -p:DisableImplicitLibraryPacksFolder=true -p:RestorePackagesPath="$PWD/.packages" && sh run.sh dotnet run --project Query.fsproj --no-build -p:Example=Control ``` Expected program output: ```text work-one, work-two control client closed; server still running ``` ## Timeouts and ownership An operation that times out may already have reached tmux. Read the current state before retrying a mutation such as creating a window. A cancellation signal does not roll back a completed tmux command. Here the launcher owns the private server and stops it after the program exits. An application connecting to an existing server should close its own client resources and leave that server running. See [attaching to tmux](https://libtmux.org/en/fsharp/latest/guides/attaching-to-tmux/) for the connection-only example. --- # Commands and control mode Source: https://libtmux.org/en/kotlin/latest/concepts/transports/ > Use Kotlin command calls and persistent control connections with explicit cleanup. Choose command calls for bounded operations and a control connection when you need a persistent tmux client. Closing a client releases its resources; it does not mean the tmux server should be stopped. [`withServer`](https://libtmux.org/en/kotlin/latest/reference/io-github-libtmux-kotlin-withserver/) closes the borrowed client scope. Suspended command calls use the configured execution policy. A suspend function is not itself a persistent control connection; open one explicitly with [`withControl`](https://libtmux.org/en/kotlin/latest/reference/io-github-libtmux-kotlin-withcontrol/). ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and JDK 25. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. The pinned source checkout supplies the Gradle wrapper and the library dependency. ```kotlin title="settings.gradle.kts" rootProject.name = "connect" includeBuild("libtmux-source") ``` ```kotlin title="build.gradle.kts" val example = providers.gradleProperty("example").getOrElse("Local") plugins { application kotlin("jvm") version "2.4.10" } repositories { mavenCentral() } dependencies { implementation("io.github.libtmux:libtmux-kotlin:0.0.1-alpha.17-SNAPSHOT") } kotlin { jvmToolchain(25) sourceSets.main { kotlin.srcDir("."); kotlin.include("${example}.kt") } } application { mainClass.set("${example}Kt") } ``` ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-java-dev directory=$(mktemp -d /tmp/libtmux-java-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Run a bounded command and inspect its result Read the session list and filter it locally. The connection uses a five-second timeout so an unavailable server fails visibly. ```kotlin title="Local.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.* import io.github.libtmux.kotlin.query.* import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.runBlocking fun main() = runBlocking { val socket = requireNotNull(System.getenv("LIBTMUX_SOCKET_PATH")) { "Set LIBTMUX_SOCKET_PATH to an existing socket" } val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() withServer(config) { server -> val sessions = server.sessions() val matching = sessions.filter(Session.name startsWith "work-") val names = matching.map { it.name }.sorted() check(names == listOf("work-one", "work-two")) println(names.joinToString(", ")) // Filtering the captured list makes no new tmux calls. check(sessions.filter { it.name.startsWith("work-") } == matching) val onlyOne = (Session.name startsWith "work-").and(Session.name endsWith "one") check(sessions.filter(onlyOne).single().name == "work-one") val either = (Session.name eq "work-one").or(Session.name eq "work-two") check(sessions.filter(either).size == 2) check(sessions.filter(!(Session.name eq "work-one")).single().name == "work-two") } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Local --console=plain --max-workers=2 ``` Expected program output: ```text work-one, work-two ``` ## Open and close a control client Send `list-sessions` over a persistent control connection, verify the response, then close the control client. A subsequent ordinary read verifies the tmux server still has both sessions. ```kotlin title="Control.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.* import io.github.libtmux.kotlin.query.* import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.runBlocking fun main() = runBlocking { val socket = requireNotNull(System.getenv("LIBTMUX_SOCKET_PATH")) { "Set LIBTMUX_SOCKET_PATH to an existing socket" } val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() withServer(config) { server -> val session = server.sessions().single { it.name == "work-one" } withControl(server, session) { control -> val reply = control.send("list-sessions", "-F", "#{session_name}") check(reply.succeeded()) { "tmux rejected list-sessions: ${reply.outcome()}" } val names = reply.lines().sorted() check(names == listOf("work-one", "work-two")) println(names.joinToString(", ")) } check(server.sessions().size == 2) println("control client closed; server still running") } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Control --console=plain --max-workers=2 ``` Expected program output: ```text work-one, work-two control client closed; server still running ``` ## Timeouts and ownership An operation that times out may already have reached tmux. Read the current state before retrying a mutation such as creating a window. A cancellation signal does not roll back a completed tmux command. Here the launcher owns the private server and stops it after the program exits. An application connecting to an existing server should close its own client resources and leave that server running. See [attaching to tmux](https://libtmux.org/en/kotlin/latest/guides/attaching-to-tmux/) for the connection-only example. --- # Commands and control mode Source: https://libtmux.org/en/scala/latest/concepts/transports/ > Use Scala command calls and persistent control connections with explicit cleanup. Choose command calls for bounded operations and a control connection when you need a persistent tmux client. Closing a client releases its resources; it does not mean the tmux server should be stopped. The direct [`Server`](https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-server/) API blocks until the operation completes. [`Using.resource`]() closes its client resources. For effectful applications, the [execution guide](https://libtmux.org/en/scala/latest/guides/execution/) covers the Cats Effect and Ox packages. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and JDK 25. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. The pinned source checkout supplies the Gradle wrapper and the library dependency. ```kotlin title="settings.gradle.kts" rootProject.name = "connect" includeBuild("libtmux-source") { dependencySubstitution { substitute(module("io.github.libtmux:libtmux-scala_3")) .using(project(":libtmux-scala")) } } ``` ```kotlin title="build.gradle.kts" val example = providers.gradleProperty("example").getOrElse("Local") plugins { application scala } repositories { mavenCentral() } dependencies { implementation("org.scala-lang:scala3-library_3:3.9.0") implementation("io.github.libtmux:libtmux-scala_3:0.0.1-alpha.17-SNAPSHOT") } java { toolchain { languageVersion.set(JavaLanguageVersion.of(25)) } } sourceSets.main { scala.srcDir("."); scala.include("${example}.scala") } application { mainClass.set(example) } ``` ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-java-dev directory=$(mktemp -d /tmp/libtmux-java-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Run a bounded command and inspect its result Read the session list and filter it locally. The connection uses a five-second timeout so an unavailable server fails visibly. ```scala title="Local.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint} import io.github.libtmux.scaladsl.* import io.github.libtmux.scaladsl.query.* import java.nio.file.Path import java.time.Duration import scala.util.Using import scala.jdk.CollectionConverters.* object Local { def main(args: Array[String]): Unit = { val socket = sys.env.getOrElse("LIBTMUX_SOCKET_PATH", throw new IllegalArgumentException("Set LIBTMUX_SOCKET_PATH to an existing socket")) val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() Using.resource(Server.open(config)) { server => val sessions = server.sessions() val matching = sessions.matching(Session.name.startsWith("work-")) val names = matching.map(_.name).sorted assert(names == Vector("work-one", "work-two")) println(names.mkString(", ")) // Filtering the captured vector makes no new tmux calls. assert(sessions.filter(_.name.startsWith("work-")) == matching) val onlyOne = Session.name.startsWith("work-") && Session.name.endsWith("one") assert(sessions.matching(onlyOne).head.name == "work-one") val either = Session.name.is("work-one") || Session.name.is("work-two") assert(sessions.matching(either).size == 2) assert(sessions.matching(!Session.name.is("work-one")).head.name == "work-two") } } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Local --console=plain --max-workers=2 ``` Expected program output: ```text work-one, work-two ``` ## Open and close a control client Send `list-sessions` over a persistent control connection, verify the response, then close the control client. A subsequent ordinary read verifies the tmux server still has both sessions. ```scala title="Control.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint} import io.github.libtmux.scaladsl.* import io.github.libtmux.scaladsl.query.* import java.nio.file.Path import java.time.Duration import scala.util.Using import scala.jdk.CollectionConverters.* object Control { def main(args: Array[String]): Unit = { val socket = sys.env.getOrElse("LIBTMUX_SOCKET_PATH", throw new IllegalArgumentException("Set LIBTMUX_SOCKET_PATH to an existing socket")) val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() Using.resource(Server.open(config)) { server => val session = server.sessions().find(_.name == "work-one").get Using.resource(server.control(session)) { control => val reply = control.send("list-sessions", "-F", "#{session_name}") require(reply.succeeded(), s"tmux rejected list-sessions: ${reply.outcome()}") val names = reply.lines().asScala.toVector.sorted assert(names == Vector("work-one", "work-two")) println(names.mkString(", ")) } assert(server.sessions().size == 2) println("control client closed; server still running") } } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Control --console=plain --max-workers=2 ``` Expected program output: ```text work-one, work-two control client closed; server still running ``` ## Timeouts and ownership An operation that times out may already have reached tmux. Read the current state before retrying a mutation such as creating a window. A cancellation signal does not roll back a completed tmux command. Here the launcher owns the private server and stops it after the program exits. An application connecting to an existing server should close its own client resources and leave that server running. See [attaching to tmux](https://libtmux.org/en/scala/latest/guides/attaching-to-tmux/) for the connection-only example. --- # Workspaces Source: https://libtmux.org/en/tmux/concepts/workspaces/ > Build pane layouts with the object API or a workspace configuration file. A workspace arranges windows and panes for a task, such as editing code, running a development server, and following logs. Build it with the object API when the layout depends on program logic. Use a declarative builder when you want to store the layout in a configuration file, such as [tmuxp](https://tmuxp.git-pull.com/) YAML or JSON. ## Building one imperatively Create a window, split it into panes, apply a layout, and send each pane its command: ```python def create_dev_workspace(session, name='dev'): window = session.new_window(window_name=name, attach=False) window.resize(height=50, width=160) main_pane = window.active_pane terminal_pane = main_pane.split(size='30%') log_pane = terminal_pane.split(direction=PaneDirection.Right) return {'window': window, 'main': main_pane, 'terminal': terminal_pane, 'logs': log_pane} ``` ```rust let mut window = session.new_window("dev").await?; let main_pane = window.active_pane().await?.expect("a new window has a pane"); let terminal_pane = main_pane .split(SplitOptions::new(SplitDirection::Below).size(PaneSize::Percent(30))) .await?; let logs_pane = terminal_pane .split(SplitOptions::new(SplitDirection::Right)) .await?; window.select_layout(Layout::MainVertical).await?; ``` ```go window, err := session.NewWindow(ctx, tmux.NewWindowRequest{Name: tmux.Ptr("dev")}) if err != nil { return err } // Attach: true makes the split active, so the next split divides it rather // than the pane that was already there. terminal, err := window.SplitPane(ctx, tmux.SplitPaneRequest{ Attach: true, Percentage: tmux.Ptr(30), }) if err != nil { return err } if _, err := window.SplitPane(ctx, tmux.SplitPaneRequest{Direction: tmux.PaneDirectionRight}); err != nil { return err } _ = terminal return window.SelectLayout(ctx, tmux.SelectLayoutRequest{Layout: "main-vertical"}) ``` ```java Window window = session.newWindow(w -> w.named("dev").detached()); Pane terminal = window.split(split -> split.percent(30)); Pane logs = terminal.split(split -> split.toRight()); window.selectLayout(Layout.MAIN_VERTICAL); ``` ```csharp Window window = await session.CreateWindowAsync(new NewWindowRequest(name: "dev")); Pane main = (await window.GetPanesAsync())[0]; Pane terminal = await main.SplitAsync(new SplitPaneRequest(percentage: 30)); Pane logs = await terminal.SplitAsync(new SplitPaneRequest(direction: PaneDirection.Right)); await window.SelectLayoutAsync(new SelectLayoutRequest("main-vertical")); ``` ```cpp 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"); ``` ```swift let session = try await server.newSession(named: "work") let window = try await server.newWindow(in: session, named: "dev").window let terminal = try await server.splitWindow(window, size: .percentage(30)) let logs = try await server.split(terminal, direction: .right) try await server.selectLayout(window, "main-vertical") ``` A split creates a pane; direction and size control its placement. Applying a layout rearranges existing panes while their processes continue running. tmux provides `even-horizontal`, `even-vertical`, `main-horizontal`, `main-vertical`, and `tiled` layouts. Choose detached creation when the user's current window should retain focus. Splits and resizes issue tmux commands; [Control mode vs one-shot](https://libtmux.org/en/tmux/concepts/transports/) covers their transport costs and batching. `attach=False` keeps a newly created window in the background. ## Building one declaratively These packages read or build workspace configurations based on tmuxp: ### Python `tmuxp` loads a workspace configuration and creates its sessions, windows, and panes. See [Workspace Manager](https://libtmux.org/en/py/latest/workspace/) for its configuration and CLI. ### TypeScript `@libtmux/workspace` applies a workspace configuration through [`applyWorkspace`](). Pass the server and a configuration containing `session_name` and `windows`. ### Go The [`workspace`]() package loads tmuxp-shaped workspace configurations. See [Workspace Manager](https://libtmux.org/en/go/latest/workspace/) for the supported fields and CLI. ### Rust The `tmux-workspace` crate loads tmuxp-shaped configurations. See [Workspace Manager](https://libtmux.org/en/rs/latest/workspace/) for the supported fields and CLI. ### Java `libtmux-workspace` supports the tmuxp configuration fields needed to describe a workspace. See [Workspace Manager](https://libtmux.org/en/java/latest/workspace/) for the supported configuration and CLI. ### C# [`LibTmux.Workspace`]() reads tmuxp YAML. See [Workspace Manager](https://libtmux.org/en/csharp/latest/workspace/) for configuration fields and the CLI. ### Swift `TmuxWorkspace` accepts configurations written in Swift, JSON, or YAML. YAML support requires the `YAMLWorkspaces` trait. TypeScript's [`applyWorkspace`]() applies a desired configuration. Applying the same configuration again reuses its existing objects: ```ts await applyWorkspace(server, { session_name: "api", windows: [ { window_name: "editor", panes: ["vim", "git status"] }, { window_name: "server", panes: [{ shell_command: "bun dev", focus: true }] }, ], }); ``` ```rust use tmux_workspace::{Workspace, WorkspaceBuilder}; let workspace = Workspace::from_yaml(yaml_source)?; let session = WorkspaceBuilder::new(&server).build(&workspace).await?; ``` ```go described, err := workspace.Parse(document) if err != nil { return err } session, err := workspace.Build(ctx, server, described) if err != nil { return err } fmt.Println("workspace session:", session.ID()) ``` ```java Workspace workspace = WorkspaceBuilder.parse(yaml); Session session = WorkspaceBuilder.build(server, workspace); ``` ```csharp WorkspaceFile workspace = WorkspaceFile.Parse(yaml); WorkspaceResult result = await new WorkspaceBuilder(server).BuildAsync(workspace, ct); ``` ```swift let workspace = Workspace( sessionName: "work", windows: [WindowPlan(windowName: "editor", panes: [PanePlan(), PanePlan()])] ) let session = try await WorkspaceBuilder.build(workspace, on: server) ``` C++ provides a consumer example in [`examples/workspace/`]() that reads tmuxp configuration. The workspace builder is part of that example, rather than a library package: ```cpp // 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 up [`Window`]() and [`Session`]() context managers kill their objects on block exit, including when the block raises: Use a named error result in the enclosing function so deferred cleanup can return its own failure. Give cleanup a fresh, bounded context: An ownership scope kills its session when `await using` exits: ```python with session.new_window(window_name='temp-window') as temp_win: pane = temp_win.active_pane pane.send_keys('echo "temporary workspace"') # window is gone here, even if the block raised ``` ```go // No context manager: defer runs the cleanup at the end of the enclosing // function instead of the end of a block. session, err := server.NewSession(ctx, tmux.NewSessionRequest{Name: "temp-session"}) if err != nil { return err } defer func() { cleanupCtx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() err = errors.Join(err, session.Kill(cleanupCtx)) }() ``` ```csharp await using OwnedSessionScope scope = await server.CreateOwnedSessionAsync( new NewSessionRequest(name: "temp-session")); Window window = (await scope.Value.GetWindowsAsync())[0]; Pane pane = (await window.GetPanesAsync())[0]; await pane.SendTextAsync("echo temporary workspace"); // session is gone here, even if an exception unwound through the block ``` See [Context managers](https://libtmux.org/en/tmux/topics/context-managers/) for cleanup support in each port. Use explicit kill methods when the handle does not provide scope-based cleanup. --- # Layouts and repeated setup Source: https://libtmux.org/en/fsharp/latest/concepts/workspaces/ > Create and reuse F# tmux layouts while preserving running processes. Build a tmux layout from F# by creating a window, splitting a pane and selecting a layout. Capture again to inspect the result. The examples use the library APIs directly and give every pane a command that stays alive. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and .NET SDK 10.0.302. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. ```xml title="Query.fsproj" Exe net10.0 Local ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-dotnet-dev directory=$(mktemp -d /tmp/libtmux-dotnet-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-dotnet libtmux-source && git -C libtmux-source checkout 2d99ead5aba8d968e85dcac8c9a9a518452e6ba6 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Create a two-pane tools window Create `tools` in `work-one`, split its pane to the right, then choose `even-horizontal`. The final read verifies two panes. The previously captured session does not automatically gain the new window. ```fsharp title="Layout.fs" open System open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let run () = task { let socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") if String.IsNullOrEmpty(socket) then invalidOp "Set LIBTMUX_SOCKET_PATH to an existing socket" use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5.0)) let token = timeout.Token let! server = LibTmux.Server.ConnectAsync( ServerConnectionOptions(SocketPath = socket), token) let! captured = server |> Server.capture token SnapshotDepth.Sessions let session = captured.Sessions |> Seq.find (fun s -> s.Name = "work-one") let request = NewWindowRequest(Name = "tools", Command = "/bin/cat") let! window = session.CreateWindowAsync(request, token) let! panes = window.GetPanesAsync(token) let split = SplitPaneRequest(Direction = PaneDirection.Right, Command = "/bin/cat") let! _ = panes[0] |> Pane.split token split let! _ = window.SelectLayoutAsync(SelectLayoutRequest(Layout = "even-horizontal"), token) let! refreshed = window.GetPanesAsync(token) if refreshed.Count <> 2 then failwith "Expected two panes" printfn "tools: 2 panes" } [] let main _ = try run().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ```console $ dotnet build Query.fsproj --maxcpucount:1 -p:Example=Layout \ -p:DisableImplicitLibraryPacksFolder=true -p:RestorePackagesPath="$PWD/.packages" && sh run.sh dotnet run --project Query.fsproj --no-build -p:Example=Layout ``` Expected program output: ```text tools: 2 panes ``` ## Reuse a named window Look for `tools` before creating it. Two sequential calls return the same window ID, and the session has only `editor` and `tools`. This is useful for a setup command you run repeatedly. ```fsharp title="ReuseLayout.fs" open System open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let run () = task { let socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") if String.IsNullOrEmpty(socket) then invalidOp "Set LIBTMUX_SOCKET_PATH to an existing socket" use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5.0)) let token = timeout.Token let! server = LibTmux.Server.ConnectAsync( ServerConnectionOptions(SocketPath = socket), token) let ensureTools () = task { let! captured = server |> Server.capture token SnapshotDepth.Windows let session = captured.Sessions |> Seq.find (fun s -> s.Name = "work-one") match session.Windows |> Seq.tryFind (fun window -> window.Name = "tools") with | Some window -> return window | None -> return! session.CreateWindowAsync( NewWindowRequest(Name = "tools", Command = "/bin/cat"), token) } let! first = ensureTools () let! second = ensureTools () if first.Id <> second.Id then failwith "Created duplicate windows" let! captured = server |> Server.capture token SnapshotDepth.Windows let session = captured.Sessions |> Seq.find (fun s -> s.Name = "work-one") if session.Windows.Count <> 2 then failwith "Expected editor and tools windows" printfn "one tools window after two calls" } [] let main _ = try run().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ```console $ dotnet build Query.fsproj --maxcpucount:1 -p:Example=ReuseLayout \ -p:DisableImplicitLibraryPacksFolder=true -p:RestorePackagesPath="$PWD/.packages" && sh run.sh dotnet run --project Query.fsproj --no-build -p:Example=ReuseLayout ``` Expected program output: ```text one tools window after two calls ``` ## Decide what repeated setup means The reuse example preserves the existing window and its running processes. It does not reset its pane count, layout or commands. Choose that policy deliberately when building a reusable workspace command. This check-then-create sequence assumes one writer. Concurrent callers can both observe an absent window and create duplicates. Serialize setup in your application when several callers share a session. A later failure also leaves earlier successful mutations in place; tmux commands are not a transaction. Use [filtering and queries](https://libtmux.org/en/fsharp/latest/concepts/queries/) for stricter target selection and [captured handles](https://libtmux.org/en/fsharp/latest/concepts/server-session-window-pane/) to understand refresh behavior. --- # Layouts and repeated setup Source: https://libtmux.org/en/kotlin/latest/concepts/workspaces/ > Create and reuse Kotlin tmux layouts while preserving running processes. Build a tmux layout from Kotlin by creating a window, splitting a pane and selecting a layout. Capture again to inspect the result. The examples use the library APIs directly and give every pane a command that stays alive. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and JDK 25. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. The pinned source checkout supplies the Gradle wrapper and the library dependency. ```kotlin title="settings.gradle.kts" rootProject.name = "connect" includeBuild("libtmux-source") ``` ```kotlin title="build.gradle.kts" val example = providers.gradleProperty("example").getOrElse("Local") plugins { application kotlin("jvm") version "2.4.10" } repositories { mavenCentral() } dependencies { implementation("io.github.libtmux:libtmux-kotlin:0.0.1-alpha.17-SNAPSHOT") } kotlin { jvmToolchain(25) sourceSets.main { kotlin.srcDir("."); kotlin.include("${example}.kt") } } application { mainClass.set("${example}Kt") } ``` ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-java-dev directory=$(mktemp -d /tmp/libtmux-java-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Create a two-pane tools window Create `tools` in `work-one`, split its pane to the right, then choose `even-horizontal`. The final read verifies two panes. The previously captured session does not automatically gain the new window. ```kotlin title="Layout.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.* import io.github.libtmux.kotlin.query.* import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.runBlocking fun main() = runBlocking { val socket = requireNotNull(System.getenv("LIBTMUX_SOCKET_PATH")) { "Set LIBTMUX_SOCKET_PATH to an existing socket" } val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() withServer(config) { server -> val session = server.sessions().single { it.name == "work-one" } val window = session.newWindow(io.github.libtmux.WindowSpec.builder() .named("tools").running("/bin/cat").build()) val original = window.panes.single() original.split(io.github.libtmux.SplitSpec.builder().toRight().running("/bin/cat").build()) window.selectLayout(io.github.libtmux.Layout.EVEN_HORIZONTAL) val refreshed = server.sessions().single { it.name == "work-one" } val tools = refreshed.windows.single { it.name == "tools" } check(tools.panes.size == 2) println("tools: 2 panes") } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Layout --console=plain --max-workers=2 ``` Expected program output: ```text tools: 2 panes ``` ## Reuse a named window Look for `tools` before creating it. Two sequential calls return the same window ID, and the session has only `editor` and `tools`. This is useful for a setup command you run repeatedly. ```kotlin title="ReuseLayout.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.* import io.github.libtmux.kotlin.query.* import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.runBlocking fun main() = runBlocking { val socket = requireNotNull(System.getenv("LIBTMUX_SOCKET_PATH")) { "Set LIBTMUX_SOCKET_PATH to an existing socket" } val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() withServer(config) { server -> suspend fun ensureTools(): Window { val session = server.sessions().single { it.name == "work-one" } val existing = session.windows.singleOrNull { it.name == "tools" } if (existing != null) return existing return session.newWindow(io.github.libtmux.WindowSpec.builder() .named("tools").running("/bin/cat").build()) } val first = ensureTools() val second = ensureTools() check(first.id == second.id) check(server.sessions().single { it.name == "work-one" }.windows.size == 2) println("one tools window after two calls") } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=ReuseLayout --console=plain --max-workers=2 ``` Expected program output: ```text one tools window after two calls ``` ## Decide what repeated setup means The reuse example preserves the existing window and its running processes. It does not reset its pane count, layout or commands. Choose that policy deliberately when building a reusable workspace command. This check-then-create sequence assumes one writer. Concurrent callers can both observe an absent window and create duplicates. Serialize setup in your application when several callers share a session. A later failure also leaves earlier successful mutations in place; tmux commands are not a transaction. Use [filtering and queries](https://libtmux.org/en/kotlin/latest/concepts/queries/) for stricter target selection and [captured handles](https://libtmux.org/en/kotlin/latest/concepts/server-session-window-pane/) to understand refresh behavior. --- # Layouts and repeated setup Source: https://libtmux.org/en/scala/latest/concepts/workspaces/ > Create and reuse Scala tmux layouts while preserving running processes. Build a tmux layout from Scala by creating a window, splitting a pane and selecting a layout. Capture again to inspect the result. The examples use the library APIs directly and give every pane a command that stays alive. ## Setup and run Use an empty directory on Linux with Git, tmux 3.2a or newer, and JDK 25. Save the project files and launcher below, then save any complete program on this page. Each program has its own imports and entry point. The pinned source checkout supplies the Gradle wrapper and the library dependency. ```kotlin title="settings.gradle.kts" rootProject.name = "connect" includeBuild("libtmux-source") { dependencySubstitution { substitute(module("io.github.libtmux:libtmux-scala_3")) .using(project(":libtmux-scala")) } } ``` ```kotlin title="build.gradle.kts" val example = providers.gradleProperty("example").getOrElse("Local") plugins { application scala } repositories { mavenCentral() } dependencies { implementation("org.scala-lang:scala3-library_3:3.9.0") implementation("io.github.libtmux:libtmux-scala_3:0.0.1-alpha.17-SNAPSHOT") } java { toolchain { languageVersion.set(JavaLanguageVersion.of(25)) } } sourceSets.main { scala.srcDir("."); scala.include("${example}.scala") } application { mainClass.set(example) } ``` ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` The launcher creates two sessions on a private socket: `work-one` with an `editor` window, and `work-two` with a `logs` window. Each pane runs `cat` so it stays alive. It stops only this server when the program finishes or fails. If shutdown fails, it reports the retained directory and exits with an error. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) mkdir -p /tmp/libtmux-java-dev directory=$(mktemp -d /tmp/libtmux-java-dev/query.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work-one -n editor /bin/cat "$binary" -S "$socket" new-session -d -s work-two -n logs /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work-one' ``` Fetch the library revision used by these examples: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15 ``` Each run starts from the same two-session fixture. Programs do not depend on another example having run first. Their assertions fail if the observed result differs. ## Create a two-pane tools window Create `tools` in `work-one`, split its pane to the right, then choose `even-horizontal`. The final read verifies two panes. The previously captured session does not automatically gain the new window. ```scala title="Layout.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint} import io.github.libtmux.scaladsl.* import io.github.libtmux.scaladsl.query.* import java.nio.file.Path import java.time.Duration import scala.util.Using import scala.jdk.CollectionConverters.* object Layout { def main(args: Array[String]): Unit = { val socket = sys.env.getOrElse("LIBTMUX_SOCKET_PATH", throw new IllegalArgumentException("Set LIBTMUX_SOCKET_PATH to an existing socket")) val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() Using.resource(Server.open(config)) { server => val session = server.sessions().find(_.name == "work-one").get val window = session.newWindow(io.github.libtmux.WindowSpec.builder() .named("tools").running("/bin/cat").build()) window.panes.head.split(io.github.libtmux.SplitSpec.builder() .toRight().running("/bin/cat").build()) window.selectLayout(io.github.libtmux.Layout.EVEN_HORIZONTAL) val refreshed = server.sessions().find(_.name == "work-one").get val tools = refreshed.windows.find(_.name == "tools").get assert(tools.panes.size == 2) println("tools: 2 panes") } } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=Layout --console=plain --max-workers=2 ``` Expected program output: ```text tools: 2 panes ``` ## Reuse a named window Look for `tools` before creating it. Two sequential calls return the same window ID, and the session has only `editor` and `tools`. This is useful for a setup command you run repeatedly. ```scala title="ReuseLayout.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint} import io.github.libtmux.scaladsl.* import io.github.libtmux.scaladsl.query.* import java.nio.file.Path import java.time.Duration import scala.util.Using import scala.jdk.CollectionConverters.* object ReuseLayout { def main(args: Array[String]): Unit = { val socket = sys.env.getOrElse("LIBTMUX_SOCKET_PATH", throw new IllegalArgumentException("Set LIBTMUX_SOCKET_PATH to an existing socket")) val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() Using.resource(Server.open(config)) { server => def ensureTools(): Window = { val session = server.sessions().find(_.name == "work-one").get session.windows.find(_.name == "tools").getOrElse { session.newWindow(io.github.libtmux.WindowSpec.builder() .named("tools").running("/bin/cat").build()) } } val first = ensureTools() val second = ensureTools() assert(first.id == second.id) assert(server.sessions().find(_.name == "work-one").get.windows.size == 2) println("one tools window after two calls") } } } ``` ```console $ sh run.sh ./libtmux-source/gradlew --project-dir . run \ -Pexample=ReuseLayout --console=plain --max-workers=2 ``` Expected program output: ```text one tools window after two calls ``` ## Decide what repeated setup means The reuse example preserves the existing window and its running processes. It does not reset its pane count, layout or commands. Choose that policy deliberately when building a reusable workspace command. This check-then-create sequence assumes one writer. Concurrent callers can both observe an absent window and create duplicates. Serialize setup in your application when several callers share a session. A later failure also leaves earlier successful mutations in place; tmux commands are not a transaction. Use [filtering and queries](https://libtmux.org/en/scala/latest/concepts/queries/) for stricter target selection and [captured handles](https://libtmux.org/en/scala/latest/concepts/server-session-window-pane/) to understand refresh behavior. --- # Workspace configuration Source: https://libtmux.org/en/csharp/latest/workspace/configuration/ > Define the session, windows, panes and commands loaded by the workspace CLI. A workspace document describes one tmux session. Save this as `configuration.yaml`: ```yaml title="configuration.yaml" session_name: configuration-example windows: - window_name: editor layout: even-horizontal panes: - printf ready - null ``` Load it on the private socket from the [installation walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/): ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ configuration.yaml ``` The CLI parses the document and validates its execution fields before creating windows and sending commands. YAML and JSON use the same field names. A successful load means construction and command delivery completed; pane applications can still be starting or failing independently. ## Choose the fields for your task - [Session](https://libtmux.org/en/csharp/latest/workspace/configuration/session/) sets the name, shared options and environment. - [Windows](https://libtmux.org/en/csharp/latest/workspace/configuration/windows/) sets indexes, layouts and option timing. - [Panes](https://libtmux.org/en/csharp/latest/workspace/configuration/panes/) defines commands, launch shells and focus. - [Commands](https://libtmux.org/en/csharp/latest/workspace/configuration/commands/) controls ordering, Enter and delays. - [Environment](https://libtmux.org/en/csharp/latest/workspace/configuration/environment/) separates loader settings from pane variables. - [Directories](https://libtmux.org/en/csharp/latest/workspace/configuration/directories/) explains discovery and working directories. - [Layouts](https://libtmux.org/en/csharp/latest/workspace/configuration/layouts/) arranges the panes. - [Hooks](https://libtmux.org/en/csharp/latest/workspace/configuration/hooks/) runs checked bootstrap programs and optional extensions. ## CLI and application code These pages describe the `tmux-workspace` executable. Application code uses the separate [workspace library](https://libtmux.org/en/csharp/latest/workspace/internals/), whose accepted fields and build semantics have their own contract. A successful generic [conversion](https://libtmux.org/en/csharp/latest/workspace/cli/convert/) preserves document values; it does not validate that a loader can execute them. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Workspace configuration Source: https://libtmux.org/en/cxx/latest/workspace/configuration/ > Define the session, windows, panes and commands loaded by the workspace CLI. A workspace document describes one tmux session. Save this as `configuration.yaml`: ```yaml title="configuration.yaml" session_name: configuration-example windows: - window_name: editor layout: even-horizontal panes: - printf ready - null ``` Load it on the private socket from the [installation walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/): ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ configuration.yaml ``` The CLI parses the document and validates its execution fields before creating windows and sending commands. YAML and JSON use the same field names. A successful load means construction and command delivery completed; pane applications can still be starting or failing independently. ## Choose the fields for your task - [Session](https://libtmux.org/en/cxx/latest/workspace/configuration/session/) sets the name, shared options and environment. - [Windows](https://libtmux.org/en/cxx/latest/workspace/configuration/windows/) sets indexes, layouts and option timing. - [Panes](https://libtmux.org/en/cxx/latest/workspace/configuration/panes/) defines commands, launch shells and focus. - [Commands](https://libtmux.org/en/cxx/latest/workspace/configuration/commands/) controls ordering, Enter and delays. - [Environment](https://libtmux.org/en/cxx/latest/workspace/configuration/environment/) separates loader settings from pane variables. - [Directories](https://libtmux.org/en/cxx/latest/workspace/configuration/directories/) explains discovery and working directories. - [Layouts](https://libtmux.org/en/cxx/latest/workspace/configuration/layouts/) arranges the panes. - [Hooks](https://libtmux.org/en/cxx/latest/workspace/configuration/hooks/) runs checked bootstrap programs and optional extensions. ## CLI and application code These pages describe the `tmux-workspace` executable. Application code uses the separate [workspace library](https://libtmux.org/en/cxx/latest/workspace/internals/), whose accepted fields and build semantics have their own contract. A successful generic [conversion](https://libtmux.org/en/cxx/latest/workspace/cli/convert/) preserves document values; it does not validate that a loader can execute them. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Workspace configuration Source: https://libtmux.org/en/go/latest/workspace/configuration/ > Define the session, windows, panes and commands loaded by the workspace CLI. A workspace document describes one tmux session. Save this as `configuration.yaml`: ```yaml title="configuration.yaml" session_name: configuration-example windows: - window_name: editor layout: even-horizontal panes: - printf ready - null ``` Load it on the private socket from the [installation walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/): ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ configuration.yaml ``` The CLI parses the document and validates its execution fields before creating windows and sending commands. YAML and JSON use the same field names. A successful load means construction and command delivery completed; pane applications can still be starting or failing independently. ## Choose the fields for your task - [Session](https://libtmux.org/en/go/latest/workspace/configuration/session/) sets the name, shared options and environment. - [Windows](https://libtmux.org/en/go/latest/workspace/configuration/windows/) sets indexes, layouts and option timing. - [Panes](https://libtmux.org/en/go/latest/workspace/configuration/panes/) defines commands, launch shells and focus. - [Commands](https://libtmux.org/en/go/latest/workspace/configuration/commands/) controls ordering, Enter and delays. - [Environment](https://libtmux.org/en/go/latest/workspace/configuration/environment/) separates loader settings from pane variables. - [Directories](https://libtmux.org/en/go/latest/workspace/configuration/directories/) explains discovery and working directories. - [Layouts](https://libtmux.org/en/go/latest/workspace/configuration/layouts/) arranges the panes. - [Hooks](https://libtmux.org/en/go/latest/workspace/configuration/hooks/) runs checked bootstrap programs and optional extensions. ## CLI and application code These pages describe the `tmux-workspace` executable. Application code uses the separate [workspace library](https://libtmux.org/en/go/latest/workspace/internals/), whose accepted fields and build semantics have their own contract. A successful generic [conversion](https://libtmux.org/en/go/latest/workspace/cli/convert/) preserves document values; it does not validate that a loader can execute them. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Workspace configuration Source: https://libtmux.org/en/java/latest/workspace/configuration/ > Define the session, windows, panes and commands loaded by the workspace CLI. A workspace document describes one tmux session. Save this as `configuration.yaml`: ```yaml title="configuration.yaml" session_name: configuration-example windows: - window_name: editor layout: even-horizontal panes: - printf ready - null ``` Load it on the private socket from the [installation walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/): ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ configuration.yaml ``` The CLI parses the document and validates its execution fields before creating windows and sending commands. YAML and JSON use the same field names. A successful load means construction and command delivery completed; pane applications can still be starting or failing independently. ## Choose the fields for your task - [Session](https://libtmux.org/en/java/latest/workspace/configuration/session/) sets the name, shared options and environment. - [Windows](https://libtmux.org/en/java/latest/workspace/configuration/windows/) sets indexes, layouts and option timing. - [Panes](https://libtmux.org/en/java/latest/workspace/configuration/panes/) defines commands, launch shells and focus. - [Commands](https://libtmux.org/en/java/latest/workspace/configuration/commands/) controls ordering, Enter and delays. - [Environment](https://libtmux.org/en/java/latest/workspace/configuration/environment/) separates loader settings from pane variables. - [Directories](https://libtmux.org/en/java/latest/workspace/configuration/directories/) explains discovery and working directories. - [Layouts](https://libtmux.org/en/java/latest/workspace/configuration/layouts/) arranges the panes. - [Hooks](https://libtmux.org/en/java/latest/workspace/configuration/hooks/) runs checked bootstrap programs and optional extensions. ## CLI and application code These pages describe the `tmux-workspace` executable. Application code uses the separate [workspace library](https://libtmux.org/en/java/latest/workspace/internals/), whose accepted fields and build semantics have their own contract. A successful generic [conversion](https://libtmux.org/en/java/latest/workspace/cli/convert/) preserves document values; it does not validate that a loader can execute them. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Workspace configuration Source: https://libtmux.org/en/py/latest/workspace/configuration/ > Define the session, windows, panes and commands loaded by the workspace CLI. A workspace file describes one tmux session, its windows and panes, and the commands sent to them. YAML and JSON carry the same field names. Save this complete example as [`workspace.yaml`](https://libtmux.org/en/py/latest/workspace/guides/installation/#create-the-input): ```yaml session_name: workspace-example start_directory: ./ windows: - window_name: editor layout: even-horizontal panes: - echo ready - blank ``` The equivalent JSON is: ```json { "session_name": "workspace-example", "start_directory": "./", "windows": [ { "window_name": "editor", "layout": "even-horizontal", "panes": ["echo ready", "blank"] } ] } ``` With Python tmuxp installed, load this file detached on a socket reserved for the example: ```console $ tmuxp load \ -L configuration-example \ -d \ workspace.yaml ``` Inspect the resulting panes: ```console $ tmux -L configuration-example list-panes -t '=workspace-example' ``` Remove the example session when finished: ```console $ tmux -L configuration-example kill-session -t '=workspace-example' ``` ## How configuration becomes a session The tmuxp loader reads a document, expands command shorthand and shell variables, and applies inherited defaults before selecting a workspace builder. The classic builder then creates tmux objects and sends commands. Completion means construction and command delivery finished; it does not establish that a server launched in a pane is ready. `"session_name"` and `"windows"` are needed by normal loading. A window can omit its name and let tmux choose one; an omitted `"panes"` list defaults to one blank pane. Supplying explicit names and pane lists makes a portable example clearer. An empty pane list is not the same input as an omitted list. The internal [`validate_schema`]() helper requires each window_name, but the current CLI/classic builder path does not call it. It is not a complete JSON Schema or an exact description of what load accepts. A YAML parser accepting a key also does not mean a builder implements it. ## Configuration reference - [Session](https://libtmux.org/en/py/latest/workspace/configuration/session/) covers identity, options, environment, and root keys. - [Windows](https://libtmux.org/en/py/latest/workspace/configuration/windows/) covers names, indexes, option timing, and focus. - [Panes](https://libtmux.org/en/py/latest/workspace/configuration/panes/) covers shorthand, blank forms, shell, and overrides. - [Commands](https://libtmux.org/en/py/latest/workspace/configuration/commands/) covers before commands, Enter, delays, and history. - [Environment](https://libtmux.org/en/py/latest/workspace/configuration/environment/) separates process settings from pane values. - [Directories](https://libtmux.org/en/py/latest/workspace/configuration/directories/) explains file discovery and path resolution. - [Layouts](https://libtmux.org/en/py/latest/workspace/configuration/layouts/) explains pane arrangement and terminal size. - [Hooks and builders](https://libtmux.org/en/py/latest/workspace/configuration/hooks/) covers scripts and Python extensions. Use the [configuration gallery](https://libtmux.org/en/py/latest/workspace/examples/gallery/) for more complete files. Configuration conversion should preserve the source mapping, including extension keys; loading that mapping requires separate support for every execution feature. ## Reference source [loader.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [validation.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/validation.py); [classic.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py). --- # Workspace configuration Source: https://libtmux.org/en/rs/latest/workspace/configuration/ > Define the session, windows, panes and commands loaded by the workspace CLI. A workspace document describes one tmux session. Save this as `configuration.yaml`: ```yaml title="configuration.yaml" session_name: configuration-example windows: - window_name: editor layout: even-horizontal panes: - printf ready - null ``` Load it on the private socket from the [installation walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/): ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ configuration.yaml ``` The CLI parses the document and validates its execution fields before creating windows and sending commands. YAML and JSON use the same field names. A successful load means construction and command delivery completed; pane applications can still be starting or failing independently. ## Choose the fields for your task - [Session](https://libtmux.org/en/rs/latest/workspace/configuration/session/) sets the name, shared options and environment. - [Windows](https://libtmux.org/en/rs/latest/workspace/configuration/windows/) sets indexes, layouts and option timing. - [Panes](https://libtmux.org/en/rs/latest/workspace/configuration/panes/) defines commands, launch shells and focus. - [Commands](https://libtmux.org/en/rs/latest/workspace/configuration/commands/) controls ordering, Enter and delays. - [Environment](https://libtmux.org/en/rs/latest/workspace/configuration/environment/) separates loader settings from pane variables. - [Directories](https://libtmux.org/en/rs/latest/workspace/configuration/directories/) explains discovery and working directories. - [Layouts](https://libtmux.org/en/rs/latest/workspace/configuration/layouts/) arranges the panes. - [Hooks](https://libtmux.org/en/rs/latest/workspace/configuration/hooks/) runs checked bootstrap programs and optional extensions. ## CLI and application code These pages describe the `tmux-workspace` executable. Application code uses the separate [workspace library](https://libtmux.org/en/rs/latest/workspace/internals/), whose accepted fields and build semantics have their own contract. A successful generic [conversion](https://libtmux.org/en/rs/latest/workspace/cli/convert/) preserves document values; it does not validate that a loader can execute them. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Workspace configuration Source: https://libtmux.org/en/swift/latest/workspace/configuration/ > Define the session, windows, panes and commands loaded by the workspace CLI. A workspace document describes one tmux session. Save this as `configuration.yaml`: ```yaml title="configuration.yaml" session_name: configuration-example windows: - window_name: editor layout: even-horizontal panes: - printf ready - null ``` Load it on the private socket from the [installation walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/): ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ configuration.yaml ``` The CLI parses the document and validates its execution fields before creating windows and sending commands. YAML and JSON use the same field names. A successful load means construction and command delivery completed; pane applications can still be starting or failing independently. ## Choose the fields for your task - [Session](https://libtmux.org/en/swift/latest/workspace/configuration/session/) sets the name, shared options and environment. - [Windows](https://libtmux.org/en/swift/latest/workspace/configuration/windows/) sets indexes, layouts and option timing. - [Panes](https://libtmux.org/en/swift/latest/workspace/configuration/panes/) defines commands, launch shells and focus. - [Commands](https://libtmux.org/en/swift/latest/workspace/configuration/commands/) controls ordering, Enter and delays. - [Environment](https://libtmux.org/en/swift/latest/workspace/configuration/environment/) separates loader settings from pane variables. - [Directories](https://libtmux.org/en/swift/latest/workspace/configuration/directories/) explains discovery and working directories. - [Layouts](https://libtmux.org/en/swift/latest/workspace/configuration/layouts/) arranges the panes. - [Hooks](https://libtmux.org/en/swift/latest/workspace/configuration/hooks/) runs checked bootstrap programs and optional extensions. ## CLI and application code These pages describe the `tmux-workspace` executable. Application code uses the separate [workspace library](https://libtmux.org/en/swift/latest/workspace/internals/), whose accepted fields and build semantics have their own contract. A successful generic [conversion](https://libtmux.org/en/swift/latest/workspace/cli/convert/) preserves document values; it does not validate that a loader can execute them. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Workspace configuration Source: https://libtmux.org/en/ts/latest/workspace/configuration/ > Define the session, windows, panes and commands loaded by the workspace CLI. A workspace document describes one tmux session. Save this as `configuration.yaml`: ```yaml title="configuration.yaml" session_name: configuration-example windows: - window_name: editor layout: even-horizontal panes: - printf ready - null ``` Load it on the private socket from the [installation walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/): ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ configuration.yaml ``` The CLI parses the document and validates its execution fields before creating windows and sending commands. YAML and JSON use the same field names. A successful load means construction and command delivery completed; pane applications can still be starting or failing independently. ## Choose the fields for your task - [Session](https://libtmux.org/en/ts/latest/workspace/configuration/session/) sets the name, shared options and environment. - [Windows](https://libtmux.org/en/ts/latest/workspace/configuration/windows/) sets indexes, layouts and option timing. - [Panes](https://libtmux.org/en/ts/latest/workspace/configuration/panes/) defines commands, launch shells and focus. - [Commands](https://libtmux.org/en/ts/latest/workspace/configuration/commands/) controls ordering, Enter and delays. - [Environment](https://libtmux.org/en/ts/latest/workspace/configuration/environment/) separates loader settings from pane variables. - [Directories](https://libtmux.org/en/ts/latest/workspace/configuration/directories/) explains discovery and working directories. - [Layouts](https://libtmux.org/en/ts/latest/workspace/configuration/layouts/) arranges the panes. - [Hooks](https://libtmux.org/en/ts/latest/workspace/configuration/hooks/) runs checked bootstrap programs and optional extensions. ## CLI and application code These pages describe the `tmux-workspace` executable. Application code uses the separate [workspace library](https://libtmux.org/en/ts/latest/workspace/internals/), whose accepted fields and build semantics have their own contract. A successful generic [conversion](https://libtmux.org/en/ts/latest/workspace/cli/convert/) preserves document values; it does not validate that a loader can execute them. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Session configuration Source: https://libtmux.org/en/csharp/latest/workspace/configuration/session/ > Name a workspace and apply session options and environment. Set `session_name` and an ordered, nonempty `windows` list. Use a simple name without tmux target separators such as `:` and `.`. ```yaml title="session.yaml" session_name: session-example environment: PROJECT_MODE: development options: status: false windows: - window_name: shell panes: [null] ``` ## Session fields | Field | Effect | | --- | --- | | `session_name` | Session to create or reuse | | `windows` | Windows to construct in order | | `start_directory` | Starting directory inherited by child configuration | | `environment` | Variables supplied to the workspace | | `options` | Options applied to this session | | `global_options` | Options applied globally on the selected tmux server | | `shell_command_before` | Commands prepended to each pane's commands | | `suppress_history` | History policy inherited by windows and panes | | `before_script` | Checked bootstrap process | | `workspace_builder_options` | Builder settings such as prompt readiness | Use `global_options` only when every session on that server should share the change. Select a private socket for examples and automated jobs. An existing session is reused under the loader's policy. Use `load -s NAME` when a second copy needs another name. Loading does not remove unrelated sessions or reconcile away extra windows. Read [environment](https://libtmux.org/en/csharp/latest/workspace/configuration/environment/), [commands](https://libtmux.org/en/csharp/latest/workspace/configuration/commands/) and [hooks](https://libtmux.org/en/csharp/latest/workspace/configuration/hooks/) for the behavior behind those fields. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Session configuration Source: https://libtmux.org/en/cxx/latest/workspace/configuration/session/ > Name a workspace and apply session options and environment. Set [`session_name`]() and an ordered, nonempty [`windows`]() list. Use a simple name without tmux target separators such as `:` and `.`. ```yaml title="session.yaml" session_name: session-example environment: PROJECT_MODE: development options: status: false windows: - window_name: shell panes: [null] ``` ## Session fields | Field | Effect | | --- | --- | | [`session_name`]() | Session to create or reuse | | [`windows`]() | Windows to construct in order | | `start_directory` | Starting directory inherited by child configuration | | `environment` | Variables supplied to the workspace | | `options` | Options applied to this session | | [`global_options`]() | Options applied globally on the selected tmux server | | `shell_command_before` | Commands prepended to each pane's commands | | [`suppress_history`]() | History policy inherited by windows and panes | | `before_script` | Checked bootstrap process | | `workspace_builder_options` | Builder settings such as prompt readiness | Use [`global_options`]() only when every session on that server should share the change. Select a private socket for examples and automated jobs. An existing session is reused under the loader's policy. Use `load -s NAME` when a second copy needs another name. Loading does not remove unrelated sessions or reconcile away extra windows. Read [environment](https://libtmux.org/en/cxx/latest/workspace/configuration/environment/), [commands](https://libtmux.org/en/cxx/latest/workspace/configuration/commands/) and [hooks](https://libtmux.org/en/cxx/latest/workspace/configuration/hooks/) for the behavior behind those fields. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Session configuration Source: https://libtmux.org/en/go/latest/workspace/configuration/session/ > Name a workspace and apply session options and environment. Set `session_name` and an ordered, nonempty `windows` list. Use a simple name without tmux target separators such as `:` and `.`. ```yaml title="session.yaml" session_name: session-example environment: PROJECT_MODE: development options: status: false windows: - window_name: shell panes: [null] ``` ## Session fields | Field | Effect | | --- | --- | | `session_name` | Session to create or reuse | | `windows` | Windows to construct in order | | `start_directory` | Starting directory inherited by child configuration | | `environment` | Variables supplied to the workspace | | `options` | Options applied to this session | | `global_options` | Options applied globally on the selected tmux server | | `shell_command_before` | Commands prepended to each pane's commands | | `suppress_history` | History policy inherited by windows and panes | | `before_script` | Checked bootstrap process | | `workspace_builder_options` | Builder settings such as prompt readiness | Use `global_options` only when every session on that server should share the change. Select a private socket for examples and automated jobs. An existing session is reused under the loader's policy. Use `load -s NAME` when a second copy needs another name. Loading does not remove unrelated sessions or reconcile away extra windows. Read [environment](https://libtmux.org/en/go/latest/workspace/configuration/environment/), [commands](https://libtmux.org/en/go/latest/workspace/configuration/commands/) and [hooks](https://libtmux.org/en/go/latest/workspace/configuration/hooks/) for the behavior behind those fields. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Session configuration Source: https://libtmux.org/en/java/latest/workspace/configuration/session/ > Name a workspace and apply session options and environment. Set `session_name` and an ordered, nonempty `windows` list. Use a simple name without tmux target separators such as `:` and `.`. ```yaml title="session.yaml" session_name: session-example environment: PROJECT_MODE: development options: status: false windows: - window_name: shell panes: [null] ``` ## Session fields | Field | Effect | | --- | --- | | `session_name` | Session to create or reuse | | `windows` | Windows to construct in order | | `start_directory` | Starting directory inherited by child configuration | | `environment` | Variables supplied to the workspace | | `options` | Options applied to this session | | `global_options` | Options applied globally on the selected tmux server | | `shell_command_before` | Commands prepended to each pane's commands | | `suppress_history` | History policy inherited by windows and panes | | `before_script` | Checked bootstrap process | | `workspace_builder_options` | Builder settings such as prompt readiness | Use `global_options` only when every session on that server should share the change. Select a private socket for examples and automated jobs. An existing session is reused under the loader's policy. Use `load -s NAME` when a second copy needs another name. Loading does not remove unrelated sessions or reconcile away extra windows. Read [environment](https://libtmux.org/en/java/latest/workspace/configuration/environment/), [commands](https://libtmux.org/en/java/latest/workspace/configuration/commands/) and [hooks](https://libtmux.org/en/java/latest/workspace/configuration/hooks/) for the behavior behind those fields. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Session configuration Source: https://libtmux.org/en/py/latest/workspace/configuration/session/ > Name a workspace and apply session options and environment. The root mapping names the session and supplies defaults inherited by its windows and panes. The file's name is independent of `"session_name"`: loading [`project.yaml`](https://libtmux.org/en/py/latest/workspace/guides/discovery/) can create a session named [`development`](). ```yaml session_name: development start_directory: ./ suppress_history: true shell_command_before: - echo preparing pane environment: WORKSPACE_ROLE: development options: default-shell: /bin/sh global_options: status: true windows: - window_name: main panes: - echo ready ``` `"global_options"` changes the shared tmux server. Use a dedicated socket while learning these options. The example assumes `/bin/sh` exists. ## Root keys | Key | Meaning | | --- | --- | | `"session_name"` | Session identity; expanded before building | | `"windows"` | Ordered list of window mappings | | `start_directory` | Starting directory and base for inherited window directories | | `"options"` | tmux session options applied during construction | | `"global_options"` | tmux options applied with global scope on the selected server | | `"environment"` | Values placed in the tmux session environment | | `shell_command_before` | Commands prepended to commands in every pane | | `"suppress_history"` | Default history suppression inherited by windows and panes | | `"before_script"` | Process run after initial session creation, before configured windows | | `"plugins"` | List of Python plugin class references | | `workspace_builder` | Classic builder, registered builder name, or Python class reference | | `workspace_builder_paths` | Trusted directories used for Python builder imports | | `workspace_builder_options` | Builder behavior settings such as pane_readiness | Options use tmux option names and values. A workspace key such as `start_directory` is not a tmux option and does not belong in `"options"`. Some tmux settings are window options even when tmux permits them through a session target; consult tmux's option scope when choosing the catalog. ## Construction order The classic builder creates the initial session, runs its initial plugin hook and workspace before_script, then applies root options, global options, and session environment before creating configured windows. The temporary initial window is replaced. Hooks can observe those tmux operations; loading is not an invisible transaction. The same-named session is handled by the [load command](https://libtmux.org/en/py/latest/workspace/cli/load/) and its attach, switch, append, and detached choices. Changing a YAML file does not automatically reconcile an existing running session. An explicit `load -s` value overrides the configured name for that invocation. ## Inherited defaults A window can override its start directory and history policy, and a pane can override them again. Before commands accumulate in session, window, then pane order. Session environment remains distinct from window/pane launch environments. Read [directories](https://libtmux.org/en/py/latest/workspace/configuration/directories/), [commands](https://libtmux.org/en/py/latest/workspace/configuration/commands/), and [environment](https://libtmux.org/en/py/latest/workspace/configuration/environment/) before relying on inheritance. Python scripts, plugins, and custom builder references execute code. Their exact timing and runtime requirements are in [hooks and builders](https://libtmux.org/en/py/latest/workspace/configuration/hooks/). ## Reference source [classic.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py); [loader.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [load.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/load.py). --- # Session configuration Source: https://libtmux.org/en/rs/latest/workspace/configuration/session/ > Name a workspace and apply session options and environment. Set [`session_name`]() and an ordered, nonempty [`windows`]() list. Use a simple name without tmux target separators such as `:` and `.`. ```yaml title="session.yaml" session_name: session-example environment: PROJECT_MODE: development options: status: false windows: - window_name: shell panes: [null] ``` ## Session fields | Field | Effect | | --- | --- | | [`session_name`]() | Session to create or reuse | | [`windows`]() | Windows to construct in order | | `start_directory` | Starting directory inherited by child configuration | | `environment` | Variables supplied to the workspace | | [`options`]() | Options applied to this session | | [`global_options`]() | Options applied globally on the selected tmux server | | `shell_command_before` | Commands prepended to each pane's commands | | `suppress_history` | History policy inherited by windows and panes | | `before_script` | Checked bootstrap process | | `workspace_builder_options` | Builder settings such as prompt readiness | Use [`global_options`]() only when every session on that server should share the change. Select a private socket for examples and automated jobs. An existing session is reused under the loader's policy. Use `load -s NAME` when a second copy needs another name. Loading does not remove unrelated sessions or reconcile away extra windows. Read [environment](https://libtmux.org/en/rs/latest/workspace/configuration/environment/), [commands](https://libtmux.org/en/rs/latest/workspace/configuration/commands/) and [hooks](https://libtmux.org/en/rs/latest/workspace/configuration/hooks/) for the behavior behind those fields. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Session configuration Source: https://libtmux.org/en/swift/latest/workspace/configuration/session/ > Name a workspace and apply session options and environment. Set `session_name` and an ordered, nonempty [`windows`]() list. Use a simple name without tmux target separators such as `:` and `.`. ```yaml title="session.yaml" session_name: session-example environment: PROJECT_MODE: development options: status: false windows: - window_name: shell panes: [null] ``` ## Session fields | Field | Effect | | --- | --- | | `session_name` | Session to create or reuse | | [`windows`]() | Windows to construct in order | | `start_directory` | Starting directory inherited by child configuration | | `environment` | Variables supplied to the workspace | | `options` | Options applied to this session | | `global_options` | Options applied globally on the selected tmux server | | `shell_command_before` | Commands prepended to each pane's commands | | `suppress_history` | History policy inherited by windows and panes | | `before_script` | Checked bootstrap process | | `workspace_builder_options` | Builder settings such as prompt readiness | Use `global_options` only when every session on that server should share the change. Select a private socket for examples and automated jobs. An existing session is reused under the loader's policy. Use `load -s NAME` when a second copy needs another name. Loading does not remove unrelated sessions or reconcile away extra windows. Read [environment](https://libtmux.org/en/swift/latest/workspace/configuration/environment/), [commands](https://libtmux.org/en/swift/latest/workspace/configuration/commands/) and [hooks](https://libtmux.org/en/swift/latest/workspace/configuration/hooks/) for the behavior behind those fields. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Session configuration Source: https://libtmux.org/en/ts/latest/workspace/configuration/session/ > Name a workspace and apply session options and environment. Set `session_name` and an ordered, nonempty `windows` list. Use a simple name without tmux target separators such as `:` and `.`. ```yaml title="session.yaml" session_name: session-example environment: PROJECT_MODE: development options: status: false windows: - window_name: shell panes: [null] ``` ## Session fields | Field | Effect | | --- | --- | | `session_name` | Session to create or reuse | | `windows` | Windows to construct in order | | `start_directory` | Starting directory inherited by child configuration | | `environment` | Variables supplied to the workspace | | `options` | Options applied to this session | | `global_options` | Options applied globally on the selected tmux server | | `shell_command_before` | Commands prepended to each pane's commands | | `suppress_history` | History policy inherited by windows and panes | | `before_script` | Checked bootstrap process | | `workspace_builder_options` | Builder settings such as prompt readiness | Use `global_options` only when every session on that server should share the change. Select a private socket for examples and automated jobs. An existing session is reused under the loader's policy. Use `load -s NAME` when a second copy needs another name. Loading does not remove unrelated sessions or reconcile away extra windows. Read [environment](https://libtmux.org/en/ts/latest/workspace/configuration/environment/), [commands](https://libtmux.org/en/ts/latest/workspace/configuration/commands/) and [hooks](https://libtmux.org/en/ts/latest/workspace/configuration/hooks/) for the behavior behind those fields. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Window configuration Source: https://libtmux.org/en/csharp/latest/workspace/configuration/windows/ > Set window names, indexes, layouts, options and focus. Each item in `windows` creates one window with its own ordered pane list. Set `window_index` when the tmux index matters independently of list position. ```yaml title="windows.yaml" session_name: windows-example windows: - window_name: tools window_index: 2 layout: even-horizontal focus: true options: automatic-rename: false options_after: synchronize-panes: true panes: - printf left - printf right ``` `options` applies during construction. `options_after` applies after initial pane commands, which is useful for enabling synchronized typing after each pane has received its own setup. Later input in a synchronized pane can reach the other panes in that window. ## Launch settings `start_directory` supplies a directory for panes that do not override it. `window_shell` supplies their launch command; a pane's `shell` overrides it. Set `environment` for a window-wide launch map and read [environment inheritance](https://libtmux.org/en/csharp/latest/workspace/configuration/environment/) before overriding it per pane. Use distinct explicit indexes. `focus: true` selects the window after building. An explicit [layout](https://libtmux.org/en/csharp/latest/workspace/configuration/layouts/) makes the intended arrangement clear across terminal sizes. [Pane configuration](https://libtmux.org/en/csharp/latest/workspace/configuration/panes/) controls each pane's contents. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Window configuration Source: https://libtmux.org/en/cxx/latest/workspace/configuration/windows/ > Set window names, indexes, layouts, options and focus. Each item in [`windows`]() creates one window with its own ordered pane list. Set `window_index` when the tmux index matters independently of list position. ```yaml title="windows.yaml" session_name: windows-example windows: - window_name: tools window_index: 2 layout: even-horizontal focus: true options: automatic-rename: false options_after: synchronize-panes: true panes: - printf left - printf right ``` `options` applies during construction. [`options_after`]() applies after initial pane commands, which is useful for enabling synchronized typing after each pane has received its own setup. Later input in a synchronized pane can reach the other panes in that window. ## Launch settings `start_directory` supplies a directory for panes that do not override it. `window_shell` supplies their launch command; a pane's `shell` overrides it. Set `environment` for a window-wide launch map and read [environment inheritance](https://libtmux.org/en/cxx/latest/workspace/configuration/environment/) before overriding it per pane. Use distinct explicit indexes. `focus: true` selects the window after building. An explicit [layout](https://libtmux.org/en/cxx/latest/workspace/configuration/layouts/) makes the intended arrangement clear across terminal sizes. [Pane configuration](https://libtmux.org/en/cxx/latest/workspace/configuration/panes/) controls each pane's contents. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Window configuration Source: https://libtmux.org/en/go/latest/workspace/configuration/windows/ > Set window names, indexes, layouts, options and focus. Each item in `windows` creates one window with its own ordered pane list. Set `window_index` when the tmux index matters independently of list position. ```yaml title="windows.yaml" session_name: windows-example windows: - window_name: tools window_index: 2 layout: even-horizontal focus: true options: automatic-rename: false options_after: synchronize-panes: true panes: - printf left - printf right ``` `options` applies during construction. `options_after` applies after initial pane commands, which is useful for enabling synchronized typing after each pane has received its own setup. Later input in a synchronized pane can reach the other panes in that window. ## Launch settings `start_directory` supplies a directory for panes that do not override it. `window_shell` supplies their launch command; a pane's `shell` overrides it. Set `environment` for a window-wide launch map and read [environment inheritance](https://libtmux.org/en/go/latest/workspace/configuration/environment/) before overriding it per pane. Use distinct explicit indexes. `focus: true` selects the window after building. An explicit [layout](https://libtmux.org/en/go/latest/workspace/configuration/layouts/) makes the intended arrangement clear across terminal sizes. [Pane configuration](https://libtmux.org/en/go/latest/workspace/configuration/panes/) controls each pane's contents. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Window configuration Source: https://libtmux.org/en/java/latest/workspace/configuration/windows/ > Set window names, indexes, layouts, options and focus. Each item in `windows` creates one window with its own ordered pane list. Set `window_index` when the tmux index matters independently of list position. ```yaml title="windows.yaml" session_name: windows-example windows: - window_name: tools window_index: 2 layout: even-horizontal focus: true options: automatic-rename: false options_after: synchronize-panes: true panes: - printf left - printf right ``` `options` applies during construction. `options_after` applies after initial pane commands, which is useful for enabling synchronized typing after each pane has received its own setup. Later input in a synchronized pane can reach the other panes in that window. ## Launch settings `start_directory` supplies a directory for panes that do not override it. `window_shell` supplies their launch command; a pane's `shell` overrides it. Set `environment` for a window-wide launch map and read [environment inheritance](https://libtmux.org/en/java/latest/workspace/configuration/environment/) before overriding it per pane. Use distinct explicit indexes. `focus: true` selects the window after building. An explicit [layout](https://libtmux.org/en/java/latest/workspace/configuration/layouts/) makes the intended arrangement clear across terminal sizes. [Pane configuration](https://libtmux.org/en/java/latest/workspace/configuration/panes/) controls each pane's contents. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Window configuration Source: https://libtmux.org/en/py/latest/workspace/configuration/windows/ > Set window names, indexes, layouts, options and focus. Each item in `"windows"` describes one window and its ordered panes. Set `"window_name"` when the name matters; an omitted name lets tmux choose it. `"window_index"` selects a tmux numeric index independently of the item's position in the list. ```yaml session_name: window-example start_directory: ./ windows: - window_name: tools window_index: 1 start_directory: ./ layout: even-horizontal focus: true options: automatic-rename: false options_after: synchronize-panes: true panes: - echo left - echo right ``` This configuration sends each pane its own initial command before enabling synchronized input. Later typing in one synchronized pane can affect the other pane. ## Window keys | Key | Meaning | | --- | --- | | `"window_name"` | Label used by tmux; shell variables are expanded | | `"window_index"` | Explicit numeric position, otherwise use tmux's available index | | `"panes"` | Ordered pane list; omission supplies one blank pane | | `"layout"` | Named tmux layout or explicit layout description | | `start_directory` | Directory inherited by panes unless a pane overrides it | | `"window_shell"` | Initial shell/application for panes, subject to pane shell override | | `focus` | Select the window after building | | `"options"` | Window options applied during creation | | `"options_after"` | Window options applied after panes and their initial commands | | `"environment"` | Launch environment used when a pane lacks its own map | | `shell_command_before` | Commands prepended after session before commands | | `"suppress_history"` | Window default overriding the session history policy | ## First pane and later panes A new window already has its initial pane. Tmuxp uses the first configured pane's start_directory, shell, and environment when launching that window, then creates splits for later panes. A first-pane override therefore matters during new-window, not only while creating splits. A pane shell overrides window_shell. Window environment is used when the pane has no environment map; providing a pane map selects that map instead. ## Index, layout, and focus The classic builder moves the temporary initial window before creating the configured first window. This permits an explicit first index without reusing the temporary window's content. Do not assume window list position and tmux numeric index are identical. Window options precede layout application. `"options_after"` exists for settings such as synchronize-panes that should take effect after individual setup commands. [Layouts](https://libtmux.org/en/py/latest/workspace/configuration/layouts/) explains named layouts, dimensions, and focus; [panes](https://libtmux.org/en/py/latest/workspace/configuration/panes/) describes the pane forms accepted inside a window. ## Reference source [classic.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py); [loader.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [2-pane-synchronized.yaml](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/2-pane-synchronized.yaml). --- # Window configuration Source: https://libtmux.org/en/rs/latest/workspace/configuration/windows/ > Set window names, indexes, layouts, options and focus. Each item in [`windows`]() creates one window with its own ordered pane list. Set [`window_index`]() when the tmux index matters independently of list position. ```yaml title="windows.yaml" session_name: windows-example windows: - window_name: tools window_index: 2 layout: even-horizontal focus: true options: automatic-rename: false options_after: synchronize-panes: true panes: - printf left - printf right ``` [`options`]() applies during construction. `options_after` applies after initial pane commands, which is useful for enabling synchronized typing after each pane has received its own setup. Later input in a synchronized pane can reach the other panes in that window. ## Launch settings `start_directory` supplies a directory for panes that do not override it. [`window_shell`]() supplies their launch command; a pane's [`shell`]() overrides it. Set `environment` for a window-wide launch map and read [environment inheritance](https://libtmux.org/en/rs/latest/workspace/configuration/environment/) before overriding it per pane. Use distinct explicit indexes. `focus: true` selects the window after building. An explicit [layout](https://libtmux.org/en/rs/latest/workspace/configuration/layouts/) makes the intended arrangement clear across terminal sizes. [Pane configuration](https://libtmux.org/en/rs/latest/workspace/configuration/panes/) controls each pane's contents. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Window configuration Source: https://libtmux.org/en/swift/latest/workspace/configuration/windows/ > Set window names, indexes, layouts, options and focus. Each item in [`windows`]() creates one window with its own ordered pane list. Set `window_index` when the tmux index matters independently of list position. ```yaml title="windows.yaml" session_name: windows-example windows: - window_name: tools window_index: 2 layout: even-horizontal focus: true options: automatic-rename: false options_after: synchronize-panes: true panes: - printf left - printf right ``` `options` applies during construction. `options_after` applies after initial pane commands, which is useful for enabling synchronized typing after each pane has received its own setup. Later input in a synchronized pane can reach the other panes in that window. ## Launch settings `start_directory` supplies a directory for panes that do not override it. `window_shell` supplies their launch command; a pane's [`shell`]() overrides it. Set `environment` for a window-wide launch map and read [environment inheritance](https://libtmux.org/en/swift/latest/workspace/configuration/environment/) before overriding it per pane. Use distinct explicit indexes. `focus: true` selects the window after building. An explicit [layout](https://libtmux.org/en/swift/latest/workspace/configuration/layouts/) makes the intended arrangement clear across terminal sizes. [Pane configuration](https://libtmux.org/en/swift/latest/workspace/configuration/panes/) controls each pane's contents. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Window configuration Source: https://libtmux.org/en/ts/latest/workspace/configuration/windows/ > Set window names, indexes, layouts, options and focus. Each item in `windows` creates one window with its own ordered pane list. Set `window_index` when the tmux index matters independently of list position. ```yaml title="windows.yaml" session_name: windows-example windows: - window_name: tools window_index: 2 layout: even-horizontal focus: true options: automatic-rename: false options_after: synchronize-panes: true panes: - printf left - printf right ``` `options` applies during construction. `options_after` applies after initial pane commands, which is useful for enabling synchronized typing after each pane has received its own setup. Later input in a synchronized pane can reach the other panes in that window. ## Launch settings `start_directory` supplies a directory for panes that do not override it. `window_shell` supplies their launch command; a pane's `shell` overrides it. Set `environment` for a window-wide launch map and read [environment inheritance](https://libtmux.org/en/ts/latest/workspace/configuration/environment/) before overriding it per pane. Use distinct explicit indexes. `focus: true` selects the window after building. An explicit [layout](https://libtmux.org/en/ts/latest/workspace/configuration/layouts/) makes the intended arrangement clear across terminal sizes. [Pane configuration](https://libtmux.org/en/ts/latest/workspace/configuration/panes/) controls each pane's contents. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Pane configuration Source: https://libtmux.org/en/csharp/latest/workspace/configuration/panes/ > Choose pane commands, launch settings and focus. Each entry in a window's `panes` list describes one pane. A string is a command; `null` leaves a blank shell pane. A mapping provides launch and command settings. ```yaml title="panes.yaml" session_name: panes-example windows: - window_name: work layout: even-horizontal panes: - null - shell: /bin/sh focus: true shell_command: - printf ready - printf second ``` The second pane launches `/bin/sh`, receives both commands in order and becomes the active pane. A command list inside one pane does not create extra panes. ## Overrides - `start_directory` overrides the inherited working directory. - `shell` overrides the window's launch command. - `environment` supplies the pane's launch environment map. - `shell_command_before` adds setup after session and window setup. - `enter`, `sleep_before` and `sleep_after` supply command defaults. - `suppress_history` overrides the inherited history policy. Set focus explicitly when automation depends on which pane is selected. Use returned pane IDs for later operations instead of assuming that creation order is a stable tmux ID. Read [commands](https://libtmux.org/en/csharp/latest/workspace/configuration/commands/) for Enter and delay behavior and [environment](https://libtmux.org/en/csharp/latest/workspace/configuration/environment/) for variable handling. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Pane configuration Source: https://libtmux.org/en/cxx/latest/workspace/configuration/panes/ > Choose pane commands, launch settings and focus. Each entry in a window's [`panes`]() list describes one pane. A string is a command; `null` leaves a blank shell pane. A mapping provides launch and command settings. ```yaml title="panes.yaml" session_name: panes-example windows: - window_name: work layout: even-horizontal panes: - null - shell: /bin/sh focus: true shell_command: - printf ready - printf second ``` The second pane launches `/bin/sh`, receives both commands in order and becomes the active pane. A command list inside one pane does not create extra panes. ## Overrides - `start_directory` overrides the inherited working directory. - `shell` overrides the window's launch command. - `environment` supplies the pane's launch environment map. - `shell_command_before` adds setup after session and window setup. - [`enter`](), `sleep_before` and `sleep_after` supply command defaults. - [`suppress_history`]() overrides the inherited history policy. Set focus explicitly when automation depends on which pane is selected. Use returned pane IDs for later operations instead of assuming that creation order is a stable tmux ID. Read [commands](https://libtmux.org/en/cxx/latest/workspace/configuration/commands/) for Enter and delay behavior and [environment](https://libtmux.org/en/cxx/latest/workspace/configuration/environment/) for variable handling. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Pane configuration Source: https://libtmux.org/en/go/latest/workspace/configuration/panes/ > Choose pane commands, launch settings and focus. Each entry in a window's `panes` list describes one pane. A string is a command; `null` leaves a blank shell pane. A mapping provides launch and command settings. ```yaml title="panes.yaml" session_name: panes-example windows: - window_name: work layout: even-horizontal panes: - null - shell: /bin/sh focus: true shell_command: - printf ready - printf second ``` The second pane launches `/bin/sh`, receives both commands in order and becomes the active pane. A command list inside one pane does not create extra panes. ## Overrides - `start_directory` overrides the inherited working directory. - `shell` overrides the window's launch command. - `environment` supplies the pane's launch environment map. - `shell_command_before` adds setup after session and window setup. - `enter`, `sleep_before` and `sleep_after` supply command defaults. - `suppress_history` overrides the inherited history policy. Set focus explicitly when automation depends on which pane is selected. Use returned pane IDs for later operations instead of assuming that creation order is a stable tmux ID. Read [commands](https://libtmux.org/en/go/latest/workspace/configuration/commands/) for Enter and delay behavior and [environment](https://libtmux.org/en/go/latest/workspace/configuration/environment/) for variable handling. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Pane configuration Source: https://libtmux.org/en/java/latest/workspace/configuration/panes/ > Choose pane commands, launch settings and focus. Each entry in a window's `panes` list describes one pane. A string is a command; `null` leaves a blank shell pane. A mapping provides launch and command settings. ```yaml title="panes.yaml" session_name: panes-example windows: - window_name: work layout: even-horizontal panes: - null - shell: /bin/sh focus: true shell_command: - printf ready - printf second ``` The second pane launches `/bin/sh`, receives both commands in order and becomes the active pane. A command list inside one pane does not create extra panes. ## Overrides - `start_directory` overrides the inherited working directory. - `shell` overrides the window's launch command. - `environment` supplies the pane's launch environment map. - `shell_command_before` adds setup after session and window setup. - `enter`, `sleep_before` and `sleep_after` supply command defaults. - `suppress_history` overrides the inherited history policy. Set focus explicitly when automation depends on which pane is selected. Use returned pane IDs for later operations instead of assuming that creation order is a stable tmux ID. Read [commands](https://libtmux.org/en/java/latest/workspace/configuration/commands/) for Enter and delay behavior and [environment](https://libtmux.org/en/java/latest/workspace/configuration/environment/) for variable handling. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Pane configuration Source: https://libtmux.org/en/py/latest/workspace/configuration/panes/ > Choose pane commands, launch settings and focus. A pane can be a command string, a list of commands, or a mapping of settings. Each item in the window's `"panes"` list creates one pane; a command list inside that item describes several commands in that same pane. ```yaml session_name: pane-example start_directory: ./ windows: - window_name: main start_directory: ./ panes: - echo one command - [echo first command, echo second command] - shell_command: - echo configured pane start_directory: ./ focus: true - blank ``` ## Blank forms | Form inside `"panes"` | Reference interpretation | | --- | --- | | null, omitted YAML value, `blank`, or `"pane"` | Pane without its own commands | | Empty mapping or empty list | Expands to a pane without its own commands | | Mapping with no shell_command | Keeps the pane's other settings and uses no own commands | | `shell_command: null` or a single null command | No own commands | | Empty string `""` | Sends an empty command, normally pressing Enter | A blank pane can still receive inherited [before commands](https://libtmux.org/en/py/latest/workspace/configuration/commands/). Blank forms do not disable session/window/pane setup. An omitted window panes key is defaulted to one blank pane; an explicitly empty panes list is a different shape and should not be used as a portable way to request that default. ## Pane keys | Key | Meaning | | --- | --- | | `shell_command` | String, ordered command list, or supported command dictionaries | | `shell_command_before` | Setup prepended after session/window before commands | | `start_directory` | Pane directory override | | `"shell"` | Shell/application launched for this pane | | `focus` | Select this pane in its window | | `"environment"` | Environment map selected for this pane's launch | | `"suppress_history"` | Pane history policy override | | `"enter"` | Default for whether to submit each command | | `sleep_before`, `sleep_after` | Default delays in seconds around each command | ## Launch a shell or type commands `"shell"` chooses the process tmux starts in the pane. `shell_command` sends text into the process already running there. Launching an application through shell can work with tmux's remain-on-exit behavior, while typing that application's name into a shell has different process semantics. A pane shell overrides window_shell, including on the first pane. The first pane also supplies its directory and environment during window creation. Use an installed shell/application path rather than assuming the same executable exists on every host. A successful build confirms command delivery, not application readiness or command exit status. See [commands](https://libtmux.org/en/py/latest/workspace/configuration/commands/) for Enter, timing, and history, and [environment](https://libtmux.org/en/py/latest/workspace/configuration/environment/) for launch-map selection. ## Reference source [loader.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [classic.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py); [blank-panes.yaml](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/blank-panes.yaml); [pane-shell.yaml](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/pane-shell.yaml). --- # Pane configuration Source: https://libtmux.org/en/rs/latest/workspace/configuration/panes/ > Choose pane commands, launch settings and focus. Each entry in a window's [`panes`]() list describes one pane. A string is a command; `null` leaves a blank shell pane. A mapping provides launch and command settings. ```yaml title="panes.yaml" session_name: panes-example windows: - window_name: work layout: even-horizontal panes: - null - shell: /bin/sh focus: true shell_command: - printf ready - printf second ``` The second pane launches `/bin/sh`, receives both commands in order and becomes the active pane. A command list inside one pane does not create extra panes. ## Overrides - `start_directory` overrides the inherited working directory. - [`shell`]() overrides the window's launch command. - `environment` supplies the pane's launch environment map. - `shell_command_before` adds setup after session and window setup. - `enter`, `sleep_before` and `sleep_after` supply command defaults. - `suppress_history` overrides the inherited history policy. Set focus explicitly when automation depends on which pane is selected. Use returned pane IDs for later operations instead of assuming that creation order is a stable tmux ID. Read [commands](https://libtmux.org/en/rs/latest/workspace/configuration/commands/) for Enter and delay behavior and [environment](https://libtmux.org/en/rs/latest/workspace/configuration/environment/) for variable handling. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Pane configuration Source: https://libtmux.org/en/swift/latest/workspace/configuration/panes/ > Choose pane commands, launch settings and focus. Each entry in a window's [`panes`]() list describes one pane. A string is a command; [`null`]() leaves a blank shell pane. A mapping provides launch and command settings. ```yaml title="panes.yaml" session_name: panes-example windows: - window_name: work layout: even-horizontal panes: - null - shell: /bin/sh focus: true shell_command: - printf ready - printf second ``` The second pane launches `/bin/sh`, receives both commands in order and becomes the active pane. A command list inside one pane does not create extra panes. ## Overrides - `start_directory` overrides the inherited working directory. - [`shell`]() overrides the window's launch command. - `environment` supplies the pane's launch environment map. - `shell_command_before` adds setup after session and window setup. - [`enter`](), `sleep_before` and `sleep_after` supply command defaults. - `suppress_history` overrides the inherited history policy. Set focus explicitly when automation depends on which pane is selected. Use returned pane IDs for later operations instead of assuming that creation order is a stable tmux ID. Read [commands](https://libtmux.org/en/swift/latest/workspace/configuration/commands/) for Enter and delay behavior and [environment](https://libtmux.org/en/swift/latest/workspace/configuration/environment/) for variable handling. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Pane configuration Source: https://libtmux.org/en/ts/latest/workspace/configuration/panes/ > Choose pane commands, launch settings and focus. Each entry in a window's `panes` list describes one pane. A string is a command; [`null`]() leaves a blank shell pane. A mapping provides launch and command settings. ```yaml title="panes.yaml" session_name: panes-example windows: - window_name: work layout: even-horizontal panes: - null - shell: /bin/sh focus: true shell_command: - printf ready - printf second ``` The second pane launches `/bin/sh`, receives both commands in order and becomes the active pane. A command list inside one pane does not create extra panes. ## Overrides - `start_directory` overrides the inherited working directory. - `shell` overrides the window's launch command. - `environment` supplies the pane's launch environment map. - `shell_command_before` adds setup after session and window setup. - [`enter`](), `sleep_before` and `sleep_after` supply command defaults. - `suppress_history` overrides the inherited history policy. Set focus explicitly when automation depends on which pane is selected. Use returned pane IDs for later operations instead of assuming that creation order is a stable tmux ID. Read [commands](https://libtmux.org/en/ts/latest/workspace/configuration/commands/) for Enter and delay behavior and [environment](https://libtmux.org/en/ts/latest/workspace/configuration/environment/) for variable handling. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Workspace commands Source: https://libtmux.org/en/csharp/latest/workspace/configuration/commands/ > Order pane setup and command delivery, Enter handling and delays. `shell_command_before` adds setup for every affected pane. Setup is ordered from session to window to pane, followed by that pane's `shell_command` entries. ```yaml title="commands.yaml" session_name: commands-example shell_command_before: - printf session-setup windows: - window_name: shell shell_command_before: - printf window-setup panes: - shell_command_before: - printf pane-setup shell_command: - cmd: printf ready sleep_after: 0.01 - cmd: printf waiting enter: false sleep_after: 0 ``` The final command is typed without Enter. Delays are measured in seconds and pause delivery; they do not verify that an application is ready or that an earlier shell command succeeded. ## Enter and timing Pane-level `enter`, `sleep_before` and `sleep_after` establish defaults. Command mappings can change those defaults. An override carries to following commands in that pane until another override. Set an explicit value when later commands need to restore Enter or remove a delay. ## History and readiness History suppression prefixes sent commands with a space. The shell still needs its own setting to ignore leading-space commands, such as Bash's `HISTCONTROL=ignorespace` or zsh's `HIST_IGNORE_SPACE`. Prompt readiness delays initial input while a shell draws its prompt. It is separate from application readiness and command completion. Use a checked [before script](https://libtmux.org/en/csharp/latest/workspace/configuration/hooks/) for bootstrap work whose exit status must stop the load on failure. See [environment](https://libtmux.org/en/csharp/latest/workspace/configuration/environment/) before putting variable expressions in commands. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Workspace commands Source: https://libtmux.org/en/cxx/latest/workspace/configuration/commands/ > Order pane setup and command delivery, Enter handling and delays. `shell_command_before` adds setup for every affected pane. Setup is ordered from session to window to pane, followed by that pane's `shell_command` entries. ```yaml title="commands.yaml" session_name: commands-example shell_command_before: - printf session-setup windows: - window_name: shell shell_command_before: - printf window-setup panes: - shell_command_before: - printf pane-setup shell_command: - cmd: printf ready sleep_after: 0.01 - cmd: printf waiting enter: false sleep_after: 0 ``` The final command is typed without Enter. Delays are measured in seconds and pause delivery; they do not verify that an application is ready or that an earlier shell command succeeded. ## Enter and timing Pane-level [`enter`](), `sleep_before` and `sleep_after` establish defaults. Command mappings can change those defaults. An override carries to following commands in that pane until another override. Set an explicit value when later commands need to restore Enter or remove a delay. ## History and readiness History suppression prefixes sent commands with a space. The shell still needs its own setting to ignore leading-space commands, such as Bash's `HISTCONTROL=ignorespace` or zsh's `HIST_IGNORE_SPACE`. Prompt readiness delays initial input while a shell draws its prompt. It is separate from application readiness and command completion. Use a checked [before script](https://libtmux.org/en/cxx/latest/workspace/configuration/hooks/) for bootstrap work whose exit status must stop the load on failure. See [environment](https://libtmux.org/en/cxx/latest/workspace/configuration/environment/) before putting variable expressions in commands. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Workspace commands Source: https://libtmux.org/en/go/latest/workspace/configuration/commands/ > Order pane setup and command delivery, Enter handling and delays. `shell_command_before` adds setup for every affected pane. Setup is ordered from session to window to pane, followed by that pane's `shell_command` entries. ```yaml title="commands.yaml" session_name: commands-example shell_command_before: - printf session-setup windows: - window_name: shell shell_command_before: - printf window-setup panes: - shell_command_before: - printf pane-setup shell_command: - cmd: printf ready sleep_after: 0.01 - cmd: printf waiting enter: false sleep_after: 0 ``` The final command is typed without Enter. Delays are measured in seconds and pause delivery; they do not verify that an application is ready or that an earlier shell command succeeded. ## Enter and timing Pane-level `enter`, `sleep_before` and `sleep_after` establish defaults. Command mappings can change those defaults. An override carries to following commands in that pane until another override. Set an explicit value when later commands need to restore Enter or remove a delay. ## History and readiness History suppression prefixes sent commands with a space. The shell still needs its own setting to ignore leading-space commands, such as Bash's `HISTCONTROL=ignorespace` or zsh's `HIST_IGNORE_SPACE`. Prompt readiness delays initial input while a shell draws its prompt. It is separate from application readiness and command completion. Use a checked [before script](https://libtmux.org/en/go/latest/workspace/configuration/hooks/) for bootstrap work whose exit status must stop the load on failure. See [environment](https://libtmux.org/en/go/latest/workspace/configuration/environment/) before putting variable expressions in commands. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Workspace commands Source: https://libtmux.org/en/java/latest/workspace/configuration/commands/ > Order pane setup and command delivery, Enter handling and delays. `shell_command_before` adds setup for every affected pane. Setup is ordered from session to window to pane, followed by that pane's `shell_command` entries. ```yaml title="commands.yaml" session_name: commands-example shell_command_before: - printf session-setup windows: - window_name: shell shell_command_before: - printf window-setup panes: - shell_command_before: - printf pane-setup shell_command: - cmd: printf ready sleep_after: 0.01 - cmd: printf waiting enter: false sleep_after: 0 ``` The final command is typed without Enter. Delays are measured in seconds and pause delivery; they do not verify that an application is ready or that an earlier shell command succeeded. ## Enter and timing Pane-level `enter`, `sleep_before` and `sleep_after` establish defaults. Command mappings can change those defaults. An override carries to following commands in that pane until another override. Set an explicit value when later commands need to restore Enter or remove a delay. ## History and readiness History suppression prefixes sent commands with a space. The shell still needs its own setting to ignore leading-space commands, such as Bash's `HISTCONTROL=ignorespace` or zsh's `HIST_IGNORE_SPACE`. Prompt readiness delays initial input while a shell draws its prompt. It is separate from application readiness and command completion. Use a checked [before script](https://libtmux.org/en/java/latest/workspace/configuration/hooks/) for bootstrap work whose exit status must stop the load on failure. See [environment](https://libtmux.org/en/java/latest/workspace/configuration/environment/) before putting variable expressions in commands. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Workspace commands Source: https://libtmux.org/en/py/latest/workspace/configuration/commands/ > Order pane setup and command delivery, Enter handling and delays. Tmuxp sends workspace commands into panes in order. A command can be a string or a mapping with `"cmd"` and execution controls. `shell_command_before` adds shared setup without copying it into every pane. ```yaml session_name: command-example shell_command_before: - echo session setup windows: - window_name: main shell_command_before: - echo window setup panes: - shell_command_before: - echo pane setup shell_command: - cmd: echo ready sleep_after: 0.2 - cmd: echo typed but not submitted enter: false sleep_after: 0 ``` This sends the three setup commands, submits echo ready, waits 0.2 seconds, and leaves the final command at the prompt. The delay pauses construction; it does not ask the application whether it is ready. ## Forms and order `shell_command` and `shell_command_before` accept a scalar command or a list. A command dictionary requires `"cmd"` for the text. The loader expands shell variables and tilde expressions in command strings before the builder sends them. Variables already known to the process running tmuxp can therefore be substituted before a pane shell sees the command. For each pane, the loader concatenates session before commands, window before commands, pane before commands, then the pane's own commands. A blank pane still receives inherited setup. Quoting affects the pane shell too; YAML quoting alone does not bypass tmuxp's expansion step. ## Enter and delays | Setting | Default and scope | | --- | --- | | `"enter"` | True; pane default, then command override | | `sleep_before` | No delay; pane default, then command override in seconds | | `sleep_after` | No delay; pane default, then command override in seconds | In the classic builder, a command's enter/delay override carries forward to subsequent commands in that pane. Set `enter: true` or an explicit zero delay to restore that behavior for a later command. Absence means keep the current value; zero is an intentional delay override. Pauses run synchronously during construction. They can let a startup command settle but do not monitor its success. A failed pane command is not necessarily a failed tmux send operation, and starting a web server is not proof it is accepting connections. ## History and prompt readiness History suppression defaults to true. A session value trickles to a window, and a pane can override it. Suppression prefixes command text with a space. Bash needs HISTCONTROL containing ignorespace or ignoreboth; zsh needs HIST_IGNORE_SPACE. Without shell support, the command can still enter history. Builder pane_readiness is separate from command delays. Auto waits for the configured zsh session shell, while custom pane/window launch commands skip prompt waiting. See [hooks and builders](https://libtmux.org/en/py/latest/workspace/configuration/hooks/) for the policy and its limits. A workspace [before_script](https://libtmux.org/en/py/latest/workspace/configuration/hooks/) runs as a process outside the panes and checks its exit status. Use it for bootstrap work that must succeed before configured windows are built, rather than treating pane command delivery as a checked process result. ## Reference source [loader.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [classic.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py); [sleep.yaml](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/sleep.yaml); [skip-send.yaml](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/skip-send.yaml). --- # Workspace commands Source: https://libtmux.org/en/rs/latest/workspace/configuration/commands/ > Order pane setup and command delivery, Enter handling and delays. `shell_command_before` adds setup for every affected pane. Setup is ordered from session to window to pane, followed by that pane's `shell_command` entries. ```yaml title="commands.yaml" session_name: commands-example shell_command_before: - printf session-setup windows: - window_name: shell shell_command_before: - printf window-setup panes: - shell_command_before: - printf pane-setup shell_command: - cmd: printf ready sleep_after: 0.01 - cmd: printf waiting enter: false sleep_after: 0 ``` The final command is typed without Enter. Delays are measured in seconds and pause delivery; they do not verify that an application is ready or that an earlier shell command succeeded. ## Enter and timing Pane-level `enter`, `sleep_before` and `sleep_after` establish defaults. Command mappings can change those defaults. An override carries to following commands in that pane until another override. Set an explicit value when later commands need to restore Enter or remove a delay. ## History and readiness History suppression prefixes sent commands with a space. The shell still needs its own setting to ignore leading-space commands, such as Bash's `HISTCONTROL=ignorespace` or zsh's `HIST_IGNORE_SPACE`. Prompt readiness delays initial input while a shell draws its prompt. It is separate from application readiness and command completion. Use a checked [before script](https://libtmux.org/en/rs/latest/workspace/configuration/hooks/) for bootstrap work whose exit status must stop the load on failure. See [environment](https://libtmux.org/en/rs/latest/workspace/configuration/environment/) before putting variable expressions in commands. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Workspace commands Source: https://libtmux.org/en/swift/latest/workspace/configuration/commands/ > Order pane setup and command delivery, Enter handling and delays. `shell_command_before` adds setup for every affected pane. Setup is ordered from session to window to pane, followed by that pane's `shell_command` entries. ```yaml title="commands.yaml" session_name: commands-example shell_command_before: - printf session-setup windows: - window_name: shell shell_command_before: - printf window-setup panes: - shell_command_before: - printf pane-setup sleep_after: 0.01 shell_command: - cmd: printf ready - cmd: printf waiting enter: false ``` The final command is typed without Enter. Delays are measured in seconds and pause delivery; they do not verify that an application is ready or that an earlier shell command succeeded. ## Enter and timing Pane-level [`enter`](), `sleep_before` and `sleep_after` establish defaults. Command mappings can override Enter, and that override carries to following commands. Set delays on the pane; timing fields inside command mappings are refused. ## History and readiness History suppression prefixes sent commands with a space. The shell still needs its own setting to ignore leading-space commands, such as Bash's `HISTCONTROL=ignorespace` or zsh's `HIST_IGNORE_SPACE`. Prompt readiness delays initial input while a shell draws its prompt. It is separate from application readiness and command completion. Use a checked [before script](https://libtmux.org/en/swift/latest/workspace/configuration/hooks/) for bootstrap work whose exit status must stop the load on failure. See [environment](https://libtmux.org/en/swift/latest/workspace/configuration/environment/) before putting variable expressions in commands. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Workspace commands Source: https://libtmux.org/en/ts/latest/workspace/configuration/commands/ > Order pane setup and command delivery, Enter handling and delays. `shell_command_before` adds setup for every affected pane. Setup is ordered from session to window to pane, followed by that pane's `shell_command` entries. ```yaml title="commands.yaml" session_name: commands-example shell_command_before: - printf session-setup windows: - window_name: shell shell_command_before: - printf window-setup panes: - shell_command_before: - printf pane-setup shell_command: - cmd: printf ready sleep_after: 0.01 - cmd: printf waiting enter: false sleep_after: 0 ``` The final command is typed without Enter. Delays are measured in seconds and pause delivery; they do not verify that an application is ready or that an earlier shell command succeeded. ## Enter and timing Pane-level [`enter`](), `sleep_before` and `sleep_after` establish defaults. Command mappings can change those defaults. An override carries to following commands in that pane until another override. Set an explicit value when later commands need to restore Enter or remove a delay. ## History and readiness History suppression prefixes sent commands with a space. The shell still needs its own setting to ignore leading-space commands, such as Bash's `HISTCONTROL=ignorespace` or zsh's `HIST_IGNORE_SPACE`. Prompt readiness delays initial input while a shell draws its prompt. It is separate from application readiness and command completion. Use a checked [before script](https://libtmux.org/en/ts/latest/workspace/configuration/hooks/) for bootstrap work whose exit status must stop the load on failure. See [environment](https://libtmux.org/en/ts/latest/workspace/configuration/environment/) before putting variable expressions in commands. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Workspace environment Source: https://libtmux.org/en/csharp/latest/workspace/configuration/environment/ > Configure the loader process and the variables available to pane commands. The CLI's process environment controls discovery and optional runtimes. Configuration `environment` maps provide variables to the workspace's shells. ```yaml title="environment.yaml" session_name: environment-example environment: DOC_SESSION: session windows: - window_name: shell environment: DOC_WINDOW: window panes: - environment: DOC_PANE: pane shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' - shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' ``` A pane map selects its launch environment in place of the window map. Session variables still apply. Repeat a window variable in the pane map when that pane needs it too. Avoid putting credentials in example files or diagnostic output. ## Variable expressions The loader expands defined variables in configuration values before delivery. An expression can therefore use the invoking process's value before the pane shell reads it. Use explicit configuration variables and inspect resulting commands when moving a workspace between environments. ## Loader settings | Variable | Use | | --- | --- | | `TMUXP_CONFIGDIR` | Preferred existing directory for saved workspaces | | `XDG_CONFIG_HOME` | Base for the `tmuxp` configuration directory | | `EDITOR` | Editor used by `edit` | | `TMUX_WORKSPACE_PYTHON` | Optional interpreter for [`shell`]() and supported extensions | | `NO_COLOR` | Disable terminal color when nonempty | These are process settings, not workspace YAML keys. Read [discovery](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/), [editing](https://libtmux.org/en/csharp/latest/workspace/cli/edit/) and [shell inspection](https://libtmux.org/en/csharp/latest/workspace/cli/shell/) for their task-specific behavior. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Workspace environment Source: https://libtmux.org/en/cxx/latest/workspace/configuration/environment/ > Configure the loader process and the variables available to pane commands. The CLI's process environment controls discovery and optional runtimes. Configuration `environment` maps provide variables to the workspace's shells. ```yaml title="environment.yaml" session_name: environment-example environment: DOC_SESSION: session windows: - window_name: shell environment: DOC_WINDOW: window panes: - environment: DOC_PANE: pane shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' - shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' ``` A pane map selects its launch environment in place of the window map. Session variables still apply. Repeat a window variable in the pane map when that pane needs it too. Avoid putting credentials in example files or diagnostic output. ## Variable expressions The loader expands defined variables in configuration values before delivery. An expression can therefore use the invoking process's value before the pane shell reads it. Use explicit configuration variables and inspect resulting commands when moving a workspace between environments. ## Loader settings | Variable | Use | | --- | --- | | `TMUXP_CONFIGDIR` | Preferred existing directory for saved workspaces | | `XDG_CONFIG_HOME` | Base for the `tmuxp` configuration directory | | `EDITOR` | Editor used by `edit` | | `TMUX_WORKSPACE_PYTHON` | Optional interpreter for [`shell`]() and supported extensions | | `NO_COLOR` | Disable terminal color when nonempty | These are process settings, not workspace YAML keys. Read [discovery](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/), [editing](https://libtmux.org/en/cxx/latest/workspace/cli/edit/) and [shell inspection](https://libtmux.org/en/cxx/latest/workspace/cli/shell/) for their task-specific behavior. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Workspace environment Source: https://libtmux.org/en/go/latest/workspace/configuration/environment/ > Configure the loader process and the variables available to pane commands. The CLI's process environment controls discovery and optional runtimes. Configuration `environment` maps provide variables to the workspace's shells. ```yaml title="environment.yaml" session_name: environment-example environment: DOC_SESSION: session windows: - window_name: shell environment: DOC_WINDOW: window panes: - environment: DOC_PANE: pane shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' - shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' ``` A pane map selects its launch environment in place of the window map. Session variables still apply. Repeat a window variable in the pane map when that pane needs it too. Avoid putting credentials in example files or diagnostic output. ## Variable expressions The loader expands defined variables in configuration values before delivery. An expression can therefore use the invoking process's value before the pane shell reads it. Use explicit configuration variables and inspect resulting commands when moving a workspace between environments. ## Loader settings | Variable | Use | | --- | --- | | `TMUXP_CONFIGDIR` | Preferred existing directory for saved workspaces | | `XDG_CONFIG_HOME` | Base for the `tmuxp` configuration directory | | `EDITOR` | Editor used by `edit` | | `TMUX_WORKSPACE_PYTHON` | Optional interpreter for [`shell`]() and supported extensions | | `NO_COLOR` | Disable terminal color when nonempty | These are process settings, not workspace YAML keys. Read [discovery](https://libtmux.org/en/go/latest/workspace/guides/discovery/), [editing](https://libtmux.org/en/go/latest/workspace/cli/edit/) and [shell inspection](https://libtmux.org/en/go/latest/workspace/cli/shell/) for their task-specific behavior. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Workspace environment Source: https://libtmux.org/en/java/latest/workspace/configuration/environment/ > Configure the loader process and the variables available to pane commands. The CLI's process environment controls discovery and optional runtimes. Configuration `environment` maps provide variables to the workspace's shells. ```yaml title="environment.yaml" session_name: environment-example environment: DOC_SESSION: session windows: - window_name: shell environment: DOC_WINDOW: window panes: - environment: DOC_PANE: pane shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' - shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' ``` A pane map selects its launch environment in place of the window map. Session variables still apply. Repeat a window variable in the pane map when that pane needs it too. Avoid putting credentials in example files or diagnostic output. ## Variable expressions The loader expands defined variables in configuration values before delivery. An expression can therefore use the invoking process's value before the pane shell reads it. Use explicit configuration variables and inspect resulting commands when moving a workspace between environments. ## Loader settings | Variable | Use | | --- | --- | | `TMUXP_CONFIGDIR` | Preferred existing directory for saved workspaces | | `XDG_CONFIG_HOME` | Base for the `tmuxp` configuration directory | | `EDITOR` | Editor used by `edit` | | `TMUX_WORKSPACE_PYTHON` | Optional interpreter for [`shell`]() and supported extensions | | `NO_COLOR` | Disable terminal color when nonempty | These are process settings, not workspace YAML keys. Read [discovery](https://libtmux.org/en/java/latest/workspace/guides/discovery/), [editing](https://libtmux.org/en/java/latest/workspace/cli/edit/) and [shell inspection](https://libtmux.org/en/java/latest/workspace/cli/shell/) for their task-specific behavior. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Workspace environment Source: https://libtmux.org/en/py/latest/workspace/configuration/environment/ > Configure the loader process and the variables available to pane commands. The environment of the process running tmuxp controls discovery, expansion, and presentation. A workspace's `"environment"` mapping controls the tmux session or the environment passed when launching a pane. These are separate settings. ```yaml session_name: environment-example environment: WORKSPACE_ROLE: shared windows: - window_name: main environment: WINDOW_ROLE: tools panes: - echo window environment - environment: PANE_ROLE: isolated shell_command: env ``` The first pane receives the window launch map. The second selects its own pane map instead of merging it with the window map. It still inherits applicable tmux session/process environment. A pane map does not mean a completely empty environment plus that map. ## Expansion before launch Tmuxp expands tilde and environment-variable expressions in session/window names, paths, before_script, command strings, environment values, and string option values. It uses the environment of the process invoking tmuxp. It does not first populate that process environment from the workspace's environment mapping. For example, a command using an already-set process variable can be substituted before pane creation. Inspect the expanded intent when a variable should instead be read dynamically by a pane shell. Unknown variables and shell-specific expressions follow the loader's expansion and the eventual shell's rules, not a general template language. ## CLI and runtime variables | Variables | Effect | | --- | --- | | `TMUXP_CONFIGDIR`, `XDG_CONFIG_HOME`, `HOME` | Global workspace directory selection and home expansion | | `TMUXINATOR_CONFIG` | Tmuxinator import source directory | | `$EDITOR` | Editor executable; reference default is vim | | `$TMUX`, `$TMUX_PANE` | Current tmux connection and shell object context | | `TMUXP_PROGRESS` | Value 0 disables animated load progress | | `TMUXP_PROGRESS_FORMAT` | Default/minimal/window/pane/verbose preset or custom tokens | | `TMUXP_PROGRESS_LINES` | Script panel lines: default 3, 0 hides, -1 caps to terminal height | | `TMUXP_DETECT_TERMINAL_SIZE` | Value 1 enables size detection; default 1 | | `TMUXP_DEFAULT_COLUMNS`, `TMUXP_DEFAULT_ROWS` | Fallback session dimensions | | `COLUMNS`, `LINES`, `ROWS` | Terminal helper overrides and fallback sizing inputs | | `NO_COLOR`, `FORCE_COLOR` | Color policy; nonempty values are significant | | [`PYTHONSTARTUP`]() | Startup file used by supported shell startup behavior | | `IPYTHON_ARGUMENTS` | Whitespace-split arguments for the IPython backend | | [`PYTHONBREAKPOINT`]() | Can affect debugger selection in tmuxp shell | | `SHELL` | Shell diagnostics and readiness fallback | | `DISABLE_AUTO_TITLE` | Oh My Zsh automatic-title warning | | `PATH` | Executable lookup and diagnostics | | `LIBTMUX_TMUX_FORMAT_SEPARATOR` | Python libtmux format collection override | Explicit progress flags take precedence over their corresponding defaults. Nonempty NO_COLOR disables color even with always; otherwise explicit never/always precede FORCE_COLOR and automatic TTY detection. Use supported machine formats when consuming output in a script. See [directories](https://libtmux.org/en/py/latest/workspace/configuration/directories/) for existing-directory precedence, [layouts](https://libtmux.org/en/py/latest/workspace/configuration/layouts/) for size resolution, and [shell](https://libtmux.org/en/py/latest/workspace/cli/shell/) for Python-specific environment effects. ## Reference source [loader.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [finders.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/finders.py); [classic.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py); [load.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/load.py); [shell.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/shell.py); [shell.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/shell.py); [colors.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/_internal/colors.py); [util.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/util.py). --- # Workspace environment Source: https://libtmux.org/en/rs/latest/workspace/configuration/environment/ > Configure the loader process and the variables available to pane commands. The CLI's process environment controls discovery and optional runtimes. Configuration `environment` maps provide variables to the workspace's shells. ```yaml title="environment.yaml" session_name: environment-example environment: DOC_SESSION: session windows: - window_name: shell environment: DOC_WINDOW: window panes: - environment: DOC_PANE: pane shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' - shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' ``` A pane map selects its launch environment in place of the window map. Session variables still apply. Repeat a window variable in the pane map when that pane needs it too. Avoid putting credentials in example files or diagnostic output. ## Variable expressions Names, directories, options and environment values expand defined variables from the loader process. Command and launch-shell text keep their expressions for the pane shell; referenced loader variables are supplied to that pane unless the document already sets them. Shell quoting therefore remains meaningful. ## Loader settings | Variable | Use | | --- | --- | | `TMUXP_CONFIGDIR` | Preferred existing directory for saved workspaces | | `XDG_CONFIG_HOME` | Base for the `tmuxp` configuration directory | | [`EDITOR`]() | Editor used by `edit` | | `TMUX_WORKSPACE_PYTHON` | Optional interpreter for [`shell`]() and supported extensions | | `NO_COLOR` | Disable terminal color when nonempty | These are process settings, not workspace YAML keys. Read [discovery](https://libtmux.org/en/rs/latest/workspace/guides/discovery/), [editing](https://libtmux.org/en/rs/latest/workspace/cli/edit/) and [shell inspection](https://libtmux.org/en/rs/latest/workspace/cli/shell/) for their task-specific behavior. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Workspace environment Source: https://libtmux.org/en/swift/latest/workspace/configuration/environment/ > Configure the loader process and the variables available to pane commands. The CLI's process environment controls discovery and optional runtimes. Configuration `environment` maps provide variables to the workspace's shells. ```yaml title="environment.yaml" session_name: environment-example environment: DOC_SESSION: session windows: - window_name: shell environment: DOC_WINDOW: window panes: - environment: DOC_PANE: pane shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' - shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' ``` A pane map selects its launch environment in place of the window map. Session variables still apply. Repeat a window variable in the pane map when that pane needs it too. Avoid putting credentials in example files or diagnostic output. ## Variable expressions The loader expands defined variables in configuration values before delivery. An expression can therefore use the invoking process's value before the pane shell reads it. Use explicit configuration variables and inspect resulting commands when moving a workspace between environments. ## Loader settings | Variable | Use | | --- | --- | | `TMUXP_CONFIGDIR` | Preferred existing directory for saved workspaces | | `XDG_CONFIG_HOME` | Base for the `tmuxp` configuration directory | | `EDITOR` | Editor used by `edit` | | `TMUX_WORKSPACE_PYTHON` | Optional interpreter for [`shell`]() and supported extensions | | `NO_COLOR` | Disable terminal color when nonempty | These are process settings, not workspace YAML keys. Read [discovery](https://libtmux.org/en/swift/latest/workspace/guides/discovery/), [editing](https://libtmux.org/en/swift/latest/workspace/cli/edit/) and [shell inspection](https://libtmux.org/en/swift/latest/workspace/cli/shell/) for their task-specific behavior. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Workspace environment Source: https://libtmux.org/en/ts/latest/workspace/configuration/environment/ > Configure the loader process and the variables available to pane commands. The CLI's process environment controls discovery and optional runtimes. Configuration `environment` maps provide variables to the workspace's shells. ```yaml title="environment.yaml" session_name: environment-example environment: DOC_SESSION: session windows: - window_name: shell environment: DOC_WINDOW: window panes: - environment: DOC_PANE: pane shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' - shell_command: 'printf "ENV=%s|%s|%s\n" "$DOC_SESSION" "$DOC_WINDOW" "$DOC_PANE"' ``` A pane map selects its launch environment in place of the window map. Session variables still apply. Repeat a window variable in the pane map when that pane needs it too. Avoid putting credentials in example files or diagnostic output. ## Variable expressions The loader expands defined variables in configuration values before delivery. An expression can therefore use the invoking process's value before the pane shell reads it. Use explicit configuration variables and inspect resulting commands when moving a workspace between environments. ## Loader settings | Variable | Use | | --- | --- | | `TMUXP_CONFIGDIR` | Preferred existing directory for saved workspaces | | `XDG_CONFIG_HOME` | Base for the `tmuxp` configuration directory | | `EDITOR` | Editor used by `edit` | | `TMUX_WORKSPACE_PYTHON` | Optional interpreter for [`shell`]() and supported extensions | | `NO_COLOR` | Disable terminal color when nonempty | These are process settings, not workspace YAML keys. Read [discovery](https://libtmux.org/en/ts/latest/workspace/guides/discovery/), [editing](https://libtmux.org/en/ts/latest/workspace/cli/edit/) and [shell inspection](https://libtmux.org/en/ts/latest/workspace/cli/shell/) for their task-specific behavior. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Files and directories Source: https://libtmux.org/en/csharp/latest/workspace/configuration/directories/ > Resolve saved workspace files and the working directories used by panes. Use an explicit file path when debugging workspace discovery. A directory such as `.` selects a project configuration; a saved name selects a global workspace. See [finding workspaces](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/) for that lookup order. ## Set a starting directory ```yaml title="directories.yaml" session_name: directories-example start_directory: ./ windows: - window_name: shell start_directory: ./ panes: - start_directory: ./ shell_command: pwd ``` An explicit relative session directory starts from the configuration file's directory. Child directories resolve through their parent configuration. Use absolute paths when a workspace deliberately points outside its project. Quote home shortcuts in YAML, such as `"~/src/project"`; an unquoted `~` is a null value. An omitted directory lets the loader and tmux use their invocation context. The explicit relative directory in this example selects the file's project context. ## Verify the running pane A saved path can be absent on another machine. Inspect the real pane directory after loading rather than relying on successful YAML parsing. tmux can fall back to a home directory when a requested path does not exist. Bootstrap paths and process working directories have separate rules. See [before scripts](https://libtmux.org/en/csharp/latest/workspace/configuration/hooks/) before using one to create directories. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Files and directories Source: https://libtmux.org/en/cxx/latest/workspace/configuration/directories/ > Resolve saved workspace files and the working directories used by panes. Use an explicit file path when debugging workspace discovery. A directory such as `.` selects a project configuration; a saved name selects a global workspace. See [finding workspaces](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/) for that lookup order. ## Set a starting directory ```yaml title="directories.yaml" session_name: directories-example start_directory: ./ windows: - window_name: shell start_directory: ./ panes: - start_directory: ./ shell_command: pwd ``` An explicit relative session directory starts from the configuration file's directory. Child directories resolve through their parent configuration. Use absolute paths when a workspace deliberately points outside its project. Quote home shortcuts in YAML, such as `"~/src/project"`; an unquoted `~` is a null value. An omitted directory lets the loader and tmux use their invocation context. The explicit relative directory in this example selects the file's project context. ## Verify the running pane A saved path can be absent on another machine. Inspect the real pane directory after loading rather than relying on successful YAML parsing. tmux can fall back to a home directory when a requested path does not exist. Bootstrap paths and process working directories have separate rules. See [before scripts](https://libtmux.org/en/cxx/latest/workspace/configuration/hooks/) before using one to create directories. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Files and directories Source: https://libtmux.org/en/go/latest/workspace/configuration/directories/ > Resolve saved workspace files and the working directories used by panes. Use an explicit file path when debugging workspace discovery. A directory such as `.` selects a project configuration; a saved name selects a global workspace. See [finding workspaces](https://libtmux.org/en/go/latest/workspace/guides/discovery/) for that lookup order. ## Set a starting directory ```yaml title="directories.yaml" session_name: directories-example start_directory: ./ windows: - window_name: shell start_directory: ./ panes: - start_directory: ./ shell_command: pwd ``` An explicit relative session directory starts from the configuration file's directory. Child directories resolve through their parent configuration. Use absolute paths when a workspace deliberately points outside its project. Quote home shortcuts in YAML, such as `"~/src/project"`; an unquoted `~` is a null value. An omitted directory lets the loader and tmux use their invocation context. The explicit relative directory in this example selects the file's project context. ## Verify the running pane A saved path can be absent on another machine. Inspect the real pane directory after loading rather than relying on successful YAML parsing. tmux can fall back to a home directory when a requested path does not exist. Bootstrap paths and process working directories have separate rules. See [before scripts](https://libtmux.org/en/go/latest/workspace/configuration/hooks/) before using one to create directories. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Files and directories Source: https://libtmux.org/en/java/latest/workspace/configuration/directories/ > Resolve saved workspace files and the working directories used by panes. Use an explicit file path when debugging workspace discovery. A directory such as `.` selects a project configuration; a saved name selects a global workspace. See [finding workspaces](https://libtmux.org/en/java/latest/workspace/guides/discovery/) for that lookup order. ## Set a starting directory ```yaml title="directories.yaml" session_name: directories-example start_directory: ./ windows: - window_name: shell start_directory: ./ panes: - start_directory: ./ shell_command: pwd ``` An explicit relative session directory starts from the configuration file's directory. Child directories resolve through their parent configuration. Use absolute paths when a workspace deliberately points outside its project. Quote home shortcuts in YAML, such as `"~/src/project"`; an unquoted `~` is a null value. An omitted directory lets the loader and tmux use their invocation context. The explicit relative directory in this example selects the file's project context. ## Verify the running pane A saved path can be absent on another machine. Inspect the real pane directory after loading rather than relying on successful YAML parsing. tmux can fall back to a home directory when a requested path does not exist. Bootstrap paths and process working directories have separate rules. See [before scripts](https://libtmux.org/en/java/latest/workspace/configuration/hooks/) before using one to create directories. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Files and directories Source: https://libtmux.org/en/py/latest/workspace/configuration/directories/ > Resolve saved workspace files and the working directories used by panes. Tmuxp accepts an explicit workspace file, a saved workspace name, or a project directory. The location of the selected file determines how config-relative paths expand. Use an explicit file while debugging a discovery problem. Load a file on a dedicated server: ```console $ tmuxp load \ -L directory-example \ -d \ ./workspace.yaml ``` Load the current project's workspace: ```console $ tmuxp load . ``` These commands use Python tmuxp and assume the corresponding workspace file already exists. The first command leaves its session detached; use the session name from the file when inspecting or cleaning it up. ## Global and local discovery For the preferred global workspace directory, tmuxp tries TMUXP_CONFIGDIR, XDG_CONFIG_HOME/tmuxp (or the XDG default), then the legacy [`~/.tmuxp`](https://libtmux.org/en/py/latest/workspace/guides/discovery/) directory. It chooses the first existing directory. If none exists, it returns the legacy location. Setting TMUXP_CONFIGDIR to a nonexistent path does not automatically select that path over an existing fallback. Project discovery walks the current directory and its parents, choosing at most one workspace per directory in [`.tmuxp.yaml`](), [`.tmuxp.yml`](https://libtmux.org/en/py/latest/workspace/guides/discovery/), [`.tmuxp.json`](https://libtmux.org/en/py/latest/workspace/guides/discovery/) order. It stops at home or filesystem root. `ls` can report global directory candidates and locally discovered workspaces; that inventory is not identical to resolving one explicit load argument. The importers use their own source roots: Teamocil uses [`~/.teamocil`](https://libtmux.org/en/py/latest/workspace/cli/import-teamocil/); tmuxinator uses TMUXINATOR_CONFIG, with tilde expansion, or [`~/.tmuxinator`](https://libtmux.org/en/py/latest/workspace/cli/import-tmuxinator/). Their source argument is effectively required, even though the parser's positional arity looks optional. ## Start directories ```yaml session_name: directory-example start_directory: ./ windows: - window_name: root panes: - pwd - window_name: child start_directory: ./src panes: - pwd - start_directory: ./ shell_command: pwd ``` This example assumes the project has a `"src"` directory. The first window inherits the session directory. The child window resolves ./src against the explicit session directory, and its second pane resolves ./ against that window directory. Both child panes start in src. The root start_directory resolves a dot-relative path from the configuration file's directory. At child levels, the pinned loader resolves dot-relative paths against the immediate parent's start_directory before inherited defaults are filled. Define that parent value explicitly when using ./ or ../ in a child. A missing parent start_directory can raise KeyError during expansion. A plain relative window directory such as src is joined to the session directory later, during trickle. A dot-relative pane under that still-relative window can resolve against the invoking process's current directory first. Use an explicit ./src window value as above, or an absolute path, to avoid that inconsistency. When a document names no `start_directory` at any level, panes start in the directory the command was run from, not the directory the workspace file lives in. Use an explicit session directory and child directories as described above when loading a file from another working directory. Absolute and expanded-home paths retain their explicit location. Quote `~` in YAML to avoid its null spelling. A pane override also applies to the first pane in the Python classic builder. Inspect resolved values and the resulting pane directory when loading a workspace from a different working directory. ## Missing directories and bootstrap A nonexistent path can make tmux start somewhere unexpected, including a home directory, rather than producing a useful configuration error. Inspect the actual pane directory when verifying a workspace. A relative before_script path is resolved from the workspace file. Its process working directory uses the session start_directory when supplied. A bootstrap process can create required project files, but it runs after the initial tmux session exists. See [hooks](https://libtmux.org/en/py/latest/workspace/configuration/hooks/) for failure handling and [environment](https://libtmux.org/en/py/latest/workspace/configuration/environment/) for variable expansion. ## Reference source [finders.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/finders.py); [loader.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [import_config.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/import_config.py); [classic.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py); [start-directory.yaml](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/start-directory.yaml). --- # Files and directories Source: https://libtmux.org/en/rs/latest/workspace/configuration/directories/ > Resolve saved workspace files and the working directories used by panes. Use an explicit file path when debugging workspace discovery. A directory such as `.` selects a project configuration; a saved name selects a global workspace. See [finding workspaces](https://libtmux.org/en/rs/latest/workspace/guides/discovery/) for that lookup order. ## Set a starting directory ```yaml title="directories.yaml" session_name: directories-example start_directory: ./ windows: - window_name: shell start_directory: ./ panes: - start_directory: ./ shell_command: pwd ``` An explicit relative session directory starts from the configuration file's directory. Child directories resolve through their parent configuration. Use absolute paths when a workspace deliberately points outside its project. Quote home shortcuts in YAML, such as `"~/src/project"`; an unquoted `~` is a null value. An omitted directory lets the loader and tmux use their invocation context. The explicit relative directory in this example selects the file's project context. ## Verify the running pane A saved path can be absent on another machine. Inspect the real pane directory after loading rather than relying on successful YAML parsing. tmux can fall back to a home directory when a requested path does not exist. Bootstrap paths and process working directories have separate rules. See [before scripts](https://libtmux.org/en/rs/latest/workspace/configuration/hooks/) before using one to create directories. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Files and directories Source: https://libtmux.org/en/swift/latest/workspace/configuration/directories/ > Resolve saved workspace files and the working directories used by panes. Use an explicit file path when debugging workspace discovery. A directory such as `.` selects a project configuration; a saved name selects a global workspace. See [finding workspaces](https://libtmux.org/en/swift/latest/workspace/guides/discovery/) for that lookup order. ## Set a starting directory ```yaml title="directories.yaml" session_name: directories-example start_directory: ./ windows: - window_name: shell start_directory: ./ panes: - start_directory: ./ shell_command: pwd ``` An explicit relative session directory starts from the configuration file's directory. Child directories resolve through their parent configuration. Use absolute paths when a workspace deliberately points outside its project. Quote home shortcuts in YAML, such as `"~/src/project"`; an unquoted `~` is a null value. An omitted directory lets the loader and tmux use their invocation context. The explicit relative directory in this example selects the file's project context. ## Verify the running pane A saved path can be absent on another machine. Inspect the real pane directory after loading rather than relying on successful YAML parsing. tmux can fall back to a home directory when a requested path does not exist. Bootstrap paths and process working directories have separate rules. See [before scripts](https://libtmux.org/en/swift/latest/workspace/configuration/hooks/) before using one to create directories. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Files and directories Source: https://libtmux.org/en/ts/latest/workspace/configuration/directories/ > Resolve saved workspace files and the working directories used by panes. Use an explicit file path when debugging workspace discovery. A directory such as `.` selects a project configuration; a saved name selects a global workspace. See [finding workspaces](https://libtmux.org/en/ts/latest/workspace/guides/discovery/) for that lookup order. ## Set a starting directory ```yaml title="directories.yaml" session_name: directories-example start_directory: ./ windows: - window_name: shell start_directory: ./ panes: - start_directory: ./ shell_command: pwd ``` An explicit relative session directory starts from the configuration file's directory. Child directories resolve through their parent configuration. Use absolute paths when a workspace deliberately points outside its project. Quote home shortcuts in YAML, such as `"~/src/project"`; an unquoted `~` is a null value. An omitted directory lets the loader and tmux use their invocation context. The explicit relative directory in this example selects the file's project context. ## Verify the running pane A saved path can be absent on another machine. Inspect the real pane directory after loading rather than relying on successful YAML parsing. tmux can fall back to a home directory when a requested path does not exist. Bootstrap paths and process working directories have separate rules. See [before scripts](https://libtmux.org/en/ts/latest/workspace/configuration/hooks/) before using one to create directories. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Window layouts Source: https://libtmux.org/en/csharp/latest/workspace/configuration/layouts/ > Arrange panes with tmux layout names or a saved layout. Choose a layout for each window. `even-horizontal` gives panes equal widths: ```yaml title="layouts.yaml" session_name: layouts-example windows: - window_name: work layout: even-horizontal panes: [null, null, null] ``` Other common tmux names include `even-vertical`, `main-horizontal`, `main-vertical` and `tiled`. Full names avoid version-dependent abbreviation ambiguity. Available names follow the selected tmux daemon. ## Saved layouts and terminal size A captured layout describes pane geometry. Loading validates its syntax and pane capacity, then tmux applies it to the actual window size. Resizing can change the final dimensions. Use a named layout when exact saved geometry is unnecessary. Set window and pane `focus` explicitly when the active target matters. Layout arrangement and active-pane selection are different settings. [Capture](https://libtmux.org/en/csharp/latest/workspace/cli/freeze/) can save a running layout; inspect it before [reloading](https://libtmux.org/en/csharp/latest/workspace/guides/export-session/) on a smaller terminal. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Window layouts Source: https://libtmux.org/en/cxx/latest/workspace/configuration/layouts/ > Arrange panes with tmux layout names or a saved layout. Choose a layout for each window. `even-horizontal` gives panes equal widths: ```yaml title="layouts.yaml" session_name: layouts-example windows: - window_name: work layout: even-horizontal panes: [null, null, null] ``` Other common tmux names include `even-vertical`, `main-horizontal`, `main-vertical` and `tiled`. Full names avoid version-dependent abbreviation ambiguity. Available names follow the selected tmux daemon. ## Saved layouts and terminal size A captured layout describes pane geometry. Loading validates its syntax and pane capacity, then tmux applies it to the actual window size. Resizing can change the final dimensions. Use a named layout when exact saved geometry is unnecessary. Set window and pane `focus` explicitly when the active target matters. Layout arrangement and active-pane selection are different settings. [Capture](https://libtmux.org/en/cxx/latest/workspace/cli/freeze/) can save a running layout; inspect it before [reloading](https://libtmux.org/en/cxx/latest/workspace/guides/export-session/) on a smaller terminal. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Window layouts Source: https://libtmux.org/en/go/latest/workspace/configuration/layouts/ > Arrange panes with tmux layout names or a saved layout. Choose a layout for each window. `even-horizontal` gives panes equal widths: ```yaml title="layouts.yaml" session_name: layouts-example windows: - window_name: work layout: even-horizontal panes: [null, null, null] ``` Other common tmux names include `even-vertical`, `main-horizontal`, `main-vertical` and `tiled`. Full names avoid version-dependent abbreviation ambiguity. Available names follow the selected tmux daemon. ## Saved layouts and terminal size A captured layout describes pane geometry. Loading validates its syntax and pane capacity, then tmux applies it to the actual window size. Resizing can change the final dimensions. Use a named layout when exact saved geometry is unnecessary. Set window and pane `focus` explicitly when the active target matters. Layout arrangement and active-pane selection are different settings. [Capture](https://libtmux.org/en/go/latest/workspace/cli/freeze/) can save a running layout; inspect it before [reloading](https://libtmux.org/en/go/latest/workspace/guides/export-session/) on a smaller terminal. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Window layouts Source: https://libtmux.org/en/java/latest/workspace/configuration/layouts/ > Arrange panes with tmux layout names or a saved layout. Choose a layout for each window. `even-horizontal` gives panes equal widths: ```yaml title="layouts.yaml" session_name: layouts-example windows: - window_name: work layout: even-horizontal panes: [null, null, null] ``` Other common tmux names include `even-vertical`, `main-horizontal`, `main-vertical` and `tiled`. Full names avoid version-dependent abbreviation ambiguity. Available names follow the selected tmux daemon. ## Saved layouts and terminal size A captured layout describes pane geometry. Loading validates its syntax and pane capacity, then tmux applies it to the actual window size. Resizing can change the final dimensions. Use a named layout when exact saved geometry is unnecessary. Set window and pane `focus` explicitly when the active target matters. Layout arrangement and active-pane selection are different settings. [Capture](https://libtmux.org/en/java/latest/workspace/cli/freeze/) can save a running layout; inspect it before [reloading](https://libtmux.org/en/java/latest/workspace/guides/export-session/) on a smaller terminal. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Window layouts Source: https://libtmux.org/en/py/latest/workspace/configuration/layouts/ > Arrange panes with tmux layout names or a saved layout. A window's `"layout"` chooses how tmux arranges its panes. Named layouts adapt to the window size; explicit layout strings describe geometry more directly. The selected tmux version and terminal dimensions affect the final result. ```yaml session_name: layout-example windows: - window_name: main layout: main-horizontal focus: true options: main-pane-height: 60% panes: - shell_command: echo main pane focus: true - echo first lower pane - echo second lower pane ``` ## Layout names and options Common tmux layout names are even-horizontal, even-vertical, main-horizontal, main-vertical, and tiled. Layout availability belongs to the target tmux version. Options such as main-pane-height and main-pane-width shape applicable main-pane layouts. A row/column count and a percentage are different values; preserve that distinction in YAML/JSON. The classic builder applies window options before selecting a layout and applies options_after after panes and their setup commands. This lets a workspace size its main pane while delaying synchronize-panes until individual setup is complete. An explicit layout string can depend on the current number of panes and window size. A layout captured from one terminal is a starting point to inspect on another, not a portable pixel diagram. ## Terminal dimensions When TMUXP_DETECT_TERMINAL_SIZE is 1 (the default), the classic builder asks Python's terminal-size helper for initial session dimensions. COLUMNS and LINES can influence that helper. Fallback width uses TMUXP_DEFAULT_COLUMNS, then COLUMNS, then 80. Fallback height uses TMUXP_DEFAULT_ROWS, then ROWS, with nominal default 24. The helper can choose terminal dimensions instead of its fallback, so a TMUXP_DEFAULT value alone is not an unconditional size override. Detached sessions also need dimensions for reproducible layouts. Invalid numeric environment values can fail before useful construction. ## Focus and indexes Set window focus to select that window after construction, and pane focus to select the active pane within its window. Prefer one focused window and one focused pane per window; multiple true values depend on build order and are harder to reason about. A window_index selects its numeric tmux position. Pane IDs such as `%3` are runtime identities, not YAML pane list positions. Base-index and pane-base-index settings can make visible indexes differ from zero-based list positions. Inspect a running workspace's geometry and selection: ```console $ tmux -L layout-example list-windows -t '=layout-example' ``` This command assumes the sample workspace was loaded on the dedicated layout-example socket. Use [load](https://libtmux.org/en/py/latest/workspace/cli/load/) to select that socket, then inspect panes as needed. ## Reference source [classic.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py); [main-pane-height.yaml](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/main-pane-height.yaml); [main-pane-height-percentage.yaml](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/main-pane-height-percentage.yaml); [focus-window-and-panes.yaml](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/focus-window-and-panes.yaml); [window-index.yaml](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/window-index.yaml). --- # Window layouts Source: https://libtmux.org/en/rs/latest/workspace/configuration/layouts/ > Arrange panes with tmux layout names or a saved layout. Choose a layout for each window. `even-horizontal` gives panes equal widths: ```yaml title="layouts.yaml" session_name: layouts-example windows: - window_name: work layout: even-horizontal panes: [null, null, null] ``` Other common tmux names include `even-vertical`, `main-horizontal`, `main-vertical` and `tiled`. Full names avoid version-dependent abbreviation ambiguity. Available names follow the selected tmux daemon. ## Saved layouts and terminal size A captured layout describes pane geometry. Loading validates its syntax and pane capacity, then tmux applies it to the actual window size. Resizing can change the final dimensions. Use a named layout when exact saved geometry is unnecessary. Set window and pane `focus` explicitly when the active target matters. Layout arrangement and active-pane selection are different settings. [Capture](https://libtmux.org/en/rs/latest/workspace/cli/freeze/) can save a running layout; inspect it before [reloading](https://libtmux.org/en/rs/latest/workspace/guides/export-session/) on a smaller terminal. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Window layouts Source: https://libtmux.org/en/swift/latest/workspace/configuration/layouts/ > Arrange panes with tmux layout names or a saved layout. Choose a layout for each window. `even-horizontal` gives panes equal widths: ```yaml title="layouts.yaml" session_name: layouts-example windows: - window_name: work layout: even-horizontal panes: [null, null, null] ``` Other common tmux names include `even-vertical`, `main-horizontal`, `main-vertical` and `tiled`. Full names avoid version-dependent abbreviation ambiguity. Available names follow the selected tmux daemon. ## Saved layouts and terminal size A captured layout describes pane geometry. Loading validates its syntax and pane capacity, then tmux applies it to the actual window size. Resizing can change the final dimensions. Use a named layout when exact saved geometry is unnecessary. Set window and pane `focus` explicitly when the active target matters. Layout arrangement and active-pane selection are different settings. [Capture](https://libtmux.org/en/swift/latest/workspace/cli/freeze/) can save a running layout; inspect it before [reloading](https://libtmux.org/en/swift/latest/workspace/guides/export-session/) on a smaller terminal. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Window layouts Source: https://libtmux.org/en/ts/latest/workspace/configuration/layouts/ > Arrange panes with tmux layout names or a saved layout. Choose a layout for each window. `even-horizontal` gives panes equal widths: ```yaml title="layouts.yaml" session_name: layouts-example windows: - window_name: work layout: even-horizontal panes: [null, null, null] ``` Other common tmux names include `even-vertical`, `main-horizontal`, `main-vertical` and `tiled`. Full names avoid version-dependent abbreviation ambiguity. Available names follow the selected tmux daemon. ## Saved layouts and terminal size A captured layout describes pane geometry. Loading validates its syntax and pane capacity, then tmux applies it to the actual window size. Resizing can change the final dimensions. Use a named layout when exact saved geometry is unnecessary. Set window and pane `focus` explicitly when the active target matters. Layout arrangement and active-pane selection are different settings. [Capture](https://libtmux.org/en/ts/latest/workspace/cli/freeze/) can save a running layout; inspect it before [reloading](https://libtmux.org/en/ts/latest/workspace/guides/export-session/) on a smaller terminal. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Bootstrap scripts and extensions Source: https://libtmux.org/en/csharp/latest/workspace/configuration/hooks/ > Run a checked bootstrap process before workspace commands. Use `before_script` when setup must finish successfully before configured windows are built. The command is split into an executable and arguments; shell operators require an explicit shell. ```yaml title="hooks.yaml" session_name: hooks-example before_script: /bin/sh -c 'printf bootstrap-ready' windows: - window_name: shell panes: [null] ``` The CLI checks the child process status. A failure stops that workspace's build. The result describes retained effects; an earlier input or borrowed session can still exist. A pane's `shell_command` only sends input and does not provide this process-status guarantee. ## Paths and output A relative script path beginning with `.` is resolved from the workspace file. The script's working directory uses the configured session directory when present, otherwise the invocation directory. The script runs before workspace pane commands. Reusing an existing session does not replay its bootstrap. Machine output captures or streams child output through the CLI protocol. Read [output](https://libtmux.org/en/csharp/latest/workspace/reference/output/) before parsing bootstrap records. ## Prompt readiness The `pane_readiness` setting under `workspace_builder_options` accepts `auto`, `always` or `never`. It controls a bounded wait before initial pane input. It does not wait for a server process to accept connections. Commands can still be delivered when the prompt wait expires. ## Optional extensions Nonempty `plugins` or `workspace_builder` values select the optional Python extension runtime. Set `TMUX_WORKSPACE_PYTHON` to an interpreter with a compatible tmuxp 1.74 installation. Ordinary documents use the native builder. Extensions run executable code and can make changes outside the CLI's own tracked operations. Inspect reported effects and errors before retrying them. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Bootstrap scripts and extensions Source: https://libtmux.org/en/cxx/latest/workspace/configuration/hooks/ > Run a checked bootstrap process before workspace commands. Use `before_script` when setup must finish successfully before configured windows are built. The command is split into an executable and arguments; shell operators require an explicit shell. ```yaml title="hooks.yaml" session_name: hooks-example before_script: /bin/sh -c 'printf bootstrap-ready' windows: - window_name: shell panes: [null] ``` The CLI checks the child process status. A failure stops that workspace's build. The result describes retained effects; an earlier input or borrowed session can still exist. A pane's `shell_command` only sends input and does not provide this process-status guarantee. ## Paths and output A relative script path beginning with `.` is resolved from the workspace file. The script's working directory uses the configured session directory when present, otherwise the invocation directory. The script runs before workspace pane commands. Reusing an existing session does not replay its bootstrap. Machine output captures or streams child output through the CLI protocol. Read [output](https://libtmux.org/en/cxx/latest/workspace/reference/output/) before parsing bootstrap records. ## Prompt readiness The `pane_readiness` setting under `workspace_builder_options` accepts `auto`, `always` or `never`. It controls a bounded wait before initial pane input. It does not wait for a server process to accept connections. Commands can still be delivered when the prompt wait expires. ## Optional extensions Plugin and custom-builder execution is unsupported. The CLI refuses those execution fields instead of treating them as successful native work. The optional [inspection shell](https://libtmux.org/en/cxx/latest/workspace/cli/shell/) is a separate feature. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Bootstrap scripts and extensions Source: https://libtmux.org/en/go/latest/workspace/configuration/hooks/ > Run a checked bootstrap process before workspace commands. Use `before_script` when setup must finish successfully before configured windows are built. The command is split into an executable and arguments; shell operators require an explicit shell. ```yaml title="hooks.yaml" session_name: hooks-example before_script: /bin/sh -c 'printf bootstrap-ready' windows: - window_name: shell panes: [null] ``` The CLI checks the child process status. A failure stops that workspace's build. The result describes retained effects; an earlier input or borrowed session can still exist. A pane's `shell_command` only sends input and does not provide this process-status guarantee. ## Paths and output A relative script path beginning with `.` is resolved from the workspace file. The script's working directory uses the configured session directory when present, otherwise the invocation directory. The script runs before workspace pane commands. Reusing an existing session does not replay its bootstrap. Machine output captures or streams child output through the CLI protocol. Read [output](https://libtmux.org/en/go/latest/workspace/reference/output/) before parsing bootstrap records. ## Prompt readiness The `pane_readiness` setting under `workspace_builder_options` accepts `auto`, `always` or `never`. It controls a bounded wait before initial pane input. It does not wait for a server process to accept connections. Commands can still be delivered when the prompt wait expires. ## Optional extensions Nonempty `plugins` or `workspace_builder` values select the optional Python extension runtime. Set `TMUX_WORKSPACE_PYTHON` to an interpreter with a compatible tmuxp 1.74 installation. Ordinary documents use the native builder. Extensions run executable code and can make changes outside the CLI's own tracked operations. Inspect reported effects and errors before retrying them. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Bootstrap scripts and extensions Source: https://libtmux.org/en/java/latest/workspace/configuration/hooks/ > Run a checked bootstrap process before workspace commands. Use `before_script` when setup must finish successfully before configured windows are built. The command is split into an executable and arguments; shell operators require an explicit shell. ```yaml title="hooks.yaml" session_name: hooks-example before_script: /bin/sh -c 'printf bootstrap-ready' windows: - window_name: shell panes: [null] ``` The CLI checks the child process status. A failure stops that workspace's build. The result describes retained effects; an earlier input or borrowed session can still exist. A pane's `shell_command` only sends input and does not provide this process-status guarantee. ## Paths and output A relative script path beginning with `.` is resolved from the workspace file. The script's working directory uses the configured session directory when present, otherwise the invocation directory. The script runs before workspace pane commands. Reusing an existing session does not replay its bootstrap. Machine output captures or streams child output through the CLI protocol. Read [output](https://libtmux.org/en/java/latest/workspace/reference/output/) before parsing bootstrap records. ## Prompt readiness The `pane_readiness` setting under `workspace_builder_options` accepts `auto`, `always` or `never`. It controls a bounded wait before initial pane input. It does not wait for a server process to accept connections. Commands can still be delivered when the prompt wait expires. ## Optional extensions Nonempty `plugins` or `workspace_builder` values select the optional Python extension runtime. Set `TMUX_WORKSPACE_PYTHON` to an interpreter with a compatible tmuxp 1.74 installation. Ordinary documents use the native builder. Extensions run executable code and can make changes outside the CLI's own tracked operations. Inspect reported effects and errors before retrying them. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Bootstrap scripts and extensions Source: https://libtmux.org/en/py/latest/workspace/configuration/hooks/ > Run a checked bootstrap process before workspace commands. Workspace scripts, plugins, and custom builders extend how Python tmuxp creates a session. They are execution features, not passive configuration metadata. A workspace naming Python code needs that code installed or importable in tmuxp's environment. ## Bootstrap with before_script ```yaml session_name: bootstrap-example start_directory: ./ before_script: ./bootstrap.sh windows: - window_name: main panes: - echo bootstrap completed ``` This complete configuration assumes bootstrap.sh exists and is executable. Tmuxp resolves the script relative to the workspace file and uses the session start_directory as the process working directory when supplied. A zero exit status permits configured-window construction to continue; a failing script raises an error. The classic builder has already created the initial session when before_script runs. It kills that session when the bootstrap process fails. That does not undo files or other external effects created by the script. Pane shell_command is different: successful text delivery does not check the command's exit status. ## Python plugins `"plugins"` is a list of Python class references, conventionally a class in a package's plugin module. Install that package into the same Python environment as tmuxp. Plugins can declare tmux, libtmux, and tmuxp version requirements. The lifecycle includes these distinct hooks: | Hook | When it applies | | --- | --- | | [`before_workspace_builder`]() | Initial session exists, before configured windows | | [`on_window_create`]() | A window has been created, before its panes finish | | [`after_window_finished`]() | That window's panes and setup have finished | | `"before_script"` | Plugin callback after session construction | | [`reattach`]() | Reattachment to a session that already exists | The plugin callback named before_script is not the workspace before_script process. Their timing and execution mechanism differ. Plugin methods can change live tmux state; choose a plugin only when its behavior is intended for the workspace. ## Select a workspace builder The default is the built-in classic builder. `workspace_builder` can name a registered entry point in the [`tmuxp.workspace_builders`](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/registry.py) group, a `module:attribute` reference, or a dotted Python path. Custom builders receive expanded configuration and a libtmux server. `workspace_builder_paths` lists trusted directories temporarily added to Python's import path. Tilde and environment variables expand, relative entries resolve against the workspace file, and entries must exist as directories. Tmuxp does not use site.addsitedir for these paths. Adding an import path is not permission to treat arbitrary workspace files as inert data. A builder implements the synchronous build/session interface and cooperates with plugin, progress, before-script, script-output, and build-event callbacks. The configuration alone cannot establish that an arbitrary custom builder honors those callbacks or the classic builder's behavior. ## Pane readiness ```yaml session_name: readiness-example workspace_builder: classic workspace_builder_options: pane_readiness: auto windows: - window_name: main panes: - echo ready ``` Auto, the default, waits for a prompt when the configured session shell is zsh. Always requests the wait for default-shell panes; never skips it. Accepted aliases include true/on/yes/1 for always and false/off/no/0 for never, with strings normalized for case and surrounding whitespace. Unknown values are rejected. Custom pane/window launch commands skip prompt waiting. Readiness checks concern a shell prompt, not the eventual application's health, and do not acknowledge that every later command was consumed. Use [commands](https://libtmux.org/en/py/latest/workspace/configuration/commands/) for explicit delays and Enter behavior. ## Reference source [classic.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py); [registry.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/registry.py); [protocol.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/protocol.py); [options.py](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/options.py); [plugins.md](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/docs/topics/plugins.md). --- # Bootstrap scripts and extensions Source: https://libtmux.org/en/rs/latest/workspace/configuration/hooks/ > Run a checked bootstrap process before workspace commands. Use `before_script` when setup must finish successfully before configured windows are built. The command is split into an executable and arguments; shell operators require an explicit shell. ```yaml title="hooks.yaml" session_name: hooks-example before_script: /bin/sh -c 'printf bootstrap-ready' windows: - window_name: shell panes: [null] ``` The CLI checks the child process status. A failure stops that workspace's build. The result describes retained effects; an earlier input or borrowed session can still exist. A pane's `shell_command` only sends input and does not provide this process-status guarantee. ## Paths and output A relative script path beginning with `.` is resolved from the workspace file. The script's working directory uses the configured session directory when present, otherwise the invocation directory. The script runs before workspace pane commands. Reusing an existing session does not replay its bootstrap. Machine output captures or streams child output through the CLI protocol. Read [output](https://libtmux.org/en/rs/latest/workspace/reference/output/) before parsing bootstrap records. ## Prompt readiness The `pane_readiness` setting under `workspace_builder_options` accepts `auto`, `always` or `never`. It controls a bounded wait before initial pane input. It does not wait for a server process to accept connections. Commands can still be delivered when the prompt wait expires. ## Optional extensions Nonempty `plugins` or `workspace_builder` values select the optional Python extension runtime. Set `TMUX_WORKSPACE_PYTHON` to an interpreter with a compatible tmuxp 1.74 installation. Ordinary documents use the native builder. Extensions run executable code and can make changes outside the CLI's own tracked operations. Inspect reported effects and errors before retrying them. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Bootstrap scripts and extensions Source: https://libtmux.org/en/swift/latest/workspace/configuration/hooks/ > Run a checked bootstrap process before workspace commands. Use `before_script` when setup must finish successfully before configured windows are built. The command is split into an executable and arguments; shell operators require an explicit shell. ```yaml title="hooks.yaml" session_name: hooks-example before_script: /bin/sh -c 'printf bootstrap-ready' windows: - window_name: shell panes: [null] ``` The CLI checks the child process status. A failure stops that workspace's build. The result describes retained effects; an earlier input or borrowed session can still exist. A pane's `shell_command` only sends input and does not provide this process-status guarantee. ## Paths and output A relative script path beginning with `.` is resolved from the workspace file. The script's working directory uses the configured session directory when present, otherwise the invocation directory. The script runs before workspace pane commands. Reusing an existing session does not replay its bootstrap. Machine output captures or streams child output through the CLI protocol. Read [output](https://libtmux.org/en/swift/latest/workspace/reference/output/) before parsing bootstrap records. ## Prompt readiness The `pane_readiness` setting under `workspace_builder_options` accepts `auto`, `always` or `never`. It controls a bounded wait before initial pane input. It does not wait for a server process to accept connections. Commands can still be delivered when the prompt wait expires. ## Optional extensions Plugin and custom-builder execution is unsupported. The CLI refuses those execution fields instead of treating them as successful native work. The optional [inspection shell](https://libtmux.org/en/swift/latest/workspace/cli/shell/) is a separate feature. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Bootstrap scripts and extensions Source: https://libtmux.org/en/ts/latest/workspace/configuration/hooks/ > Run a checked bootstrap process before workspace commands. Use `before_script` when setup must finish successfully before configured windows are built. The command is split into an executable and arguments; shell operators require an explicit shell. ```yaml title="hooks.yaml" session_name: hooks-example before_script: /bin/sh -c 'printf bootstrap-ready' windows: - window_name: shell panes: [null] ``` The CLI checks the child process status. A failure stops that workspace's build. The result describes retained effects; an earlier input or borrowed session can still exist. A pane's `shell_command` only sends input and does not provide this process-status guarantee. ## Paths and output A relative script path beginning with `.` is resolved from the workspace file. The script's working directory uses the configured session directory when present, otherwise the invocation directory. The script runs before workspace pane commands. Reusing an existing session does not replay its bootstrap. Machine output captures or streams child output through the CLI protocol. Read [output](https://libtmux.org/en/ts/latest/workspace/reference/output/) before parsing bootstrap records. ## Prompt readiness The `pane_readiness` setting under `workspace_builder_options` accepts `auto`, `always` or [`never`](). It controls a bounded wait before initial pane input. It does not wait for a server process to accept connections. Commands can still be delivered when the prompt wait expires. ## Optional extensions Nonempty `plugins` or `workspace_builder` values select the optional Python extension runtime. Set `TMUX_WORKSPACE_PYTHON` to an interpreter with a compatible tmuxp 1.74 installation. Ordinary documents use the native builder. Extensions run executable code and can make changes outside the CLI's own tracked operations. Inspect reported effects and errors before retrying them. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Examples Source: https://libtmux.org/en/csharp/latest/workspace/examples/ > Workspace configurations and complete command walkthroughs. These examples use the workspace command. For programs using the builder library, read the [internal API examples](https://libtmux.org/en/csharp/latest/workspace/internals/examples/). - [Workspace gallery](https://libtmux.org/en/csharp/latest/workspace/examples/gallery/): Configurations for pane layouts, commands and environment, with prerequisites. - [Load a workspace](https://libtmux.org/en/csharp/latest/workspace/guides/installation/): Run the installation and loading walkthrough on a private socket. - [Capture and reload](https://libtmux.org/en/csharp/latest/workspace/guides/export-session/): Export a live session and use the result as a workspace. --- # Examples Source: https://libtmux.org/en/cxx/latest/workspace/examples/ > Workspace configurations and complete command walkthroughs. These examples use the workspace command. For programs using the builder library, read the [internal API examples](https://libtmux.org/en/cxx/latest/workspace/internals/examples/). - [Workspace gallery](https://libtmux.org/en/cxx/latest/workspace/examples/gallery/): Configurations for pane layouts, commands and environment, with prerequisites. - [Load a workspace](https://libtmux.org/en/cxx/latest/workspace/guides/installation/): Run the installation and loading walkthrough on a private socket. - [Capture and reload](https://libtmux.org/en/cxx/latest/workspace/guides/export-session/): Export a live session and use the result as a workspace. --- # Examples Source: https://libtmux.org/en/go/latest/workspace/examples/ > Workspace configurations and complete command walkthroughs. These examples use the workspace command. For programs using the builder library, read the [internal API examples](https://libtmux.org/en/go/latest/workspace/internals/examples/). - [Workspace gallery](https://libtmux.org/en/go/latest/workspace/examples/gallery/): Configurations for pane layouts, commands and environment, with prerequisites. - [Load a workspace](https://libtmux.org/en/go/latest/workspace/guides/installation/): Run the installation and loading walkthrough on a private socket. - [Capture and reload](https://libtmux.org/en/go/latest/workspace/guides/export-session/): Export a live session and use the result as a workspace. --- # Examples Source: https://libtmux.org/en/java/latest/workspace/examples/ > Workspace configurations and complete command walkthroughs. These examples use the workspace command. For programs using the builder library, read the [internal API examples](https://libtmux.org/en/java/latest/workspace/internals/examples/). - [Workspace gallery](https://libtmux.org/en/java/latest/workspace/examples/gallery/): Configurations for pane layouts, commands and environment, with prerequisites. - [Load a workspace](https://libtmux.org/en/java/latest/workspace/guides/installation/): Run the installation and loading walkthrough on a private socket. - [Capture and reload](https://libtmux.org/en/java/latest/workspace/guides/export-session/): Export a live session and use the result as a workspace. --- # Examples Source: https://libtmux.org/en/rs/latest/workspace/examples/ > Workspace configurations and complete command walkthroughs. These examples use the workspace command. For programs using the builder library, read the [internal API examples](https://libtmux.org/en/rs/latest/workspace/internals/examples/). - [Workspace gallery](https://libtmux.org/en/rs/latest/workspace/examples/gallery/): Configurations for pane layouts, commands and environment, with prerequisites. - [Load a workspace](https://libtmux.org/en/rs/latest/workspace/guides/installation/): Run the installation and loading walkthrough on a private socket. - [Capture and reload](https://libtmux.org/en/rs/latest/workspace/guides/export-session/): Export a live session and use the result as a workspace. --- # Examples Source: https://libtmux.org/en/swift/latest/workspace/examples/ > Workspace configurations and complete command walkthroughs. These examples use the workspace command. For programs using the builder library, read the [internal API examples](https://libtmux.org/en/swift/latest/workspace/internals/examples/). - [Workspace gallery](https://libtmux.org/en/swift/latest/workspace/examples/gallery/): Configurations for pane layouts, commands and environment, with prerequisites. - [Load a workspace](https://libtmux.org/en/swift/latest/workspace/guides/installation/): Run the installation and loading walkthrough on a private socket. - [Capture and reload](https://libtmux.org/en/swift/latest/workspace/guides/export-session/): Export a live session and use the result as a workspace. --- # Examples Source: https://libtmux.org/en/ts/latest/workspace/examples/ > Workspace configurations and complete command walkthroughs. These examples use the workspace command. For programs using the builder library, read the [internal API examples](https://libtmux.org/en/ts/latest/workspace/internals/examples/). - [Workspace gallery](https://libtmux.org/en/ts/latest/workspace/examples/gallery/): Configurations for pane layouts, commands and environment, with prerequisites. - [Load a workspace](https://libtmux.org/en/ts/latest/workspace/guides/installation/): Run the installation and loading walkthrough on a private socket. - [Capture and reload](https://libtmux.org/en/ts/latest/workspace/guides/export-session/): Export a live session and use the result as a workspace. --- # Examples Source: https://libtmux.org/en/lua/latest/examples/ > Examples for libtmux. Run complete programs with their documented setup and cleanup. - [Capture pane output](https://libtmux.org/en/lua/latest/examples/capture-pane-output/): Send a command, wait for its output, and clean up the private server. --- # Examples Source: https://libtmux.org/en/ruby/latest/examples/ > Examples for libtmux. Run complete programs with their documented setup and cleanup. - [Capture pane output](https://libtmux.org/en/ruby/latest/examples/capture-pane-output/): Send a command, wait for its output, and clean up the private server. - [Recipes](https://libtmux.org/en/ruby/latest/examples/recipes/): Run programs for queries, linked windows, capture, and cancellation. --- # Examples Source: https://libtmux.org/en/tmux/examples/ > Programs for sending input, capturing output, and building workspaces. Use these programs to send input, capture output, and build a workspace. Each example page includes its source and test coverage. Check those details before adapting an excerpt into a standalone program. ## Source and verification Port repositories use the following checks for their source examples. This site reads or copies those examples; a successful site build alone does not execute them: ### Python The test configuration includes [`README.md`]() and [`src/libtmux/`]() in its doctest collection. The `>>>` examples run against isolated tmux sessions. ### TypeScript [`scripts/check-doc-runnable.ts`]() checks that a block tagged with its example source matches that file line for line. The integration suite executes the source program. ### Go `go generate ./tmux` refreshes documented regions from matching source regions under [`examples/`](). CI checks that those generated excerpts are current. ### Rust The library includes its README as a crate doc comment. `cargo test --doc` compiles and runs its executable Rust code blocks. ### Java `./gradlew :docs-tests:test` compiles executable Java blocks in READMEs and guides against the library artifacts, then runs them against tmux through `libtmux-junit5`. ### C# `sync_snippets.py --check` checks excerpts from tested `[Example]` methods. `ReadmeExampleTests` also compiles and executes blocks marked `csharp run`. ### C++ [`tools/docs/check_readme.py`]() checks that README examples match their source regions in [`examples/05-readme.cpp`](). CTest builds and runs that program. ### Swift [`Scripts/check_examples.py`]() checks that README examples match sources under [`Examples/Sources/`](). `swift test --package-path Examples` compiles those examples through the public products. See [Testing with libtmux](https://libtmux.org/en/tmux/guides/testing-with-libtmux/) for the fixture each of those test suites runs against, and each example page for the exact file a given snippet was quoted from. - [Attach and send keys](https://libtmux.org/en/tmux/examples/attach-and-send-keys/): Find a session, send a command, and read its output. - [Capture pane output](https://libtmux.org/en/tmux/examples/capture-pane-output/): Read a pane's screen and wait for output to appear. - [Build a workspace from a file](https://libtmux.org/en/tmux/examples/workspace-from-file/): Create a session, windows, and panes from configuration. --- # Examples Source: https://libtmux.org/en/fsharp/latest/examples/ > Tested F# examples against an isolated tmux server. Start with [Capture pane output](https://libtmux.org/en/fsharp/latest/examples/capture-pane-output/) for a standalone program with imports, a project file, and private-server cleanup. ## Query, send and wait This complete program creates an isolated tmux server, filters its live sessions, sends a command and waits for its output, then reads another command's exit status. The owned server closes when the task completes. Follow the [package quickstart](https://libtmux.org/en/fsharp/latest/guides/quickstart/) to create an F# project and install LibTmux.FSharp, then use this as Program.fs. ```fsharp file="examples/LibTmux.FSharp.Quickstart/Program.fs" // fsharp-snippet: Quickstart open System open System.Threading open LibTmux open LibTmux.FSharp let runAsync () = task { use deadline = new CancellationTokenSource(TimeSpan.FromSeconds 30.) let token = deadline.Token let options = ServerConnectionOptions( SocketName = "fsharp-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = (Environment.GetEnvironmentVariable "LIBTMUX_TMUX" |> Option.ofObj |> Option.defaultValue "tmux") ) use! owned = LibTmux.Server.CreateOwnedAsync(options, token) for name in [ "build"; "web"; "worker" ] do let! _ = owned.Value.CreateSessionAsync(NewSessionRequest(Name = name, Command = "/bin/sh"), token) () let! server = LibTmux.Server.ConnectAsync(options, token) // List and filter: tmux narrows the listing, then every row is rechecked. // atMostOne is None when nothing matches and raises when several do. let! build = server |> Server.sessions |> Query.where (SessionFields.name |> Filter.eq "build") |> Query.atMostOne token let! others = server |> Server.sessions |> Query.where (SessionFields.name |> Filter.ne "build") |> Query.list token printfn "other sessions: %s" (String.Join(", ", [ for session in others -> session.Name ])) match build with | None -> printfn "no build session" | Some session -> let! panes = session |> Session.panes |> Query.list token let pane = panes[0] // Type a command and wait for what it prints, not for its echo. let! started = pane |> Pane.sendAndWait token (TimeSpan.FromSeconds 10.) "echo build started" "build started" // Run a command to its exit status and read what it printed. let! result = pane |> Pane.run token (TimeSpan.FromSeconds 10.) "printf 'ok\\n'; exit 3" printfn "wait found: %b" started.Found printfn "run: exit %d, output %A" result.ExitStatus.Value (List.ofSeq result.Output) } runAsync().GetAwaiter().GetResult() // endfsharp-snippet ``` --- # Examples Source: https://libtmux.org/en/kotlin/latest/examples/ > Tested Kotlin examples against an isolated tmux server. Start with [Capture pane output](https://libtmux.org/en/kotlin/latest/examples/capture-pane-output/) for a standalone program with imports, Gradle files, and private-server cleanup. ## Read a Flow Read pushed pane output as a coroutine Flow and cancel a pending wait. The complete program belongs to the Java repository's examples module; that module also supplies `WatchPaneOutput`, and its test starts an isolated tmux server before calling this program's [`main`](). Run `./gradlew :examples:test` from that repository. ```kotlin file="examples/src/main/kotlin/io/github/libtmux/examples/WatchWithFlow.kt" package io.github.libtmux.examples import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.control.Delivery import io.github.libtmux.kotlin.Server import io.github.libtmux.kotlin.await import io.github.libtmux.kotlin.send import io.github.libtmux.kotlin.sessions import io.github.libtmux.kotlin.withControl import io.github.libtmux.kotlin.withServer import java.nio.file.Path import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeoutOrNull /** * Reads a pane's output as a `Flow`, then gives up on a wait by cancelling it. * * ``` * java -cp ... io.github.libtmux.examples.WatchWithFlowKt /tmp/libtmux-java-dev/demo/s * ``` */ fun main(args: Array) { val socket = Path.of(args.getOrElse(0) { "/tmp/libtmux-java-dev/demo/s" }) runBlocking { println(watchWithFlow(socket, 10.seconds)) } } /** * Collects output until the line `echo` printed arrives, then starts a channel wait that nothing * will signal and cancels it after a moment. Cancelling ends the coroutine at once and is not a * timeout; the tmux client behind the wait is stopped with it. * * @return one line for each: whether the echo arrived, and whether the wait was cancelled */ suspend fun watchWithFlow(socket: Path, deadline: Duration): String { val config = ServerConfig.builder().endpoint(ServerEndpoint.socketPath(socket)).build() return withServer(config) { server: Server -> val session = server.sessions().first() withControl(server, session) { control -> // control.output(...) is a cold Flow: the subscription it opens on first collection // closes when collection ends, is cancelled, or throws — nothing to close by hand. The // command goes in onSubscribed: sent before collecting, its output could arrive before // there was a subscription to hold it. val seen = StringBuilder() val echoed = withTimeoutOrNull(deadline) { control.output(capacity = 32) { control.send("send-keys", "-t", session.name, "echo flowed", "Enter") }.map { Delivery.kept(it).data }.first { chunk -> seen.append(chunk) WatchPaneOutput.printedLine(seen.toString(), "flowed") } } != null val cancelled = withTimeoutOrNull(200.milliseconds) { server.channel("never-signalled").await(30.seconds) } == null "echoed=$echoed\ncancelled=$cancelled" } } } ``` --- # Examples Source: https://libtmux.org/en/scala/latest/examples/ > Tested Scala examples against an isolated tmux server. Start with [Capture pane output](https://libtmux.org/en/scala/latest/examples/capture-pane-output/) for a standalone program with imports, Gradle files, and private-server cleanup. For an existing server, use [Attaching to tmux](https://libtmux.org/en/scala/latest/guides/attaching-to-tmux/). That program includes the imports, build files, and launcher. It reads a session without stopping the server that owns it. --- # Attach and send keys Source: https://libtmux.org/en/tmux/examples/attach-and-send-keys/ > Get a session handle, send a command to a pane, and capture output. Get a session handle, send a command to a pane, and capture output. These examples use libtmux from your program; to attach your terminal interactively, see [Attaching to tmux](https://libtmux.org/en/tmux/guides/attaching-to-tmux/). The examples include setup, error handling, and cleanup. [Source and verification](https://libtmux.org/en/tmux/examples/attach-and-send-keys/#where-this-comes-from) identifies their files and checks. ```python >>> import libtmux >>> server = libtmux.Server() >>> session = server.new_session(session_name='demo') Session(...) >>> window = session.active_window >>> pane = window.split(shell='sh') >>> pane.capture_pane() ['$'] >>> pane.send_keys('echo "Hello world"', enter=True) >>> pane.capture_pane() ['$ echo "Hello world"', 'Hello world', '$'] ``` ```typescript file="examples/quickstart/quickstart.ts" import { Server, TmuxCommandError, type ServerSnapshot } from "libtmux"; /** * A runnable tour of the API, driven by the tests so it cannot rot. * * Every step here appears in README.md. */ export async function quickstart(server: Server): Promise { // Nothing is read until you ask. `snapshot()` is the only step that talks to // tmux; everything reachable from it resolves locally. const session = await server.newSession({ name: "quickstart" }); const editor = await session.newWindow({ name: "editor" }); await editor.split(); const snapshot = await server.snapshot(); // Declarative filtering, serializable and stable on the wire. const found = snapshot.windows.where({ name: "editor" }).one(); // Relations are plain properties: no await, no tmux command. const paneCount = found.panes.length; if (paneCount !== 2) throw new Error(`expected two panes, saw ${String(paneCount)}`); // A criterion is spelled like the handle accessor it filters. if (snapshot.panes.count({ currentCommand: { contains: "" } }) === 0) { throw new Error("expected panes to report a current command"); } const first = found.panes.at(0); if (first === undefined) throw new Error("expected a pane"); await first.sendKeys("echo hello-from-libtmux", { literal: true }); // Failures carry their parts rather than a formatted sentence. try { await server.setOption("not-a-real-option", "1"); } catch (error) { if (!(error instanceof TmuxCommandError)) throw error; if (error.args[0] !== "set-option") throw error; } return snapshot; } ``` ```rust file="crates/libtmux/examples/scratch.rs" //! Build a throwaway session, use it, and leave nothing behind. //! //! ```console //! $ cargo run --example scratch //! ``` use std::time::Duration; use libtmux::test::unique_name; use libtmux::{NewWindowOptions, PaneWait, Server, SplitDirection, SplitOptions}; #[tokio::main] async fn main() -> Result<(), Box> { // An example must not build sessions on whatever server the reader // happens to be using, so this one gets a socket of its own. More than one // libtmux runs on a developer's machine, so it goes in a directory this // one owns rather than straight into the temporary directory. let root = std::path::Path::new("/tmp/libtmux-rs-dev"); std::fs::create_dir_all(root)?; let socket = root.join(format!("{}.sock", unique_name("libtmux-scratch"))); let server = Server::builder().socket_path(&socket).build()?; // The scope kills the session whether the body succeeds or fails, so a // failure partway through does not leave a session behind. println!("server on {}", socket.display()); let output = server .with_session(unique_name("scratch").as_str(), async |session| { println!(" session {} created", session.id()); let window = session .new_window(NewWindowOptions::new("work").command("sh")) .await?; println!(" window {} running sh", window.id()); window .split(SplitOptions::new(SplitDirection::Below).command("sh")) .await?; println!(" split it: {} panes", window.panes().await?.len()); // A window always has an active pane, but saying so with a panic // would be a worse example than handling it. let Some(pane) = window.active_pane().await? else { return Ok(0); }; println!(" typing into {}", pane.id()); pane.send_line("printf 'hello from tmux\\n'").await?; // tmux runs the shell asynchronously, so wait for the output // rather than sleeping and hoping. The outcome is checked because // a wait that reached its deadline still returns successfully. match pane.wait_for_text("hello", Duration::from_secs(5)).await? { PaneWait::Arrived => println!(" the pane printed it"), other => println!(" gave up: {other:?}"), } // region: capture let lines = pane.capture().await?; for line in lines.iter().filter(|line| !line.as_bytes().is_empty()) { println!(" | {}", line.to_string_lossy()); } // endregion Ok::<_, Box>(lines.len()) }) .await?; println!("captured {output} lines, then the scope killed the session"); // The lenient form is the one that answers this question. The scope killed // the only session, so tmux exited with it, and the loud form reports that // as the failure it is rather than as the empty listing this is asking for. assert!( server.sessions().await.unwrap_or_default().is_empty(), "the scope cleaned up", ); println!( "sessions left behind: {}", server.sessions().await.unwrap_or_default().len() ); server.shutdown().await?; // tmux does not unlink its socket when the server exits, so whatever named // one owns removing it. Leaving it behind is invisible until /tmp fills up. std::fs::remove_file(&socket)?; Ok(()) } ``` ```go file="examples/quickstart/main.go" // Command quickstart demonstrates a complete session, window, and pane lifecycle. package main import ( "bufio" "context" "errors" "fmt" "log" "time" "github.com/libtmux/libtmux-go/tmux" ) func main() { if err := start(); err != nil { log.Fatal(err) } } // start owns cleanup because log.Fatal skips deferred calls in main. func start() error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() server, err := tmux.NewServer(tmux.ServerOptions{}) if err != nil { return fmt.Errorf("configure tmux server: %w", err) } return run(ctx, server) } // run accepts injected server state so tests can isolate the example. func run(ctx context.Context, server tmux.Server) (err error) { // docs:quickstart given:ctx context.Context; server tmux.Server session, err := server.NewSession(ctx, tmux.NewSessionRequest{ Name: "libtmux-go-quickstart", WindowName: "start", }) if err != nil { return fmt.Errorf("create session: %w", err) } defer func() { cleanupCtx, cleanupCancel := context.WithTimeout(context.WithoutCancel(ctx), time.Second) defer cleanupCancel() err = errors.Join(err, session.Kill(cleanupCtx)) }() window, err := session.NewWindow(ctx, tmux.NewWindowRequest{Name: new("work")}) if err != nil { return fmt.Errorf("create window: %w", err) } pane, err := window.SplitPane(ctx, tmux.SplitPaneRequest{ Direction: tmux.PaneDirectionRight, Command: "sh", }) if err != nil { return fmt.Errorf("split window: %w", err) } output, err := pane.OpenObservation(ctx) if err != nil { return fmt.Errorf("watch pane: %w", err) } defer func() { err = errors.Join(err, output.Close()) }() if _, err := fmt.Fprintln(pane.Writer(ctx), "printf 'libtmux ready\\n'"); err != nil { return fmt.Errorf("send command: %w", err) } // docs:end scanner := bufio.NewScanner(output.Reader(ctx)) for scanner.Scan() { if scanner.Text() == "libtmux ready" { fmt.Println("libtmux ready") return nil } } return fmt.Errorf("read pane: %w", scanner.Err()) } ``` ```java file="examples/src/main/java/io/github/libtmux/examples/BuildAWorkspace.java" package io.github.libtmux.examples; import io.github.libtmux.Layout; import io.github.libtmux.Pane; import io.github.libtmux.Server; import io.github.libtmux.ServerConfig; import io.github.libtmux.ServerEndpoint; import io.github.libtmux.Session; import io.github.libtmux.Window; import io.github.libtmux.exception.ServerUnavailableException; import java.nio.file.Path; import java.util.Optional; /** * Lays out a session the way you would set one up by hand before starting work. * *
{@code
 * java BuildAWorkspace.java /tmp/libtmux-java-dev/demo/s
 * }
*/ public final class BuildAWorkspace { private BuildAWorkspace() {} public static void main(String[] args) { System.out.println(run(Path.of(args.length > 0 ? args[0] : "/tmp/libtmux-java-dev/demo/s"))); } /** Separated from {@code main} so the suite can run exactly what a reader runs. */ public static String run(Path socket) { ServerConfig config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(socket)) .configFile(Path.of("/dev/null")) .build(); // Closing a server closes this client. The tmux server, and the session, outlive the program // — which is the whole point of tmux and the reason nothing here kills it. try (Server server = Server.open(config)) { // One read decides and answers. An absent daemon means the name cannot be taken, so // that specific failure is the other way this resolves to "not found". Optional existing; try { existing = server.session("work"); } catch (ServerUnavailableException absent) { existing = Optional.empty(); } Session session = existing.orElseGet(() -> server.newSession("work")); Window editor = session.newWindow(window -> window.named("editor").detached()); Pane shell = editor.split(split -> split.toRight()); shell.sendLine("git status --short"); editor.selectLayout(Layout.MAIN_VERTICAL); return "session " + session.name() + " has " + session.refresh().windows().size() + " windows"; } } } ``` ```csharp file="examples/LibTmux.Examples/Snippets/OneShot.cs" using System.Runtime.Versioning; namespace LibTmux.Examples.Snippets; /// The default mode: one command, one client, one materialized object. [UnsupportedOSPlatform("windows")] public static class OneShot { /// Connects, builds a hierarchy, and types into the pane it made. [Example("Connect, build a session and window, and type into a pane")] public static async Task ConnectAndBuild() { #region ConnectAndBuild // Requires a tmux server already listening on this socket: // ConnectAsync() discovers one, it never starts one. With nothing // running yet, call Server.CreateOwnedAsync() instead. Server server = await Server.ConnectAsync(); Session session = await server.CreateSessionAsync(new NewSessionRequest { Name = "build" }); Window window = await session.CreateWindowAsync(new NewWindowRequest { Name = "tests" }); Pane pane = (await window.GetPanesAsync())[0]; await pane.SendTextAsync("dotnet test"); #endregion } /// Creates a window and prints what tmux answered about it. [Example("One command, one materialized window")] public static async Task CreateWindow(Session session, CancellationToken ct) { #region CreateWindow Window window = await session.CreateWindowAsync(new NewWindowRequest { Name = "build" }, ct); Console.WriteLine($"{window.Id} {window.Index}:{window.Name}"); #endregion } } ``` ```cpp // No tmux failure is thrown. Every call answers with a value that is either // the result or the reason there isn't one. const auto sessions = server.sessions(); if (!sessions.has_value()) { std::fprintf(stderr, "%s\n", sessions.error().diagnostic.c_str()); return 1; } for (const libtmux::Session& session : *sessions) { std::printf("%s has %lld window(s)\n", std::string{session.name()}.c_str(), session.window_count()); } const libtmux::Session& session = sessions->at(0); // Build an arrangement without composing a single tmux argument. const auto editor = session.new_window({.name = "editor"}); if (!editor.has_value()) { std::fprintf(stderr, "%s\n", editor.error().diagnostic.c_str()); return 1; } const auto logs = editor->split({.horizontal = true, .percentage = 30}); if (!logs.has_value()) { std::fprintf(stderr, "%s\n", logs.error().diagnostic.c_str()); return 1; } (void)logs->send_text("journalctl -f"); (void)logs->send_key("Enter"); ``` ```swift file="Examples/Sources/ExampleCode/Changing.swift" // The examples in the README's "Change what is there" section. import LibTmux public func buildASessionByHand(_ server: Server) async throws -> Pane { let session = try await server.newSession(named: "work", windowName: "editor") _ = try await server.setOption("@purpose", to: "development", scope: .session(session)) let logs = try await server.newWindow(in: session, named: "logs").window let pane = try await server.splitWindow(logs, direction: .right) try await server.run("tail -f /tmp/build.log", in: pane) return pane } public func readBackWhatAPanePrinted(_ server: Server, _ pane: Pane) async throws -> [String] { let lines = try await server.capture(pane) print(lines.suffix(5).joined(separator: "\n")) return lines } public func spendOneProcessOnAllOfIt(_ server: Server) async throws { var plan = TmuxCommandList() for name in ["edit", "test", "logs"] { plan = plan.then("new-window", ["-d", "-n", name]) } _ = try await server.run(plan) } ``` ## Finding an existing session instead For a script that runs repeatedly, look up a session before creating it. [Attaching to tmux](https://libtmux.org/en/tmux/guides/attaching-to-tmux/#finding-a-session-instead-of-always-creating-one) shows that pattern, and [Filtering and querying, in practice](https://libtmux.org/en/tmux/guides/querying-and-filtering/) covers absent and ambiguous matches. ## Where this comes from ### Python **Source:** [`src/libtmux/server.py`](), [`session.py`](), [`pane.py`]() docstrings **In this page:** hand-quoted, composed from three separate docstrings **Checked by:** `pytest` runs every `>>>` doctest (`testpaths` includes `src/libtmux`) against a real, isolated tmux session on every test run ### TypeScript **Source:** [`examples/quickstart/quickstart.ts`]() **In this page:** read whole from the file **Checked by:** run against real tmux by `bun test examples`; its first half is also mirrored into README.md under a `` marker, checked line-for-line by [`scripts/check-doc-runnable.ts`]() ### Rust **Source:** [`crates/libtmux/examples/scratch.rs`]() **In this page:** read whole from the file **Checked by:** run to completion against a throwaway tmux by [`scripts/run-examples.sh`]() (`just examples`), which CI runs and which also asserts the example leaves no session behind ### Go **Source:** [`examples/quickstart/main.go`]() **In this page:** read whole from the file **Checked by:** the whole file runs against a real tmux server as `TestQuickstart`; the `docs:quickstart` region inside it is additionally mirrored into README.md by `go generate ./tmux`, and CI fails if the two drift ### Java **Source:** [`examples/src/main/java/io/github/libtmux/examples/BuildAWorkspace.java`]() **In this page:** read whole from the file **Checked by:** run against real tmux by the `examples` module's own `ExamplesRunTest` ### C# **Source:** [`examples/LibTmux.Examples/Snippets/OneShot.cs`]() **In this page:** read whole from the file **Checked by:** its `ConnectAndBuild` region is mirrored into README.md and checked by `sync_snippets.py --check`; the mirrored `csharp run` block is additionally compiled and run by `ReadmeExampleTests` ### C++ **Source:** [`examples/05-readme.cpp`](), the [`connect`]() and [`build`]() regions **In this page:** Copied excerpts from the [`connect`]() and [`build`]() regions. **Checked by:** quoted verbatim into README.md, checked for drift by [`tools/docs/check_readme.py`](), and the whole file is built and run by CTest ### Swift **Source:** [`Examples/Sources/ExampleCode/Changing.swift`]() **In this page:** read whole from the file **Checked by:** matched against the README's "Change what is there" section by [`Scripts/check_examples.py`](); compiled and run through the package's public products by `swift test --package-path Examples` ### Source inclusion A `file="..."` fence reads the named source during the site build. Hand-quoted excerpts are copies; their source files and regions are listed above. --- # C# MCP examples Source: https://libtmux.org/en/csharp/latest/mcp/examples/ > Run complete C# clients that discover sessions and execute a command in an owned tmux server. Each example includes its project file, complete program, pinned tool installation, run command, and expected output. The programs create private tmux servers and attempt cleanup after successful and failed requests. ## List sessions [List sessions through MCP](https://libtmux.org/en/csharp/latest/mcp/examples/inspect-sessions/) uses an inspection-only connection. It checks the advertised tools, reads `tmux://capabilities`, and verifies the session name and window count in structured content. ## Run a command [Run a command through MCP](https://libtmux.org/en/csharp/latest/mcp/examples/run-command/) discovers the pane ID, submits a bounded shell command, and checks its exit status separately from the MCP result. It also checks whether the captured output is complete. For an existing server, follow the [connection guide](https://libtmux.org/en/csharp/latest/mcp/guides/connect-client/) and keep its ownership separate from the private servers in these examples. See [Waits and captured output](https://libtmux.org/en/csharp/latest/mcp/topics/waits-and-output/) before adding retries or cancellation to a client that controls long-running processes. - [List sessions through MCP](https://libtmux.org/en/csharp/latest/mcp/examples/inspect-sessions/): Verify tool discovery, read the capability resource, and check structured session metadata. - [Run a command through MCP](https://libtmux.org/en/csharp/latest/mcp/examples/run-command/): Discover a pane, check shell completion and output, and clean up the owned server. --- # Capture pane output Source: https://libtmux.org/en/tmux/examples/capture-pane-output/ > Capture a tmux pane's screen and wait for a complete output line. `capture-pane -p` prints a pane's visible screen. Sending a command and reading its result are separate operations: the pane's shell may still be processing input when the first capture runs. ## Read what's on screen This complete shell program starts a private tmux server, sends a command, and captures until the expected line appears. It removes the server on exit and fails after 100 unsuccessful checks with 50-millisecond pauses. Save it as `capture.sh` and run `sh capture.sh`, or paste the whole block into a POSIX shell. It requires tmux 3.2 or newer and `sleep` with fractional seconds. ```sh title="capture.sh" ( set -eu directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-capture.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - EXIT if [ -S "$socket" ] && ! tmux -S "$socket" kill-server; then printf '%s\n' "Cannot stop tmux; kept $directory." >&2 exit 1 fi rm -rf "$directory" || status=$? exit "$status" } trap cleanup EXIT trap 'exit 1' HUP INT TERM tmux -S "$socket" -f /dev/null new-session -d -s capture \ -e ENV=/dev/null 'sh' tmux -S "$socket" send-keys -t capture:0.0 -l \ "printf '\\nlibtmux capture ready\\n'" tmux -S "$socket" send-keys -t capture:0.0 Enter attempt=0 while [ "$attempt" -lt 100 ]; do screen=$(tmux -S "$socket" capture-pane -p -t capture:0.0) if printf '%s\n' "$screen" | grep -Fqx 'libtmux capture ready'; then printf '%s\n' "$screen" exit 0 fi attempt=$((attempt + 1)) sleep 0.05 done printf '%s\n' 'Timed out waiting for captured output.' >&2 exit 1 ) ``` Cleanup also runs if startup fails after creating the server. If tmux cannot be stopped, the script reports the error and keeps its socket directory so you can inspect or stop that server. ## Wait for output or completion The leading newline puts the output on a fresh screen row even if the shell's first prompt arrives late. `grep -Fx` matches the complete line, so the echoed command cannot satisfy the check. The short pause limits polling; the captured output determines when the program finishes. Capture reads screen state, so it can miss output that has scrolled away. [Capturing output](https://libtmux.org/en/tmux/guides/capturing-output/) covers history and streaming; [Sending keys](https://libtmux.org/en/tmux/guides/sending-keys/) explains input and completion. ## Use a language library Complete programs with imports, setup, and cleanup: [Python](https://libtmux.org/en/py/latest/examples/capture-pane-output/) · [TypeScript](https://libtmux.org/en/ts/latest/examples/capture-pane-output/) · [Go](https://libtmux.org/en/go/latest/examples/capture-pane-output/) · [Rust](https://libtmux.org/en/rs/latest/examples/capture-pane-output/) · [Java](https://libtmux.org/en/java/latest/examples/capture-pane-output/) · [Kotlin](https://libtmux.org/en/kotlin/latest/examples/capture-pane-output/) · [Scala](https://libtmux.org/en/scala/latest/examples/capture-pane-output/) · [C#](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/) · [F#](https://libtmux.org/en/fsharp/latest/examples/capture-pane-output/) · [C++](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/) · [Swift](https://libtmux.org/en/swift/latest/examples/capture-pane-output/) · [Ruby](https://libtmux.org/en/ruby/latest/examples/capture-pane-output/) · [Lua](https://libtmux.org/en/lua/latest/examples/capture-pane-output/) The [tmux manual source](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1) describes `capture-pane`, `send-keys`, and `kill-server`. --- # Capture pane output Source: https://libtmux.org/en/csharp/latest/examples/capture-pane-output/ > Run a complete program that captures a pane and waits for a complete output line. A pane runs asynchronously: sending a command does not mean its output is already on screen. Capture repeatedly until the expected line appears, with a deadline so a failed command cannot leave the program waiting forever. This complete program creates a private tmux server, captures its output, and cleans up. Follow the [setup and run instructions](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/#setup-and-run) below. You need tmux and a Unix environment; no existing tmux session is required. ## Read what's on screen The program sends `printf` with a leading newline, then waits for the complete line `libtmux capture ready`. The newline keeps a late shell prompt off that line. Matching the whole line avoids mistaking the echoed command for its output. ```csharp title="Program.cs" using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using LibTmux; if (OperatingSystem.IsWindows()) throw new PlatformNotSupportedException("Run this example on Linux or macOS"); string directory = Path.Combine( "/tmp/libtmux-dotnet-dev", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(directory); try { using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); CancellationToken token = timeout.Token; await using OwnedServerScope owned = await Server.CreateOwnedAsync( new ServerConnectionOptions { SocketPath = Path.Combine(directory, "tmux.sock"), ConfigurationFile = "/dev/null", ChildEnvironment = new Dictionary { ["TMUX"] = null, ["TMUX_PANE"] = null, ["ENV"] = null, ["BASH_ENV"] = null, }, }, token); Session session = await owned.Value.CreateSessionAsync( new NewSessionRequest { Name = "capture", Command = "/bin/sh" }, token); Pane pane = (await session.GetPanesAsync(token))[0]; await pane.SendTextAsync( "printf '\\nlibtmux capture ready\\n'", cancellationToken: token); var elapsed = Stopwatch.StartNew(); bool captured = false; while (elapsed.Elapsed < TimeSpan.FromSeconds(5)) { var lines = await pane.CaptureAsync(cancellationToken: token); if (lines.Contains("libtmux capture ready")) { Console.WriteLine("libtmux capture ready"); captured = true; break; } await Task.Delay(25, token); } if (!captured) throw new TimeoutException("Output did not arrive within five seconds"); } finally { Directory.Delete(directory, recursive: true); } ``` ## Wait for output or completion The program above checks the captured screen for up to five seconds. The short pause between checks limits polling; the observed output determines when the loop finishes. A tmux capture is a view of the screen and scrollback, so it can miss output that has already scrolled away. Use a stream or a completion signal for long-running commands when that distinction matters. [Capturing output](https://libtmux.org/en/csharp/latest/guides/capturing-output/) covers capture options, while [Sending keys](https://libtmux.org/en/csharp/latest/guides/sending-keys/#the-race-you-cant-see-from-the-call-site) explains why sending and waiting are separate operations. ## Setup and run Use an empty directory. The commands pin the library revision used to verify the program. Save the program and project file using the displayed names. Use the .NET 10 SDK. The project disables implicit imports, so every required import appears in the program. ```xml title="Capture.csproj" Exe net10.0 disable enable false ``` ```console $ git clone https://github.com/libtmux/libtmux-dotnet libtmux-source && git -C libtmux-source checkout 320dc64f4b8b7815842471327a5e6b84a1499bf8 && dotnet build Capture.csproj --maxcpucount:1 && dotnet run --project Capture.csproj --no-build ``` ## Where this comes from This complete program was run against the library revision pinned above. The displayed code is checked against the bytes from that run. --- # Capture pane output Source: https://libtmux.org/en/cxx/latest/examples/capture-pane-output/ > Run a complete program that captures a pane and waits for a complete output line. A pane runs asynchronously: sending a command does not mean its output is already on screen. Capture repeatedly until the expected line appears, with a deadline so a failed command cannot leave the program waiting forever. This complete program creates a private tmux server, captures its output, and cleans up. Follow the [setup and run instructions](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/#setup-and-run) below. You need tmux and a Unix environment; no existing tmux session is required. [`ScopedTmuxServer`]() is temporary example scaffolding. In an application, use a [`Server`](https://libtmux.org/en/cxx/latest/reference/libtmux-server/) connected to the tmux server you manage. Future versions of this example will use that regular server object directly. ## Read what's on screen The program sends `printf` with a leading newline, then waits for the complete line `libtmux capture ready`. The newline keeps a late shell prompt off that line. Matching the whole line avoids mistaking the echoed command for its output. ```cpp title="capture.cpp" #include #include #include #include #include #include #include #include #include int main() { auto cleanup = std::make_shared(); bool captured = false; try { // This public fixture owns a private socket, uses /dev/null as its // tmux configuration, and stops its server when the scope ends. auto owned = libtmux::test::ScopedTmuxServer::start({ .session_name = "capture", .socket_namespace = libtmux::test::SocketNamespace::consumer("capture"), .teardown_report = cleanup, }); if (!owned) throw std::runtime_error(owned.error()); auto server = libtmux::Server::at_socket_path(owned->socket_path()); if (!server) throw std::runtime_error(server.error().diagnostic); auto panes = server->panes(); if (!panes) throw std::runtime_error(panes.error().diagnostic); if (panes->empty()) throw std::runtime_error("The session has no pane"); const auto& pane = panes->front(); auto sent = pane.send_line("printf '\\nlibtmux capture ready\\n'"); if (!sent) throw std::runtime_error(sent.error().diagnostic); const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds{5}; while (std::chrono::steady_clock::now() < deadline && !captured) { auto text = pane.capture(); if (!text) throw std::runtime_error(text.error().diagnostic); std::istringstream lines{*text}; for (std::string line; std::getline(lines, line);) { if (line == "libtmux capture ready") { std::cout << line << '\n'; captured = true; break; } } if (!captured) std::this_thread::sleep_for(std::chrono::milliseconds{25}); } if (!captured) { throw std::runtime_error("Output did not arrive within five seconds"); } } catch (const std::exception& error) { std::cerr << error.what() << '\n'; captured = false; } for (const auto& message : cleanup->messages) { if (message != "server teardown complete") { std::cerr << message << '\n'; captured = false; } } return captured ? 0 : 1; } ``` ## Wait for output or completion The program above checks the captured screen for up to five seconds. The short pause between checks limits polling; the observed output determines when the loop finishes. A tmux capture is a view of the screen and scrollback, so it can miss output that has already scrolled away. Use a stream or a completion signal for long-running commands when that distinction matters. [Capturing output](https://libtmux.org/en/cxx/latest/guides/capturing-output/) covers capture options, while [Sending keys](https://libtmux.org/en/cxx/latest/guides/sending-keys/#the-race-you-cant-see-from-the-call-site) explains why sending and waiting are separate operations. ## Setup and run Use an empty directory. The commands pin the library revision used to verify the program. No separate header is needed for this single-file executable. Save the program and build file using the displayed names. Use CMake 3.25 or newer, Ninja, and Clang 18 with libc++ 18 on Linux. The public testing library supplies the private server's lifetime management; it is linked explicitly below. ```cmake title="CMakeLists.txt" cmake_minimum_required(VERSION 3.25) project(capture_example LANGUAGES CXX) set(LIBTMUX_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(LIBTMUX_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) set(LIBTMUX_BUILD_TESTING_LIBRARY ON CACHE BOOL "" FORCE) add_subdirectory(libtmux-source) add_executable(capture capture.cpp) target_compile_features(capture PRIVATE cxx_std_23) target_link_libraries(capture PRIVATE libtmux::libtmux libtmux::testing) ``` ```console $ git clone https://github.com/libtmux/libtmux-cxx libtmux-source && git -C libtmux-source checkout 393d4b0ad666f18a6581f1eb281741a75a7503f0 && cmake -S . -B build -G Ninja \ -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_CXX_FLAGS=-stdlib=libc++ \ -DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++ && cmake --build build --target capture --parallel 2 && ./build/capture ``` ## Where this comes from This complete program was run against the library revision pinned above. The displayed code is checked against the bytes from that run. --- # Capture pane output Source: https://libtmux.org/en/fsharp/latest/examples/capture-pane-output/ > Run a complete F# program that captures output on an isolated tmux server. This complete F# program starts a private tmux server, sends a command, and captures the line it prints. It includes imports, setup, and cleanup. You need tmux and a Unix environment; no existing session is required. ## Read what's on screen The leading newline puts the output on a fresh row. Matching the whole line avoids mistaking the echoed command for its output. ```fsharp title="Program.fs" open System open System.Collections.Generic open System.Diagnostics open System.IO open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let capture () = task { let directory = Path.Combine("/tmp/libtmux-dotnet-dev", Guid.NewGuid().ToString("N")) Directory.CreateDirectory(directory) |> ignore let errors = ResizeArray() let mutable owned: OwnedServerScope option = None let mutable stopped = false try use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10.0)) let token = timeout.Token let environment = Dictionary() for name in [ "TMUX"; "TMUX_PANE"; "ENV"; "BASH_ENV" ] do environment[name] <- null let! scope = LibTmux.Server.CreateOwnedAsync( ServerConnectionOptions( SocketPath = Path.Combine(directory, "tmux.sock"), ConfigurationFile = "/dev/null", ChildEnvironment = environment), token) owned <- Some scope let! session = scope.Value.CreateSessionAsync( NewSessionRequest(Name = "capture", Command = "/bin/sh"), token) let! panes = session.GetPanesAsync(token) let pane = panes[0] do! pane |> Pane.sendKeys token (SendKeysRequest( Text = "printf '\\nlibtmux capture ready\\n'", Literal = true, Enter = true)) let elapsed = Stopwatch.StartNew() let mutable captured = false while not captured && elapsed.Elapsed < TimeSpan.FromSeconds(5.0) do let! lines = pane |> Pane.capture token (CapturePaneRequest()) captured <- Seq.contains "libtmux capture ready" lines if not captured then do! Task.Delay(25, token) if not captured then raise (TimeoutException("Output did not arrive within five seconds")) printfn "libtmux capture ready" with error -> errors.Add(error) // Keep the endpoint available for inspection if stopping the server fails. match owned with | Some scope -> try do! scope.DisposeAsync().AsTask() stopped <- true with error -> errors.Add(error) | None -> stopped <- not (File.Exists(Path.Combine(directory, "tmux.sock"))) if stopped then try Directory.Delete(directory, true) with error -> errors.Add(error) if errors.Count > 0 then raise (AggregateException(errors)) } [] let main _ = try capture().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ## Wait for output or completion [`Pane.sendKeys`]() and [`Pane.capture`]() return tasks. The program stops its owned server after either success or failure. It reports cleanup errors alongside the original error and keeps the socket directory if stopping fails. Capture reads screen state and scrollback, so output that has scrolled away may be absent. The program prints `libtmux capture ready` when its check passes and exits unsuccessfully if an operation fails. ## Setup and run Use an empty directory and save the files using the displayed names. You need .NET SDK 10.0.302. Restore into a project-local cache from NuGet so FSharp.Core matches the library’s lockfile. Save `Capture.fsproj` beside `Program.fs`. ```xml title="Capture.fsproj" Exe net10.0 ``` The commands pin the library revision used to run this program. ```console $ git clone https://github.com/libtmux/libtmux-dotnet libtmux-source && git -C libtmux-source checkout 661287848a6cfb407f37114b25e8249a29f99e3f && dotnet build Capture.fsproj --maxcpucount:1 \ -p:DisableImplicitLibraryPacksFolder=true \ -p:RestorePackagesPath="$PWD/.packages" && dotnet run --project Capture.fsproj --no-build ``` ## Where this comes from The displayed files were compiled or loaded with their native tools and run on Linux with tmux 3.2a and 3.7c. The rendering checks preserve those file bytes. --- # Capture pane output Source: https://libtmux.org/en/go/latest/examples/capture-pane-output/ > Run a complete program that captures a pane and waits for a complete output line. A pane runs asynchronously: sending a command does not mean its output is already on screen. Capture repeatedly until the expected line appears, with a deadline so a failed command cannot leave the program waiting forever. This complete program creates a private tmux server, captures its output, and cleans up. Follow the [setup and run instructions](https://libtmux.org/en/go/latest/examples/capture-pane-output/#setup-and-run) below. You need tmux and a Unix environment; no existing tmux session is required. ## Read what's on screen The program sends `printf` with a leading newline, then waits for the complete line `libtmux capture ready`. The newline keeps a late shell prompt off that line. Matching the whole line avoids mistaking the echoed command for its output. ```go title="main.go" package main import ( "context" "errors" "fmt" "log" "os" "path/filepath" "time" "github.com/libtmux/libtmux-go/tmux" ) func main() { if err := capture(); err != nil { log.Fatal(err) } } func capture() (err error) { directory, err := os.MkdirTemp("", "libtmux-capture-") if err != nil { return err } server, err := tmux.NewServer(tmux.ServerOptions{ SocketPath: filepath.Join(directory, "tmux.sock"), ConfigFile: "/dev/null", }) if err != nil { return errors.Join(err, os.RemoveAll(directory)) } defer func() { cleanup, stop := context.WithTimeout(context.Background(), time.Second) defer stop() if cleanupErr := server.Kill(cleanup); cleanupErr != nil { err = errors.Join(err, fmt.Errorf("stop private server at %s: %w", filepath.Join(directory, "tmux.sock"), cleanupErr)) return } err = errors.Join(err, os.RemoveAll(directory)) }() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if _, err = server.NewSession(ctx, tmux.NewSessionRequest{ Name: "capture", Command: "sh", Environment: map[string]string{"ENV": "/dev/null"}, }); err != nil { return err } panes, err := server.Panes(ctx) if err != nil { return err } if len(panes) == 0 { return errors.New("the session has no pane") } pane := panes[0] command := "printf '\\nlibtmux capture ready\\n'" if err := pane.SendKeys(ctx, tmux.SendKeysRequest{Command: &command}); err != nil { return err } for { lines, err := pane.Capture(ctx, tmux.CapturePaneRequest{}) if err != nil { return err } for _, line := range lines { if line == "libtmux capture ready" { fmt.Println(line) return nil } } select { case <-ctx.Done(): return ctx.Err() case <-time.After(20 * time.Millisecond): } } } ``` Cleanup is registered before session creation. If stopping tmux fails, the error reports the retained socket path so the server remains reachable. ## Wait for output or completion The program above checks the captured screen for up to five seconds. The short pause between checks limits polling; the observed output determines when the loop finishes. A tmux capture is a view of the screen and scrollback, so it can miss output that has already scrolled away. Use a stream or a completion signal for long-running commands when that distinction matters. [Capturing output](https://libtmux.org/en/go/latest/guides/capturing-output/) covers capture options, while [Sending keys](https://libtmux.org/en/go/latest/guides/sending-keys/#the-race-you-cant-see-from-the-call-site) explains why sending and waiting are separate operations. ## Setup and run Use an empty directory. The commands pin the library revision used to verify the program. Save the program and module file using the displayed names. Use Go 1.26 or newer. ```text title="go.mod" module example.com/capture go 1.26.0 require github.com/libtmux/libtmux-go v0.0.0 replace github.com/libtmux/libtmux-go => ./libtmux ``` ```console $ git clone https://github.com/libtmux/libtmux-go libtmux && git -C libtmux checkout bb06e26e116e941813ca40bf45e7e3a47d38f52a && GOWORK=off go mod tidy && GOWORK=off go run . ``` ## Where this comes from This complete program was run against the library revision pinned above. The displayed code is checked against the bytes from that run. --- # Capture pane output Source: https://libtmux.org/en/java/latest/examples/capture-pane-output/ > Run a complete program that captures a pane and waits for a complete output line. A pane runs asynchronously: sending a command does not mean its output is already on screen. Capture repeatedly until the expected line appears, with a deadline so a failed command cannot leave the program waiting forever. This complete program creates a private tmux server, captures its output, and cleans up. Follow the [setup and run instructions](https://libtmux.org/en/java/latest/examples/capture-pane-output/#setup-and-run) below. You need tmux and a Unix environment; no existing tmux session is required. ## Read what's on screen The program sends `printf` with a leading newline, then waits for the complete line `libtmux capture ready`. The newline keeps a late shell prompt off that line. Matching the whole line avoids mistaking the echoed command for its output. ```java title="Capture.java" import io.github.libtmux.Pane; import io.github.libtmux.Server; import io.github.libtmux.ServerConfig; import io.github.libtmux.ServerEndpoint; import io.github.libtmux.Session; import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; import java.util.List; public final class Capture { public static void main(String[] args) throws Exception { Path directory = Files.createTempDirectory("libtmux-capture-"); Path socket = directory.resolve("tmux.sock"); ServerConfig config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(socket)) .configFile(Path.of("/dev/null")) .defaultTimeout(Duration.ofSeconds(1)) .build(); try (Server server = Server.open(config)) { try { Session session = server.newSession(s -> s .named("capture").running("sh").env("ENV", "/dev/null")); Pane pane = session.windows().get(0).panes().get(0); pane.sendLine("printf '\\nlibtmux capture ready\\n'"); long deadline = System.nanoTime() + Duration.ofSeconds(5).toNanos(); while (System.nanoTime() < deadline) { List lines = pane.capture(); if (lines.contains("libtmux capture ready")) { System.out.println("libtmux capture ready"); return; } Thread.sleep(20); } throw new IllegalStateException("Timed out waiting for pane output"); } finally { server.killServer(); } } finally { Files.deleteIfExists(socket); Files.delete(directory); } } } ``` ## Wait for output or completion The program above checks the captured screen for up to five seconds. The short pause between checks limits polling; the observed output determines when the loop finishes. A tmux capture is a view of the screen and scrollback, so it can miss output that has already scrolled away. Use a stream or a completion signal for long-running commands when that distinction matters. [Capturing output](https://libtmux.org/en/java/latest/guides/capturing-output/) covers capture options, while [Sending keys](https://libtmux.org/en/java/latest/guides/sending-keys/#the-race-you-cant-see-from-the-call-site) explains why sending and waiting are separate operations. ## Setup and run Use an empty directory. The commands pin the library revision used to verify the program. Save the program as `Capture.java`. Use JDK 21 or newer. The repository's Gradle wrapper builds the library; the Java source launcher runs the complete program. ```console $ git clone https://github.com/libtmux/libtmux-java libtmux && git -C libtmux checkout 842228310449e879ebcaa3f910597757c9dbffd6 && (cd libtmux && ./gradlew :libtmux:jar) && java --class-path 'libtmux/libtmux/build/libs/*' Capture.java ``` ## Where this comes from This complete program was run against the library revision pinned above. The displayed code is checked against the bytes from that run. --- # Capture pane output Source: https://libtmux.org/en/kotlin/latest/examples/capture-pane-output/ > Run a complete Kotlin program that captures output on an isolated tmux server. This complete Kotlin program starts a private tmux server, sends a command, and captures the line it prints. It includes imports, setup, and cleanup. You need tmux and a Unix environment; no existing session is required. ## Read what's on screen The leading newline puts the output on a fresh row. Matching the whole line avoids mistaking the echoed command for its output. ```kotlin title="Capture.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.capture import io.github.libtmux.kotlin.killServer import io.github.libtmux.kotlin.newSession import io.github.libtmux.kotlin.sendLine import io.github.libtmux.kotlin.withServer import java.nio.file.Files import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout fun main() = runBlocking { val root = Files.createDirectories(Path.of("/tmp/libtmux-java-dev")) val directory = Files.createTempDirectory(root, "capture-") val socket = directory.resolve("tmux.sock") val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(socket)) .configFile(Path.of("/dev/null")) .defaultTimeout(Duration.ofSeconds(1)) .build() var failure: Throwable? = null try { withServer(config) { server -> try { val session = server.newSession { name = "capture" running("/bin/sh") env("ENV", "/dev/null") } val pane = session.windows.first().panes.first() pane.sendLine("printf '\\nlibtmux capture ready\\n'") withTimeout(5_000) { while (!pane.capture().contains("libtmux capture ready")) { delay(25) } } println("libtmux capture ready") } catch (error: Throwable) { failure = error throw error } finally { withContext(NonCancellable) { try { if (Files.exists(socket)) server.killServer() Files.deleteIfExists(socket) Files.delete(directory) } catch (cleanup: Throwable) { val original = failure if (original == null) throw cleanup original.addSuppressed(cleanup) } } } } } finally { // Opening a client can fail before the cleanup block is entered. if (!Files.exists(socket)) Files.deleteIfExists(directory) } } ``` ## Wait for output or completion Capture and input calls suspend. `withTimeout` bounds the polling loop, and `delay` yields between captures. [`withServer`]() closes the client; the [`finally`]() block also stops the tmux server this program created. Cleanup errors stay visible, and a server that cannot be stopped keeps its socket. Capture reads screen state and scrollback, so output that has scrolled away may be absent. The program prints `libtmux capture ready` when its check passes and exits unsuccessfully if an operation fails. ## Setup and run Use an empty directory and save the files using the displayed names. You need JDK 25. The pinned repository supplies Gradle; the project files select Kotlin 2.4.10 and include the library build. Save `settings.gradle.kts` beside `Capture.kt`. ```kotlin title="settings.gradle.kts" rootProject.name = "capture" includeBuild("libtmux-source") ``` Save `build.gradle.kts` beside `Capture.kt`. ```kotlin title="build.gradle.kts" plugins { application kotlin("jvm") version "2.4.10" } repositories { mavenCentral() } dependencies { implementation("io.github.libtmux:libtmux-kotlin:0.0.1-alpha.17-SNAPSHOT") } kotlin { jvmToolchain(25) sourceSets.main { kotlin.srcDir("."); kotlin.include("Capture.kt") } } application { mainClass.set("CaptureKt") } ``` Save `gradle.properties` beside `Capture.kt`. ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` The commands pin the library revision used to run this program. ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout 85ebf6955e56703c5be74e2afd34a18309044741 && ./libtmux-source/gradlew --project-dir . run --console=plain --max-workers=2 ``` ## Where this comes from The displayed files were compiled or loaded with their native tools and run on Linux with tmux 3.2a and 3.7c. The rendering checks preserve those file bytes. --- # Capture pane output Source: https://libtmux.org/en/lua/latest/examples/capture-pane-output/ > Run a complete Lua program that captures output on an isolated tmux server. This complete Lua program starts a private tmux server, sends a command, and captures the line it prints. It includes imports, setup, and cleanup. You need tmux and a Unix environment; no existing session is required. Save both files shown below. Run `sh run.sh` after the [setup](https://libtmux.org/en/lua/latest/examples/capture-pane-output/#setup-and-run); the launcher creates the server and passes its socket to the Lua program. ## Read what's on screen The leading newline puts the output on a fresh row. Matching the whole line avoids mistaking the echoed command for its output. ```lua title="capture.lua" local adapter = require("libtmux.runtime.luv") local function must(value, err) if err ~= nil then error(tostring(err), 0) end return value end local function quote(text) return "'" .. text:gsub("'", "'\\''") .. "'" end local socket = assert(arg[1], "pass the private socket path") local binary = assert(arg[2], "pass the absolute tmux executable path") must(adapter.run(function(runtime) local server = must(runtime:connect({ binary = binary, socket_path = socket }):await()) local created = must(server:new_session({ name = "capture", argv = { "/bin/sh" }, }):await()) local pane = created.pane local command = "printf '\\nlibtmux capture ready\\n'; " .. quote(binary) .. " -S " .. quote(socket) .. " wait-for -S capture-ready" must(pane:send_text(command):await()) must(pane:send_keys({ "Enter" }):await()) must(server:command({ "wait-for", "capture-ready" }, { timeout = 5000 }):await()) local capture = must(pane:capture({ history_lines = 20 }):await()) local found = false for line in must(capture:text()):gmatch("[^\r\n]+") do if line == "libtmux capture ready" then found = true end end assert(found, "The completed command did not produce the expected line") print("libtmux capture ready") must(server:close():await()) return true end)) ``` ## Wait for output or completion The pane prints its line, then signals a tmux `wait-for` channel on the same private socket. The awaited command has a five-second deadline. Capture runs after that signal and checks the complete line. The launcher stops its server on success or failure; if stopping fails, it reports the error and keeps the socket directory. Capture reads screen state and scrollback, so output that has scrolled away may be absent. The program prints `libtmux capture ready` when its check passes and exits unsuccessfully if an operation fails. ## Setup and run Use an empty directory and save the files using the displayed names. You need Lua 5.5, LuaRocks, a C compiler, and CMake. The commands install libtmux and its luv runtime adapter into a local rocks tree. Save this launcher beside the Lua program. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) case "$binary" in /*) ;; *) printf '%s\n' 'tmux must resolve to an absolute path' >&2; exit 1 ;; esac mkdir -p /tmp/libtmux-lua-dev directory=$(mktemp -d /tmp/libtmux-lua-dev/capture.XXXXXX) socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ]; then if ! "$binary" -S "$socket" kill-server; then printf 'Could not stop server; retained %s\n' "$directory" >&2 exit 1 fi fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM export ENV=/dev/null "$binary" -S "$socket" -f /dev/null new-session -d -s bootstrap /bin/cat lua capture.lua "$socket" "$binary" ``` The commands pin the library revision used to run this program. ```console $ git clone https://github.com/libtmux/libtmux-lua libtmux-source && git -C libtmux-source checkout 5baa3f9b830ebdbc76fb50b5b3d7a5ad3f76d443 && luarocks --tree ./rocks install luv 1.52.1-0 && (cd libtmux-source && luarocks --tree ../rocks make rockspecs/libtmux-scm-1.rockspec) && eval "$(luarocks --tree ./rocks path)" && sh run.sh ``` ## Where this comes from The displayed files were compiled or loaded with their native tools and run on Linux with tmux 3.2a and 3.7c. The rendering checks preserve those file bytes. --- # Capture pane output Source: https://libtmux.org/en/py/latest/examples/capture-pane-output/ > Run a complete program that captures a pane and waits for a complete output line. A pane runs asynchronously: sending a command does not mean its output is already on screen. Capture repeatedly until the expected line appears, with a deadline so a failed command cannot leave the program waiting forever. This complete program creates a private tmux server, captures its output, and cleans up. Follow the [setup and run instructions](https://libtmux.org/en/py/latest/examples/capture-pane-output/#setup-and-run) below. You need tmux and a Unix environment; no existing tmux session is required. ## Read what's on screen The program sends `printf` with a leading newline, then waits for the complete line `libtmux capture ready`. The newline keeps a late shell prompt off that line. Matching the whole line avoids mistaking the echoed command for its output. ```python title="capture.py" from pathlib import Path from tempfile import TemporaryDirectory from time import monotonic, sleep import libtmux with TemporaryDirectory(prefix="libtmux-capture-") as directory: server = libtmux.Server( socket_path=Path(directory) / "tmux.sock", config_file="/dev/null", ) try: session = server.new_session( session_name="capture", window_command="sh", environment={"ENV": "/dev/null"}, ) pane = session.active_window.active_pane pane.send_keys("printf '\\nlibtmux capture ready\\n'", literal=True) deadline = monotonic() + 5 while True: lines = pane.capture_pane() if "libtmux capture ready" in lines: print("\n".join(lines)) break if monotonic() >= deadline: raise TimeoutError("The pane did not print the expected line") sleep(0.05) finally: server.kill() ``` ## Wait for output or completion The program above checks the captured screen for up to five seconds. The short pause between checks limits polling; the observed output determines when the loop finishes. A tmux capture is a view of the screen and scrollback, so it can miss output that has already scrolled away. Use a stream or a completion signal for long-running commands when that distinction matters. [Capturing output](https://libtmux.org/en/py/latest/guides/capturing-output/) covers capture options, while [Sending keys](https://libtmux.org/en/py/latest/guides/sending-keys/#the-race-you-cant-see-from-the-call-site) explains why sending and waiting are separate operations. ## Setup and run Use an empty directory. The commands pin the library revision used to verify the program. Save the program as `capture.py`. With Python 3.10 or newer and uv installed: ```console $ uv run \ --with 'libtmux @ git+https://github.com/tmux-python/libtmux@9fdd083a8181a827889337b63cd4e6daea661a8c' \ capture.py ``` ## Where this comes from This complete program was run against the library revision pinned above. The displayed code is checked against the bytes from that run. --- # Capture pane output Source: https://libtmux.org/en/rs/latest/examples/capture-pane-output/ > Run a complete program that captures a pane and waits for a complete output line. A pane runs asynchronously: sending a command does not mean its output is already on screen. Capture repeatedly until the expected line appears, with a deadline so a failed command cannot leave the program waiting forever. This complete program creates a private tmux server, captures its output, and cleans up. Follow the [setup and run instructions](https://libtmux.org/en/rs/latest/examples/capture-pane-output/#setup-and-run) below. You need tmux and a Unix environment; no existing tmux session is required. ## Read what's on screen The program sends `printf` with a leading newline, then waits for the complete line `libtmux capture ready`. The newline keeps a late shell prompt off that line. Matching the whole line avoids mistaking the echoed command for its output. ```rust title="main.rs" use std::error::Error; use std::time::Duration; use libtmux::{NewSessionOptions, Server}; use tokio::time::{sleep, timeout}; #[tokio::main] async fn main() -> Result<(), Box> { let directory = tempfile::tempdir()?; let server = Server::builder() .socket_path(directory.path().join("tmux.sock")) .config_file("/dev/null") .build()?; let captured = timeout(Duration::from_secs(5), async { let session = server .new_session(NewSessionOptions::new("capture").command("env ENV=/dev/null sh")) .await?; let panes = session.panes().await?; let pane = panes.first().ok_or("the session has no pane")?; pane.send_line("printf '\\nlibtmux capture ready\\n'").await?; loop { let lines = pane.capture().await?; if let Some(line) = lines .iter() .find(|line| line.as_bytes() == b"libtmux capture ready") { println!("{}", line.to_string_lossy()); return Ok::<_, Box>(()); } sleep(Duration::from_millis(20)).await; } }) .await; let killed = server.kill().await; let closed = server.shutdown().await; captured??; killed?; closed?; Ok(()) } ``` ## Wait for output or completion The program above checks the captured screen for up to five seconds. The short pause between checks limits polling; the observed output determines when the loop finishes. A tmux capture is a view of the screen and scrollback, so it can miss output that has already scrolled away. Use a stream or a completion signal for long-running commands when that distinction matters. [Capturing output](https://libtmux.org/en/rs/latest/guides/capturing-output/) covers capture options, while [Sending keys](https://libtmux.org/en/rs/latest/guides/sending-keys/#the-race-you-cant-see-from-the-call-site) explains why sending and waiting are separate operations. ## Setup and run Use an empty directory. The commands pin the library revision used to verify the program. Save the program as `src/main.rs` and this file as [`Cargo.toml`](). Use the repository's Rust 1.97.1 toolchain for this pinned revision. ```toml title="Cargo.toml" [package] name = "capture-example" version = "0.1.0" edition = "2024" [dependencies] libtmux = { path = "libtmux/crates/libtmux" } tempfile = "3.27.0" tokio = { version = "1.53.1", features = ["macros", "rt-multi-thread", "time"] } ``` ```console $ git clone https://github.com/libtmux/libtmux-rs libtmux && git -C libtmux checkout d4e08b4eaab62ef4eeedab79b47973ae9a1de310 && cargo +1.97.1 run ``` ## Where this comes from This complete program was run against the library revision pinned above. The displayed code is checked against the bytes from that run. --- # Capture pane output Source: https://libtmux.org/en/ruby/latest/examples/capture-pane-output/ > Run a complete Ruby program that captures output on an isolated tmux server. This complete Ruby program starts a private tmux server, sends a command, and captures the line it prints. It includes imports, setup, and cleanup. You need tmux and a Unix environment; no existing session is required. ## Read what's on screen The leading newline puts the output on a fresh row. Matching the whole line avoids mistaking the echoed command for its output. ```ruby title="capture.rb" require "libtmux" LibTmux::Server.start do |server| created = server.new_session( name: "capture", command: ["/bin/sh"], environment: {"ENV" => "/dev/null"}, receipt: true ) pane = created.pane pane.send_text("printf '\\nlibtmux capture ready\\n'") pane.send_keys("Enter") deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + 5 loop do if pane.capture.stdout.lines(chomp: true).include?("libtmux capture ready") puts "libtmux capture ready" break end if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline raise "Output did not arrive within five seconds" end sleep 0.025 end end ``` ## Wait for output or completion [`LibTmux::Server.start`]() owns the private server. Leaving its block stops the server, including when capture or the deadline raises an error. Capture reads screen state and scrollback, so output that has scrolled away may be absent. The program prints `libtmux capture ready` when its check passes and exits unsuccessfully if an operation fails. ## Setup and run Use an empty directory and save the files using the displayed names. You need Ruby 4.0.7 and Bundler. Bundler installs the library and its runtime dependencies. Save this dependency file beside the program. ```ruby title="Gemfile" source "https://rubygems.org" gem "libtmux", path: "libtmux-source/gems/libtmux" ``` The commands pin the library revision used to run this program. ```console $ git clone https://github.com/libtmux/libtmux-ruby libtmux-source && git -C libtmux-source checkout 2599d45369515aaf2fd5793bfe71cdc20de641b6 && bundle config set --local path vendor/bundle && bundle install && bundle exec ruby capture.rb ``` ## Where this comes from The displayed files were compiled or loaded with their native tools and run on Linux with tmux 3.2a and 3.7c. The rendering checks preserve those file bytes. --- # Capture pane output Source: https://libtmux.org/en/scala/latest/examples/capture-pane-output/ > Run a complete Scala program that captures output on an isolated tmux server. This complete Scala program starts a private tmux server, sends a command, and captures the line it prints. It includes imports, setup, and cleanup. You need tmux and a Unix environment; no existing session is required. ## Read what's on screen The leading newline puts the output on a fresh row. Matching the whole line avoids mistaking the echoed command for its output. ```scala title="Capture.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint, SessionSpec} import io.github.libtmux.scaladsl.* import java.nio.file.{Files, Path} import java.time.Duration import scala.util.Using object Capture { def main(args: Array[String]): Unit = { val root = Files.createDirectories(Path.of("/tmp/libtmux-java-dev")) val directory = Files.createTempDirectory(root, "capture-") val socket = directory.resolve("tmux.sock") val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(socket)) .configFile(Path.of("/dev/null")) .defaultTimeout(Duration.ofSeconds(1)) .build() var failure: Option[Throwable] = None try { Using.resource(Server.open(config)) { server => try { val session = server.newSession(SessionSpec.builder() .named("capture").running("/bin/sh").env("ENV", "/dev/null").build()) val pane = session.windows.head.panes.head pane.sendLine("printf '\\nlibtmux capture ready\\n'") val deadline = System.nanoTime() + Duration.ofSeconds(5).toNanos var captured = false while (!captured && System.nanoTime() < deadline) { captured = pane.capture().contains("libtmux capture ready") if (!captured) Thread.sleep(25) } if (!captured) throw new IllegalStateException("Output did not arrive within five seconds") println("libtmux capture ready") } catch { case error: Throwable => failure = Some(error) throw error } finally { try { if (Files.exists(socket)) server.killServer() Files.deleteIfExists(socket) Files.delete(directory) } catch { case cleanup: Throwable => failure match { case Some(original) => original.addSuppressed(cleanup) case None => throw cleanup } } } } } finally { // Opening a client can fail before the cleanup block is entered. if (!Files.exists(socket)) Files.deleteIfExists(directory) } } } ``` ## Wait for output or completion The Scala facade uses blocking calls. The loop checks complete captured lines against a monotonic deadline. [`Using.resource`](https://www.scala-lang.org/api/3.x/scala/util/Using$.html) closes the client; the `finally` block also stops the tmux server this program created. Cleanup errors stay visible, and a server that cannot be stopped keeps its socket. Capture reads screen state and scrollback, so output that has scrolled away may be absent. The program prints `libtmux capture ready` when its check passes and exits unsuccessfully if an operation fails. ## Setup and run Use an empty directory and save the files using the displayed names. You need JDK 25. The pinned repository supplies Gradle; the project files select Scala 3.9.0 and include the library build. Save `settings.gradle.kts` beside `Capture.scala`. ```kotlin title="settings.gradle.kts" rootProject.name = "capture" includeBuild("libtmux-source") { dependencySubstitution { substitute(module("io.github.libtmux:libtmux-scala_3")) .using(project(":libtmux-scala")) } } ``` Save `build.gradle.kts` beside `Capture.scala`. ```kotlin title="build.gradle.kts" plugins { application scala } repositories { mavenCentral() } dependencies { implementation("org.scala-lang:scala3-library_3:3.9.0") implementation("io.github.libtmux:libtmux-scala_3:0.0.1-alpha.17-SNAPSHOT") } java { toolchain { languageVersion.set(JavaLanguageVersion.of(25)) } } sourceSets.main { scala.srcDir("."); scala.include("Capture.scala") } application { mainClass.set("Capture") } ``` Save `gradle.properties` beside `Capture.scala`. ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` The commands pin the library revision used to run this program. ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout 85ebf6955e56703c5be74e2afd34a18309044741 && ./libtmux-source/gradlew --project-dir . run --console=plain --max-workers=2 ``` ## Where this comes from The displayed files were compiled or loaded with their native tools and run on Linux with tmux 3.2a and 3.7c. The rendering checks preserve those file bytes. --- # Capture pane output Source: https://libtmux.org/en/swift/latest/examples/capture-pane-output/ > Run a complete program that captures a pane and waits for a complete output line. A pane runs asynchronously: sending a command does not mean its output is already on screen. Capture repeatedly until the expected line appears, with a deadline so a failed command cannot leave the program waiting forever. This complete program creates a private tmux server, captures its output, and cleans up. Follow the [setup and run instructions](https://libtmux.org/en/swift/latest/examples/capture-pane-output/#setup-and-run) below. You need tmux and a Unix environment; no existing tmux session is required. ## Read what's on screen The program sends `printf` with a leading newline, then waits for the complete line `libtmux capture ready`. The newline keeps a late shell prompt off that line. Matching the whole line avoids mistaking the echoed command for its output. ```swift title="Capture.swift" import Foundation import LibTmux enum CaptureError: Error { case failed(String) } @main struct Capture { static func main() async throws { let directory = URL(fileURLWithPath: "/tmp/libtmux-swift-dev") .appendingPathComponent(UUID().uuidString) try FileManager.default.createDirectory( at: directory, withIntermediateDirectories: true, attributes: [.posixPermissions: 0o700] ) let server = try Server( socketPath: directory.appendingPathComponent("tmux.sock").path, configurationFile: "/dev/null" ) var started = false var failure: (any Error)? do { let created = try await server.run(TmuxCommand( "new-session", ["-d", "-s", "capture", "env -u ENV -u BASH_ENV /bin/sh"] )) guard created.isSuccess else { throw CaptureError.failed(created.errorText) } started = true guard let pane = try await server.panes().first else { throw CaptureError.failed("The session has no pane") } try await server.run("printf '\\nlibtmux capture ready\\n'", in: pane) let clock = ContinuousClock() let deadline = clock.now.advanced(by: .seconds(5)) var captured = false while clock.now < deadline { let lines = try await server.capture(pane) if lines.contains("libtmux capture ready") { print("libtmux capture ready") captured = true break } try await Task.sleep(for: .milliseconds(25)) } guard captured else { throw CaptureError.failed("Output did not arrive within five seconds") } } catch { failure = error } var cleanupFailed = false if started { do { try await server.killServer() } catch { FileHandle.standardError.write(Data("Stop tmux: \(error)\n".utf8)) cleanupFailed = true } } do { try FileManager.default.removeItem(at: directory) } catch { FileHandle.standardError.write(Data("Remove socket: \(error)\n".utf8)) cleanupFailed = true } if let failure { throw failure } if cleanupFailed { throw CaptureError.failed("Cleanup failed; see diagnostics") } } } ``` ## Wait for output or completion The program above checks the captured screen for up to five seconds. The short pause between checks limits polling; the observed output determines when the loop finishes. A tmux capture is a view of the screen and scrollback, so it can miss output that has already scrolled away. Use a stream or a completion signal for long-running commands when that distinction matters. [Capturing output](https://libtmux.org/en/swift/latest/guides/capturing-output/) covers capture options, while [Sending keys](https://libtmux.org/en/swift/latest/guides/sending-keys/#the-race-you-cant-see-from-the-call-site) explains why sending and waiting are separate operations. ## Setup and run Use an empty directory. The commands pin the library revision used to verify the program. Save the program as `Sources/Capture/Capture.swift` and this file as [`Package.swift`](). Use Swift 6.2 or newer. ```swift title="Package.swift" // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "CaptureExample", platforms: [.macOS(.v13)], dependencies: [.package(path: "libtmux-source")], targets: [ .executableTarget( name: "Capture", dependencies: [.product(name: "LibTmux", package: "libtmux-source")] ), ] ) ``` ```console $ git clone https://github.com/libtmux/libtmux-swift libtmux-source && git -C libtmux-source checkout 254f8b2be7eb60cacc3ffcb3ea8e456784f582df && swift run --jobs 2 Capture ``` ## Where this comes from This complete program was run against the library revision pinned above. The displayed code is checked against the bytes from that run. --- # Capture pane output Source: https://libtmux.org/en/ts/latest/examples/capture-pane-output/ > Run a complete program that captures a pane and waits for a complete output line. A pane runs asynchronously: sending a command does not mean its output is already on screen. Capture repeatedly until the expected line appears, with a deadline so a failed command cannot leave the program waiting forever. This complete program creates a private tmux server, captures its output, and cleans up. Follow the [setup and run instructions](https://libtmux.org/en/ts/latest/examples/capture-pane-output/#setup-and-run) below. You need tmux and a Unix environment; no existing tmux session is required. ## Read what's on screen The program sends `printf` with a leading newline, then waits for the complete line `libtmux capture ready`. The newline keeps a late shell prompt off that line. Matching the whole line avoids mistaking the echoed command for its output. ```typescript title="capture.ts" import { mkdtemp, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { setTimeout as delay } from "node:timers/promises"; import { Server } from "libtmux"; const directory = await mkdtemp(join(tmpdir(), "libtmux-capture-")); const server = new Server({ socketPath: join(directory, "tmux.sock"), configFile: "/dev/null", timeoutMs: 5_000, }); const failures: unknown[] = []; try { const signal = AbortSignal.timeout(5_000); const session = await server.newSession({ name: "capture", shellCommand: "sh", signal, environment: { ENV: "/dev/null" }, }); const pane = session.activePane; if (!pane) throw new Error("The session has no active pane"); await pane.sendKeys("printf '\\nlibtmux capture ready\\n'", { signal }); for (;;) { const lines = await pane.capture({ signal }); const line = lines.find((line) => line === "libtmux capture ready"); if (line !== undefined) { console.log(line); break; } await delay(20, undefined, { signal }); } } catch (error) { failures.push(error); } finally { try { if ((await readdir(directory)).includes("tmux.sock")) await server.kill(); await rm(directory, { recursive: true }); } catch (error) { failures.push(new Error( `Cleanup failed; inspect ${directory}`, { cause: error }, )); } } if (failures.length > 0) throw new AggregateError(failures, "Capture failed"); ``` Cleanup checks the private socket even if startup fails. If stopping tmux fails, the error reports the retained directory so the server remains reachable. ## Wait for output or completion The program above checks the captured screen for up to five seconds. The short pause between checks limits polling; the observed output determines when the loop finishes. A tmux capture is a view of the screen and scrollback, so it can miss output that has already scrolled away. Use a stream or a completion signal for long-running commands when that distinction matters. [Capturing output](https://libtmux.org/en/ts/latest/guides/capturing-output/) covers capture options, while [Sending keys](https://libtmux.org/en/ts/latest/guides/sending-keys/#the-race-you-cant-see-from-the-call-site) explains why sending and waiting are separate operations. ## Setup and run Use an empty directory. The commands pin the library revision used to verify the program. Save the program as `capture.ts` and this file as [`package.json`](). Use Bun 1.4.2 or newer. ```json title="package.json" {"type":"module","dependencies":{"libtmux":"file:./libtmux/packages/libtmux"}} ``` ```console $ git clone https://github.com/libtmux/libtmux-ts libtmux && git -C libtmux checkout 3fe1ca654b81b8cbf4a13b777a001a3298c87a6f && bun install && bun run capture.ts ``` ## Where this comes from This complete program was run against the library revision pinned above. The displayed code is checked against the bytes from that run. --- # Go MCP examples Source: https://libtmux.org/en/go/latest/mcp/examples/ > Run complete SDK clients that inspect sessions and check a shell command's result. Each program includes its dependencies, entry point, private tmux server, client transport, deadlines, and cleanup. The MCP executable is installed inside the example directory. No pre-existing tmux session is required. ## List sessions The [session inspector](https://libtmux.org/en/go/latest/mcp/examples/inspect-sessions/) calls [`list_sessions`](https://libtmux.org/en/go/latest/mcp/tools/list_sessions/) and verifies the returned session ID against the session it created. It reads metadata without sending input or capturing terminal content through MCP. ## Internals Applications can also embed the server and use an in-memory client transport. The upstream [agent-workflow program](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/examples/agent-workflow/main.go) demonstrates caller context, pane creation, command completion, and topology inspection. The [language API reference](https://libtmux.org/en/go/latest/mcp/reference/) documents the types used to embed the server. ### Run the agent workflow The [upstream example instructions](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/examples/agent-workflow/README.md) describe its repository setup and socket selection. For a standalone program with all setup on one page, use [Run a command](https://libtmux.org/en/go/latest/mcp/examples/run-command/). ### Clean up The standalone programs close the MCP connection before stopping their owned tmux server. They use a fresh cleanup deadline even when a request times out, and retain the temporary directory if server cleanup fails. They never select your default tmux socket. For workspace configuration without MCP, see [Workspace builder examples](https://libtmux.org/en/go/latest/workspace/internals/examples/). - [List sessions through MCP](https://libtmux.org/en/go/latest/mcp/examples/inspect-sessions/): Create a private server and read structured session metadata. - [Run a command through MCP](https://libtmux.org/en/go/latest/mcp/examples/run-command/): Execute a command in one pane and check its exit status and output. --- # Recipes Source: https://libtmux.org/en/ruby/latest/examples/recipes/ > Run programs for queries, linked windows, capture, and cancellation. Every linked program loads installed gems, starts an isolated server, asserts its result and verifies owned-daemon cleanup. The shared [support module](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/support.rb) supplies assertions and the cleanup wrapper. No program adds checkout paths to Ruby's load path. Run a program from the repository after installing its required local gems: ```console $ ruby examples/window_links.rb ``` The artifact suite copies programs outside the checkout and runs them against each gem's isolated dependency closure. [The manifest](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/manifest.json) owns file discovery and the source regions used below. `scripts/examples --check` rejects an unlisted program or a changed excerpt. ## Captured queries [Complete list/filter/exact-one program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/list_filter.rb). A fresh window does not alter an existing capture; local filtering still works after the binding closes. ```ruby session = server.new_session(name: "capture", command: ["/bin/cat"]) session.new_window(name: "second", command: ["/bin/cat"]) snapshot = server.snapshot panes = snapshot.panes first = panes.one(id: panes.first.id) session.new_window(name: "later", command: ["/bin/cat"]) Example.check(panes.size == 2, "captured membership changed") Example.check(panes.where(id: first.id).one.ref == first.ref, "wrong exact match") Example.raises(LibTmux::MultipleMatchesError) { panes.one } Example.check(panes.one_or_nil(id: "%4294967294").nil?, "missing pane was invented") ``` ## Layout and bytes [Complete layout/capture/send program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/layout_io.rb). A control output event establishes that the literal input has reached the pane before capture. Binary buffers round-trip without text decoding. ```ruby receipt = server.new_session(name: "layout", command: ["/bin/cat"], receipt: true) pane = receipt.pane second = pane.split(direction: :horizontal, size: "40%", command: ["/bin/cat"]) receipt.window.select_layout("tiled") Example.check(receipt.window.list_panes.map(&:id).sort == [pane.id, second.id].sort, "assigned pane IDs differ") server.open_control(session: receipt.entity.ref) do |control| control.exchange("display-message -p ready", timeout: 0.5) output = control.subscribe(pane_id: pane.id, max_bytes: 8192, max_events: 32) literal = "literal; #{'#{pane_id}'} $HOME" pane.send_text(literal) bytes = "".b bytes << output.next(timeout: 0.5).data until bytes.include?(literal) Example.check(pane.capture.stdout.include?(literal), "capture lost literal input") end payload = "NUL\0\xff\n".b server.write_buffer(name: "bytes", data: payload) Example.check(server.read_buffer("bytes").stdout == payload, "buffer bytes changed") ``` ## One window at three indexes [Complete window-link program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/window_links.rb). Window identity and selection context remain distinct. ```ruby session = server.new_session(name: "links", command: ["/bin/cat"]) window = session.list_windows.fetch(0) session.link_window(window.ref, index: 4) session.link_window(window.ref, index: 9) links = session.list_window_links Example.check(links.map(&:index) == [0, 4, 9], "link indexes differ") Example.check(links.map { |link| link.window.ref }.uniq == [window.ref], "window identity split") Example.check(links.map(&:ref).uniq.length == 3, "link contexts collapsed") links.find { |link| link.index == 9 }.select Example.check(session.display('#{window_index}').text == "9\n", "wrong current link") ``` ## Blocking request cancellation [Complete plain-Ruby cancellation program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/cancel.rb). A tmux event proves dispatch before another thread cancels the blocked client. The program joins the caller, checks client reaping and closes the token's owned pipe. ```ruby cancellation = LibTmux::Cancellation.new waiting = nil begin waiting = Thread.new do server.run(["wait-for", "-S", "ready", ";", "wait-for", "held"], timeout: 0.5, cancel: cancellation) rescue LibTmux::Cancelled => error error end server.wait_for("ready", timeout: 0.5) cancellation.cancel failure = waiting.value Example.check(failure.is_a?(LibTmux::Cancelled), "cancellation lost") Example.check(failure.delivery == :possibly_sent, "dispatched wait claimed no effects") Example.raises(Errno::ECHILD) { Process.waitpid(failure.pid, Process::WNOHANG) } Example.check(server.diagnostics.fetch(:admitted_requests).zero?, "client remains admitted") ensure begin cancellation.cancel waiting&.join ensure cancellation.close end end ``` ## Async capture and cancellation [Complete Async program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/async_cancel.rb). A second task captures while another tmux client waits; cancellation retires that client's process. ```ruby Async do |parent| LibTmux::Async.open(parent: parent, server: server) do |scope| waiting = parent.async do scope.server.run(["wait-for", "-S", "ready", ";", "wait-for", "held"], timeout: 0.5) rescue LibTmux::Cancelled => error error end scope.server.wait_for("ready", timeout: 0.5) Example.check(scope.diagnostics.fetch(:active_process_slots) == 1, "waiting client lost its slot") captures = scope.map(scope.server.list_panes.map(&:ref), concurrency: 2) do |ref| scope.server.pane(ref).capture end Example.check(captures.all?(&:success?), "sibling captures stalled") waiting.cancel failure = waiting.wait Example.check(failure.is_a?(LibTmux::Cancelled), "cancellation lost") Example.check(failure.delivery == :possibly_sent, "cancelled dispatch claimed no effects") Example.raises(Errno::ECHILD) { Process.waitpid(failure.pid, Process::WNOHANG) } Example.check(scope.server.diagnostics.fetch(:admitted_requests).zero?, "cancelled client remains admitted") end end.wait ``` ## Control overflow [Complete control program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/control_overflow.rb). A slow reliable subscriber fails explicitly; a tail subscriber reports a gap and replies continue to drain. ```ruby server.open_control(session: session.ref) do |control| control.exchange("display-message -p ready", timeout: 0.5) reliable = control.subscribe(max_events: 1, max_bytes: 1024) tail = control.subscribe(mode: :tail, max_events: 1, max_bytes: 1024) 3.times { |index| window.rename("event#{index}") } reply = control.exchange("display-message -p alive", timeout: 0.5) Example.check(reply.blocks.last.body == "alive\n", "slow reader blocked commands") Example.check(reply.attribution == :boundary_window, "reply overclaims attribution") Example.check(reliable.diagnostics.fetch(:overflowed), "overflow is missing from diagnostics") Example.check(control.diagnostics.fetch(:retained_reply_bytes).zero?, "consumed reply remains retained") reliable.next(timeout: 0.5) Example.raises(LibTmux::SubscriptionOverflow) { reliable.next(timeout: 0.5) } gap = tail.next(timeout: 0.5) Example.check(gap.kind == :gap && gap.dropped_bytes.positive?, "tail hid lost bytes") end ``` ## Failure inside a group [Complete group program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/failed_group.rb). The first mutation survives a later failure. A separate read establishes the missing later effect; the group result does not invent statuses for its members. ```ruby group = server.run_group([ ["set-option", "-g", "@before", "retained"], ["select-pane", "-t", "%4294967294"], ["set-option", "-g", "@after", "not-executed"] ]) Example.check(!group.success?, "failing group succeeded") Example.check(group.steps.all? { |step| step.fetch(:outcome) == :unknown }, "invented per-step status") Example.check(server.options(scope: :session).get("@before").raw == "retained", "earlier effect rolled back") Example.check(server.options(scope: :session).list.none? { |option| option.name == "@after" }, "later step executed") ``` ## MCP protocol [Complete MCP program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/mcp_protocol.rb). Real pipe frames exercise discovery, snapshot reads, default mutation denial and cancellation of an application-owned WAIT method. The custom WAIT method is a transport probe, not part of the advertised tmux tool catalog. ```ruby application = LibTmux::MCP::Application.new(server: scope.server, endpoint_name: "example") sdk = application.sdk_server input, client_input = IO.pipe client_output, output = IO.pipe transport = LibTmux::MCP::StdioTransport.new(server: sdk, parent: parent, input: input, output: output) runner = parent.async { transport.run } ``` The installed executable also exercises explicitly enabled create, send, close and authored-run tools. Its complete program creates a zsh pane whose startup file explicitly sources the CLI's mode-0600 enrollment file, waits for the authenticated acknowledgement, and checks binary stderr and native exit status. It closes stdin and verifies enrollment cleanup and borrowed daemon survival. An unsupported advertised process backend exercises the structured refusal instead; that is not positive enrollment evidence. ```ruby executable = Gem.bin_path("libtmux-mcp", "libtmux-mcp") Open3.popen3(Gem.ruby, "-W:no-experimental", executable, "--socket", server.endpoint.socket_path, "--tmux", Example.executable, "--endpoint", "installed", "--enable-tool", "tmux_create", "--enable-tool", "tmux_send", "--enable-tool", "tmux_close", "--enable-tool", "tmux_run", *enrollment_arguments) do |input, output, errors, process| request = lambda do |id, method, params = {}| input.write(JSON.generate({jsonrpc: "2.0", id: id, method: method, params: params}) + "\n") Example.check(IO.select([output], nil, nil, id == 1 ? 1.0 : 0.5), "installed MCP did not return a frame") response = JSON.parse(output.gets) Example.check(response.fetch("id") == id, "MCP response identity changed") response.fetch("result") end request.call(1, "initialize", {protocolVersion: "2025-11-25", capabilities: {}, clientInfo: {name: "recipe", version: "1"}}) input.write(JSON.generate({jsonrpc: "2.0", method: "notifications/initialized"}) + "\n") names = request.call(2, "tools/list").fetch("tools").map { |tool| tool.fetch("name") } Example.check(names.sort == %w[tmux_capabilities tmux_close tmux_create tmux_run tmux_send tmux_snapshot], "tool policy differs") created = request.call(3, "tools/call", {name: "tmux_create", arguments: { kind: "session", name: "via-protocol", argv: ["/bin/cat"]}}).fetch("structuredContent") Example.check(created.fetch("ok"), "protocol creation failed") data = created.fetch("data") pane = data.fetch("created").find { |ref| ref.fetch("kind") == "pane" } sent = request.call(4, "tools/call", {name: "tmux_send", arguments: { target: pane, input: {type: "text", text: "literal;"}}}).fetch("structuredContent") Example.check(sent.fetch("data").fetch("completion") == "dispatch_only", "send claimed shell completion") target = pane if channel Example.check(File.stat(setup).mode & 0o777 == 0o600, "enrollment setup permissions differ") channel.puts(setup) Example.check(IO.select([channel], nil, nil, 0.5) && channel.gets == "ready\n", "shell enrollment was not acknowledged") target = pane.merge("id" => shell_pane.id) end script = 'printf "%s:%s" "$EXAMPLE_CONTEXT" "$TMUX_PANE"; printf "\\000\\377" >&2; exit 9' run = request.call(5, "tools/call", {name: "tmux_run", arguments: { target: target, script: script, stdout_limit: 128, stderr_limit: 2}}).fetch("structuredContent") if channel Example.check(run.fetch("ok"), "installed authored run failed") result = run.fetch("data") Example.check(result.fetch("stdout").fetch("data") == "installed:#{shell_pane.id}", "authored shell context differs") Example.check(result.fetch("stderr") == {"encoding" => "base64", "data" => "AP8=", "bytes" => 2, "truncated" => false}, "authored bytes differ") Example.check(result.fetch("completion") == {"state" => "exited", "exit_status" => 9, "signal" => nil}, "native completion differs") Example.check(result.fetch("authorization").fetch("state") == "authorized", "authorization receipt missing") else Example.check(run.dig("error", "code") == "unsupported" && run.dig("error", "delivery") == "not_sent", "unsupported enrollment did not refuse") end closed = request.call(6, "tools/call", {name: "tmux_close", arguments: {target: data.fetch("entity")}}) Example.check(closed.fetch("structuredContent").fetch("ok"), "protocol close failed") input.close Example.check(process.join(0.5), "MCP EOF did not retire its process") Example.check(process.value.success? && errors.read.empty?, "MCP executable failed") Example.check(!File.exist?(setup), "enrollment setup survived EOF") end ``` ## Workspace plan, load and failure [Complete workspace program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/workspace_apply.rb) consumes the [checked configuration](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/workspace.yaml), applies it, then verifies partial failure and guarded compensation when another layout exceeds available pane space. It also runs installed CLI validation, planning and loading. ```ruby workspace = LibTmux::Workspace.load(File.join(__dir__, "workspace.yaml")) plan = workspace.plan(snapshot: server.snapshot) Example.check(server.list_sessions.size == 1, "planning changed tmux") result = plan.apply(server: server) Example.check(result.success?, "workspace apply failed") Example.check(result.effects.any? { |effect| effect.outcome == :dispatch_only }, "shell dispatch overclaims completion") crowded = LibTmux::Workspace.parse(JSON.generate({ session_name: "crowded", windows: [{window_name: "small", panes: Array.new(40) { {} }}] }), format: :json, base_directory: __dir__) error = Example.raises(LibTmux::Workspace::ApplyError) do crowded.plan.apply(server: server, compensate: true) end Example.check(!error.result.created_refs.empty?, "failure lost partial creation ledger") Example.check(error.result.compensation == :completed, "owned compensation failed") Example.check(server.list_sessions.map(&:ref).include?(borrowed.ref), "borrowed session was removed") ``` --- # Ruby MCP examples Source: https://libtmux.org/en/ruby/latest/mcp/examples/ > Run complete Ruby programs for an MCP client or an embedded application. Both examples include their complete program, pinned dependencies, run commands, expected results, and cleanup. Each creates its own tmux daemon. ## Default read-only catalog The [client guide](https://libtmux.org/en/ruby/latest/mcp/guides/connect-client/#configure-a-client) generates an MCP configuration using the launcher's absolute path and the current Ruby executable. Its default catalog contains `tmux_capabilities` and `tmux_snapshot`. Listing the tools and querying the example session verifies the connection. The [embedded example](https://libtmux.org/en/ruby/latest/mcp/examples/page-session-metadata/) calls those tools from Ruby inside an Async scope. It creates two sessions and prints their names by following a snapshot cursor. ## Add bounded observation For capture or waits in the client launcher, add `"--enable-tool", "tmux_capture"` or `"--enable-tool", "tmux_wait"` to the array passed to [`LibTmux::MCP::CLI.run`]() in `run-mcp.rb`. Adding them to the generated client configuration's arguments has no effect: the launcher does not forward those arguments. Enable creation, input, close, or authored execution only when the client needs those effects. The [guides overview](https://libtmux.org/en/ruby/latest/mcp/guides/#enable-observation) explains the tool choices; the [source-owned guide](https://libtmux.org/en/ruby/latest/mcp/source-guide/) gives their lifecycle contracts. - [Page session metadata](https://libtmux.org/en/ruby/latest/mcp/examples/page-session-metadata/): Embed the MCP application, page two session names from one capture, and close owned resources. - [Launch a client server](https://libtmux.org/en/ruby/latest/mcp/guides/connect-client/): Run a stdio MCP server with a private tmux daemon and a generated client configuration. --- # Rust MCP examples Source: https://libtmux.org/en/rs/latest/mcp/examples/ > Run a complete Rust client and inspect structured session metadata over MCP. The [session example](https://libtmux.org/en/rs/latest/mcp/examples/inspect-sessions/) includes the complete Cargo project, program, setup commands, and expected output. It creates its own tmux server. The [connection guide](https://libtmux.org/en/rs/latest/mcp/guides/connect-client/) configures an existing MCP client to launch the executable instead. ## List sessions Send this `params` object through a connected client's MCP `tools/call` method: ```json { "name": "list_sessions", "arguments": {} } ``` Check whether the result reports a tool error before reading its structured content. Use the returned IDs to choose a window or pane. The [list_sessions reference](https://libtmux.org/en/rs/latest/mcp/tools/list_sessions/) describes the result. ## Internals The complete example embeds both protocol endpoints in one Rust process. They exchange JSON-RPC over an in-memory stream and perform normal tool discovery. An installed MCP client is not needed to run it. ### Choose tools in Rust The example supplies the `inspect` selection to the embedded server. It checks that discovery contains the session-listing tool and excludes pane input. The [selection topic](https://libtmux.org/en/rs/latest/mcp/topics/tool-selection/) describes other combinations. ### Run the program Follow the [complete setup](https://libtmux.org/en/rs/latest/mcp/examples/inspect-sessions/#run-the-example) in a fresh directory. The program prints both session names, closes the protocol endpoints, stops its tmux daemon, and verifies that the socket has closed. Operation and cleanup errors both produce a failing exit status. - [List sessions through MCP](https://libtmux.org/en/rs/latest/mcp/examples/inspect-sessions/): Run an embedded client and server against a private tmux daemon, then close owned resources. - [Connect an MCP client](https://libtmux.org/en/rs/latest/mcp/guides/connect-client/): Install the executable and configure a client to launch it. --- # Build a workspace from a file Source: https://libtmux.org/en/tmux/examples/workspace-from-file/ > Create tmux windows and panes from a command file on a private server. A tmux command file can create a session, arrange its windows, and split its panes. This example builds two windows with three panes, prints their names and pane counts, then removes its private server. It requires tmux 3.2 or newer and a POSIX shell. ## Define the layout Save this command file: ```text title="workspace.conf" new-session -d -s dev -n editor -x 100 -y 30 'sh' split-window -h -t '=dev:editor' 'sh' new-window -t '=dev' -n logs 'sh' select-window -t '=dev:editor' select-pane -t '=dev:editor.0' ``` The `editor` window has two panes; `logs` has one. Each pane starts `sh`. Explicit targets keep each command tied to the intended session and window. ## Build and inspect it Save this complete program as `workspace.sh` beside the configuration file: ```sh title="workspace.sh" ( set -eu directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-workspace.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - EXIT if [ -S "$socket" ] && ! tmux -S "$socket" kill-server; then printf '%s\n' "Cannot stop tmux; kept $directory." >&2 exit 1 fi rm -rf "$directory" || status=$? exit "$status" } trap cleanup EXIT trap 'exit 1' HUP INT TERM tmux -S "$socket" -f /dev/null start-server \; \ set-option -s exit-empty off tmux -S "$socket" source-file ./workspace.conf tmux -S "$socket" list-windows -t '=dev' \ -F '#{window_name}: #{window_panes} panes' ) ``` Run it from that directory: ```console $ sh workspace.sh ``` The result is: ```text editor: 2 panes logs: 1 panes ``` `source-file` executes the configuration on the private server. Setting `exit-empty` to `off` keeps that server available for cleanup even when a configuration error prevents session creation. Errors remain visible and make the program fail. Cleanup runs after partial creation too; if stopping tmux fails, the script keeps the socket directory and reports its location. ## Use a workspace manager For YAML or JSON configuration, validation, and language APIs, choose a port: [Python CLI](https://libtmux.org/en/py/latest/workspace/examples/) · [TypeScript](https://libtmux.org/en/ts/latest/workspace/internals/examples/) · [Go](https://libtmux.org/en/go/latest/workspace/internals/examples/) · [Rust](https://libtmux.org/en/rs/latest/workspace/internals/examples/) · [Java](https://libtmux.org/en/java/latest/workspace/internals/examples/) · [C#](https://libtmux.org/en/csharp/latest/workspace/internals/examples/) · [C++](https://libtmux.org/en/cxx/latest/workspace/internals/examples/) · [Swift](https://libtmux.org/en/swift/latest/workspace/internals/examples/) The [workspace concept guide](https://libtmux.org/en/tmux/concepts/workspaces/) explains configuration and ownership. The [capture example](https://libtmux.org/en/tmux/examples/capture-pane-output/) shows how to wait for pane output after sending a command. The [tmux manual source](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1) describes `source-file`, window targets, and `exit-empty`. --- # List sessions through MCP Source: https://libtmux.org/en/csharp/latest/mcp/examples/inspect-sessions/ > Start an inspection client, verify its tool selection, and read structured session metadata. This program starts a private tmux server, creates a session, and launches `libtmux-mcp` as a child process. It checks the offered tools and reads [`list_sessions`](https://libtmux.org/en/csharp/latest/mcp/tools/list_sessions/) through the official C# MCP client. The program stops its owned server when the request succeeds or fails. ## Run the example Use the .NET 10 SDK and tmux 3.2a or newer on Linux, macOS, or WSL. The project pins the library and tool to the same published alpha release. The package source is [libtmux-dotnet at the documented release](https://github.com/libtmux/libtmux-dotnet/tree/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc). Create an empty directory: ```console $ mkdir inspect-mcp-sessions ``` ```console $ cd inspect-mcp-sessions ``` Install the MCP executable into that directory: ```console $ dotnet tool install \ --tool-path .tools \ --version 0.0.0-alpha.20 \ LibTmux.Mcp ``` Save the project file: ```xml title="McpExample.csproj" Exe net10.0 enable enable ``` ### Client program Save this as `Program.cs`: ```csharp title="Program.cs" using System.Text.Json; using LibTmux; using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; if (OperatingSystem.IsWindows()) { throw new PlatformNotSupportedException("Use Linux, macOS, or WSL with tmux."); } using CancellationTokenSource deadline = new(TimeSpan.FromSeconds(30)); CancellationToken token = deadline.Token; DirectoryInfo directory = Directory.CreateTempSubdirectory("libtmux-mcp-"); string socket = Path.Combine(directory.FullName, "tmux.sock"); Console.Error.WriteLine($"Private socket: {socket}"); OwnedServerScope? owned = null; McpClient? client = null; List failures = []; bool stopped = false; try { ServerConnectionOptions options = new() { SocketPath = socket, ConfigurationFile = "/dev/null", }; owned = await Server.CreateOwnedAsync(options, token); await owned.Value.CreateSessionAsync( new NewSessionRequest { Name = "docs-demo", Command = "/bin/cat" }, token); Dictionary environment = StdioClientTransportOptions.GetDefaultEnvironmentVariables(); environment["DOTNET_ROOT"] = Environment.GetEnvironmentVariable("DOTNET_ROOT"); environment["LIBTMUX_SOCKET_PATH"] = socket; environment["LIBTMUX_TOOLSETS"] = "inspect"; StdioClientTransport transport = new(new StdioClientTransportOptions { Name = "tmux", Command = Path.GetFullPath(".tools/libtmux-mcp"), InheritEnvironmentVariables = false, EnvironmentVariables = environment, ShutdownTimeout = TimeSpan.FromSeconds(5), }); client = await McpClient.CreateAsync(transport, cancellationToken: token); var tools = await client.ListToolsAsync(cancellationToken: token); if (!tools.Any(tool => tool.Name == "list_sessions") || tools.Any(tool => tool.Name == "run_shell_command")) { throw new InvalidOperationException("Unexpected tool selection."); } ReadResourceResult resource = await client.ReadResourceAsync( "tmux://capabilities", cancellationToken: token); TextResourceContents text = (TextResourceContents)resource.Contents.Single(); using JsonDocument capabilities = JsonDocument.Parse(text.Text); string?[] selection = capabilities.RootElement.GetProperty("toolsets") .EnumerateArray().Select(value => value.GetString()).ToArray(); if (!selection.SequenceEqual(new[] { "inspect" })) { throw new InvalidOperationException("Unexpected capability report."); } Console.WriteLine("Tool selection: inspect"); CallToolResult result = await client.CallToolAsync( "list_sessions", cancellationToken: token); if (result.IsError == true || result.StructuredContent is not JsonElement data) { throw new InvalidOperationException(JsonSerializer.Serialize(result)); } JsonElement session = data.EnumerateArray().Single(); string? name = session.GetProperty("name").GetString(); int windows = session.GetProperty("windowCount").GetInt32(); if (name != "docs-demo" || windows != 1) { throw new InvalidOperationException("Unexpected session metadata."); } Console.WriteLine($"Session: {name} ({windows} window)"); } catch (Exception error) { failures.Add(error); } if (client is not null) { try { await client.DisposeAsync(); } catch (Exception error) { failures.Add(new IOException("MCP client cleanup failed.", error)); } } if (owned is not null) { try { await owned.DisposeAsync(); stopped = true; } catch (Exception error) { failures.Add(new IOException("Owned server cleanup failed.", error)); } } if (stopped) { try { directory.Delete(recursive: true); } catch (Exception error) { failures.Add(new IOException("Temporary directory cleanup failed.", error)); } } else { Console.Error.WriteLine($"Retained directory: {directory.FullName}"); } if (failures.Count != 0) { throw new AggregateException(failures); } Console.WriteLine("Owned server stopped."); ``` Run it from the directory containing both files and `.tools`: ```console $ dotnet run --project McpExample.csproj --no-launch-profile ``` The program prints its private socket path to stderr. Its stdout is: ```text Tool selection: inspect Session: docs-demo (1 window) Owned server stopped. ``` ## Read the result The client connects and discovers tools before making a request. It verifies that `list_sessions` is offered and `run_shell_command` is absent, then checks the frozen selection reported by `tmux://capabilities`. A successful protocol exchange can still contain a tool error. Check [`IsError`](https://csharp.sdk.modelcontextprotocol.io/v2/api/ModelContextProtocol.Protocol.CallToolResult.html#ModelContextProtocol_Protocol_CallToolResult_IsError) before reading [`StructuredContent`](https://csharp.sdk.modelcontextprotocol.io/v2/api/ModelContextProtocol.Protocol.CallToolResult.html#ModelContextProtocol_Protocol_CallToolResult_StructuredContent). Here, structured content is an array of session records. The example checks the created session's name and window count. It reads metadata without capturing terminal output or sending input through MCP. The result shape follows the negotiated protocol. For versions before 2026-07-28, the SDK server [wraps the array in a `result` property](https://github.com/modelcontextprotocol/csharp-sdk/blob/6fa3825973949a9c4f0cd8af344e15a8db09dc35/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs#L528-L535). Use the tool's advertised output schema when writing a different client. The client passes the SDK's ordinary launch environment plus its explicit socket and tool selection. It does not inherit an interactive shell's `TMUX`, `TMUX_PANE`, or other `LIBTMUX_*` settings. `DOTNET_ROOT` is carried over when the runtime installation needs it. ## Shutdown Startup and requests share a 30-second deadline. Closing the MCP client gives its child process five seconds to exit before the SDK terminates it. Closing the owned server uses a separate cleanup deadline, so an expired request token does not skip daemon cleanup. The program attempts both cleanups and reports their failures alongside any request error. It removes the temporary directory only after owned-server cleanup succeeds. If ownership was not established or server cleanup fails, it prints the retained directory for inspection. The [connection guide](https://libtmux.org/en/csharp/latest/mcp/guides/) covers connecting to an existing server. The [tool reference](https://libtmux.org/en/csharp/latest/mcp/tools/list_sessions/) describes the session fields, and the [owned-server implementation](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux/Server.Lifecycle.cs) defines daemon ownership and cleanup. --- # List sessions through MCP Source: https://libtmux.org/en/go/latest/mcp/examples/inspect-sessions/ > Start a private tmux server and read its session metadata through a complete Go SDK client. This program creates a private tmux session, launches `libtmux-mcp` as a child process with the `inspect` toolset, and calls [`list_sessions`](https://libtmux.org/en/go/latest/mcp/tools/list_sessions/). It checks the returned session ID against the session it created, then closes the client and stops its server. ## Run the example Use Go 1.26 or newer and tmux 3.2a or newer on Linux, macOS, or WSL. The project pins the [core library](https://github.com/libtmux/libtmux-go/tree/3f6f99dd41f077aaac2fa18acf7c82d99f58c7cd) and [MCP executable](https://github.com/libtmux/libtmux-go/tree/6e7420927f4cb717fe089a710328e44e8d551025/mcp) to their published releases. The client uses the official Go MCP SDK. Create an empty directory: ```console $ mkdir inspect-mcp-sessions ``` Enter it: ```console $ cd inspect-mcp-sessions ``` Install the MCP executable inside the project: ```console $ GOBIN="$PWD/.tools" go install \ github.com/libtmux/libtmux-go/mcp/cmd/libtmux-mcp@v0.0.1-alpha.12 ``` Save the module file: ```go title="go.mod" module example.com/session-inspector go 1.26.0 require ( github.com/libtmux/libtmux-go v0.0.1-alpha.9 github.com/modelcontextprotocol/go-sdk v1.6.1 ) require ( github.com/google/jsonschema-go v0.4.3 // indirect github.com/segmentio/asm v1.1.3 // indirect github.com/segmentio/encoding v0.5.4 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect golang.org/x/oauth2 v0.35.0 // indirect golang.org/x/sys v0.41.0 // indirect ) ``` ### Client program Save this as `main.go`: ```go title="main.go" package main import ( "context" "encoding/json" "errors" "fmt" "os" "os/exec" "path/filepath" "time" "github.com/libtmux/libtmux-go/tmux" sdk "github.com/modelcontextprotocol/go-sdk/mcp" ) func main() { if err := run(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func run() (result error) { directory, err := os.MkdirTemp("", "libtmux-go-mcp-") if err != nil { return err } server, err := tmux.NewServer(tmux.ServerOptions{ SocketPath: filepath.Join(directory, "tmux.sock"), ConfigFile: "/dev/null", }) if err != nil { return errors.Join(err, os.RemoveAll(directory)) } defer func() { cleanup, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := server.Kill(cleanup); err != nil { result = errors.Join(result, fmt.Errorf( "stop tmux; resources retained at %s: %w", directory, err, )) return } result = errors.Join(result, os.RemoveAll(directory)) }() ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() created, err := server.NewSession(ctx, tmux.NewSessionRequest{ Name: "demo", Command: "sh", }) if err != nil { return err } binary, err := filepath.Abs(".tools/libtmux-mcp") if err != nil { return err } command := exec.Command(binary, "-socket-path", server.SocketPath(), "-binary", server.Executable(), ) command.Stderr = os.Stderr command.Env = []string{ "PATH=" + os.Getenv("PATH"), "HOME=" + os.Getenv("HOME"), "LANG=C.UTF-8", "TMPDIR=" + directory, "LIBTMUX_TOOLSETS=inspect", } client := sdk.NewClient(&sdk.Implementation{ Name: "session-inspector", Version: "1.0.0", }, nil) connection, err := client.Connect(ctx, &sdk.CommandTransport{ Command: command, TerminateDuration: 3 * time.Second, }, nil) if err != nil { return fmt.Errorf("connect MCP client: %w", err) } defer func() { if err := connection.Close(); err != nil { result = errors.Join(result, fmt.Errorf("close MCP client: %w", err)) } }() reply, err := connection.CallTool(ctx, &sdk.CallToolParams{ Name: "list_sessions", Arguments: map[string]any{}, }) if err != nil { return fmt.Errorf("call list_sessions: %w", err) } if reply.IsError { for _, content := range reply.Content { if text, ok := content.(*sdk.TextContent); ok { return fmt.Errorf("list_sessions: %s", text.Text) } } return errors.New("list_sessions failed without a text explanation") } data, err := json.Marshal(reply.StructuredContent) if err != nil { return err } var listed struct { Sessions []struct { ID string `json:"id"` Name string `json:"name"` Windows int `json:"windows"` Attached int `json:"attached"` } `json:"sessions"` } if err := json.Unmarshal(data, &listed); err != nil { return fmt.Errorf("decode sessions: %w", err) } if len(listed.Sessions) != 1 || listed.Sessions[0].ID != string(created.ID()) { return fmt.Errorf("unexpected session listing: %s", data) } session := listed.Sessions[0] fmt.Printf("%s: %d window(s), %d attached client(s)\n", session.Name, session.Windows, session.Attached, ) return nil } ``` Resolve the module dependencies: ```console $ go mod tidy ``` Run the program from the directory containing both files and `.tools`: ```console $ go run . ``` Its stdout is: ```text demo: 1 window(s), 0 attached client(s) ``` ## Read the result [`tmux.NewServer`](https://libtmux.org/en/go/latest/reference/tmux-newserver/) configures the private endpoint, and [`Server.NewSession`](https://libtmux.org/en/go/latest/reference/tmux-server-newsession/) starts the daemon with an empty tmux configuration. The MCP child connects to that exact socket using the same tmux executable. The SDK's [`CallTool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk@v1.6.1/mcp#ClientSession.CallTool) can return a protocol error before there is a tool result. A returned reply can also set [`IsError`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk@v1.6.1/mcp#CallToolResult); the program checks both before reading [`StructuredContent`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk@v1.6.1/mcp#CallToolResult). For this tool, structured content contains a `sessions` array with `id`, `name`, `windows`, and `attached` fields. The example decodes only the fields it needs and verifies that exactly one session is returned with the expected ID. It does not assume that the first item belongs to it. See the [tool reference](https://libtmux.org/en/go/latest/mcp/tools/list_sessions/) for all returned fields and the [session-list handler](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/orientation_tools.go) for the selected release's implementation. ## Shutdown Startup and requests share a 20-second context. During shutdown, the client closes the child's stdin, then escalates to SIGTERM and SIGKILL if needed. It waits up to three seconds after each step. Deferred cleanup closes the client before stopping the owned tmux server with a fresh five-second context, so an expired request context does not skip daemon cleanup. The child receives a curated environment with the selected socket and tmux binary. Its temporary files live under the program's owned directory through `TMPDIR`. It does not inherit `TMUX`, `TMUX_PANE`, or unrelated `LIBTMUX_*` settings from your interactive shell. The program joins operation and cleanup errors. It removes its temporary directory only after [`Server.Kill`](https://libtmux.org/en/go/latest/reference/tmux-server-kill/) succeeds; otherwise, it prints the retained directory for inspection. Its [server cleanup implementation](https://github.com/libtmux/libtmux-go/blob/3f6f99dd41f077aaac2fa18acf7c82d99f58c7cd/tmux/lifecycle_kill.go) defines the library's kill behavior. The [connection guide](https://libtmux.org/en/go/latest/mcp/guides/connect-client/) covers connecting to an existing server instead. The example's cleanup is appropriate because it creates its own private socket and session. --- # List sessions through MCP Source: https://libtmux.org/en/rs/latest/mcp/examples/inspect-sessions/ > Connect a Rust MCP client to an inspection server and read structured session metadata. This program connects an `rmcp` client to an embedded `tmux-mcp` server. It discovers the tools, calls [list_sessions](https://libtmux.org/en/rs/latest/mcp/tools/list_sessions/), and reads the session names from structured content. It creates a private tmux server with two sessions running `cat`, then stops that server before exiting. The socket lives in a temporary directory under `/tmp/libtmux-rs-dev/`; the program does not select a server from your shell's `TMUX` variable or load your tmux configuration. ## Run the example Use Git, Rust 1.97.1, and tmux 3.2a or newer on Linux or macOS. Both libtmux crates below use the source revision documented by the MCP reference. The example was run on Linux with tmux 3.2a and 3.7c. Create a directory for the program: ```console $ mkdir inspect-mcp-sessions ``` ```console $ cd inspect-mcp-sessions ``` ```console $ mkdir src ``` Save this as `Cargo.toml`: ```toml title="Cargo.toml" [package] name = "inspect-mcp-sessions" version = "0.1.0" edition = "2024" publish = false [dependencies] libtmux = { git = "https://github.com/libtmux/libtmux-rs", rev = "a6fc2a65674177b92b17fa380757155d2ba150fd" } tmux-mcp = { git = "https://github.com/libtmux/libtmux-rs", rev = "a6fc2a65674177b92b17fa380757155d2ba150fd" } rmcp = { version = "=3.1.2", features = ["client", "server", "transport-io"] } serde_json = "=1.0.151" tempfile = "=3.27.0" tokio = { version = "=1.53.1", features = ["io-util", "macros", "net", "rt-multi-thread", "time"] } ``` Save this as `src/main.rs`: ```rust title="src/main.rs" use std::error::Error; use std::io::ErrorKind; use std::path::Path; use std::time::Duration; use libtmux::{NewSessionOptions, Server}; use rmcp::model::CallToolRequestParams; use rmcp::service::QuitReason; use rmcp::{Peer, RoleClient, ServiceExt as _}; use tmux_mcp::{Selection, TmuxTools}; use tokio::time::timeout; type ExampleError = Box; fn check(condition: bool, message: &str) -> Result<(), ExampleError> { if condition { Ok(()) } else { Err(message.into()) } } async fn inspect(client: &Peer) -> Result<(), ExampleError> { let offered = client.list_all_tools().await?; check( offered.iter().any(|tool| tool.name == "list_sessions"), "list_sessions was not offered", )?; check( !offered.iter().any(|tool| tool.name == "send_keys"), "send_keys was offered by the inspection server", )?; let result = client .call_tool(CallToolRequestParams::new("list_sessions").with_arguments(Default::default())) .await?; if result.is_error == Some(true) { return Err(format!("list_sessions failed: {}", serde_json::to_string(&result)?).into()); } let data = result .structured_content .ok_or("list_sessions returned no structured content")?; let sessions = data["sessions"] .as_array() .ok_or("structured content has no sessions array")?; let mut names = Vec::new(); for session in sessions { names.push(session["name"].as_str().ok_or("session has no name")?); check( session["id"].as_str().is_some_and(|id| id.starts_with('$')), "session has no tmux ID", )?; } names.sort_unstable(); check(names == ["build", "editor"], "unexpected session list")?; for name in names { println!("session: {name}"); } Ok(()) } fn record_close( label: &str, result: Result, tokio::task::JoinError>, failures: &mut Vec, ) { match result { Ok(Some(QuitReason::Cancelled | QuitReason::Closed)) => {} Ok(Some(reason)) => failures.push(format!("{label}: {reason:?}")), Ok(None) => failures.push(format!("{label}: cleanup deadline exceeded")), Err(error) => failures.push(format!("{label}: {error}")), } } async fn exchange(server: &Server) -> Result<(), ExampleError> { let tools = TmuxTools::builder(server.clone()) .caller(None) .selection(Selection::parse(Some("inspect"), None, None)?) .build(); let (client_io, server_io) = tokio::io::duplex(1 << 20); let startup = async { tokio::try_join!( async { ().serve(client_io).await.map_err(ExampleError::from) }, async { tools.serve(server_io).await.map_err(ExampleError::from) }, ) }; let (mut client, mut service) = timeout(Duration::from_secs(5), startup).await??; let outcome = timeout(Duration::from_secs(10), inspect(client.peer())).await; let mut failures = Vec::new(); match outcome { Ok(Ok(())) => {} Ok(Err(error)) => failures.push(format!("MCP request: {error}")), Err(error) => failures.push(format!("MCP request deadline: {error}")), } record_close( "MCP client cleanup", client.close_with_timeout(Duration::from_secs(5)).await, &mut failures, ); record_close( "MCP server cleanup", service.close_with_timeout(Duration::from_secs(5)).await, &mut failures, ); if failures.is_empty() { Ok(()) } else { Err(failures.join("; ").into()) } } async fn demonstrate(server: &Server) -> Result<(), ExampleError> { for name in ["build", "editor"] { server .new_session(NewSessionOptions::new(name).command("cat")) .await?; } exchange(server).await } async fn wait_until_stopped(socket: &Path) -> Result<(), ExampleError> { loop { match tokio::net::UnixStream::connect(socket).await { Ok(_) => tokio::time::sleep(Duration::from_millis(20)).await, Err(error) if matches!( error.kind(), ErrorKind::NotFound | ErrorKind::ConnectionRefused ) => { return Ok(()); } Err(error) => return Err(error.into()), } } } #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), ExampleError> { let root = std::path::Path::new("/tmp/libtmux-rs-dev"); std::fs::create_dir_all(root)?; let directory = tempfile::Builder::new() .prefix("mcp-sessions-") .tempdir_in(root)?; std::fs::write( directory.path().join("owner"), std::process::id().to_string(), )?; let socket = directory.path().join("tmux.sock"); let server = Server::builder() .socket_path(&socket) .config_file("/dev/null") .default_timeout(Duration::from_secs(5)) .build()?; eprintln!("owned socket: {}", socket.display()); let outcome = demonstrate(&server).await; // Stop the owned daemon before closing its command executor. let killed = server.kill().await; let stopped = timeout(Duration::from_secs(5), wait_until_stopped(&socket)).await; let closed = timeout(Duration::from_secs(5), server.shutdown()).await; let cleanup_failed = killed.is_err() || !matches!(&stopped, Ok(Ok(()))) || !matches!(&closed, Ok(Ok(()))); let mut failures = Vec::new(); if let Err(error) = outcome { failures.push(format!("example: {error}")); } if let Err(error) = killed { failures.push(format!("daemon cleanup: {error}")); } match stopped { Ok(Ok(())) => {} Ok(Err(error)) => failures.push(format!("daemon cleanup verification: {error}")), Err(error) => failures.push(format!("daemon cleanup verification deadline: {error}")), } match closed { Ok(Ok(())) => {} Ok(Err(error)) => failures.push(format!("executor cleanup: {error}")), Err(error) => failures.push(format!("executor cleanup deadline: {error}")), } if cleanup_failed { let retained = directory.keep(); failures.push(format!("inspect retained directory {}", retained.display())); } else if let Err(error) = directory.close() { failures.push(format!("directory cleanup: {error}")); } if failures.is_empty() { Ok(()) } else { Err(failures.join("; ").into()) } } ``` Resolve the dependencies, then run the program: ```console $ cargo +1.97.1 generate-lockfile ``` ```console $ cargo +1.97.1 run --locked --quiet ``` Keep `Cargo.lock` with the program to retain the resolved transitive versions. The program prints the private socket path to stderr. Its stdout is: ```text session: build session: editor ``` ## Read the result The two protocol endpoints exchange JSON-RPC over an in-memory byte stream. They perform the MCP handshake and tool discovery before the call. The server offers `inspect`; the program checks that discovery contains [`list_sessions`]() and excludes [`send_keys`](). A completed protocol request can still report a tool failure. The program checks `isError` before reading `structuredContent`, then verifies the returned names and tmux IDs. It reads metadata; it does not capture pane output or send input through MCP. The embedded server receives its selection in code. The [client connection guide](https://libtmux.org/en/rs/latest/mcp/guides/connect-client/) covers a separate MCP process launched from a client's configuration, and [Tool selection](https://libtmux.org/en/rs/latest/mcp/topics/tool-selection/) explains the available groups. ## Shutdown Handshake and request waits have deadlines. The program closes both MCP endpoints after a successful or failed request, then stops its owned tmux daemon, waits for its Unix socket to close, and shuts down the libtmux command executor. It reports operation and cleanup failures together. If daemon or executor cleanup fails, or the socket still accepts connections at the deadline, it retains the temporary directory and prints its path for inspection. The program exits with an error. --- # Page session metadata from Ruby Source: https://libtmux.org/en/ruby/latest/mcp/examples/page-session-metadata/ > Embed the Ruby MCP application, read a retained session listing, and close its owned resources. Use the MCP application directly when a Ruby host needs the same tool policy and result envelopes as its MCP clients. This complete example creates two sessions, selects one row per page, and prints both names from one retained metadata capture. It calls the application in process. For a client that launches a stdio server, use the [client guide](https://libtmux.org/en/ruby/latest/mcp/guides/connect-client/). ## Prepare the project Use Ruby 4.0.7 with its development headers, Bundler, Git, a C compiler and Make, and tmux 3.2a or newer on a Unix host. The locked bundle includes native extensions. Start with an empty directory: ```console $ mkdir ruby-mcp-pages && cd ruby-mcp-pages ``` Fetch the source: ```console $ git clone https://github.com/libtmux/libtmux-ruby libtmux-source ``` Select the documented revision: ```console $ git -C libtmux-source checkout 9b1545562a112353c2c893a1d3e8c0d9b4b51f8d ``` Install the locked dependencies: ```console $ BUNDLE_FROZEN=true BUNDLE_GEMFILE=./libtmux-source/Gemfile bundle install ``` ## Run the complete example Save this file beside the source checkout: ```ruby title="snapshot-sessions.rb" # frozen_string_literal: true ENV["BUNDLE_GEMFILE"] = File.expand_path("libtmux-source/Gemfile", __dir__) require "bundler/setup" require "libtmux/mcp" def describe_failure(error) details = ["#{error.class}: #{error.message}"] if error.is_a?(LibTmux::Error) details.concat(error.cleanup_errors.map { |message| "Cleanup: #{message}" }) end if error.respond_to?(:async_cleanup_errors) details.concat(error.async_cleanup_errors.map { |message| "Cleanup: #{message}" }) end details.join("\n") end def tool_data(application, name, arguments = {}) result = application.call(name, arguments).structured_content return result.fetch("data") if result.fetch("ok") error = result.fetch("error") raise "#{name}: #{error.fetch('code')} (#{error.fetch('delivery')}): " \ "#{error.fetch('message')}" end server = nil failures = [] begin server = LibTmux::Server.start(timeout: 5.0) %w[build editor].each do |name| server.new_session(name: name, command: ["/bin/cat"], timeout: 5.0) end Async do |parent| LibTmux::Async.open(parent: parent, server: server) do |scope| application = nil begin application = LibTmux::MCP::Application.new( server: scope.server, endpoint_name: "example", request_timeout: 5.0 ) capabilities = tool_data(application, "tmux_capabilities") puts "Endpoint: #{capabilities.fetch('endpoint')}" page = tool_data( application, "tmux_snapshot", {entity: "session", limit: 1} ) loop do page.fetch("items").each do |item| puts item.fetch("fields").fetch("name") end break unless page.fetch("truncated") page = tool_data( application, "tmux_snapshot", {cursor: page.fetch("next_cursor")} ) end ensure begin application&.close rescue StandardError => error failures << "MCP cleanup failed: #{describe_failure(error)}" end end end end.wait rescue StandardError => error failures << describe_failure(error) ensure begin server&.close rescue StandardError => error failures << "Server cleanup failed: #{describe_failure(error)}" end end abort failures.join("\n") unless failures.empty? ``` Run it with tmux available on `PATH`: ```console $ ruby -W:no-experimental snapshot-sessions.rb ``` Expected output: ```text Endpoint: example build editor ``` The Ruby option suppresses the experimental [`IO::Buffer`](https://docs.ruby-lang.org/en/4.0/IO/Buffer.html) warning. It does not suppress operation or cleanup errors. A failure produces a nonzero exit and diagnostics on stderr; earlier stdout may contain partial results. ## Pagination [`Application`]() requires a [`LibTmux::Async::Server`]() facade inside its owning Async scheduler. [`LibTmux::Async.open`]() supplies that facade and closes the scope after the block. The application and its calls stay in the same scheduler throughout the example. The first `tmux_snapshot` call selects session metadata with a page limit of one. A continuation sends only the returned `next_cursor`. It keeps the same capture and selection; it does not relist sessions. The private daemon has two sessions, so this example receives two pages. `truncated: false` ends the loop. Every call checks the application's `structured_content` envelope before using `"data"`. Tool failures include a code, delivery state, and message. A missing or expired cursor is an error to handle, not an instruction to silently restart the listing. The [snapshot topic](https://libtmux.org/en/ruby/latest/mcp/topics/snapshots-and-references/) explains cursor lifetime, capacity, and reference identity. ## Resource ownership `Server.start` creates a private socket directory and foreground tmux daemon with an empty configuration. The program creates its own `build` and `editor` sessions running `cat`; no existing socket, session, or pane is required. The MCP application uses its default capability and snapshot tools. The two sessions are ordinary Ruby API setup, not mutations admitted through the MCP tool policy. Embedding the application does not constrain what other Ruby code in the host can do. Startup and each session creation have separate five-second deadlines. The application uses `request_timeout: 5.0` for metadata acquisition during capability discovery and fresh snapshot calls. Continuations read retained data. Shutdown first closes the application, then its Async scope, then the owned daemon. Each cleanup attempt still runs if an earlier operation or cleanup fails, and the program reports the collected errors. The [pinned application implementation](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/application.rb) and [Async scope](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-async/lib/libtmux/async.rb) define these ownership and request contracts. --- # Run a command through MCP Source: https://libtmux.org/en/go/latest/mcp/examples/run-command/ > Use a complete Go SDK client to check command completion, exit status, and captured output. This program creates a private session, selects its active pane, and exposes only [`run_shell_command`](https://libtmux.org/en/go/latest/mcp/tools/run_shell_command/) to the MCP client. The shell command prints one line and deliberately exits with status 7. The client checks completion and output before reporting the result. ## Run the example Use Go 1.26 or newer and tmux 3.2a or newer on Linux, macOS, or WSL. The project pins the [core library](https://github.com/libtmux/libtmux-go/tree/3f6f99dd41f077aaac2fa18acf7c82d99f58c7cd) and [MCP executable](https://github.com/libtmux/libtmux-go/tree/6e7420927f4cb717fe089a710328e44e8d551025/mcp) to their published releases. The client uses the official Go MCP SDK. Create an empty directory: ```console $ mkdir run-mcp-command ``` Enter it: ```console $ cd run-mcp-command ``` Install the MCP executable inside the project: ```console $ GOBIN="$PWD/.tools" go install \ github.com/libtmux/libtmux-go/mcp/cmd/libtmux-mcp@v0.0.1-alpha.12 ``` Save the module file: ```go title="go.mod" module example.com/command-runner go 1.26.0 require ( github.com/libtmux/libtmux-go v0.0.1-alpha.9 github.com/modelcontextprotocol/go-sdk v1.6.1 ) require ( github.com/google/jsonschema-go v0.4.3 // indirect github.com/segmentio/asm v1.1.3 // indirect github.com/segmentio/encoding v0.5.4 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect golang.org/x/oauth2 v0.35.0 // indirect golang.org/x/sys v0.41.0 // indirect ) ``` ### Client program Save this as `main.go`: ```go title="main.go" package main import ( "context" "encoding/json" "errors" "fmt" "os" "os/exec" "path/filepath" "time" "github.com/libtmux/libtmux-go/tmux" sdk "github.com/modelcontextprotocol/go-sdk/mcp" ) func main() { if err := run(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func run() (result error) { directory, err := os.MkdirTemp("", "libtmux-go-command-") if err != nil { return err } server, err := tmux.NewServer(tmux.ServerOptions{ SocketPath: filepath.Join(directory, "tmux.sock"), ConfigFile: "/dev/null", }) if err != nil { return errors.Join(err, os.RemoveAll(directory)) } defer func() { cleanup, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := server.Kill(cleanup); err != nil { result = errors.Join(result, fmt.Errorf( "stop tmux; resources retained at %s: %w", directory, err, )) return } result = errors.Join(result, os.RemoveAll(directory)) }() ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() created, err := server.NewSession(ctx, tmux.NewSessionRequest{ Name: "demo", Command: "sh", }) if err != nil { return err } pane, err := created.ResolveActivePane(ctx) if err != nil { return err } binary, err := filepath.Abs(".tools/libtmux-mcp") if err != nil { return err } command := exec.Command(binary, "-socket-path", server.SocketPath(), "-binary", server.Executable(), ) command.Stderr = os.Stderr command.Env = []string{ "PATH=" + os.Getenv("PATH"), "HOME=" + os.Getenv("HOME"), "LANG=C.UTF-8", "TMPDIR=" + directory, "LIBTMUX_TOOLSETS=", "LIBTMUX_TOOLS=run_shell_command", } client := sdk.NewClient(&sdk.Implementation{ Name: "command-runner", Version: "1.0.0", }, nil) connection, err := client.Connect(ctx, &sdk.CommandTransport{ Command: command, TerminateDuration: 3 * time.Second, }, nil) if err != nil { return fmt.Errorf("connect MCP client: %w", err) } defer func() { if err := connection.Close(); err != nil { result = errors.Join(result, fmt.Errorf("close MCP client: %w", err)) } }() reply, err := connection.CallTool(ctx, &sdk.CallToolParams{ Name: "run_shell_command", Arguments: map[string]any{ "pane_id": string(pane.ID()), "command": "printf 'command finished\\n'; (exit 7)", "timeout": 5, "max_lines": 20, }, }) if err != nil { return fmt.Errorf("call run_shell_command: %w", err) } if reply.IsError { for _, content := range reply.Content { if text, ok := content.(*sdk.TextContent); ok { return fmt.Errorf("run_shell_command: %s", text.Text) } } return errors.New("run_shell_command failed without a text explanation") } data, err := json.Marshal(reply.StructuredContent) if err != nil { return err } var ran struct { PaneID string `json:"pane_id"` ResolvedPaneIDs []string `json:"resolved_pane_ids"` ExitStatus *int `json:"exit_status"` TimedOut bool `json:"timed_out"` Output []string `json:"output"` OutputUnavailable string `json:"output_unavailable"` LinesMissed bool `json:"lines_missed"` } if err := json.Unmarshal(data, &ran); err != nil { return fmt.Errorf("decode command result: %w", err) } if ran.TimedOut || ran.ExitStatus == nil { return errors.New("command completion is unconfirmed; do not retry it automatically") } if ran.PaneID != string(pane.ID()) || len(ran.ResolvedPaneIDs) != 1 || ran.ResolvedPaneIDs[0] != ran.PaneID { return fmt.Errorf("unexpected pane selection: %s", data) } if ran.OutputUnavailable != "" || ran.LinesMissed { return fmt.Errorf("command exited %d, but its output is incomplete: %s", *ran.ExitStatus, data) } fmt.Printf("exit status: %d\n", *ran.ExitStatus) for _, line := range ran.Output { fmt.Println(line) } return nil } ``` Resolve the module dependencies: ```console $ go mod tidy ``` Run the program from the directory containing both files and `.tools`: ```console $ go run . ``` Its stdout is: ```text exit status: 7 command finished ``` ## Check completion and output [`Session.ResolveActivePane`](https://libtmux.org/en/go/latest/reference/tmux-session-resolveactivepane/) supplies the pane ID. The request uses the public wire fields `pane_id`, `command`, `timeout`, and `max_lines`; the client checks that the reply names the same pane exactly once. A nonzero shell exit status is distinct from a tool error. The request here succeeds, completion is observed, and the shell's status is 7. A missing exit status or `timed_out` means completion is unconfirmed. The program reports an error instead of automatically sending the command again. It also rejects `output_unavailable` and `lines_missed`. A command can finish successfully while its terminal output is incomplete. The request retains at most the newest 20 lines. The public reply does not report whether that cap discarded earlier lines. Applications that retain partial output should display its bounds and limitations alongside it. See [Waits and output](https://libtmux.org/en/go/latest/mcp/topics/waits-and-output/) for timeout behavior and other observation tools. The [public command handler](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/capability_handlers.go) validates the request and constructs the snake_case reply. The client decodes that reply rather than depending on an internal Go result type. ## Shutdown Startup and requests share a 20-second context. During shutdown, the client closes the child's stdin, then escalates to SIGTERM and SIGKILL if needed. It waits up to three seconds after each step. Deferred cleanup closes the client before stopping the owned tmux server with a fresh five-second context, so an expired request context does not skip daemon cleanup. The child receives a curated environment with the selected socket and tmux binary. Its temporary files live under the program's owned directory through `TMPDIR`. It does not inherit `TMUX`, `TMUX_PANE`, or unrelated `LIBTMUX_*` settings from your interactive shell. The program joins operation and cleanup errors. It removes its temporary directory only after [`Server.Kill`](https://libtmux.org/en/go/latest/reference/tmux-server-kill/) succeeds; otherwise, it prints the retained directory for inspection. Its [server cleanup implementation](https://github.com/libtmux/libtmux-go/blob/3f6f99dd41f077aaac2fa18acf7c82d99f58c7cd/tmux/lifecycle_kill.go) defines the library's kill behavior. The [connection guide](https://libtmux.org/en/go/latest/mcp/guides/connect-client/) covers connecting to an existing server instead. The example's cleanup is appropriate because it creates its own private socket and session. --- # Run a command through MCP Source: https://libtmux.org/en/csharp/latest/mcp/examples/run-command/ > Discover a pane, run a bounded shell command, and check its exit status and captured output. This program creates a private shell pane and discovers its ID through [`list_panes`](https://libtmux.org/en/csharp/latest/mcp/tools/list_panes/). It calls [`run_shell_command`](https://libtmux.org/en/csharp/latest/mcp/tools/run_shell_command/), checks the shell exit status, and verifies that the captured output contains the expected line. The program owns the tmux server it creates and attempts cleanup after both successful and failed requests. It does not select a pane from your existing sessions. ## Run the example Use the .NET 10 SDK and tmux 3.2a or newer on Linux, macOS, or WSL. The library and tool use the same [published source revision](https://github.com/libtmux/libtmux-dotnet/tree/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc). Create an empty directory: ```console $ mkdir run-mcp-command ``` ```console $ cd run-mcp-command ``` Install the MCP executable into that directory: ```console $ dotnet tool install \ --tool-path .tools \ --version 0.0.0-alpha.20 \ LibTmux.Mcp ``` Save the project file: ```xml title="McpExample.csproj" Exe net10.0 enable enable ``` ### Client program Save this as `Program.cs`: ```csharp title="Program.cs" using System.Text.Json; using LibTmux; using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; if (OperatingSystem.IsWindows()) { throw new PlatformNotSupportedException("Use Linux, macOS, or WSL with tmux."); } using CancellationTokenSource deadline = new(TimeSpan.FromSeconds(30)); CancellationToken token = deadline.Token; DirectoryInfo directory = Directory.CreateTempSubdirectory("libtmux-mcp-"); string socket = Path.Combine(directory.FullName, "tmux.sock"); Console.Error.WriteLine($"Private socket: {socket}"); OwnedServerScope? owned = null; McpClient? client = null; List failures = []; bool stopped = false; try { ServerConnectionOptions options = new() { SocketPath = socket, ConfigurationFile = "/dev/null", }; owned = await Server.CreateOwnedAsync(options, token); await owned.Value.CreateSessionAsync( new NewSessionRequest { Name = "docs-demo", Command = "/bin/sh" }, token); Dictionary environment = StdioClientTransportOptions.GetDefaultEnvironmentVariables(); environment["DOTNET_ROOT"] = Environment.GetEnvironmentVariable("DOTNET_ROOT"); environment["LIBTMUX_SOCKET_PATH"] = socket; environment["LIBTMUX_TOOLSETS"] = "inspect,execute"; environment["LIBTMUX_MCP_WAIT_MAX_SECONDS"] = "5"; StdioClientTransport transport = new(new StdioClientTransportOptions { Name = "tmux", Command = Path.GetFullPath(".tools/libtmux-mcp"), InheritEnvironmentVariables = false, EnvironmentVariables = environment, ShutdownTimeout = TimeSpan.FromSeconds(5), }); client = await McpClient.CreateAsync(transport, cancellationToken: token); var tools = await client.ListToolsAsync(cancellationToken: token); if (!tools.Any(tool => tool.Name == "run_shell_command")) { throw new InvalidOperationException("Command execution is not offered."); } JsonElement panes = ReadResult(await client.CallToolAsync( "list_panes", cancellationToken: token)); string pane = panes.EnumerateArray().Single() .GetProperty("paneId").GetString() ?? throw new InvalidOperationException("The pane has no ID."); JsonElement result = ReadResult(await client.CallToolAsync( "run_shell_command", new Dictionary { ["paneId"] = pane, ["command"] = "printf 'MCP command ready\\n'", ["timeoutSeconds"] = 5, }, cancellationToken: token)); if (result.GetProperty("timedOut").GetBoolean() || result.GetProperty("paneExited").GetBoolean() || !result.GetProperty("started").GetBoolean()) { throw new InvalidOperationException($"Command did not finish: {result}"); } int status = result.GetProperty("exitStatus").GetInt32(); if (status != 0) { throw new InvalidOperationException($"Shell exit status: {status}"); } JsonElement output = result.GetProperty("output"); bool found = output.GetProperty("lines").EnumerateArray() .Any(line => line.GetString() == "MCP command ready"); if (!found || output.GetProperty("truncated").GetBoolean() || result.GetProperty("linesMissed").GetBoolean() || result.GetProperty("anchorLost").GetBoolean()) { throw new InvalidOperationException($"Incomplete command output: {result}"); } Console.WriteLine($"Command exit status: {status}"); Console.WriteLine("Captured marker: MCP command ready"); } catch (Exception error) { failures.Add(error); } if (client is not null) { try { await client.DisposeAsync(); } catch (Exception error) { failures.Add(new IOException("MCP client cleanup failed.", error)); } } if (owned is not null) { try { await owned.DisposeAsync(); stopped = true; } catch (Exception error) { failures.Add(new IOException("Owned server cleanup failed.", error)); } } if (stopped) { try { directory.Delete(recursive: true); } catch (Exception error) { failures.Add(new IOException("Temporary directory cleanup failed.", error)); } } else { Console.Error.WriteLine($"Retained directory: {directory.FullName}"); } if (failures.Count != 0) { throw new AggregateException(failures); } Console.WriteLine("Owned server stopped."); static JsonElement ReadResult(CallToolResult result) { if (result.IsError == true || result.StructuredContent is not JsonElement data) { throw new InvalidOperationException(JsonSerializer.Serialize(result)); } return data; } ``` Run the program from the directory containing these files and `.tools`: ```console $ dotnet run --project McpExample.csproj --no-launch-profile ``` It prints the private socket path to stderr. Its stdout is: ```text Command exit status: 0 Captured marker: MCP command ready Owned server stopped. ``` ## Completion and output The client offers `inspect` and `execute`. It discovers the actual pane ID instead of assuming that the first pane has a particular number. The command wait is limited to five seconds; startup and MCP requests share a separate 30-second deadline. Check the tool result before reading the shell result. The [`ReadResult`](https://libtmux.org/en/csharp/latest/mcp/examples/run-command/#client-program) helper in this example rejects `isError` and missing structured content. The program then checks completion, shell status, and capture completeness separately. `linesMissed`, `anchorLost`, or a truncated capture means output may be missing even if the command exited successfully. The command runs in a subshell. A `cd` or `export` inside one call does not persist into another call. Combine dependent shell operations in one command when they need to share a directory or environment. ## Failures and cleanup A timeout with `started: false` means the command wrapper was not seen to begin; inspect whether the pane is at an empty, ready shell prompt. A timeout after startup can leave the command running. `paneExited` instead reports that the pane's program ended before returning a shell status. For this private example, cleanup stops the owned server and any remaining pane command. In an application that borrows an existing pane, cancelling the wait does not stop the command. Inspect that pane before deciding to retry or send more input. MCP shutdown and owned-server shutdown are attempted independently, and the program reports cleanup failures alongside request failures. It deletes its temporary directory only after owned-server cleanup succeeds. The [session inspection example](https://libtmux.org/en/csharp/latest/mcp/examples/inspect-sessions/#shutdown) explains that ownership pattern, and [Waits and captured output](https://libtmux.org/en/csharp/latest/mcp/topics/waits-and-output/) covers observation, cancellation, and response budgets. --- # Workspace examples Source: https://libtmux.org/en/csharp/latest/workspace/examples/gallery/ > Start from complete configurations for pane layout, commands and environment. Each configuration below is a complete workspace document. Save it to a file and load it on the private socket from the [installation walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/). ## Two blank panes ```yaml title="gallery-blank.yaml" session_name: gallery-blank windows: - window_name: work layout: even-horizontal panes: [null, null] ``` Blank panes open their shells without application-specific prerequisites. Change the [layout](https://libtmux.org/en/csharp/latest/workspace/configuration/layouts/) to arrange them vertically. ## Setup before pane commands ```yaml title="gallery-commands.yaml" session_name: gallery-commands shell_command_before: - printf setup windows: - window_name: shell panes: - shell_command: - printf first - printf second ``` Both commands run in one pane after its inherited setup. Read [command ordering](https://libtmux.org/en/csharp/latest/workspace/configuration/commands/) before adding delays or commands that should remain unsubmitted. ## More complete examples - [Session options and environment](https://libtmux.org/en/csharp/latest/workspace/configuration/session/). - [Explicit window index and synchronized input](https://libtmux.org/en/csharp/latest/workspace/configuration/windows/). - [Pane launch shell and focus](https://libtmux.org/en/csharp/latest/workspace/configuration/panes/). - [Inherited directories](https://libtmux.org/en/csharp/latest/workspace/configuration/directories/). - [Environment overrides](https://libtmux.org/en/csharp/latest/workspace/configuration/environment/). - [Checked bootstrap process](https://libtmux.org/en/csharp/latest/workspace/configuration/hooks/). Use the [workspace library](https://libtmux.org/en/csharp/latest/workspace/internals/) when application code needs to construct sessions directly. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Workspace examples Source: https://libtmux.org/en/cxx/latest/workspace/examples/gallery/ > Start from complete configurations for pane layout, commands and environment. Each configuration below is a complete workspace document. Save it to a file and load it on the private socket from the [installation walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/). ## Two blank panes ```yaml title="gallery-blank.yaml" session_name: gallery-blank windows: - window_name: work layout: even-horizontal panes: [null, null] ``` Blank panes open their shells without application-specific prerequisites. Change the [layout](https://libtmux.org/en/cxx/latest/workspace/configuration/layouts/) to arrange them vertically. ## Setup before pane commands ```yaml title="gallery-commands.yaml" session_name: gallery-commands shell_command_before: - printf setup windows: - window_name: shell panes: - shell_command: - printf first - printf second ``` Both commands run in one pane after its inherited setup. Read [command ordering](https://libtmux.org/en/cxx/latest/workspace/configuration/commands/) before adding delays or commands that should remain unsubmitted. ## More complete examples - [Session options and environment](https://libtmux.org/en/cxx/latest/workspace/configuration/session/). - [Explicit window index and synchronized input](https://libtmux.org/en/cxx/latest/workspace/configuration/windows/). - [Pane launch shell and focus](https://libtmux.org/en/cxx/latest/workspace/configuration/panes/). - [Inherited directories](https://libtmux.org/en/cxx/latest/workspace/configuration/directories/). - [Environment overrides](https://libtmux.org/en/cxx/latest/workspace/configuration/environment/). - [Checked bootstrap process](https://libtmux.org/en/cxx/latest/workspace/configuration/hooks/). Use the [workspace library](https://libtmux.org/en/cxx/latest/workspace/internals/) when application code needs to construct sessions directly. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Workspace examples Source: https://libtmux.org/en/go/latest/workspace/examples/gallery/ > Start from complete configurations for pane layout, commands and environment. Each configuration below is a complete workspace document. Save it to a file and load it on the private socket from the [installation walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/). ## Two blank panes ```yaml title="gallery-blank.yaml" session_name: gallery-blank windows: - window_name: work layout: even-horizontal panes: [null, null] ``` Blank panes open their shells without application-specific prerequisites. Change the [layout](https://libtmux.org/en/go/latest/workspace/configuration/layouts/) to arrange them vertically. ## Setup before pane commands ```yaml title="gallery-commands.yaml" session_name: gallery-commands shell_command_before: - printf setup windows: - window_name: shell panes: - shell_command: - printf first - printf second ``` Both commands run in one pane after its inherited setup. Read [command ordering](https://libtmux.org/en/go/latest/workspace/configuration/commands/) before adding delays or commands that should remain unsubmitted. ## More complete examples - [Session options and environment](https://libtmux.org/en/go/latest/workspace/configuration/session/). - [Explicit window index and synchronized input](https://libtmux.org/en/go/latest/workspace/configuration/windows/). - [Pane launch shell and focus](https://libtmux.org/en/go/latest/workspace/configuration/panes/). - [Inherited directories](https://libtmux.org/en/go/latest/workspace/configuration/directories/). - [Environment overrides](https://libtmux.org/en/go/latest/workspace/configuration/environment/). - [Checked bootstrap process](https://libtmux.org/en/go/latest/workspace/configuration/hooks/). Use the [workspace library](https://libtmux.org/en/go/latest/workspace/internals/) when application code needs to construct sessions directly. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Workspace examples Source: https://libtmux.org/en/java/latest/workspace/examples/gallery/ > Start from complete configurations for pane layout, commands and environment. Each configuration below is a complete workspace document. Save it to a file and load it on the private socket from the [installation walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/). ## Two blank panes ```yaml title="gallery-blank.yaml" session_name: gallery-blank windows: - window_name: work layout: even-horizontal panes: [null, null] ``` Blank panes open their shells without application-specific prerequisites. Change the [layout](https://libtmux.org/en/java/latest/workspace/configuration/layouts/) to arrange them vertically. ## Setup before pane commands ```yaml title="gallery-commands.yaml" session_name: gallery-commands shell_command_before: - printf setup windows: - window_name: shell panes: - shell_command: - printf first - printf second ``` Both commands run in one pane after its inherited setup. Read [command ordering](https://libtmux.org/en/java/latest/workspace/configuration/commands/) before adding delays or commands that should remain unsubmitted. ## More complete examples - [Session options and environment](https://libtmux.org/en/java/latest/workspace/configuration/session/). - [Explicit window index and synchronized input](https://libtmux.org/en/java/latest/workspace/configuration/windows/). - [Pane launch shell and focus](https://libtmux.org/en/java/latest/workspace/configuration/panes/). - [Inherited directories](https://libtmux.org/en/java/latest/workspace/configuration/directories/). - [Environment overrides](https://libtmux.org/en/java/latest/workspace/configuration/environment/). - [Checked bootstrap process](https://libtmux.org/en/java/latest/workspace/configuration/hooks/). Use the [workspace library](https://libtmux.org/en/java/latest/workspace/internals/) when application code needs to construct sessions directly. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Workspace examples Source: https://libtmux.org/en/py/latest/workspace/examples/gallery/ > Start from complete configurations for pane layout, commands and environment. The examples below reproduce the pinned tmuxp YAML fixture corpus. Each record links to its source and, where present, its JSON twin. They illustrate configuration features; they are not all self-contained runnable projects. The `minimal` fixture and several other files omit window names despite the validator requiring them. Treat these as normalization and compatibility probes, not a promise that every fixture passes every load path. The [installation walkthrough](https://libtmux.org/en/py/latest/workspace/guides/installation/) supplies a complete runnable starting file. ## 2-pane-synchronized Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/2-pane-synchronized.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/2-pane-synchronized.json). ```yaml session_name: 2-pane-synchronized windows: - window_name: Two synchronized panes panes: - ssh server1 - ssh server2 options_after: synchronize-panes: on ``` ## 2-pane-vertical Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/2-pane-vertical.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/2-pane-vertical.json). ```yaml session_name: 2-pane-vertical windows: - window_name: my test window panes: - echo hello - echo hello ``` ## 3-pane Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/3-pane.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/3-pane.json). ```yaml session_name: 3-panes windows: - window_name: dev window layout: main-vertical shell_command_before: - cd ~/ panes: - shell_command: - cd /var/log - ls -al | grep \.log - echo hello - echo hello ``` ## 4-pane Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/4-pane.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/4-pane.json). ```yaml session_name: 4-pane-split windows: - window_name: dev window layout: tiled shell_command_before: - cd ~/ panes: - shell_command: - cd /var/log - ls -al | grep \.log - echo hello - echo hello - echo hello ``` ## blank-panes Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/blank-panes.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/blank-panes.json). ```yaml session_name: Blank pane test windows: # Emptiness will simply open a blank pane, if no shell_command_before. # All these are equivalent - window_name: Blank pane test panes: - - pane - blank - window_name: More blank panes panes: - null - shell_command: - shell_command: - # an empty string will be treated as a carriage return - window_name: Empty string (return) panes: - "" - shell_command: "" - shell_command: - "" # a pane can have other options but still be blank - window_name: Blank with options panes: - focus: true - start_directory: /tmp ``` ## env-variables Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/env-variables.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/env-variables.json). ```yaml start_directory: "${PWD}/test" shell_command_before: "echo ${PWD}" before_script: "${MY_ENV_VAR}/test3.sh" session_name: session - ${USER} (${MY_ENV_VAR}) windows: - window_name: editor panes: - shell_command: - tail -F /var/log/syslog start_directory: /var/log - window_name: logging for ${USER} options: automatic-rename: true panes: - shell_command: - htop - ls $PWD ``` ## focus-window-and-panes Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/focus-window-and-panes.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/focus-window-and-panes.json). ```yaml session_name: focus windows: - window_name: attached window focus: true panes: - shell_command: - echo hello - echo 'this pane should be selected on load' focus: true - shell_command: - cd /var/log - echo hello - window_name: second window shell_command_before: cd /var/log panes: - pane - shell_command: - echo 'this pane should be focused, when window switched to first time' focus: true - pane ``` ## main-pane-height-percentage Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/main-pane-height-percentage.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/main-pane-height-percentage.json). ```yaml session_name: main-pane-height start_directory: "~" windows: - layout: main-horizontal options: main-pane-height: 67% panes: - shell_command: - top start_directory: "~" - shell_command: - echo "hey" - shell_command: - echo "moo" window_name: my window name ``` ## main-pane-height Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/main-pane-height.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/main-pane-height.json). ```yaml session_name: main-pane-height start_directory: "~" windows: - layout: main-horizontal options: main-pane-height: 30 panes: - shell_command: - top start_directory: "~" - shell_command: - echo "hey" - shell_command: - echo "moo" window_name: my window name ``` ## minimal Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/minimal.yaml). ```yaml session_name: My tmux session windows: - panes: - ``` ## options Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/options.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/options.json). ```yaml session_name: test window options start_directory: "~" global_options: default-shell: /bin/sh default-command: /bin/sh options: main-pane-height: ${MAIN_PANE_HEIGHT} # works with env variables windows: - layout: main-horizontal options: automatic-rename: on panes: - shell_command: - man echo start_directory: "~" - shell_command: - echo "hey" - shell_command: - echo "moo" ``` ## pane-shell Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/pane-shell.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/pane-shell.json). ```yaml session_name: Pane shell example windows: - window_name: first window_shell: /usr/bin/python2 layout: even-vertical suppress_history: false options: remain-on-exit: true panes: - shell: /usr/bin/python3 shell_command: - print('This is python 3') - shell: /usr/bin/vim -u none shell_command: - iAll panes have the `remain-on-exit` setting on. - When you exit out of the shell or application, the panes will remain. - Use tmux command `:kill-pane` to remove the pane. - Use tmux command `:respawn-pane` to restart the shell in the pane. - Use and then `:q!` to get out of this vim window. :-) - shell_command: - print('Hello World 2') - shell: /usr/bin/top ``` ## plugin-system Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/plugin-system.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/plugin-system.json). ```yaml session_name: plugin-system plugins: - "tmuxp_plugin_extended_build.plugin.PluginExtendedBuild" windows: - window_name: editor layout: tiled shell_command_before: - cd ~/ panes: - shell_command: - cd /var/log - ls -al | grep *.log - echo "hello world" ``` ## session-environment Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/session-environment.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/session-environment.json). ```yaml session_name: Environment variables test environment: EDITOR: /usr/bin/vim DJANGO_SETTINGS_MODULE: my_app.settings.local SERVER_PORT: "8009" windows: - window_name: Django project panes: - ./manage.py runserver 0.0.0.0:${SERVER_PORT} - window_name: Another Django project environment: DJANGO_SETTINGS_MODULE: my_app.settings.local SERVER_PORT: "8010" panes: - ./manage.py runserver 0.0.0.0:${SERVER_PORT} - environment: DJANGO_SETTINGS_MODULE: my_app.settings.local-testing SERVER_PORT: "8011" shell_command: ./manage.py runserver 0.0.0.0:${SERVER_PORT} ``` ## shorthands Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/shorthands.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/shorthands.json). ```yaml session_name: shorthands windows: - window_name: long form panes: - shell_command: - echo 'did you know' - echo 'you can inline' - shell_command: echo 'single commands' - echo 'for panes' ``` ## skip-send-pane-level Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/skip-send-pane-level.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/skip-send-pane-level.json). ```yaml session_name: Skip command execution (pane-level) windows: - panes: - shell_command: echo "___$((1 + 3))___" enter: false - shell_command: - echo "___$((1 + 3))___"\; - echo "___$((1 + 3))___" enter: false ``` ## skip-send Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/skip-send.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/skip-send.json). ```yaml session_name: Skip command execution (command-level) windows: - panes: - shell_command: # You can see this - echo "___$((11 + 1))___" # This is skipped - cmd: echo "___$((1 + 3))___" enter: false ``` ## sleep-pane-level Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/sleep-pane-level.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/sleep-pane-level.json). ```yaml session_name: Pause / skip command execution (pane-level) windows: - panes: - # Wait 2 seconds before sending all commands in this pane sleep_before: 2 shell_command: - echo "___$((11 + 1))___" - cmd: echo "___$((1 + 3))___" - cmd: echo "___$((1 + 3))___" - cmd: echo "Stuff rendering here!" - cmd: echo "2 seconds later" ``` ## sleep-virtualenv Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/sleep-virtualenv.yaml). ```yaml session_name: virtualenv shell_command_before: # - cmd: source $(poetry env info --path)/bin/activate # - cmd: source `pipenv --venv`/bin/activate - cmd: source .venv/bin/activate sleep_before: 1 sleep_after: 1 windows: - panes: - shell_command: - ./manage.py runserver ``` ## sleep Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/sleep.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/sleep.json). ```yaml session_name: Pause / skip command execution (command-level) windows: - panes: - shell_command: # Executes immediately - echo "___$((11 + 1))___" # Delays before sending 2 seconds - cmd: echo "___$((1 + 3))___" sleep_before: 2 # Executes immediately - cmd: echo "___$((1 + 3))___" # Pauses 2 seconds after - cmd: echo "Stuff rendering here!" sleep_after: 2 # Executes after earlier commands (after 2 sec) - cmd: echo "2 seconds later" ``` ## start-directory Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/start-directory.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/start-directory.json). ```yaml session_name: start directory start_directory: /var/ windows: - window_name: should be /var/ panes: - shell_command: - echo "\033c - it trickles down from session-level" - echo hello - window_name: should be /var/log start_directory: log panes: - shell_command: - echo '\033c - window start_directory concatenates to session start_directory - if it is not absolute' - echo hello - window_name: should be ~ start_directory: "~" panes: - shell_command: - 'echo \\033c ~ has precedence. note: remember to quote ~ in YAML' - echo hello - window_name: should be /bin start_directory: /bin panes: - echo '\033c absolute paths also have precedence.' - echo hello - window_name: should be workspace file's dir start_directory: ./ panes: - shell_command: - echo '\033c - ./ is relative to workspace file location - ../ will be parent of workspace file - ./test will be \"test\" dir inside dir of workspace file' - shell_command: - echo '\033c - This way you can load up workspaces from projects and maintain - relative paths.' ``` ## suppress-history Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/suppress-history.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/suppress-history.json). ```yaml session_name: suppress suppress_history: false windows: - window_name: appended focus: true suppress_history: false panes: - echo "window in the history!" - window_name: suppressed suppress_history: true panes: - echo "window not in the history!" - window_name: default panes: - echo "session in the history!" - window_name: mixed suppress_history: false panes: - shell_command: - echo "command in the history!" suppress_history: false - shell_command: - echo "command not in the history!" suppress_history: true - shell_command: - echo "window in the history!" ``` ## window-index Pinned Python reference fixture. This docs run did not execute its full application environment. [YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/window-index.yaml); [JSON source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/window-index.json). ```yaml session_name: Window index example windows: - window_name: zero panes: - echo "this window's index will be zero" - window_name: five panes: - echo "this window's index will be five" window_index: 5 - window_name: one panes: - echo "this window's index will be one" ``` ## Prerequisites and portability SSH examples need the named hosts. Django and virtualenv examples need their project and environment. The plugin example needs its named Python plugin. Shell paths, log directories, top, `htop`, and editors are host-specific. The pane-shell fixture includes an obsolete Python 2 path; it is retained as upstream evidence, not recommended installation guidance. Review [configuration](https://libtmux.org/en/py/latest/workspace/configuration/), [commands](https://libtmux.org/en/py/latest/workspace/configuration/commands/), and [compatibility](https://libtmux.org/en/py/latest/workspace/reference/compatibility/) before adapting these fixtures. [tmuxp reference source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Workspace examples Source: https://libtmux.org/en/rs/latest/workspace/examples/gallery/ > Start from complete configurations for pane layout, commands and environment. Each configuration below is a complete workspace document. Save it to a file and load it on the private socket from the [installation walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/). ## Two blank panes ```yaml title="gallery-blank.yaml" session_name: gallery-blank windows: - window_name: work layout: even-horizontal panes: [null, null] ``` Blank panes open their shells without application-specific prerequisites. Change the [layout](https://libtmux.org/en/rs/latest/workspace/configuration/layouts/) to arrange them vertically. ## Setup before pane commands ```yaml title="gallery-commands.yaml" session_name: gallery-commands shell_command_before: - printf setup windows: - window_name: shell panes: - shell_command: - printf first - printf second ``` Both commands run in one pane after its inherited setup. Read [command ordering](https://libtmux.org/en/rs/latest/workspace/configuration/commands/) before adding delays or commands that should remain unsubmitted. ## More complete examples - [Session options and environment](https://libtmux.org/en/rs/latest/workspace/configuration/session/). - [Explicit window index and synchronized input](https://libtmux.org/en/rs/latest/workspace/configuration/windows/). - [Pane launch shell and focus](https://libtmux.org/en/rs/latest/workspace/configuration/panes/). - [Inherited directories](https://libtmux.org/en/rs/latest/workspace/configuration/directories/). - [Environment overrides](https://libtmux.org/en/rs/latest/workspace/configuration/environment/). - [Checked bootstrap process](https://libtmux.org/en/rs/latest/workspace/configuration/hooks/). Use the [workspace library](https://libtmux.org/en/rs/latest/workspace/internals/) when application code needs to construct sessions directly. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Workspace examples Source: https://libtmux.org/en/swift/latest/workspace/examples/gallery/ > Start from complete configurations for pane layout, commands and environment. Each configuration below is a complete workspace document. Save it to a file and load it on the private socket from the [installation walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/). ## Two blank panes ```yaml title="gallery-blank.yaml" session_name: gallery-blank windows: - window_name: work layout: even-horizontal panes: [null, null] ``` Blank panes open their shells without application-specific prerequisites. Change the [layout](https://libtmux.org/en/swift/latest/workspace/configuration/layouts/) to arrange them vertically. ## Setup before pane commands ```yaml title="gallery-commands.yaml" session_name: gallery-commands shell_command_before: - printf setup windows: - window_name: shell panes: - shell_command: - printf first - printf second ``` Both commands run in one pane after its inherited setup. Read [command ordering](https://libtmux.org/en/swift/latest/workspace/configuration/commands/) before adding delays or commands that should remain unsubmitted. ## More complete examples - [Session options and environment](https://libtmux.org/en/swift/latest/workspace/configuration/session/). - [Explicit window index and synchronized input](https://libtmux.org/en/swift/latest/workspace/configuration/windows/). - [Pane launch shell and focus](https://libtmux.org/en/swift/latest/workspace/configuration/panes/). - [Inherited directories](https://libtmux.org/en/swift/latest/workspace/configuration/directories/). - [Environment overrides](https://libtmux.org/en/swift/latest/workspace/configuration/environment/). - [Checked bootstrap process](https://libtmux.org/en/swift/latest/workspace/configuration/hooks/). Use the [workspace library](https://libtmux.org/en/swift/latest/workspace/internals/) when application code needs to construct sessions directly. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Workspace examples Source: https://libtmux.org/en/ts/latest/workspace/examples/gallery/ > Start from complete configurations for pane layout, commands and environment. Each configuration below is a complete workspace document. Save it to a file and load it on the private socket from the [installation walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/). ## Two blank panes ```yaml title="gallery-blank.yaml" session_name: gallery-blank windows: - window_name: work layout: even-horizontal panes: [null, null] ``` Blank panes open their shells without application-specific prerequisites. Change the [layout](https://libtmux.org/en/ts/latest/workspace/configuration/layouts/) to arrange them vertically. ## Setup before pane commands ```yaml title="gallery-commands.yaml" session_name: gallery-commands shell_command_before: - printf setup windows: - window_name: shell panes: - shell_command: - printf first - printf second ``` Both commands run in one pane after its inherited setup. Read [command ordering](https://libtmux.org/en/ts/latest/workspace/configuration/commands/) before adding delays or commands that should remain unsubmitted. ## More complete examples - [Session options and environment](https://libtmux.org/en/ts/latest/workspace/configuration/session/). - [Explicit window index and synchronized input](https://libtmux.org/en/ts/latest/workspace/configuration/windows/). - [Pane launch shell and focus](https://libtmux.org/en/ts/latest/workspace/configuration/panes/). - [Inherited directories](https://libtmux.org/en/ts/latest/workspace/configuration/directories/). - [Environment overrides](https://libtmux.org/en/ts/latest/workspace/configuration/environment/). - [Checked bootstrap process](https://libtmux.org/en/ts/latest/workspace/configuration/hooks/). Use the [workspace library](https://libtmux.org/en/ts/latest/workspace/internals/) when application code needs to construct sessions directly. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # tmux MCP for Go Source: https://libtmux.org/en/go/latest/mcp/ > Connect an MCP client to tmux and read structured results from complete Go programs. [`github.com/libtmux/libtmux-go/mcp`](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/README.md) is a separate Go module that exposes tmux through MCP. Its executable is `libtmux-mcp`. Installing the core tmux module does not install this server or its protocol dependencies. The server requires Go 1.26 or newer to build and tmux 3.2a or newer to run. The MCP client launches `libtmux-mcp` and exchanges messages over stdin and stdout. The server selects one tmux endpoint and its offered tools at startup. Reconnect after changing that configuration. ## Start here - [Install](https://libtmux.org/en/go/latest/mcp/#install) points an MCP client at this server. - [Tools](https://libtmux.org/en/go/latest/mcp/tools/) lists the MCP operations, arguments, and results. - [Guides](https://libtmux.org/en/go/latest/mcp/guides/) install the command and diagnose its connection. - [Topics](https://libtmux.org/en/go/latest/mcp/topics/) explain toolsets, command waits, and capability discovery. - [Examples](https://libtmux.org/en/go/latest/mcp/examples/) include complete client programs and their setup. - [Language API](https://libtmux.org/en/go/latest/mcp/reference/) documents embedding and implementation types. Read `tmux://capabilities` for the effective startup selection. The [Workspace Manager](https://libtmux.org/en/go/latest/workspace/) is a separate module; the current MCP catalog does not include a workspace-file operation. [Module contract](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/README.md). - [Connect a client](https://libtmux.org/en/go/latest/mcp/guides/connect-client/): Install the executable, select a socket, and diagnose startup. - [Tool selection](https://libtmux.org/en/go/latest/mcp/topics/tool-selection/): Choose toolsets, individual tools, and exclusions. - [List sessions](https://libtmux.org/en/go/latest/mcp/examples/inspect-sessions/): Run a complete SDK client against its own tmux server. - [Run a command](https://libtmux.org/en/go/latest/mcp/examples/run-command/): Check command completion, exit status, and captured output. --- # Go MCP API Source: https://libtmux.org/en/go/latest/mcp/reference/ > Find the Go managed server lifecycle and distinguish exported APIs from wire operations. For MCP client requests, use the [tool reference](https://libtmux.org/en/go/latest/mcp/tools/). This page covers language APIs for embedding or extending the server. The Go MCP module exports a managed server instance. Tool handlers can be private Go functions while their registered names remain public MCP operations. ## Embedding lifecycle [`mcp.NewServer(target)`]() accepts a core tmux [`Server`]() and returns an [`Instance`]() plus an error. Close the instance after serving to release its runtime resources. [`Instance.Connect`]() connects a client transport. Custom transports use [`AssumeResponseCommit`]() only when a successful write commits exactly one response. This is a transport contract, not a retry wrapper. Applications that need the ordinary stdio lifecycle can use [`mcp.Run(ctx, target)`](). The [package reference](https://pkg.go.dev/github.com/libtmux/libtmux-go/mcp) describes lifecycle, capacity, and transport ownership. ## MCP operations The [tool reference](https://libtmux.org/en/go/latest/mcp/tools/) covers registered names and schemas. Toolsets and exact names filter both listing and invocation. The static `tmux://capabilities` resource reports the startup-frozen surface. Live reads use inspect tools. Workspace construction belongs to the separate [workspace module](https://libtmux.org/en/go/latest/workspace/reference/). [Server registration](https://github.com/libtmux/libtmux-go/blob/52968a3181c1c9e6d1b26c565d4b170968ae61c0/mcp/server.go) and [agent example](https://libtmux.org/en/go/latest/mcp/examples/) connect the language and protocol APIs. ## API declarations - [mcp.AdvertisedTools](https://libtmux.org/en/go/latest/mcp/reference/mcp-advertisedtools/) - [mcp.AdvertisedToolsFor](https://libtmux.org/en/go/latest/mcp/reference/mcp-advertisedtoolsfor/) - [mcp.AssumeResponseCommit](https://libtmux.org/en/go/latest/mcp/reference/mcp-assumeresponsecommit/) - [mcp.AuditEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-auditenvironmentvariable/) - [mcp.BinaryEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-binaryenvironmentvariable/) - [mcp.CapabilitiesResourceURI](https://libtmux.org/en/go/latest/mcp/reference/mcp-capabilitiesresourceuri/) - [mcp.CapabilityMetaKey](https://libtmux.org/en/go/latest/mcp/reference/mcp-capabilitymetakey/) - [mcp.ErrInstanceClosed](https://libtmux.org/en/go/latest/mcp/reference/mcp-errinstanceclosed/) - [mcp.ErrRequestCapacity](https://libtmux.org/en/go/latest/mcp/reference/mcp-errrequestcapacity/) - [mcp.ErrResponseCommitUnknown](https://libtmux.org/en/go/latest/mcp/reference/mcp-errresponsecommitunknown/) - [mcp.ErrRuntimeTargetBound](https://libtmux.org/en/go/latest/mcp/reference/mcp-errruntimetargetbound/) - [mcp.ExcludeToolsEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-excludetoolsenvironmentvariable/) - [mcp.HandshakeOrdered](https://libtmux.org/en/go/latest/mcp/reference/mcp-handshakeordered/) - [mcp.Instance](https://libtmux.org/en/go/latest/mcp/reference/mcp-instance/) - [mcp.MaterializeMinimalConfig](https://libtmux.org/en/go/latest/mcp/reference/mcp-materializeminimalconfig/) - [mcp.NewServer](https://libtmux.org/en/go/latest/mcp/reference/mcp-newserver/) - [mcp.RecipeToolEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-recipetoolenvironmentvariable/) - [mcp.Run](https://libtmux.org/en/go/latest/mcp/reference/mcp-run/) - [mcp.RunDefaultMinimal](https://libtmux.org/en/go/latest/mcp/reference/mcp-rundefaultminimal/) - [mcp.SafetyEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-safetyenvironmentvariable/) - [mcp.ServerSession](https://libtmux.org/en/go/latest/mcp/reference/mcp-serversession/) - [mcp.SocketEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-socketenvironmentvariable/) - [mcp.SocketPathEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-socketpathenvironmentvariable/) - [mcp.TmuxConfigEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-tmuxconfigenvironmentvariable/) - [mcp.ToolDetails](https://libtmux.org/en/go/latest/mcp/reference/mcp-tooldetails/) - [mcp.ToolsEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-toolsenvironmentvariable/) - [mcp.ToolsetsEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-toolsetsenvironmentvariable/) - [mcp.Version](https://libtmux.org/en/go/latest/mcp/reference/mcp-version/) - [mcp.WaitCeilingEnvironmentVariable](https://libtmux.org/en/go/latest/mcp/reference/mcp-waitceilingenvironmentvariable/) [Protocol catalog](https://libtmux.org/en/go/latest/mcp/tools.json) --- # Go workspace manager Source: https://libtmux.org/en/go/latest/workspace/ > Describe a tmux session in a file, then load, inspect and capture it. **Workspace Manager for Go is in development.** Build `tmux-workspace` from the source revision in the installation guide. Its CLI and workspace library have separate installation and configuration contracts. `tmux-workspace` creates tmux sessions from YAML or JSON. A file describes windows, panes, commands, directories and environment. Load it from a terminal or request machine output for automation. ## Load a workspace from the terminal 1. [Install the command and load a workspace](https://libtmux.org/en/go/latest/workspace/guides/installation/). 2. [Configure windows and panes](https://libtmux.org/en/go/latest/workspace/configuration/). 3. [Capture and reload a session](https://libtmux.org/en/go/latest/workspace/guides/export-session/). The [CLI manual](https://libtmux.org/en/go/latest/workspace/cli/) covers discovery, search, editing, loading, capture, conversion and import. [Examples](https://libtmux.org/en/go/latest/workspace/examples/gallery/) provide complete configurations with their prerequisites. ## Automate and inspect Use `load -d` when the caller should return without attaching. `--json` returns a result, and `--ndjson` supports a stream of records. Read [automation](https://libtmux.org/en/go/latest/workspace/guides/automation/) for retry and cleanup decisions and [errors](https://libtmux.org/en/go/latest/workspace/reference/exit-codes/) for failure handling. Loaded workspaces are ordinary tmux sessions. Select the same socket when inspecting them from tmux or the [MCP server](https://libtmux.org/en/go/latest/mcp/). ## Build from application code The [workspace library](https://libtmux.org/en/go/latest/workspace/internals/) has its own API and configuration contract. Use it when a program needs direct control over construction. The CLI task guides here describe the `tmux-workspace` executable and link to its documented source revision. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). - [CLI Manual](https://libtmux.org/en/go/latest/workspace/cli/): Commands, options and machine output. - [Configuration](https://libtmux.org/en/go/latest/workspace/configuration/): Workspace fields, normalization and execution. - [Install and load](https://libtmux.org/en/go/latest/workspace/guides/installation/): Load a workspace on a private socket, then capture it. - [Example gallery](https://libtmux.org/en/go/latest/workspace/examples/gallery/): Workspace files to start from, with their prerequisites. - [Runtime support](https://libtmux.org/en/go/latest/workspace/reference/compatibility/): Runtime requirements and supported behavior. - [Internals](https://libtmux.org/en/go/latest/workspace/internals/): The workspace library, for building sessions from code. --- # Guides Source: https://libtmux.org/en/csharp/latest/workspace/guides/ > Install the workspace command, find configurations and automate tmux sessions. Choose a task below. The [CLI reference](https://libtmux.org/en/csharp/latest/workspace/cli/) documents commands and options; [Internals](https://libtmux.org/en/csharp/latest/workspace/internals/) covers the workspace builder library. - [Install and load](https://libtmux.org/en/csharp/latest/workspace/guides/installation/): Install the command and load a workspace on a private socket. - [Find workspace files](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/): Discover, search and edit configurations. - [Automate workspace loading](https://libtmux.org/en/csharp/latest/workspace/guides/automation/): Use machine output and exit codes in scripts. - [Export a session](https://libtmux.org/en/csharp/latest/workspace/guides/export-session/): Capture a running session and load it again. - [Troubleshooting](https://libtmux.org/en/csharp/latest/workspace/guides/troubleshooting/): Diagnose installation, configuration and execution problems. --- # Guides Source: https://libtmux.org/en/cxx/latest/workspace/guides/ > Install the workspace command, find configurations and automate tmux sessions. Choose a task below. The [CLI reference](https://libtmux.org/en/cxx/latest/workspace/cli/) documents commands and options; [Internals](https://libtmux.org/en/cxx/latest/workspace/internals/) covers the workspace builder library. - [Install and load](https://libtmux.org/en/cxx/latest/workspace/guides/installation/): Install the command and load a workspace on a private socket. - [Find workspace files](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/): Discover, search and edit configurations. - [Automate workspace loading](https://libtmux.org/en/cxx/latest/workspace/guides/automation/): Use machine output and exit codes in scripts. - [Export a session](https://libtmux.org/en/cxx/latest/workspace/guides/export-session/): Capture a running session and load it again. - [Troubleshooting](https://libtmux.org/en/cxx/latest/workspace/guides/troubleshooting/): Diagnose installation, configuration and execution problems. --- # Guides Source: https://libtmux.org/en/go/latest/workspace/guides/ > Install the workspace command, find configurations and automate tmux sessions. Choose a task below. The [CLI reference](https://libtmux.org/en/go/latest/workspace/cli/) documents commands and options; [Internals](https://libtmux.org/en/go/latest/workspace/internals/) covers the workspace builder library. - [Install and load](https://libtmux.org/en/go/latest/workspace/guides/installation/): Install the command and load a workspace on a private socket. - [Find workspace files](https://libtmux.org/en/go/latest/workspace/guides/discovery/): Discover, search and edit configurations. - [Automate workspace loading](https://libtmux.org/en/go/latest/workspace/guides/automation/): Use machine output and exit codes in scripts. - [Export a session](https://libtmux.org/en/go/latest/workspace/guides/export-session/): Capture a running session and load it again. - [Troubleshooting](https://libtmux.org/en/go/latest/workspace/guides/troubleshooting/): Diagnose installation, configuration and execution problems. - [Inspect with MCP](https://libtmux.org/en/go/latest/workspace/guides/inspect-with-mcp/): Connect the Go MCP server to a loaded workspace. --- # Guides Source: https://libtmux.org/en/java/latest/workspace/guides/ > Install the workspace command, find configurations and automate tmux sessions. Choose a task below. The [CLI reference](https://libtmux.org/en/java/latest/workspace/cli/) documents commands and options; [Internals](https://libtmux.org/en/java/latest/workspace/internals/) covers the workspace builder library. - [Install and load](https://libtmux.org/en/java/latest/workspace/guides/installation/): Install the command and load a workspace on a private socket. - [Find workspace files](https://libtmux.org/en/java/latest/workspace/guides/discovery/): Discover, search and edit configurations. - [Automate workspace loading](https://libtmux.org/en/java/latest/workspace/guides/automation/): Use machine output and exit codes in scripts. - [Export a session](https://libtmux.org/en/java/latest/workspace/guides/export-session/): Capture a running session and load it again. - [Troubleshooting](https://libtmux.org/en/java/latest/workspace/guides/troubleshooting/): Diagnose installation, configuration and execution problems. --- # Guides Source: https://libtmux.org/en/rs/latest/workspace/guides/ > Install the workspace command, find configurations and automate tmux sessions. Choose a task below. The [CLI reference](https://libtmux.org/en/rs/latest/workspace/cli/) documents commands and options; [Internals](https://libtmux.org/en/rs/latest/workspace/internals/) covers the workspace builder library. - [Install and load](https://libtmux.org/en/rs/latest/workspace/guides/installation/): Install the command and load a workspace on a private socket. - [Find workspace files](https://libtmux.org/en/rs/latest/workspace/guides/discovery/): Discover, search and edit configurations. - [Automate workspace loading](https://libtmux.org/en/rs/latest/workspace/guides/automation/): Use machine output and exit codes in scripts. - [Export a session](https://libtmux.org/en/rs/latest/workspace/guides/export-session/): Capture a running session and load it again. - [Troubleshooting](https://libtmux.org/en/rs/latest/workspace/guides/troubleshooting/): Diagnose installation, configuration and execution problems. --- # Guides Source: https://libtmux.org/en/swift/latest/workspace/guides/ > Install the workspace command, find configurations and automate tmux sessions. Choose a task below. The [CLI reference](https://libtmux.org/en/swift/latest/workspace/cli/) documents commands and options; [Internals](https://libtmux.org/en/swift/latest/workspace/internals/) covers the workspace builder library. - [Install and load](https://libtmux.org/en/swift/latest/workspace/guides/installation/): Install the command and load a workspace on a private socket. - [Find workspace files](https://libtmux.org/en/swift/latest/workspace/guides/discovery/): Discover, search and edit configurations. - [Automate workspace loading](https://libtmux.org/en/swift/latest/workspace/guides/automation/): Use machine output and exit codes in scripts. - [Export a session](https://libtmux.org/en/swift/latest/workspace/guides/export-session/): Capture a running session and load it again. - [Troubleshooting](https://libtmux.org/en/swift/latest/workspace/guides/troubleshooting/): Diagnose installation, configuration and execution problems. --- # Guides Source: https://libtmux.org/en/ts/latest/workspace/guides/ > Install the workspace command, find configurations and automate tmux sessions. Choose a task below. The [CLI reference](https://libtmux.org/en/ts/latest/workspace/cli/) documents commands and options; [Internals](https://libtmux.org/en/ts/latest/workspace/internals/) covers the workspace builder library. - [Install and load](https://libtmux.org/en/ts/latest/workspace/guides/installation/): Install the command and load a workspace on a private socket. - [Find workspace files](https://libtmux.org/en/ts/latest/workspace/guides/discovery/): Discover, search and edit configurations. - [Automate workspace loading](https://libtmux.org/en/ts/latest/workspace/guides/automation/): Use machine output and exit codes in scripts. - [Export a session](https://libtmux.org/en/ts/latest/workspace/guides/export-session/): Capture a running session and load it again. - [Troubleshooting](https://libtmux.org/en/ts/latest/workspace/guides/troubleshooting/): Diagnose installation, configuration and execution problems. --- # Guides Source: https://libtmux.org/en/fsharp/latest/guides/ > Guides for LibTmux.FSharp. Connect to tmux and work with its sessions, windows, and panes. - [Getting started](https://libtmux.org/en/fsharp/latest/guides/getting-started/): Create a project and connect to a tmux server. - [Attaching to tmux](https://libtmux.org/en/fsharp/latest/guides/attaching-to-tmux/): Connect to an existing socket and leave its server running. - [Quick start](https://libtmux.org/en/fsharp/latest/guides/quickstart/): Install the package, capture server state, and choose a read operation. - [Querying and filtering](https://libtmux.org/en/fsharp/latest/guides/queries/): List objects, handle missing matches, and filter captured relations. - [Streams and cleanup](https://libtmux.org/en/fsharp/latest/guides/streams/): Consume events with bounded lifetimes and cancellation. - [.NET interoperation](https://libtmux.org/en/fsharp/latest/guides/interop/): Use core operations alongside the F# helpers. - [Execution modes](https://libtmux.org/en/fsharp/latest/guides/modes/): Choose commands, control mode, or bounded concurrent reads. - [Query fields](https://libtmux.org/en/fsharp/latest/guides/supported-query-fields/): Browse the fields supported by typed filters. --- # Guides Source: https://libtmux.org/en/kotlin/latest/guides/ > Guides for io.github.libtmux:libtmux-kotlin. Connect to tmux and work with its sessions, windows, and panes. - [Getting started](https://libtmux.org/en/kotlin/latest/guides/getting-started/): Read about libtmux-kotlin. - [Attaching to tmux](https://libtmux.org/en/kotlin/latest/guides/attaching-to-tmux/): Connect to an existing socket and leave its server running. - [Coroutines and flows](https://libtmux.org/en/kotlin/latest/guides/coroutines/): Read about kotlin. --- # Guides Source: https://libtmux.org/en/lua/latest/guides/ > Guides for libtmux. Connect to tmux and work with its sessions, windows, and panes. - [Getting started](https://libtmux.org/en/lua/latest/guides/overview/): Read about libtmux for lua. - [Attaching to tmux](https://libtmux.org/en/lua/latest/guides/attaching-to-tmux/): Connect to an existing socket and leave its server running. - [Capture server state](https://libtmux.org/en/lua/latest/guides/snapshots/): Read about capture server state. - [Compatibility targets](https://libtmux.org/en/lua/latest/guides/compatibility/): Read about compatibility targets. - [Create sessions, windows and panes](https://libtmux.org/en/lua/latest/guides/creation/): Read about create sessions, windows and panes. - [Execute tmux commands](https://libtmux.org/en/lua/latest/guides/commands/): Read about execute tmux commands. - [Observing a session](https://libtmux.org/en/lua/latest/guides/control/): Read about observing a session. - [Pane operations](https://libtmux.org/en/lua/latest/guides/panes/): Read about pane operations. - [Query captured data](https://libtmux.org/en/lua/latest/guides/query/): Read about query captured data. - [Read and paste named buffers](https://libtmux.org/en/lua/latest/guides/buffers/): Read about read and paste named buffers. - [Switch and detach clients](https://libtmux.org/en/lua/latest/guides/clients/): Read about switch and detach clients. - [tmux option and hook reference](https://libtmux.org/en/lua/latest/guides/options/): Read about tmux option and hook reference. - [Topology operations](https://libtmux.org/en/lua/latest/guides/topology/): Read about topology operations. --- # Guides Source: https://libtmux.org/en/ruby/latest/guides/ > Guides for libtmux. Connect to tmux and work with its sessions, windows, and panes. - [Getting started](https://libtmux.org/en/ruby/latest/guides/getting-started/): Install the gem, create a session, and query a snapshot. - [Attaching to tmux](https://libtmux.org/en/ruby/latest/guides/attaching-to-tmux/): Connect to an existing socket and leave its server running. - [Server bindings](https://libtmux.org/en/ruby/latest/guides/core/): Own a private server or connect to an existing socket. --- # Guides Source: https://libtmux.org/en/scala/latest/guides/ > Guides for io.github.libtmux:libtmux-scala_3. Connect to tmux and work with its sessions, windows, and panes. - [Getting started](https://libtmux.org/en/scala/latest/guides/getting-started/): Read about getting started. - [Attaching to tmux](https://libtmux.org/en/scala/latest/guides/attaching-to-tmux/): Connect to an existing socket and leave its server running. - [Installation and requirements](https://libtmux.org/en/scala/latest/guides/overview/): Read about libtmux-scala. - [Queries](https://libtmux.org/en/scala/latest/guides/query/): Read about queries. - [Ownership](https://libtmux.org/en/scala/latest/guides/ownership/): Read about ownership. - [Execution](https://libtmux.org/en/scala/latest/guides/execution/): Read about execution. - [Streaming](https://libtmux.org/en/scala/latest/guides/streaming/): Read about streaming. - [Compatibility](https://libtmux.org/en/scala/latest/guides/compatibility/): Read about compatibility. --- # Guides Source: https://libtmux.org/en/tmux/guides/ > Task-oriented walkthroughs that sit between the concepts and each port's own API reference. Use these guides to connect to tmux, send input, capture output, query objects, and test your program. [Concepts](https://libtmux.org/en/tmux/concepts/) explains the object model and transport choices. [Examples](https://libtmux.org/en/tmux/examples/) provides complete programs with setup and cleanup. The general guides use tmux shell commands. Select a port from the dropdown for its library APIs, imports and native project setup. - [Getting started](https://libtmux.org/en/tmux/guides/getting-started/): Install tmux and run a complete example. - [Attaching to tmux](https://libtmux.org/en/tmux/guides/attaching-to-tmux/): Select a socket and find or create a session. - [Sending keys](https://libtmux.org/en/tmux/guides/sending-keys/): Send literal text, named keys, and Enter. - [Capturing output](https://libtmux.org/en/tmux/guides/capturing-output/): Read the screen or scrollback and wait for a result. - [Filtering and querying](https://libtmux.org/en/tmux/guides/querying-and-filtering/): Find objects and handle missing or ambiguous matches. - [Testing](https://libtmux.org/en/tmux/guides/testing-with-libtmux/): Use isolated tmux servers and manage test cleanup. --- # Ruby MCP guides Source: https://libtmux.org/en/ruby/latest/mcp/guides/ > Connect an MCP client to a private tmux server and select its tools. Start with a private tmux server and the default read-only catalog. The client guide includes the complete launcher, dependency setup, client configuration, and connection checks. ## Select the tmux server `--socket PATH` selects an explicit socket; `--socket-name NAME` selects a named socket. `--endpoint` assigns the public alias used in discovery and resource URIs. It does not choose the socket. The [client launcher](https://libtmux.org/en/ruby/latest/mcp/guides/connect-client/) creates and owns its tmux daemon. When an application already owns the daemon, the MCP command borrows its endpoint: end of input closes the protocol clients without stopping tmux. The owning application remains responsible for the daemon's lifetime. ## Enable observation Screen capture and waits are absent from the default catalog. In the client guide's `run-mcp.rb`, add `"--enable-tool", "tmux_capture"` or `"--enable-tool", "tmux_wait"` to the array passed to [`LibTmux::MCP::CLI.run`](). The launcher does not forward arguments from the client configuration. When launching the installed `libtmux-mcp` executable directly, pass `--enable-tool tmux_capture` or `--enable-tool tmux_wait` as command arguments. `tmux_wait` can observe screen text or a process exit. Strong process tracking requires tmux 3.3 or newer and a supported native identity backend. A refusal means the required evidence is unavailable; it is not a successful wait. See the [tool reference](https://libtmux.org/en/ruby/latest/mcp/tools/) for arguments and results. ## Enable mutations Add another `--enable-tool` pair for `tmux_create`, `tmux_send`, or `tmux_close` in the same launcher array or executable arguments. Creation accepts command argument arrays. Sending text and sending named keys are separate variants. A dispatch receipt does not claim that the pane program completed. The [source-owned MCP guide](https://libtmux.org/en/ruby/latest/mcp/source-guide/) covers tool policy and shell enrollment. The [snapshot topic](https://libtmux.org/en/ruby/latest/mcp/topics/snapshots-and-references/) explains the references used to address observed objects. - [Connect a client](https://libtmux.org/en/ruby/latest/mcp/guides/connect-client/): Build a pinned launcher, inspect its tools, and close its private daemon with the client. --- # Rust MCP guides Source: https://libtmux.org/en/rs/latest/mcp/guides/ > Install tmux-mcp, choose a socket, and check the client's tool selection. The [connection guide](https://libtmux.org/en/rs/latest/mcp/guides/connect-client/) includes installation, client configuration, and checks for the selected tmux server. It uses the same source revision as the MCP reference. ## Install and connect Let the MCP client launch `tmux-mcp` and communicate over stdin and stdout. Choose the tool selection in the client configuration. For an existing tmux server, select its socket explicitly. The [installation steps](https://libtmux.org/en/rs/latest/mcp/guides/connect-client/#install-and-connect) use the tested Rust toolchain and Git revision. The [socket settings](https://libtmux.org/en/rs/latest/mcp/guides/connect-client/#connect-to-an-existing-server) distinguish an existing server from the launcher's default dedicated daemon. ## Verify the selection Ask the client to list tools and read `tmux://capabilities`. Its tool list and socket report describe this connection. The [tool-selection topic](https://libtmux.org/en/rs/latest/mcp/topics/tool-selection/) explains how groups, exact names, and exclusions combine. ## Diagnose failures Read the client's server log for stderr. The [startup checks](https://libtmux.org/en/rs/latest/mcp/guides/connect-client/#diagnose-startup-failures) cover invalid selection, conflicting socket settings, and executable lookup. Reconnect after changing the environment; the server chooses these settings once at startup. - [Connect a client](https://libtmux.org/en/rs/latest/mcp/guides/connect-client/): Install the pinned executable, configure the client, and check discovery and socket ownership. --- # C# MCP guides Source: https://libtmux.org/en/csharp/latest/mcp/guides/ > Install the MCP executable, choose its tmux server, and verify the client's connection. Let the MCP client launch `libtmux-mcp` and exchange protocol messages over stdin and stdout. The [connection guide](https://libtmux.org/en/csharp/latest/mcp/guides/connect-client/) covers installation, an existing tmux server, and the launcher's default dedicated server. ## Install the tool [`LibTmux.Mcp`]() is a framework-dependent .NET tool targeting .NET 8 and .NET 10. Follow the [pinned installation steps](https://libtmux.org/en/csharp/latest/mcp/guides/connect-client/#install-the-tool). The [complete client example](https://libtmux.org/en/csharp/latest/mcp/examples/inspect-sessions/) installs the executable into its own directory and includes the client project files. ## Connect a client Choose the socket and [tool selection](https://libtmux.org/en/csharp/latest/mcp/topics/tool-selection/) in the startup environment, then inspect `tmux://capabilities` and the offered tools. Use `manage` for topology changes and `execute` for terminal input and command execution. Reconnect after changing the configuration. ## Diagnose startup The client's server log contains stderr diagnostics. The [startup checks](https://libtmux.org/en/csharp/latest/mcp/guides/connect-client/#diagnose-startup) cover executable lookup, runtime installation, conflicting socket settings, and invalid tool names. Keep stdout available for MCP messages. - [Connect a client](https://libtmux.org/en/csharp/latest/mcp/guides/connect-client/): Install the pinned tool, choose a socket, and check startup and shutdown. --- # Getting started Source: https://libtmux.org/en/fsharp/latest/guides/getting-started/ > Create a project and connect to a tmux server. Start with the package [quickstart](https://libtmux.org/en/fsharp/latest/guides/quickstart/#quick-start) for installation and a complete `Program.fs` that runs against an owned tmux server. This guide continues from that path. `LibTmux.FSharp` is built on [LibTmux](https://github.com/libtmux/libtmux-dotnet/). Both packages are maintained in the `libtmux` organization by the same primary author. It keeps the core handles and task-based I/O. This example creates a server on a unique socket, creates one session, lists its pane, splits it, sends literal text, and reads the resulting pane IDs. Both owned scopes dispose at the end of the task. ```fsharp run open System open System.Threading open LibTmux open LibTmux.FSharp let inspectOwnedSessionAsync (cancellationToken: CancellationToken) = task { let binary = Environment.GetEnvironmentVariable("LIBTMUX_TMUX") |> Option.ofObj |> Option.defaultValue "tmux" let options = ServerConnectionOptions( SocketName = "libtmux-fsharp-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = binary ) use! ownedServer = LibTmux.Server.CreateOwnedAsync(options, cancellationToken) let server = ownedServer.Value use! ownedSession = server.CreateOwnedSessionAsync(NewSessionRequest(Name = "demo", Command = "/bin/sh"), cancellationToken) let! panes = ownedSession.Value |> Session.panes |> Query.list cancellationToken let! second = panes[0] |> Pane.split cancellationToken (SplitPaneRequest(Command = "/bin/sh")) do! second |> Pane.sendKeys cancellationToken (SendKeysRequest(Text = "printf 'ready\\n'", Literal = true)) let! found = server |> Server.tryFindPane cancellationToken second.Id let! captured = server |> Server.capture cancellationToken SnapshotDepth.Panes return captured.Panes |> Seq.map (fun pane -> pane.Id) |> Seq.toList, found |> Option.map (fun pane -> pane.Id) } ``` [`Pane.sendKeys`]() completes after tmux accepts the keys; it does not wait for the shell to print. To wait for what it prints, use [`Pane.sendAndWait`]() below. [`Server.capture`]() performs I/O, then the ID projection is local. [`Server.tryFindPane`]() returns `Some pane` after a successful lookup or [`None`]() when the pane is absent. This example returns two pane IDs and [`Some`]() of the new pane's ID. Failures and cancellation still propagate. ## Send, wait, read To act on what a pane prints, wait for it instead of sleeping. This complete program types a command and waits for its output, waits for a condition over the whole screen, and runs a command to its exit status: ```fsharp run open System open System.Threading open LibTmux open LibTmux.FSharp let runAsync () = task { use deadline = new CancellationTokenSource(TimeSpan.FromSeconds 20.) let token = deadline.Token let options = ServerConnectionOptions( SocketName = "fsharp-send-wait-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = (Environment.GetEnvironmentVariable "LIBTMUX_TMUX" |> Option.ofObj |> Option.defaultValue "tmux") ) use! owned = LibTmux.Server.CreateOwnedAsync(options, token) let! session = owned.Value.CreateSessionAsync(NewSessionRequest(Name = "work", Command = "/bin/sh"), token) let! panes = session |> Session.panes |> Query.list token let pane = panes[0] // Type a line and wait for what it prints. The screen before it and // the line's own echo do not count. let! ready = pane |> Pane.sendAndWait token (TimeSpan.FromSeconds 5.) "echo server ready" "server ready" // A condition sees every visible row each time the pane changes. do! pane |> Pane.sendKeys token (SendKeysRequest(Text = "seq 3", Literal = true)) let! counted = pane |> Pane.waitUntil token (TimeSpan.FromSeconds 5.) (fun rows -> rows |> Seq.exists ((=) "3")) // Running a command waits for its exit status and returns its output. let! listing = pane |> Pane.run token (TimeSpan.FromSeconds 10.) "printf 'a\\nb\\n'; exit 4" let! screen = pane |> Pane.capture token (CapturePaneRequest()) printfn "ready: %b" ready.Found printfn "counted: %b" counted.Found printfn "run: exit %A, output %A" listing.ExitStatus (List.ofSeq listing.Output) printfn "screen shows the run: %b" (screen |> Seq.exists (fun row -> row = "a")) } runAsync().GetAwaiter().GetResult() ``` It prints: ```text ready: true counted: true run: exit 4, output ["a"; "b"] screen shows the run: true ``` ### Which wait | You want to | Call | It ends when | | --- | --- | --- | | Type a line and wait for its output | [`Pane.sendAndWait`]() | A later line contains the text. The screen before the line and the line's own echo do not count. | | Send keys by request and wait by patterns | [`Pane.sendAndWaitFor`]() | A pattern or stop pattern matches later output. The echo of literal text does not count; keys sent by name are not discounted. | | Wait for output you did not type | [`Pane.waitForText`](), [`Pane.waitFor`]() | A line contains the text. Text already on screen answers at once with [`PresentAtEntry`](). | | Wait for a condition over the whole screen | [`Pane.waitUntil`]() | The condition holds over the visible rows, including what a full-screen program draws. | | Run a command to its exit status | [`Pane.run`]() | The command exits. It returns the status and the lines it printed. | | Follow output as it prints | [`Control.watchPane`](), or [`Control.watchPanes`]() for several panes on one client | You stop reading, or the panes are gone; see [streams](https://libtmux.org/en/fsharp/latest/guides/streams/). | Calling [`Pane.sendKeys`]() and then [`Pane.waitForText`]() for text the typed line contains can end on the shell's echo before the command runs; use [`Pane.sendAndWait`]() instead. Every wait also ends early when the pane's program exits or a full-screen program takes over, and each sleeps on the pane's own output through a control client rather than polling. [`Pane.run`]() needs the pane at a prompt of `sh`, `ash`, `bash`, `dash`, `zsh` or a Korn shell; fish, PowerShell and a REPL are refused. It runs the command in a subshell, so `cd` and `export` do not persist into the pane. A command still running at the timeout keeps running, and the result reports [`TimedOut`](). ## Describe a session Describe a session as F# records, then create it in one call. [`Server.newSession`]() makes the session with its first window, adds each later window, and splits each window's panes in order. A chain adds commands tmux runs together, each acting on what the one before made, and [`Server.within`]() bounds every command a handle sends: ```fsharp run open System open System.Threading open LibTmux open LibTmux.FSharp let runAsync () = task { use deadline = new CancellationTokenSource(TimeSpan.FromSeconds 20.) let token = deadline.Token let options = ServerConnectionOptions( SocketName = "fsharp-build-session-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = (Environment.GetEnvironmentVariable "LIBTMUX_TMUX" |> Option.ofObj |> Option.defaultValue "tmux") ) use! owned = LibTmux.Server.CreateOwnedAsync(options, token) // Describe the session, then create it in one call: the first window is // the one tmux makes with the session, and each split goes beside the // pane before it. let dev = { SessionSpec.named "dev" with Windows = [ { WindowSpec.named "editor" with Command = Some "exec sleep 60" } { WindowSpec.named "logs" with Command = Some "exec sleep 60" Splits = [ { SplitSpec.empty with Direction = Some PaneDirection.Right Command = Some "exec sleep 60" } { SplitSpec.empty with Command = Some "exec sleep 60" } ] } ] } let! session = owned.Value |> Server.newSession token dev // A chain runs in one tmux invocation; each step acts on what the one // before made. let! _ = owned.Value |> Chain.start |> Chain.newWindow session "watch" |> Chain.splitLeftRight |> Chain.sendLine "exec sleep 60" |> Chain.run token // Every command through this handle, and the handles taken from it, // gives tmux five seconds. let bounded = owned.Value |> Server.within (TimeSpan.FromSeconds 5.) let! windows = bounded |> Server.windows |> Query.list token for window in windows do let! panes = window |> Window.panes |> Query.list token printfn "%s: %d panes" window.Name panes.Count } runAsync().GetAwaiter().GetResult() ``` It prints: ```text editor: 1 panes logs: 3 panes watch: 2 panes ``` `LibTmux.Workspace` builds the same kind of session from a tmuxp workspace file, and can wait for each shell's prompt before sending it commands. Add the package and describe the session, or parse tmuxp YAML: ```console $ dotnet package add LibTmux.Workspace --prerelease ``` ```fsharp run open System.Threading open LibTmux open LibTmux.Workspace let buildWorkspaceAsync (cancellationToken: CancellationToken) (server: Server) = task { let description = WorkspaceFile( sessionName = "build", windows = [ WorkspaceWindow( windowName = "editor", panes = [ WorkspacePane([ "printf 'editing\\n'" ]); WorkspacePane() ] ) WorkspaceWindow(windowName = "logs", panes = [ WorkspacePane([ "printf 'tailing\\n'" ]) ]) ] ) // Creates the session, its windows and panes, and sends each pane its // commands once its shell is ready. let! built = WorkspaceBuilder(server).BuildAsync(description, cancellationToken) return built.Session.Name, [ for window in built.Windows -> window.Name ] } ``` `WorkspaceBuilder` creates every pane and applies each layout before typing, then waits for each pane's shell to show a prompt; pass `PaneReadiness.Never` to type at once. `BuildAsync` returns the session and windows it created. `WorkspaceFile.Parse` reads the same description from tmuxp YAML text. ## Read a snapshot For a server the caller already owns, capture once and use F# sequences: ```fsharp run open System.Threading open LibTmux open LibTmux.FSharp let readPaneCommandsAsync (cancellationToken: CancellationToken) (server: Server) = task { let! captured = server |> Server.capture cancellationToken SnapshotDepth.Panes return captured.Panes |> Seq.choose Pane.currentCommand |> Seq.toList } ``` [`Server.capture`]() performs I/O. The sequence projection only reads the captured snapshot. A null command becomes [`None`](); an uncaptured command still raises [`IncompleteSnapshotException`](). Use [portable filters](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/docs/fsharp/filters.md) when the condition must become a [`QueryDocument`](); use [`Seq.filter`]() for application-specific snapshot work. The [F# API reference](https://libtmux.org/en/fsharp/latest/reference/) is generated from compiled signatures and XML summaries. Use the core request records and entity methods for mutations. Task cancellation stops waiting; it does not undo a mutation that tmux received. The [F# example](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/examples/LibTmux.FSharp.Examples) is compiled and run against an owned tmux server. It checks that portable and native F# queries select the same panes on both target frameworks. CI repeats it against the freshly packed F# package through an isolated cache. A successful run writes `PASS F# snapshot and portable query example`. From the repository root, run that example against real tmux: ```console $ dotnet run \ --project examples/LibTmux.FSharp.Examples/LibTmux.FSharp.Examples.fsproj \ --framework net8.0 ``` --- # Getting started Source: https://libtmux.org/en/kotlin/latest/guides/getting-started/ > Getting started: io.github.libtmux:libtmux-kotlin documentation. **Coroutine wrapper classes, a session/window/split DSL, and [`Flow`]()/[`StateFlow`]() bridges over the Java API.** `io.github.libtmux:libtmux-kotlin` — [on Maven Central](https://central.sonatype.com/artifact/io.github.libtmux/libtmux-kotlin). > **Alpha.** The API will change without notice. Needs Kotlin 2.1 or later. The module is compiled for Kotlin 2.2 metadata and the 2.2 standard library, the level kotlinx-coroutines 1.11 is compiled for, and a Kotlin compiler reads metadata up to one minor version newer than itself. `ConsumerBaselineTest` fails if a build raises that level. Every Kotlin example below is executed against a real tmux server by [`ReadmeExamplesTest`](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-kotlin/src/test/kotlin/io/github/libtmux/kotlin/ReadmeExamplesTest.kt), one test per section. ## Install ```kotlin dependencies { implementation(platform("io.github.libtmux:libtmux-bom:0.0.1-alpha.17")) implementation("io.github.libtmux:libtmux-kotlin") } ``` ## Wrapper classes, not the Java types directly [`Server`](), [`Session`](), [`Window`](), [`Pane`](), [`Client`](), and [`ControlClient`]() here are Kotlin classes over the matching Java handle, which each answers as `asJava`; [`Server.fromJava`]() wraps a server opened in Java. Every operation that reaches tmux is [`suspend`](); captured state is a plain property. A tmux subsystem an accessor answers — [`Pane.options()`](), [`Server.hooks()`](), [`Server.keys()`](), and the rest — is wrapped the same way, so calling into it never blocks the caller's thread outside [`ExecutionPolicy`](). [`withServer`]() opens one and closes it even if the block throws or is cancelled: ```kotlin // Given: config: ServerConfig withServer(config) { server -> val session = server.newSession("build") session.name // → build server.admissionBound > 0 // → true } ``` ## Declare a session, its windows, and their splits with the DSL `@DslMarker` keeps a nested block from reaching an outer block's receiver by accident: a `split { }` inside a `window { }` cannot set the *session's* `directory` without writing `this@newSession.directory` to say so. tmux always gives a new session one window; the first `window { }` block renames that one, and each later block is a genuine new window — two blocks make two windows, not three. ```kotlin // Given: config: ServerConfig withServer(config) { server -> val session = server.newSession { name = "editors" window { name = "left" } window { name = "right" split { toRight(); percent(30) } } } session.windows.size // → 2 } ``` ## Send keys, capture output, run a command ```kotlin // Given: config: ServerConfig import io.github.libtmux.kotlin.orNull import kotlin.time.Duration.Companion.seconds withServer(config) { server -> val session = server.newSession("keys-demo") val pane = session.activeWindow?.activePane ?: error("no active pane") pane.sendLine("echo ready") pane.awaitText("ready", timeout = 5.seconds) val lines = pane.capture() val run = pane.run("echo hi && exit 3", timeout = 5.seconds) run.exitStatus.orNull() // → 3 lines.isNotEmpty() // → true } ``` ## Query with typed fields on the companion Fields live on the handle type's companion — [`Pane.command`](), not a static [`Pane_.command()`]() — generated from the same `field-catalog.tsv` that generates the Java metamodel, so the two can never disagree. ```kotlin // Given: config: ServerConfig import io.github.libtmux.kotlin.query.active import io.github.libtmux.kotlin.query.command withServer(config) { server -> server.newSession("query-demo") val editors = server.panes(Pane.command startsWith "nvim") val activePanes = server.panes(Pane.active.isTrue()) editors.size >= 0 // → true activePanes.isNotEmpty() // → true } ``` [`server.session(expr)`]() throws [`CardinalityException`]() on no match or more than one; [`server.sessionOrNull(expr)`]() is null on no match and still throws on more than one — Kotlin's own collection convention (`single`/`singleOrNull`), applied to a tmux lookup. ## Exhaustive `when` over the sealed failure tree ```kotlin import io.github.libtmux.exception.CardinalityException import io.github.libtmux.exception.CommandRejectedException import io.github.libtmux.exception.ControlEndedException import io.github.libtmux.exception.DispatchException import io.github.libtmux.exception.LibTmuxException import io.github.libtmux.exception.MalformedResponseException import io.github.libtmux.exception.ServerUnavailableException import io.github.libtmux.exception.TargetGoneException import io.github.libtmux.exception.UnencodableTextException import io.github.libtmux.exception.UnsupportedFeatureException fun nextStep(failure: LibTmuxException): String = when (failure) { // exhaustive, no else is TargetGoneException -> "look it up again" is ServerUnavailableException -> "start a server" is CommandRejectedException -> "change the request" is DispatchException -> if (failure.safeToRetry()) "send it again" else "read state first" is ControlEndedException -> "attach again" is UnsupportedFeatureException -> "do without" is UnencodableTextException -> "use a UTF-8 locale" is MalformedResponseException -> "report it" is CardinalityException.NoMatch -> "nothing matched" is CardinalityException.MultipleMatches -> "ambiguous" } nextStep(CardinalityException.MultipleMatches("many", 3)) // → ambiguous ``` A new leaf breaks every such `when` at the branch that omits it: `ExhaustivenessCompileTest` compiles a `when` one branch short and asserts the compiler rejects it. ## A subscription as a cold `Flow` ```kotlin // Given: config: ServerConfig import io.github.libtmux.control.Delivery import kotlinx.coroutines.flow.first withServer(config) { server -> val session = server.newSession("flow-demo") withControl(server, session) { control -> val step = control.output(capacity = 64) { control.send("send-keys", "-t", session.name, "echo flowed", "Enter") }.first() val outcome = when (step) { // exhaustive, no else is Delivery.Event -> "kept" is Delivery.Gap -> "lost ${step.missed}" } outcome // → kept } } ``` [`output`]()/[`events`]() open a *fresh* Java subscription per [`collect()`]() — over [`EventSubscription.poll`]()/[`onReady`](), never a parked thread — and close it when collection ends, is cancelled, or throws. Output tmux sends before that subscription opens is not delivered, so the command whose output you want goes in the trailing `onSubscribed` block, which runs once the subscription exists and before the first read. A [`Delivery.Gap`]() is an element like any other, ahead of the events that survived a full buffer; nothing is silently dropped. ## The live server as a `StateFlow` ```kotlin // Given: config: ServerConfig import kotlinx.coroutines.flow.first withServer(config) { server -> val session = server.newSession("live-demo") server.withLiveState(session) { live -> val view = live.first() view.epoch >= 0L // → true } } ``` Wraps Java's [`ServerMirror`]() — resnapshot on notification, on gap, and on reconnect happen once, inside it — rather than patching state in Kotlin. Named [`liveState`](), not [`ServerMirror`](), so it does not collide with the Java type it wraps. [`liveState`]()'s own background pump runs until its scope ends, by design — a caller collecting for a program's whole life passes its own long-lived scope — so [`withLiveState`]() is the scoped form for everything shorter: it cancels the pump once its block returns, the same shape [`withServer`]()/[`withControl`]() already have for the resources they open. ## Retry using the safe-to-retry predicate ```kotlin // Given: config: ServerConfig withServer(config) { server -> val version = retryIfSafe(times = 3) { server.version() } version.major >= 3 // → true } ``` [`retryIfSafe`]() catches only [`DispatchException`]() and checks `failure.safeToRetry()`, computed by the operation that threw it from its own catalogued idempotence — no retry executor, and no catalog lookup at the call site. ## Why nothing in Java may depend on this The build fails if it does. Per the JSpecify specification a class carrying `@kotlin.Metadata` is **not** null-marked, because the Kotlin compiler does not yet emit full nullness into binaries ([KT-47417](https://youtrack.jetbrains.com/projects/KT/issues/KT-47417/Emit-jspecify-annotations-for-types-in-Kotlin-binaries)). A Kotlin-authored API would therefore be worse for a Java caller and invisible to NullAway. The dependency runs one way only. ## Next - [Kotlin guide](https://libtmux.org/en/kotlin/latest/guides/coroutines/) - [`libtmux`](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux/) — the API this wraps - [Root README](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/README.md) --- # Getting started Source: https://libtmux.org/en/lua/latest/guides/overview/ > Getting started: libtmux documentation. Script tmux from Lua: create sessions and panes, capture terminal output, query server state, and watch pane output. Use standalone Lua with luv or Neovim's event loop. **Alpha software.** The core API is still changing. The separate MCP and workspace packages are unpublished scaffolds. [Install](https://libtmux.org/en/lua/latest/guides/overview/#install) · [Read a server](https://libtmux.org/en/lua/latest/guides/overview/#read-a-server) · [Query](https://libtmux.org/en/lua/latest/guides/overview/#query-captured-state) · [Create panes](https://libtmux.org/en/lua/latest/guides/overview/#create-sessions-and-panes) · [Neovim](https://libtmux.org/en/lua/latest/guides/overview/#neovim) · [Guides](https://libtmux.org/en/lua/latest/guides/overview/#guides) · [CI](https://github.com/libtmux/libtmux-lua/actions/workflows/ci.yml) · [MIT license](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/LICENSE) ## Install Install the core alpha with LuaRocks configured for your Lua interpreter: ```console $ luarocks --local install libtmux 0.1.0alpha1-1 ``` To install from a checkout: ```console $ luarocks --local make rockspecs/libtmux-scm-1.rockspec ``` See the [changelog](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/CHANGES.md) and [release instructions](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/.github/CONTRIBUTING.md#releases) for release history and verification. Linux is tested; macOS remains unverified. Add the local rocks tree to Lua's module paths: ```console $ eval "$(luarocks --local path)" ``` For standalone scripts, also install luv. Building it requires a C compiler and CMake. Neovim provides its own libuv binding. ```console $ luarocks --local install luv 1.52.1-0 ``` Core and local queries require only Lua. Importing a module does not start tmux or an event loop. CI runs unit tests on Lua 5.1–5.5 and LuaJIT, plus live tests across tmux 3.2a–3.7c. See the [compatibility matrix](https://libtmux.org/en/lua/latest/guides/compatibility/) for exact versions and remaining platform coverage. ## Read a server Connect to an existing server by its explicit socket path. This is the full [snapshot example](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/examples/snapshot.lua), which prints pane and window IDs: ```lua local adapter = require("libtmux.runtime.luv") local function must(value, err) if err ~= nil then error(err, 0) end return value end must(adapter.run(function(runtime) local server = must(runtime :connect({ binary = assert(os.getenv("TMUX_BIN"), "set TMUX_BIN to an absolute tmux executable"), socket_path = assert(os.getenv("TMUX_SOCKET"), "set TMUX_SOCKET to an explicit socket"), }) :await()) local snapshot = must(server:snapshot({ strict = true }):await()) for _, pane in ipairs(snapshot.panes) do io.stdout:write(pane.id, "\t", pane.window_id, "\n") end must(server:close():await()) return true end)) ``` Live operations return Requests; `:await()` yields inside the runtime body and returns `value, err`. The `must` helper propagates errors. Closing the connection leaves the tmux server and its sessions running. Set `TMUX_BIN` and `TMUX_SOCKET` to absolute paths for your server, then run: ```console $ lua examples/snapshot.lua ```
Try it on a temporary server Run from the checkout after installing the dependencies above. This starts a private tmux server and removes it when the example finishes. ```console $ sh <<'SH' set -eu unset TMUX TMUX_PANE TMUX_BIN=$(command -v tmux) demo_dir=$(mktemp -d /tmp/libtmux-lua-XXXXXX) TMUX_SOCKET="$demo_dir/tmux.sock" export TMUX_BIN TMUX_SOCKET cleanup() { "$TMUX_BIN" -S "$TMUX_SOCKET" kill-server 2>/dev/null || true rm -rf "$demo_dir" } trap cleanup EXIT "$TMUX_BIN" -f /dev/null -S "$TMUX_SOCKET" new-session -d -s demo lua examples/snapshot.lua SH ```
## Query captured state After capturing `snapshot` in the example above, filter its panes with structured criteria or an ordinary Lua function: ```lua local editors = snapshot.panes:where({ current_command = { one_of = { "nvim", "vim" } }, }) local inactive = snapshot.panes:filter(function(pane) return not pane.active end) print(#editors, #inactive) for _, pane in ipairs(editors) do print(pane.id, pane.current_command) end ``` Selections are dense, one-based Lua tables. Both queries read the snapshot without calling tmux. Capture again to refresh it; a snapshot spans multiple tmux commands and is not an atomic view. See [criteria, relationships and live queries](https://libtmux.org/en/lua/latest/guides/query/), the [field reference](https://libtmux.org/en/lua/latest/topics/format-token-fields/), or run the [standalone table-query example](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/examples/native_query.lua): ```console $ lua examples/native_query.lua ``` ## Create sessions and panes Before closing `server` in that runtime body, create a session and split a window. These calls use the same `must` helper: ```lua local work = must(server:new_session({ name = "work" }):await()) local editor = must(work.session:new_window({ name = "editor" }):await()) local split = must(editor.pane:split({ direction = "right", percent = 40 }):await()) must(split.pane:send_text("printf '%s\\n' hello"):await()) must(split.pane:send_keys({ "Enter" }):await()) ``` Creation returns a table with `session`, `window`, `pane` and [`window_link`]() handles. These operations leave the new sessions and panes running. Sending keys confirms that tmux accepted input; it does not wait for a shell command to finish. See [creation](https://libtmux.org/en/lua/latest/guides/creation/) and [pane operations](https://libtmux.org/en/lua/latest/guides/panes/) for literal argv, capture, resize and cleanup. ## Neovim From the checkout, start Neovim with the library on its `runtimepath`: ```console $ nvim --cmd 'set runtimepath+=.' ``` With `TMUX_SOCKET` set to an existing server's absolute socket path, run this Lua code. [`start`]() uses the editor's loop and reports the result in a callback: ```lua local adapter = require("libtmux.runtime.nvim") adapter.start(function(runtime) local server, err = runtime:connect({ binary = vim.fn.exepath("tmux"), socket_path = assert(os.getenv("TMUX_SOCKET")), }):await() if err then return nil, err end return server:snapshot({ strict = true }):await() end, function(snapshot, err) if err then vim.notify(tostring(err), vim.log.levels.ERROR) return end vim.notify(("Panes: %d"):format(#snapshot.panes)) end) ``` The runtime closes its connections when the body finishes and leaves the tmux server running. See [runtime ownership and cancellation](https://libtmux.org/en/lua/latest/guides/runtime/). ## Guides - **Clients:** [switch sessions and detach terminals](https://libtmux.org/en/lua/latest/guides/clients/). - **Read and watch:** [snapshots](https://libtmux.org/en/lua/latest/guides/snapshots/), [session notifications and pane streams](https://libtmux.org/en/lua/latest/guides/control/). - **Run and arrange:** [commands and batches](https://libtmux.org/en/lua/latest/guides/commands/), [session/window topology](https://libtmux.org/en/lua/latest/guides/topology/), [binary buffers](https://libtmux.org/en/lua/latest/guides/buffers/). - **Configure:** [options and hooks](https://libtmux.org/en/lua/latest/topics/options-and-hooks/), [option reference](https://libtmux.org/en/lua/latest/guides/options/), [environment values](https://libtmux.org/en/lua/latest/topics/environment/). - **Contribute:** [setup and validation](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/.github/CONTRIBUTING.md), [writing conventions](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/.github/WRITING.md). Live tests use private sockets and clean up their own servers. See the contributing guide for the same offline checks that run in CI. --- # Getting started Source: https://libtmux.org/en/ruby/latest/guides/getting-started/ > Install the gem, create a session, and query a snapshot. Create tmux sessions, split windows, send input, and capture pane output from Ruby. Read server state into a snapshot, then query it with [`where`](), `select`, and the rest of `Enumerable`. [Quick start](https://libtmux.org/en/ruby/latest/guides/getting-started/#quick-start) · [Queries](https://libtmux.org/en/ruby/latest/guides/getting-started/#query-a-snapshot) · [Gems](https://libtmux.org/en/ruby/latest/guides/getting-started/#gems) · [Guide](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/docs/index.md) · [API reference](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/docs/reference/api.md) · [Recipes](https://libtmux.org/en/ruby/latest/examples/recipes/) **Alpha.** APIs may change between releases. See the [initial alpha notes](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/CHANGELOG.md) and [release guide](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/docs/releasing.md). ## Install Install the core prerelease from RubyGems: ```console $ gem install libtmux --pre ``` The [companion gems](https://libtmux.org/en/ruby/latest/guides/getting-started/#gems) install separately; use `--pre` for their alpha versions too. ## Install from source Use the Ruby pinned in [.tool-versions](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/.tool-versions) and have `tmux` on your `PATH`. From this checkout, install the development bundle: ```console $ mise install ``` ```console $ mise exec -- bundle config set --local path vendor/bundle ``` ```console $ mise exec -- bundle install ``` The gemspecs declare Ruby 3.3+. The [compatibility workflow](https://github.com/libtmux/libtmux-ruby/actions/workflows/compatibility.yml) tests Ruby 3.3, 3.4, and 4.0 with tmux 3.2a–3.7c on Linux and macOS. Check the results for your revision before relying on a particular combination. ## Quick start Create a session and split its `logs` window. `Server.start` owns a private tmux server and closes it when the block exits. The snapshot remains readable afterward. ```ruby require "libtmux" snapshot = LibTmux::Server.start do |server| session = server.new_session(name: "work", window_name: "main", command: ["/bin/cat"]) window = session.new_window(name: "logs", command: ["/bin/cat"]) window.split(direction: :horizontal, size: "40%", command: ["/bin/cat"]) server.snapshot end snapshot.windows.each do |window| puts "#{window.name}: #{window.panes.map(&:id).join(', ')}" end ``` Run the [complete example](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/quickstart.rb): ```console $ mise exec -- bundle exec ruby examples/quickstart.rb ``` Output: ```text main: %0 logs: %1, %2 ``` Pane commands take argument arrays. To use an existing server, open an explicit endpoint with [`LibTmux::Server.open(socket_path: ...)`](); closing that binding leaves the daemon running. See [ownership and errors](https://libtmux.org/en/ruby/latest/topics/errors-and-exceptions/). ## Query a snapshot Continue with the snapshot above. [`where`]() accepts criteria as data; `select` accepts a Ruby block. These queries make no tmux calls. ```ruby panes = snapshot.panes active_ids = panes.where(active: true).map(&:id) wide_panes = panes.select { |pane| pane.width >= 40 } panes_by_window = panes.group_by { |pane| pane.window.name } logs = snapshot.windows.one(name: "logs") missing = snapshot.windows.one_or_nil(name: "missing") ``` [`one`]() raises [`NoMatchError`]() or [`MultipleMatchesError`]() unless exactly one record matches. [`one_or_nil`]() returns `nil` for no match and still rejects duplicates. Both errors live under `LibTmux`. Selections retain captured membership. Call [`server.snapshot`]() again while the server is open to read later changes. The [field catalog](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/docs/reference/fields.md) lists query fields and wire names; the [list/filter recipe](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/list_filter.rb) also covers exact matches and queries after close. ## Gems Start with `libtmux`. Add the companion for your caller: | Gem | Require | Use it for | | --- | --- | --- | | [libtmux](https://libtmux.org/en/ruby/latest/guides/core/) | `libtmux` | Blocking scripts, snapshots, and control connections | | [libtmux-async](https://libtmux.org/en/ruby/latest/guides/async/) | `libtmux/async` | Concurrent commands and bounded streams in Async tasks | | [libtmux-mcp](https://libtmux.org/en/ruby/latest/mcp/source-guide/) | `libtmux/mcp` | An MCP server with explicit endpoints and tool policy | | [libtmux-workspace](https://libtmux.org/en/ruby/latest/workspace/source-guide/) | `libtmux/workspace` | YAML/JSON workspace plans and a CLI to apply them | Requiring a gem starts no tmux process, scheduler, or protocol server. [Execution modes](https://libtmux.org/en/ruby/latest/concepts/transports/) explains blocking calls, Async tasks, and control subscriptions. Tracked MCP captures, waits, and authored runs require tmux 3.3+ and native process identity; see the [MCP guide](https://libtmux.org/en/ruby/latest/mcp/source-guide/). Workspace client-switching semantics are in the [workspace guide](https://libtmux.org/en/ruby/latest/workspace/source-guide/). To use the core outside this checkout, build the artifacts: ```console $ mise exec -- bundle exec rake build ``` Install into the Ruby environment that will run your application. The core's runtime dependencies must already be installed for this local-only command: ```console $ gem install \ --local \ --no-document \ pkg/libtmux-0.1.0.alpha.1.gem ``` Companion gems need their declared runtime dependencies too. The [packaging check](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/.github/CONTRIBUTING.md#checks) verifies each gem in an isolated installation and runs the recipes outside the checkout. ## More examples and reference - [Send text and capture output](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/layout_io.rb): split panes, wait for output events, and round-trip binary buffers. - [Work with linked windows](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/window_links.rb): address one window at several session indexes. - [Capture concurrently](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/async_cancel.rb): read panes while another request waits, then cancel it. - [Load a workspace](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/workspace_apply.rb): parse a configuration, plan, and apply it. - [All recipes](https://libtmux.org/en/ruby/latest/examples/recipes/): cancellation, control streams, command groups, and MCP. - [API reference](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/docs/reference/api.md): public methods, source links, and behavioral contracts. RBS declarations ship with each gem; selected installed calls are checked, without a whole-program typing guarantee. - [Benchmarks](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/docs/benchmark.md): workloads, measurements, and their limits. See [Contributing](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/.github/CONTRIBUTING.md) for setup and checks. [MIT license](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/LICENSE). --- # Getting started Source: https://libtmux.org/en/scala/latest/guides/getting-started/ > Getting started: io.github.libtmux:libtmux-scala_3 documentation. The Scala facades need Scala 3.9 and JDK 25 or newer, and tmux 3.2a through 3.7c on the machine they drive. ## Install Three artifacts, all in group `io.github.libtmux` and all at the same version as `libtmux` itself. `%%` adds the `_3` suffix that marks a Scala 3 artifact. They are on Maven Central and release with the Java artifacts. - **`libtmux-scala_3`** — direct-style handles, collections and the typed query DSL. - **`libtmux-scala-cats_3`** — Cats Effect resources and FS2 observations. - **`libtmux-scala-ox_3`** — an Ox [`Flow`]() over subscriptions and live views. ```sbt libraryDependencies += "io.github.libtmux" %% "libtmux-scala" % "" ``` For Cats Effect and FS2, or for Ox, add the matching module: ```sbt libraryDependencies += "io.github.libtmux" %% "libtmux-scala-cats" % "" ``` ```sbt libraryDependencies += "io.github.libtmux" %% "libtmux-scala-ox" % "" ``` From Gradle or Maven, name the suffixed artifact directly: `io.github.libtmux:libtmux-scala_3:`. The core facade depends on `libtmux` and the Scala 3 library, and on nothing else. ## A first client The function below takes three caller-supplied values and constructs a Java [`ServerConfig`]() before opening the Scala client: | Parameter | Value to supply | | --- | --- | | `binary` | Absolute path to your tmux executable | | `socket` | An isolated socket you own under `/tmp/libtmux-java-dev/` | | `configFile` | Your tmux configuration file, or `/dev/null` for none | For example, choose `/tmp/libtmux-java-dev/scala-start/socket`; the function creates its parent directory. Opening the client does not create tmux; [`newSession`]() does. The operation creates a session, splits its window, verifies the resulting panes and kills that session. Closing the client is separate from session cleanup. An existing server's other sessions remain running; tmux normally exits when its final session closes. Call `firstClient` with your three values from your application. The final call in this tested snippet takes those inputs from the owned test fixture's `config`; the function builds and uses its own configuration. ```scala import io.github.libtmux.{ Layout, ServerConfig, ServerEndpoint, SessionSpec, SplitSpec } import io.github.libtmux.scaladsl.{config => _, *} import java.nio.file.{Files, Path} import java.time.Duration import scala.util.Using def firstClient(binary: String, socket: Path, configFile: Path): Unit = { require(Path.of(binary).isAbsolute, "supply an absolute tmux executable") val ownedSocket = socket.toAbsolutePath.normalize() require( ownedSocket.startsWith(Path.of("/tmp/libtmux-java-dev")) || ownedSocket.startsWith(Path.of("/tmp/libtmux-java-test")), "choose a socket under an owned libtmux Java directory" ) Files.createDirectories(ownedSocket.getParent) val selected = ServerConfig.builder() .binary(binary) .endpoint(ServerEndpoint.socketPath(ownedSocket)) .configFile(configFile) .defaultTimeout(Duration.ofMillis(800)) .build() Using.resource(Server.open(selected)) { server => val session = server.newSession( SessionSpec.builder().named("scala-start").running("cat", "-").build() ) try { val window = session.windows.head val second = window.split( SplitSpec.builder().running("cat", "-").build() ) window.selectLayout(Layout.EVEN_HORIZONTAL) second.select() // window.panes is CAPTURED: it answers from window's own frozen capture, taken before the // split, so this refreshes first rather than reading stale data. val panes = window.refresh().panes assert(panes.size == 2) assert(panes.exists(_.info.id().value() == second.info.id().value())) } finally session.kill() } } config.endpoint() match { case endpoint: ServerEndpoint.SocketPath => firstClient( config.binaryPath(), endpoint.path(), config.configFile().orElse(Path.of("/dev/null")) ) case _ => throw new IllegalArgumentException("an explicit socket is required") } ``` Timeouts are [`scala.concurrent.duration.FiniteDuration`]() at every public entry point, converted once at the boundary: `pane.awaitText("$", 5.seconds)` never surfaces [`java.time.Duration`]() to the caller. Follow with [queries](https://libtmux.org/en/scala/latest/guides/query/), [ownership](https://libtmux.org/en/scala/latest/guides/ownership/), then [execution](https://libtmux.org/en/scala/latest/guides/execution/). For immediate access without the facade, use the [direct Java guide](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/docs/guide/scala.md). ## Build from source The facades build with the rest of the repository, from its root: ```console $ ./gradlew :libtmux-scala:check :libtmux-scala-cats:check :libtmux-scala-ox:check ``` The real-tmux suites run with the Java ones in `integration-tests`: ```console $ ./gradlew :integration-tests:test --tests 'io.github.libtmux.scaladsl.*' ``` Format Scala sources before committing: ```console $ ./gradlew spotlessApply ``` The API documentation, with a browser for every source it documents, generated operations included, starts at `libtmux-scala/build/docs/scaladoc/index.html`: ```console $ ./gradlew :libtmux-scala:scaladocSite ``` Begin with [direct-style `Server`][server] or [Cats `Server`][cats-server]. [server]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Server.scala [cats-server]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/src/main/scala/io/github/libtmux/scaladsl/cats/Server.scala --- # Getting started Source: https://libtmux.org/en/tmux/guides/getting-started/ > Create a tmux session, add a window and split it into panes. Create a session, add a window, and split that window into panes. These are the same tmux objects that the language libraries control. ## Install tmux Install tmux with your platform's package manager. These examples require tmux 3.2a or newer and a POSIX shell. Confirm the installed version: ```console $ tmux -V ``` ## Run the smallest thing that proves it works Save this complete script as `start.sh`, or paste its entire block into a shell. It creates a private server, so it does not need an existing session. Each pane runs `cat` to keep it alive until cleanup. ```sh title="start.sh" #!/bin/sh set -eu directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-guide.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! tmux -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || status=$? exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM tmux -S "$socket" -f /dev/null new-session -d -s work -n main 'cat' tmux -S "$socket" new-window -t work: -n editor 'cat' tmux -S "$socket" split-window -h -t work:editor 'cat' tmux -S "$socket" list-panes -a -F '#{session_name}:#{window_name}' ``` Run the saved script: ```console $ sh start.sh ``` The output contains `work:main` once and `work:editor` twice: one session, two windows, and three panes. The script stops its server on exit, including after a failed command. If shutdown fails, it reports and retains the socket path. ## What just happened `-S` selects the server socket. `new-session` starts that server and its first window; `new-window` adds another window; `split-window` adds a pane. `-d` starts the session without taking over the terminal. `-f /dev/null` starts this private server without a user configuration file. [Server, session, window, pane](https://libtmux.org/en/tmux/concepts/server-session-window-pane/) explains the hierarchy. [Attaching to tmux](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) shows how to open a session interactively and leave it running after detaching. ## Pick a port Use the port dropdown for language-specific installation and APIs. The complete programs below include imports, project files, setup, error handling and cleanup: [Python](https://libtmux.org/en/py/latest/examples/capture-pane-output/) · [TypeScript](https://libtmux.org/en/ts/latest/examples/capture-pane-output/) · [Go](https://libtmux.org/en/go/latest/examples/capture-pane-output/) · [Rust](https://libtmux.org/en/rs/latest/examples/capture-pane-output/) · [Java](https://libtmux.org/en/java/latest/examples/capture-pane-output/) · [Kotlin](https://libtmux.org/en/kotlin/latest/examples/capture-pane-output/) · [Scala](https://libtmux.org/en/scala/latest/examples/capture-pane-output/) · [C#](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/) · [F#](https://libtmux.org/en/fsharp/latest/examples/capture-pane-output/) · [C++](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/) · [Swift](https://libtmux.org/en/swift/latest/examples/capture-pane-output/) · [Ruby](https://libtmux.org/en/ruby/latest/examples/capture-pane-output/) · [Lua](https://libtmux.org/en/lua/latest/examples/capture-pane-output/) ## Where to go next [Sending keys](https://libtmux.org/en/tmux/guides/sending-keys/) types input, and [Capturing output](https://libtmux.org/en/tmux/guides/capturing-output/) reads a result. Use [Querying and filtering](https://libtmux.org/en/tmux/guides/querying-and-filtering/) to choose a target. ## tmux reference Read the command references for [new-session](https://libtmux.org/en/tmux/latest/manual/new-session/), [list-sessions](https://libtmux.org/en/tmux/latest/manual/list-sessions/), and [kill-server](https://libtmux.org/en/tmux/latest/manual/kill-server/). Select your tmux version on any reference page. The [tmux manual](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1) documents these commands and their flags. --- # Getting started Source: https://libtmux.org/en/csharp/latest/guides/getting-started/ > Run a complete program with this language library. Use [`LibTmux`]() to create sessions, send input and read pane output from C#. The [complete capture program](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/) includes imports, its entry point, project files, dependency setup and a run command. ## Run the smallest thing that proves it works Open that example in an empty directory and save the files using their displayed names. Its setup pins the library revision that was used to execute the program. It needs tmux on `PATH` and the native tools named on the example page. The program creates a private server, sends a command, waits for the complete line `libtmux capture ready`, then cleans up. A timeout or command failure is reported. It does not need an existing tmux session. ## What just happened [`Pane.CaptureAsync`]() reads visible pane lines. The complete program passes a cancellation token, compares whole lines and bounds its waits with a [`CancellationTokenSource`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=net-10.0). Its [`OwnedServerScope`]() owns the private server and is disposed with `await using`. ## Connect to an existing server Use the [complete attach program](https://libtmux.org/en/csharp/latest/guides/attaching-to-tmux/) to select an existing socket and find the `work` session. That example leaves tmux running; its launcher owns setup and cleanup for trying it safely. ## Where to go next [Sending keys](https://libtmux.org/en/csharp/latest/guides/sending-keys/) explains input, and [Capturing output](https://libtmux.org/en/csharp/latest/guides/capturing-output/) explains completion. [Querying and filtering](https://libtmux.org/en/csharp/latest/guides/querying-and-filtering/) selects a target. --- # Getting started Source: https://libtmux.org/en/cxx/latest/guides/getting-started/ > Run a complete program with this language library. Use [`libtmux`]() to create sessions, send input and read pane output from C++. The [complete capture program](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/) includes imports, its entry point, project files, dependency setup and a run command. ## Run the smallest thing that proves it works Open that example in an empty directory and save the files using their displayed names. Its setup pins the library revision that was used to execute the program. It needs tmux on `PATH` and the native tools named on the example page. The program creates a private server, sends a command, waits for the complete line `libtmux capture ready`, then cleans up. A timeout or command failure is reported. It does not need an existing tmux session. ## What just happened [`Pane::capture`]() returns captured text through a result that must be checked. The complete program splits that text into lines and compares a whole line before its deadline. Capture options select history and bound the output size; an exceeded output limit is reported as an error. ## Connect to an existing server Use the [complete attach program](https://libtmux.org/en/cxx/latest/guides/attaching-to-tmux/) to select an existing socket and find the `work` session. That example leaves tmux running; its launcher owns setup and cleanup for trying it safely. ## Where to go next [Sending keys](https://libtmux.org/en/cxx/latest/guides/sending-keys/) explains input, and [Capturing output](https://libtmux.org/en/cxx/latest/guides/capturing-output/) explains completion. [Querying and filtering](https://libtmux.org/en/cxx/latest/guides/querying-and-filtering/) selects a target. --- # Getting started Source: https://libtmux.org/en/go/latest/guides/getting-started/ > Run a complete program with this language library. Use the [`tmux`]() package to create sessions, send input and read pane output from Go. The [complete capture program](https://libtmux.org/en/go/latest/examples/capture-pane-output/) includes imports, its entry point, project files, dependency setup and a run command. ## Run the smallest thing that proves it works Open that example in an empty directory and save the files using their displayed names. Its setup pins the library revision that was used to execute the program. It needs tmux on `PATH` and the native tools named on the example page. The program creates a private server, sends a command, waits for the complete line `libtmux capture ready`, then cleans up. A timeout or command failure is reported. It does not need an existing tmux session. ## What just happened [`Pane.Capture`]() takes a [`tmux.CapturePaneRequest`](). Use `Start` and [`End`]() to choose a range; [`tmux.CaptureBoundary`]() reaches the corresponding history or screen boundary. The complete program reads the visible screen, compares full lines and stops when its context expires. ## Connect to an existing server Use the [complete attach program](https://libtmux.org/en/go/latest/guides/attaching-to-tmux/) to select an existing socket and find the `work` session. That example leaves tmux running; its launcher owns setup and cleanup for trying it safely. ## Create and inspect the hierarchy The [complete hierarchy programs](https://libtmux.org/en/go/latest/concepts/server-session-window-pane/) create a session, add a window, split a pane and list the resulting objects. They also show how captured records differ from a fresh read after a rename. ## Where to go next [Sending keys](https://libtmux.org/en/go/latest/guides/sending-keys/) explains input, and [Capturing output](https://libtmux.org/en/go/latest/guides/capturing-output/) explains completion. [Querying and filtering](https://libtmux.org/en/go/latest/guides/querying-and-filtering/) selects a target. --- # Getting started Source: https://libtmux.org/en/java/latest/guides/getting-started/ > Run a complete program with this language library. Use [`Server`]() to create sessions, send input and read pane output from Java. The [complete capture program](https://libtmux.org/en/java/latest/examples/capture-pane-output/) includes imports, its entry point, project files, dependency setup and a run command. ## Run the smallest thing that proves it works Open that example in an empty directory and save the files using their displayed names. Its setup pins the library revision that was used to execute the program. It needs tmux on `PATH` and the native tools named on the example page. The program creates a private server, sends a command, waits for the complete line `libtmux capture ready`, then cleans up. A timeout or command failure is reported. It does not need an existing tmux session. ## What just happened [`Pane.capture`]() returns visible pane contents as a list of lines. The complete program compares a full line with its expected value and checks a monotonic deadline. A `finally` block kills its private tmux server, while try-with-resources closes the [`Server`]() handle. ## Connect to an existing server Use the [complete attach program](https://libtmux.org/en/java/latest/guides/attaching-to-tmux/) to select an existing socket and find the `work` session. That example leaves tmux running; its launcher owns setup and cleanup for trying it safely. ## Where to go next [Sending keys](https://libtmux.org/en/java/latest/guides/sending-keys/) explains input, and [Capturing output](https://libtmux.org/en/java/latest/guides/capturing-output/) explains completion. [Querying and filtering](https://libtmux.org/en/java/latest/guides/querying-and-filtering/) selects a target. --- # Getting started Source: https://libtmux.org/en/py/latest/guides/getting-started/ > Run a complete program with this language library. Use [`libtmux`]() to create sessions, send input and read pane output from Python. The [complete capture program](https://libtmux.org/en/py/latest/examples/capture-pane-output/) includes imports, its entry point, project files, dependency setup and a run command. ## Run the smallest thing that proves it works Open that example in an empty directory and save the files using their displayed names. Its setup pins the library revision that was used to execute the program. It needs tmux on `PATH` and the native tools named on the example page. The program creates a private server, sends a command, waits for the complete line `libtmux capture ready`, then cleans up. A timeout or command failure is reported. It does not need an existing tmux session. ## What just happened [`Pane.capture_pane`]() returns a list of lines. The complete program compares whole lines, uses a monotonic deadline and closes its private server in [`finally`](). The echoed shell command cannot satisfy its output check. ## Connect to an existing server Use the [complete attach program](https://libtmux.org/en/py/latest/guides/attaching-to-tmux/) to select an existing socket and find the `work` session. That example leaves tmux running; its launcher owns setup and cleanup for trying it safely. ## Where to go next [Sending keys](https://libtmux.org/en/py/latest/guides/sending-keys/) explains input, and [Capturing output](https://libtmux.org/en/py/latest/guides/capturing-output/) explains completion. [Querying and filtering](https://libtmux.org/en/py/latest/guides/querying-and-filtering/) selects a target. --- # Getting started Source: https://libtmux.org/en/rs/latest/guides/getting-started/ > Run a complete program with this language library. Use `libtmux` to create sessions, send input and read pane output from Rust. The [complete capture program](https://libtmux.org/en/rs/latest/examples/capture-pane-output/) includes imports, its entry point, project files, dependency setup and a run command. ## Run the smallest thing that proves it works Open that example in an empty directory and save the files using their displayed names. Its setup pins the library revision that was used to execute the program. It needs tmux on `PATH` and the native tools named on the example page. The program creates a private server, sends a command, waits for the complete line `libtmux capture ready`, then cleans up. A timeout or command failure is reported. It does not need an existing tmux session. ## What just happened [`Pane::capture`]() reads the visible screen. The complete program compares the returned line bytes with the expected output and uses [`tokio::time::timeout`](https://docs.rs/tokio/latest/tokio/time/fn.timeout.html) to bound the task. It kills its private server and shuts down the client before returning a capture error. ## Connect to an existing server Use the [complete attach program](https://libtmux.org/en/rs/latest/guides/attaching-to-tmux/) to select an existing socket and find the `work` session. That example leaves tmux running; its launcher owns setup and cleanup for trying it safely. ## Where to go next [Sending keys](https://libtmux.org/en/rs/latest/guides/sending-keys/) explains input, and [Capturing output](https://libtmux.org/en/rs/latest/guides/capturing-output/) explains completion. [Querying and filtering](https://libtmux.org/en/rs/latest/guides/querying-and-filtering/) selects a target. --- # Getting started Source: https://libtmux.org/en/swift/latest/guides/getting-started/ > Run a complete program with this language library. Use [`Server`]() to create sessions, send input and read pane output from Swift. The [complete capture program](https://libtmux.org/en/swift/latest/examples/capture-pane-output/) includes imports, its entry point, project files, dependency setup and a run command. ## Run the smallest thing that proves it works Open that example in an empty directory and save the files using their displayed names. Its setup pins the library revision that was used to execute the program. It needs tmux on `PATH` and the native tools named on the example page. The program creates a private server, sends a command, waits for the complete line `libtmux capture ready`, then cleans up. A timeout or command failure is reported. It does not need an existing tmux session. ## What just happened `Server.capture` reads pane lines. The complete program compares a whole line, bounds the wait and reports cleanup errors. For repeated reads of changing output, the streaming APIs can track output beyond one screen snapshot; consult this version's API reference for their lifetime and completion rules. ## Connect to an existing server Use the [complete attach program](https://libtmux.org/en/swift/latest/guides/attaching-to-tmux/) to select an existing socket and find the `work` session. That example leaves tmux running; its launcher owns setup and cleanup for trying it safely. ## Where to go next [Sending keys](https://libtmux.org/en/swift/latest/guides/sending-keys/) explains input, and [Capturing output](https://libtmux.org/en/swift/latest/guides/capturing-output/) explains completion. [Querying and filtering](https://libtmux.org/en/swift/latest/guides/querying-and-filtering/) selects a target. --- # Getting started Source: https://libtmux.org/en/ts/latest/guides/getting-started/ > Run a complete program with this language library. Use `libtmux` to create sessions, send input and read pane output from TypeScript. The [complete capture program](https://libtmux.org/en/ts/latest/examples/capture-pane-output/) includes imports, its entry point, project files, dependency setup and a run command. ## Run the smallest thing that proves it works Open that example in an empty directory and save the files using their displayed names. Its setup pins the library revision that was used to execute the program. It needs tmux on `PATH` and the native tools named on the example page. The program creates a private server, sends a command, waits for the complete line `libtmux capture ready`, then cleans up. A timeout or command failure is reported. It does not need an existing tmux session. ## What just happened [`Pane.capture`]() returns captured lines. The complete program uses [`AbortSignal.timeout`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static) for a deadline and matches a whole output line. Its cleanup checks whether the private socket exists, including when startup fails, and reports shutdown errors. ## Connect to an existing server Use the [complete attach program](https://libtmux.org/en/ts/latest/guides/attaching-to-tmux/) to select an existing socket and find the `work` session. That example leaves tmux running; its launcher owns setup and cleanup for trying it safely. ## Where to go next [Sending keys](https://libtmux.org/en/ts/latest/guides/sending-keys/) explains input, and [Capturing output](https://libtmux.org/en/ts/latest/guides/capturing-output/) explains completion. [Querying and filtering](https://libtmux.org/en/ts/latest/guides/querying-and-filtering/) selects a target. --- # Go MCP guides Source: https://libtmux.org/en/go/latest/mcp/guides/ > Install the executable, select a tmux endpoint, and diagnose an MCP client's connection. Let your MCP client start `libtmux-mcp` as a subprocess. The [connection guide](https://libtmux.org/en/go/latest/mcp/guides/connect-client/) covers installation, a dedicated server, and selecting an existing socket. ## Install the command Build the executable with Go 1.26 or newer and run it with tmux 3.2a or newer. Follow the [installation steps](https://libtmux.org/en/go/latest/mcp/guides/connect-client/#install-the-command), or use the [complete client example](https://libtmux.org/en/go/latest/mcp/examples/inspect-sessions/) to install into an isolated project directory. ## Inspect the selection The launcher's `-tools` report checks whether the selected tmux server is answering, without starting it. Use the client's socket and environment when [checking the configuration](https://libtmux.org/en/go/latest/mcp/guides/connect-client/#inspect-the-selection). ## Connect a client Configure one socket and the [tools you need](https://libtmux.org/en/go/latest/mcp/topics/tool-selection/) in the client's startup environment. Keep stdout available for MCP messages; read startup errors in the client's stderr log. Use the [startup checks](https://libtmux.org/en/go/latest/mcp/guides/connect-client/#diagnose-startup) when a connection fails. - [Connect a client](https://libtmux.org/en/go/latest/mcp/guides/connect-client/): Install the pinned executable and configure its socket and tools. --- # Attaching to tmux Source: https://libtmux.org/en/tmux/guides/attaching-to-tmux/ > Create or attach to a tmux session, select its socket, and keep terminal attachment separate from automation. Attaching opens a tmux session in your terminal. Its shells and programs keep running when you detach. A script can also query or control that session without taking over a terminal. ## Open a session in your terminal Run this from a terminal outside tmux. It creates `work` if needed and attaches to it otherwise. `-L libtmux-demo` keeps this demonstration on its own named server. `-f /dev/null` skips personal tmux configuration for this demonstration. ```console $ tmux -L libtmux-demo -f /dev/null new-session -A -s work ``` Detach with **Ctrl-b**, then **d**. You return to the original shell while the tmux session keeps running. List that server's sessions: ```console $ tmux -L libtmux-demo list-sessions ``` Attach to the existing session again. The leading `=` selects its exact name: ```console $ tmux -L libtmux-demo attach-session -t '=work' ``` `attach-session` expects a session to exist. `new-session -A` is the command to use when either creating or attaching is acceptable. From inside tmux, `attach-session` switches the attached client to the target session. After detaching, remove the demonstration session when you are finished: ```console $ tmux -L libtmux-demo kill-session -t '=work' ``` ## Choose the server socket A socket identifies a tmux server. Use the same selection on every command: - `-L name` selects a named socket in tmux's socket directory. - `-S path` selects an explicit socket path and overrides `-L`. - Without either flag, tmux uses the socket from [`TMUX`]() when applicable, otherwise its default socket. Inside a pane, [`TMUX`]() identifies its server and [`TMUX_PANE`]() identifies the pane. Prefer explicit socket selection in automation that may run both inside and outside tmux. ## Query a session from a shell script This complete program creates an isolated server, looks up `work`, and prints its name. Each command stays in the calling shell; no terminal is attached. It stops its own server on success or failure. Save it as `connect.sh` and run `sh connect.sh`, or paste the whole block into a POSIX shell. It requires tmux 3.2a or newer. ```sh title="connect.sh" ( set -eu directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! tmux -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE tmux -S "$socket" -f /dev/null new-session -d -s work /bin/cat tmux -S "$socket" has-session -t '=work' tmux -S "$socket" list-sessions -F '#{session_name}' ) ``` `-d` starts the session without attaching. `/bin/cat` keeps its pane open without loading a shell configuration. The script addresses only its private socket. If shutdown fails, it reports the error and keeps that socket's directory for inspection. ## Find a session before creating one Use `has-session -t '=name'` to check an exact session name. It exits unsuccessfully when tmux cannot find the session or contact the server; keep the diagnostic so you can distinguish those failures. A lookup does not reserve a name. Another client can create or remove a session before your next command. Handle the result of `new-session` even after checking. Use `new-session -A` for the interactive create-or-attach workflow shown above. ## Connect from a language library Use the port menu to open this guide with a complete program, imports, build files, and a private-server launcher. Each program connects to an existing socket and leaves that server running: [Python](https://libtmux.org/en/py/latest/guides/attaching-to-tmux/) · [TypeScript](https://libtmux.org/en/ts/latest/guides/attaching-to-tmux/) · [Go](https://libtmux.org/en/go/latest/guides/attaching-to-tmux/) · [Rust](https://libtmux.org/en/rs/latest/guides/attaching-to-tmux/) · [Java](https://libtmux.org/en/java/latest/guides/attaching-to-tmux/) · [Kotlin](https://libtmux.org/en/kotlin/latest/guides/attaching-to-tmux/) · [Scala](https://libtmux.org/en/scala/latest/guides/attaching-to-tmux/) · [C#](https://libtmux.org/en/csharp/latest/guides/attaching-to-tmux/) · [F#](https://libtmux.org/en/fsharp/latest/guides/attaching-to-tmux/) · [C++](https://libtmux.org/en/cxx/latest/guides/attaching-to-tmux/) · [Swift](https://libtmux.org/en/swift/latest/guides/attaching-to-tmux/) · [Ruby](https://libtmux.org/en/ruby/latest/guides/attaching-to-tmux/) · [Lua](https://libtmux.org/en/lua/latest/guides/attaching-to-tmux/) ## Where to go next - [Sending keys](https://libtmux.org/en/tmux/guides/sending-keys/) explains input and command completion. - [Capturing output](https://libtmux.org/en/tmux/guides/capturing-output/) reads a pane's screen and history. - [Socket and servers](https://libtmux.org/en/tmux/topics/socket-and-servers/) covers server selection. The [attach-session reference](https://libtmux.org/en/tmux/latest/manual/attach-session/) covers attachment flags. See [has-session](https://libtmux.org/en/tmux/latest/manual/has-session/) for existence checks and the [global options](https://libtmux.org/en/tmux/latest/manual/full/#DESCRIPTION) for selecting a server socket. The [tmux manual source](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1) describes `new-session`, `attach-session`, socket selection, and targeting. --- # Attaching to tmux Source: https://libtmux.org/en/csharp/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with C#. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `Program.cs`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```csharp title="Program.cs" using System; using System.Threading; using System.Threading.Tasks; using LibTmux; string socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") ?? throw new InvalidOperationException("Set LIBTMUX_SOCKET_PATH to an existing socket"); using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); Server server = await Server.ConnectAsync( new ServerConnectionOptions { SocketPath = socket }, timeout.Token); if (!await server.HasSessionAsync("work", cancellationToken: timeout.Token)) throw new InvalidOperationException("The work session does not exist"); Console.WriteLine("work"); ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with .NET SDK 10.0.302. Save this file beside the program using the displayed filename. ```xml title="Connect.csproj" Exe net10.0 disable enable false ``` Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-dotnet-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-dotnet libtmux-source && git -C libtmux-source checkout 320dc64f4b8b7815842471327a5e6b84a1499bf8 && dotnet build Connect.csproj --maxcpucount:1 && sh run.sh dotnet run --project Connect.csproj --no-build ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/). Continue with [Sending keys](https://libtmux.org/en/csharp/latest/guides/sending-keys/) once you have a pane handle. --- # Attaching to tmux Source: https://libtmux.org/en/cxx/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with C++. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `connect.cpp`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```cpp title="connect.cpp" #include #include #include #include int main() { try { const char* socket = std::getenv("LIBTMUX_SOCKET_PATH"); if (!socket) throw std::runtime_error("Set LIBTMUX_SOCKET_PATH to an existing socket"); auto server = libtmux::Server::at_socket_path(socket); if (!server) throw std::runtime_error(server.error().diagnostic); auto sessions = server->sessions(); if (!sessions) throw std::runtime_error(sessions.error().diagnostic); for (const auto& session : *sessions) { if (session.name() == "work") { std::cout << "work\n"; return 0; } } throw std::runtime_error("The work session does not exist"); } catch (const std::exception& error) { std::cerr << error.what() << '\n'; return 1; } } ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with Clang 18, libc++ 18, CMake 3.25+. Use CMake 3.25 or newer, Ninja, and Clang 18 with libc++ 18. Save this file beside the program using the displayed filename. ```cmake title="CMakeLists.txt" cmake_minimum_required(VERSION 3.25) project(connect_example LANGUAGES CXX) set(LIBTMUX_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(LIBTMUX_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) add_subdirectory(libtmux-source) add_executable(connect connect.cpp) target_compile_features(connect PRIVATE cxx_std_23) target_link_libraries(connect PRIVATE libtmux::libtmux) ``` Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-cxx-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-cxx libtmux-source && git -C libtmux-source checkout 393d4b0ad666f18a6581f1eb281741a75a7503f0 && cmake -S . -B build -G Ninja \ -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_CXX_FLAGS=-stdlib=libc++ \ -DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++ && cmake --build build --target connect --parallel 2 && sh run.sh ./build/connect ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/). Continue with [Sending keys](https://libtmux.org/en/cxx/latest/guides/sending-keys/) once you have a pane handle. --- # Attaching to tmux Source: https://libtmux.org/en/fsharp/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with F#. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `Program.fs`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```fsharp title="Program.fs" open System open System.Threading open System.Threading.Tasks open LibTmux let connect () = task { let socket = Environment.GetEnvironmentVariable("LIBTMUX_SOCKET_PATH") if String.IsNullOrEmpty(socket) then invalidOp "Set LIBTMUX_SOCKET_PATH to an existing socket" use timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5.0)) let! server = Server.ConnectAsync( ServerConnectionOptions(SocketPath = socket), timeout.Token) let! exists = server.HasSessionAsync("work", cancellationToken = timeout.Token) if not exists then invalidOp "The work session does not exist" printfn "work" } [] let main _ = try connect().GetAwaiter().GetResult() 0 with error -> eprintfn "%O" error 1 ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with .NET SDK 10.0.302. Save this file beside the program using the displayed filename. ```xml title="Connect.fsproj" Exe net10.0 ``` Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-fsharp-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-dotnet libtmux-source && git -C libtmux-source checkout 661287848a6cfb407f37114b25e8249a29f99e3f && dotnet build Connect.fsproj --maxcpucount:1 \ -p:DisableImplicitLibraryPacksFolder=true \ -p:RestorePackagesPath="$PWD/.packages" && sh run.sh dotnet run --project Connect.fsproj --no-build ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/tmux/examples/capture-pane-output/). --- # Attaching to tmux Source: https://libtmux.org/en/go/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with Go. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `main.go`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```go title="main.go" package main import ( "context" "fmt" "log" "os" "time" "github.com/libtmux/libtmux-go/tmux" ) func main() { socket := os.Getenv("LIBTMUX_SOCKET_PATH") if socket == "" { log.Fatal("Set LIBTMUX_SOCKET_PATH to an existing socket") } server, err := tmux.NewServer(tmux.ServerOptions{SocketPath: socket}) if err != nil { log.Fatal(err) } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() filter := tmux.TmuxFilter("#{==:#{session_name},work}") sessions, err := server.SearchSessions(ctx, &filter) if err != nil { log.Fatal(err) } if len(sessions) != 1 { log.Fatalf("Expected one work session, found %d", len(sessions)) } fmt.Println("work") } ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with Go 1.26.8. Save this file beside the program using the displayed filename. ```text title="go.mod" module example.com/connect go 1.26.0 require github.com/libtmux/libtmux-go v0.0.0 replace github.com/libtmux/libtmux-go => ./libtmux ``` Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-go-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-go libtmux && git -C libtmux checkout bb06e26e116e941813ca40bf45e7e3a47d38f52a && GOWORK=off go mod tidy && sh run.sh env GOWORK=off go run . ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/go/latest/examples/capture-pane-output/). Continue with [Sending keys](https://libtmux.org/en/go/latest/guides/sending-keys/) once you have a pane handle. --- # Attaching to tmux Source: https://libtmux.org/en/java/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with Java. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `Connect.java`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```java title="Connect.java" import io.github.libtmux.Server; import io.github.libtmux.ServerConfig; import io.github.libtmux.ServerEndpoint; import io.github.libtmux.Session; import java.nio.file.Path; import java.time.Duration; import java.util.Objects; public final class Connect { public static void main(String[] args) { String socket = Objects.requireNonNull(System.getenv("LIBTMUX_SOCKET_PATH"), "Set LIBTMUX_SOCKET_PATH to an existing socket"); ServerConfig config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build(); try (Server server = Server.open(config)) { Session session = server.sessions().stream() .filter(candidate -> candidate.name().equals("work")) .findFirst() .orElseThrow(() -> new IllegalStateException("The work session does not exist")); System.out.println(session.name()); } } } ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with JDK 25.0.3, library bytecode target Java 21. Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-java-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux && git -C libtmux checkout 842228310449e879ebcaa3f910597757c9dbffd6 && (cd libtmux && ./gradlew :libtmux:jar) && sh run.sh java --class-path 'libtmux/libtmux/build/libs/*' Connect.java ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/java/latest/examples/capture-pane-output/). Continue with [Sending keys](https://libtmux.org/en/java/latest/guides/sending-keys/) once you have a pane handle. --- # Attaching to tmux Source: https://libtmux.org/en/kotlin/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with Kotlin. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `Connect.kt`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```kotlin title="Connect.kt" import io.github.libtmux.ServerConfig import io.github.libtmux.ServerEndpoint import io.github.libtmux.kotlin.sessions import io.github.libtmux.kotlin.withServer import java.nio.file.Path import java.time.Duration import kotlinx.coroutines.runBlocking fun main() = runBlocking { val socket = requireNotNull(System.getenv("LIBTMUX_SOCKET_PATH")) { "Set LIBTMUX_SOCKET_PATH to an existing socket" } val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() withServer(config) { server -> val session = server.sessions().single { it.name == "work" } println(session.name) } } ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with JDK 25.0.3, Kotlin 2.4.10. Save this file beside the program using the displayed filename. ```kotlin title="build.gradle.kts" plugins { application kotlin("jvm") version "2.4.10" } repositories { mavenCentral() } dependencies { implementation("io.github.libtmux:libtmux-kotlin:0.0.1-alpha.17-SNAPSHOT") } kotlin { jvmToolchain(25) sourceSets.main { kotlin.srcDir("."); kotlin.include("Connect.kt") } } application { mainClass.set("ConnectKt") } ``` Save this file beside the program using the displayed filename. ```kotlin title="settings.gradle.kts" rootProject.name = "connect" includeBuild("libtmux-source") ``` Save this file beside the program using the displayed filename. ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-kotlin-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout 85ebf6955e56703c5be74e2afd34a18309044741 && sh run.sh ./libtmux-source/gradlew --project-dir . run --console=plain --max-workers=2 ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/tmux/examples/capture-pane-output/). --- # Attaching to tmux Source: https://libtmux.org/en/lua/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with Lua. Connect a `Server` to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `connect.lua`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```lua title="connect.lua" local adapter = require("libtmux.runtime.luv") local function must(value, err) if err ~= nil then error(tostring(err), 0) end return value end local socket = assert(os.getenv("LIBTMUX_SOCKET_PATH"), "set LIBTMUX_SOCKET_PATH") local binary = assert(os.getenv("TMUX_BIN"), "set TMUX_BIN to the absolute tmux path") must(adapter.run(function(runtime) local server = must(runtime:connect({ binary = binary, socket_path = socket }):await()) local snapshot, capture_error = server:snapshot({ strict = true }):await() local closed, close_error = server:close():await() must(snapshot, capture_error) must(closed, close_error) for _, session in ipairs(snapshot.sessions) do if session.name == "work" then print("work") return true end end error("The work session does not exist", 0) end)) ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with Lua 5.5.1, luv 1.52.1-0. Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-lua-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-lua libtmux-source && git -C libtmux-source checkout 5baa3f9b830ebdbc76fb50b5b3d7a5ad3f76d443 && luarocks --tree ./rocks install luv 1.52.1-0 && (cd libtmux-source && luarocks --tree ../rocks make rockspecs/libtmux-scm-1.rockspec) && eval "$(luarocks --tree ./rocks path)" && sh run.sh lua connect.lua ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. Also set `TMUX_BIN` to the absolute path of the tmux executable. The launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/lua/latest/examples/capture-pane-output/). --- # Attaching to tmux Source: https://libtmux.org/en/py/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with Python. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `connect.py`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```python title="connect.py" import os import libtmux server = libtmux.Server(socket_path=os.environ["LIBTMUX_SOCKET_PATH"]) session = server.sessions.get(session_name="work") print(session.session_name) ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with Python 3.14.6. Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-py-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ sh run.sh uv run \ --with 'libtmux @ git+https://github.com/tmux-python/libtmux@9fdd083a8181a827889337b63cd4e6daea661a8c' \ connect.py ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/py/latest/examples/capture-pane-output/). Continue with [Sending keys](https://libtmux.org/en/py/latest/guides/sending-keys/) once you have a pane handle. --- # Attaching to tmux Source: https://libtmux.org/en/rs/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with Rust. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `src/main.rs`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```rust title="src/main.rs" use std::error::Error; use std::time::Duration; use libtmux::Server; use tokio::time::timeout; #[tokio::main] async fn main() -> Result<(), Box> { let socket = std::env::var("LIBTMUX_SOCKET_PATH")?; let server = Server::builder().socket_path(socket).build()?; let result = timeout(Duration::from_secs(5), async { let sessions = server.sessions().await?; if !sessions .iter() .any(|session| session.name().as_bytes() == b"work") { return Err("The work session does not exist".into()); } println!("work"); Ok::<_, Box>(()) }) .await; let closed = server.shutdown().await; result??; closed?; Ok(()) } ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with Rust 1.97.1. Save this file beside the program using the displayed filename. ```toml title="Cargo.toml" [package] name = "connect-example" version = "0.1.0" edition = "2024" [dependencies] libtmux = { path = "libtmux/crates/libtmux" } tokio = { version = "1.53.1", features = ["macros", "rt-multi-thread", "time"] } ``` Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-rs-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-rs libtmux && git -C libtmux checkout d4e08b4eaab62ef4eeedab79b47973ae9a1de310 && sh run.sh cargo +1.97.1 run ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/rs/latest/examples/capture-pane-output/). Continue with [Sending keys](https://libtmux.org/en/rs/latest/guides/sending-keys/) once you have a pane handle. --- # Attaching to tmux Source: https://libtmux.org/en/ruby/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with Ruby. Connect a `Server` to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `connect.rb`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```ruby title="connect.rb" require "libtmux" LibTmux::Server.open(socket_path: ENV.fetch("LIBTMUX_SOCKET_PATH")) do |server| session = server.snapshot.sessions.find { |candidate| candidate.name == "work" } raise "The work session does not exist" unless session puts session.name end ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with Ruby 4.0.7, Bundler. Save this file beside the program using the displayed filename. ```ruby title="Gemfile" source "https://rubygems.org" gem "libtmux", path: "libtmux-source/gems/libtmux" ``` Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-ruby-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-ruby libtmux-source && git -C libtmux-source checkout 2599d45369515aaf2fd5793bfe71cdc20de641b6 && bundle config set --local path vendor/bundle && bundle install && sh run.sh bundle exec ruby connect.rb ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/ruby/latest/examples/capture-pane-output/). --- # Attaching to tmux Source: https://libtmux.org/en/scala/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with Scala. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `Connect.scala`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```scala title="Connect.scala" import io.github.libtmux.{ServerConfig, ServerEndpoint} import io.github.libtmux.scaladsl.* import java.nio.file.Path import java.time.Duration import scala.util.Using object Connect { def main(args: Array[String]): Unit = { val socket = sys.env.getOrElse("LIBTMUX_SOCKET_PATH", throw new IllegalArgumentException("Set LIBTMUX_SOCKET_PATH to an existing socket")) val config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(Path.of(socket))) .defaultTimeout(Duration.ofSeconds(5)) .build() Using.resource(Server.open(config)) { server => val session = server.sessions().find(_.name == "work").getOrElse( throw new IllegalStateException("The work session does not exist")) println(session.name) } } } ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with JDK 25.0.3, Scala 3.9.0. Save this file beside the program using the displayed filename. ```kotlin title="build.gradle.kts" plugins { application scala } repositories { mavenCentral() } dependencies { implementation("org.scala-lang:scala3-library_3:3.9.0") implementation("io.github.libtmux:libtmux-scala_3:0.0.1-alpha.17-SNAPSHOT") } java { toolchain { languageVersion.set(JavaLanguageVersion.of(25)) } } sourceSets.main { scala.srcDir("."); scala.include("Connect.scala") } application { mainClass.set("Connect") } ``` Save this file beside the program using the displayed filename. ```kotlin title="settings.gradle.kts" rootProject.name = "connect" includeBuild("libtmux-source") { dependencySubstitution { substitute(module("io.github.libtmux:libtmux-scala_3")) .using(project(":libtmux-scala")) } } ``` Save this file beside the program using the displayed filename. ```properties title="gradle.properties" org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=768m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx2g org.gradle.workers.max=2 ``` Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-scala-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-java libtmux-source && git -C libtmux-source checkout 85ebf6955e56703c5be74e2afd34a18309044741 && sh run.sh ./libtmux-source/gradlew --project-dir . run --console=plain --max-workers=2 ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/tmux/examples/capture-pane-output/). --- # Attaching to tmux Source: https://libtmux.org/en/swift/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with Swift. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `Sources/Connect/Connect.swift`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```swift title="Connect.swift" import Foundation import LibTmux enum ConnectError: Error { case failed(String) } @main struct Connect { static func main() async throws { guard let socket = ProcessInfo.processInfo.environment["LIBTMUX_SOCKET_PATH"] else { throw ConnectError.failed("Set LIBTMUX_SOCKET_PATH to an existing socket") } let server = try Server(socketPath: socket) guard try await server.hasSession("=work") else { throw ConnectError.failed("The work session does not exist") } print("work") } } ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with Swift 6.2.4. Save this file beside the program using the displayed filename. ```swift title="Package.swift" // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "ConnectExample", platforms: [.macOS(.v13)], dependencies: [.package(path: "libtmux-source")], targets: [ .executableTarget( name: "Connect", dependencies: [.product(name: "LibTmux", package: "libtmux-source")] ), ] ) ``` Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-swift-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-swift libtmux-source && git -C libtmux-source checkout 254f8b2be7eb60cacc3ffcb3ea8e456784f582df && sh run.sh swift run --jobs 2 Connect ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/swift/latest/examples/capture-pane-output/). Continue with [Sending keys](https://libtmux.org/en/swift/latest/guides/sending-keys/) once you have a pane handle. --- # Attaching to tmux Source: https://libtmux.org/en/ts/latest/guides/attaching-to-tmux/ > Connect to an existing tmux server and find a session with TypeScript. Connect a [`Server`]() to an explicit socket and find the existing `work` session. The program prints its name and leaves the tmux server running. It reports an error if the connection fails or the session is absent. This controls tmux from your program. To open a session in your terminal, use `tmux attach-session`; the [shared guide](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) covers interactive attachment and detaching. ## Connect to an existing server Save the complete program as `connect.ts`. `LIBTMUX_SOCKET_PATH` selects the existing server. The launcher below supplies a private socket for trying the example. ```typescript title="connect.ts" import { Server } from "libtmux"; const socketPath = process.env.LIBTMUX_SOCKET_PATH; if (!socketPath) throw new Error("Set LIBTMUX_SOCKET_PATH to an existing socket"); const server = new Server({ socketPath, timeoutMs: 5_000 }); const snapshot = await server.snapshot({ signal: AbortSignal.timeout(5_000) }); const session = snapshot.sessions.one({ name: "work" }); console.log(session.name); ``` ## Setup and run Use an empty directory on Linux with Git and tmux 3.2a or newer installed. This example was checked with Bun 1.4.2. Save this file beside the program using the displayed filename. ```json title="package.json" {"type":"module","dependencies":{"libtmux":"file:./libtmux/packages/libtmux"}} ``` Save the launcher as `run.sh`. It starts an isolated tmux server, runs the program, checks that the session still exists, then stops only that server. Cleanup runs after failures too. A failed shutdown keeps its socket directory and prints its location for inspection. ```sh title="run.sh" #!/bin/sh set -eu binary=$(command -v tmux) directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-ts-attach.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! "$binary" -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || exit 1 exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM unset TMUX TMUX_PANE export LIBTMUX_SOCKET_PATH="$socket" TMUX_BIN="$binary" "$binary" -S "$socket" -f /dev/null new-session -d -s work /bin/cat "$@" "$binary" -S "$socket" has-session -t '=work' ``` Fetch the verified library revision, build, and run: ```console $ git clone https://github.com/libtmux/libtmux-ts libtmux && git -C libtmux checkout 3fe1ca654b81b8cbf4a13b777a001a3298c87a6f && bun install && sh run.sh bun run connect.ts ``` The program prints `work`. To use an existing server of your own, set `LIBTMUX_SOCKET_PATH` to its socket and run the program without the launcher. That launcher is responsible for the demonstration server's lifetime. ## Find or create a session The example only looks up a session. If your application creates a session after an unsuccessful lookup, another client may create the same name between those operations. Handle the creation error instead of assuming the lookup reserves the name. For a complete program that starts and owns its server, see [Capture pane output](https://libtmux.org/en/ts/latest/examples/capture-pane-output/). Continue with [Sending keys](https://libtmux.org/en/ts/latest/guides/sending-keys/) once you have a pane handle. --- # MCP server guide Source: https://libtmux.org/en/ruby/latest/mcp/source-guide/ > MCP server guide: libtmux documentation. Expose an existing tmux server over MCP stdio. Read snapshots, capture pane output, wait for events, or explicitly enable creation, input and shell commands. The official MCP SDK handles the protocol; bounded Async tasks handle transport. Install the alpha and its `libtmux-mcp` executable: ```console $ gem install libtmux-mcp --pre ``` ## Start the server Set `TMUX_SOCKET` to an existing tmux socket. This command borrows that daemon and serves MCP on stdin/stdout: ```console $ libtmux-mcp \ --socket "$TMUX_SOCKET" \ --endpoint local ``` Use `--socket-name NAME` instead of `--socket PATH` to select a named socket. `--endpoint` sets the public alias used in discovery and resource URIs; it does not select the socket. EOF retires owned clients and preserves the daemon. | Tools | Default | Purpose | | --- | --- | --- | | `tmux_capabilities`, `tmux_snapshot` | Enabled | Discover capabilities and query captured metadata | | `tmux_capture`, `tmux_wait` | Disabled | Capture a screen or wait for text/process exit | | `tmux_create`, `tmux_send`, `tmux_close` | Disabled | Create entities, send text/keys and tear down exact targets | | `tmux_run` | Disabled | Run a script in an explicitly enrolled zsh shell | Repeat `--enable-tool` for each additional tool. For screen capture and waits: ```console $ libtmux-mcp \ --socket "$TMUX_SOCKET" \ --enable-tool tmux_capture \ --enable-tool tmux_wait ``` Disabled tools are absent from discovery and denied on direct application calls. The [complete protocol recipe](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/mcp_protocol.rb) exercises discovery, snapshots, default denial, enabled mutations, cancellation and EOF cleanup through actual pipes, including the installed executable. ## Snapshots, capture and waits Snapshot pages retain one immutable capture and query. Cursor expiry or eviction returns an error; it never substitutes a new live listing. Defaults retain up to 16 captures and 8 MiB for 30 seconds, with a five-second acquisition deadline and one-MiB structured response limit. A cursor pages captured metadata; it does not claim that an old pane process still exists. Schema validation supplements the core decoder's stricter byte, depth, node and duplicate-key rules. Opt into `tmux_capture` for a bounded screen snapshot. Results retain line endings, encode invalid UTF-8 as base64, and distinguish truncated screen content from unknown history continuity. Tracking produces a retained cursor; subsequent calls return a splice against that exact captured state. A screen delta does not establish that every intervening output byte was observed. Capture refuses nonempty effective `after-capture-pane` hooks, including inherited sparse entries. On tmux 3.2a–3.4, callers must keep capture-hook configuration stable throughout observation: those versions require a separate hook preflight. tmux 3.5+ checks the hook in the capture command queue. Both paths retain an explicit session/pane context and refuse its removal instead of switching to another session's hooks. Process tracking retains its native identity checks on every version that supports it. `tmux_wait` observes screen text or process exit through events. Canceling it retires its observation resources without signaling the pane program. Strong process tracking requires tmux 3.3 or later and a native identity backend: Linux peer pidfds with matching process namespaces, or Darwin kqueue process observation. Acquisition verifies the live daemon and pane before retaining a cursor; unavailable evidence produces an explicit refusal. The [compatibility workflow](https://github.com/libtmux/libtmux-ruby/actions/workflows/compatibility.yml) records each exact platform/version result, including the required tmux 3.2a refusal and positive identity cases on later versions. Resource templates expose metadata pages and pane screens under encoded endpoint/generation URIs. They enforce the same policy and response limits as their tools. Metadata pages preserve capture identity; screen resources include interval, truncation and history-continuity metadata. Resource subscriptions are not advertised. ## Create, send and close Add `--enable-tool tmux_create`, `--enable-tool tmux_send` or `--enable-tool tmux_close` to authorize those tools. Creation accepts argument arrays; sending text and sending named keys are separate variants. Mutation results contain delivery evidence and positively returned references. `dispatch_only` input results do not claim program completion, and unknown effects remain unknown after cancellation. ## Run authored commands `tmux_run` requires separate policy and shell enrollment. Add `--enable-tool tmux_run --enroll-pane %ID=FILE` for each exact pane, then explicitly source the generated file in that pane's interactive zsh 5.9. The CLI creates a private setup file and never types into the terminal. It refuses existing files and symlinks. Invitations expire after 60 seconds; `--enrollment-timeout` accepts at most 300 seconds. At most eight panes may be enrolled. EOF retires pending enrollment and removes only files the CLI owns. The tool accepts an exact pane target, a POSIX `script`, and separate `stdout_limit`/`stderr_limit` byte counts. Scripts may contain at most 65,536 bytes. Each output defaults to 65,536 bytes and is capped at 262,144; the application reserves its worst-case serialized response before authorization. The helper inherits the enrolled shell's cwd and exported environment, uses closed stdin, and reports separate UTF-8 or base64 outputs. Nonzero exit and signal termination are completion results. Output overflow is an error with completion unobserved, not silently truncated success. Shell variables, functions, options and cwd changes do not persist in the interactive parent. An idle, empty primary ZLE editor receives the request through a private socket. A guarded tmux queue operation authorizes one script digest for one retained server, pane process and enrollment generation. Execution may follow that authorization; a later respawn does not redirect the prepared helper to its replacement. Error responses retain known authorization and native completion receipts. Cancellation does not prove that arbitrary descendants stopped. The Linux and macOS compatibility jobs exercise enrollment and the installed helper dependency closure; consult their results for the revision being used. ## Embed in Ruby Require `libtmux/mcp`; imports start no tmux process, scheduler or MCP server. [`Application`]() borrows an application-owned [`LibTmux::Async::Server`](). Its [`sdk_server`]() supplies the SDK server consumed by [`StdioTransport`](). Both objects stay on that application's reactor thread. See the [execution guide](https://libtmux.org/en/ruby/latest/concepts/transports/) for result and ownership boundaries. For shell enrollment, call `Application#invite_shell(reference, timeout:, expires_in:)` and pass the returned invitation to [`accept_shell`](). The invitation exposes an immutable `shell_arguments` array for an explicitly sourced setup command and a monotonic `expires_at`. Its acquisition deadline is separate from its enrollment lifetime. The application owns invitations and accepted connections until `close`; direct enrollment calls enforce tool policy. --- # Workspace guide Source: https://libtmux.org/en/ruby/latest/workspace/source-guide/ > Workspace guide: libtmux documentation. Load bounded YAML or JSON, inspect an immutable creation plan, then explicitly apply it to an open libtmux server. The library and installed command-line executable share the core [compatibility matrix](https://github.com/libtmux/libtmux-ruby/actions/workflows/compatibility.yml); consult its exact per-revision results. The gem declares Ruby 3.3 or newer and depends on the same-version `libtmux` gem, JSON 3.0 and Psych 5.5. See the repository's [contribution guide](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/.github/CONTRIBUTING.md) for local builds and checks. Imports and planning do not start tmux or run commands. Install the alpha and its `libtmux-workspace` executable: ```console $ gem install libtmux-workspace --pre ``` ## Example Save this declared subset of tmuxp-style data as `workspace.yaml`. Relative directories resolve against the configuration file's directory. ```yaml session_name: work environment: PROJECT_MODE: development windows: - window_name: editor window_index: 1 layout: tiled panes: - shell_command: printf 'editor ready\n' - {} ``` The [complete workspace program](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/workspace_apply.rb) creates an isolated server, applies this document and checks compensation after a later failure. Calling [`apply`]() authorizes the configuration's shell commands. This excerpt runs inside that program's cleanup wrapper: ```ruby workspace = LibTmux::Workspace.load(File.join(__dir__, "workspace.yaml")) plan = workspace.plan(snapshot: server.snapshot) Example.check(server.list_sessions.size == 1, "planning changed tmux") result = plan.apply(server: server) Example.check(result.success?, "workspace apply failed") Example.check(result.effects.any? { |effect| effect.outcome == :dispatch_only }, "shell dispatch overclaims completion") crowded = LibTmux::Workspace.parse(JSON.generate({ session_name: "crowded", windows: [{window_name: "small", panes: Array.new(40) { {} }}] }), format: :json, base_directory: __dir__) error = Example.raises(LibTmux::Workspace::ApplyError) do crowded.plan.apply(server: server, compensate: true) end Example.check(!error.result.created_refs.empty?, "failure lost partial creation ledger") Example.check(error.result.compensation == :completed, "owned compensation failed") Example.check(server.list_sessions.map(&:ref).include?(borrowed.ref), "borrowed session was removed") ``` ## Configuration The plain declared subset has effective version 1. Optional `profile` and `version` must appear together as `libtmux-ruby.workspace` and `1`. [`workspace.to_h`]() exports an immutable, normalized, reloadable configuration. It contains expanded values and absolute directories; callers control its storage and disclosure. - Root: `session_name`, nonempty `windows`, `options`, `window_options`. - Window: `window_name`, nonempty `panes`, `window_index`, `focus`, [`layout`](), `options`. Indexes are unique nonnegative integers; unspecified indexes use the lowest available value starting at the declared `base-index` or zero. - Pane: a command string or a mapping with `focus`, `split`, [`size`](). Split is `horizontal` or `vertical`. Size is positive cells or `1%` through `99%`; neither applies to the initial pane. Explicit sizes cannot accompany a final named layout. - Root, windows and pane mappings accept `start_directory`, `environment`, `shell_command` and `shell_command_before`. Environment maps merge from parent to child. Commands inherit unless overridden; before-commands append in parent-to-child order. Command values accept a string or string array. At most one window and one pane per window can declare focus; each defaults to the first. Layouts are `even-horizontal`, `even-vertical`, `main-horizontal`, `main-vertical` and `tiled`. Unknown fields and unsupported features fail with a [`ConfigError`]() identifying their configuration position. Session options accept boolean `status`, `mouse`, `renumber-windows`; nonnegative `base-index`, `history-limit`, `status-interval`; and enumerated `status-position` and `status-justify`. Window options accept boolean `automatic-rename`, `allow-rename`, `remain-on-exit`, `synchronize-panes`, `aggressive-resize`; nonnegative `pane-base-index`, `main-pane-width`, `main-pane-height`; text `window-status-format`, `window-status-current-format`; and enumerated `pane-border-status`. Option text remains tmux option text, including any formats that tmux evaluates. `pane-base-index` cannot exceed 65535; the other numeric options accept integers through 2147483647. YAML tags, anchors, aliases, duplicate keys, multiple documents and complex mapping keys are rejected. JSON duplicate keys are rejected too. No Ruby, ERB, plugins or callbacks are evaluated. Defaults bound source and canonical bytes to 1 MiB, strings to 64 KiB, nesting to 32, nodes to 10,000, windows to 128 and panes to 1,024. The corresponding `max_*` parse/load keywords can adjust these positive limits. Configuration files must be regular files. `${NAME}` substitution is opt-in for directories and environment values: pass `expand_environment: true, environment: {"NAME" => "value"}` to load or parse. Only the supplied bounded mapping is consulted. Shell text and option values are unchanged; `~` has no special path meaning. Missing variables fail validation. Parsing checks path syntax; apply checks current accessibility. Concurrent filesystem changes can still trigger tmux's cwd fallback. ## Apply and failure results [`workspace.plan(snapshot: snapshot)`]() retains that capture's binding identity and rejects a captured name conflict. Every apply takes a fresh snapshot and rechecks identity and name absence. The plan creates a new session; it does not reconcile, replace or remove a preexisting workspace. The first window and pane from each creation command are reused. Apply is synchronous, uses one monotonic timeout across its core operations, and accepts a cancellation token. Panes run `/bin/sh`; explicit initial pane environment overrides do not modify the session environment. Window indexes, splits, options, layout and focus follow the plan's order. Temporary local option overrides disable renumbering and pane synchronization during setup; the plan then restores declared values or inheritance. Session options apply before subsequent windows and split panes are created. On tmux 3.2a–3.6, the reused initial pane retains the global `history-limit` inherited at session creation. Later panes use the configured session value. For uniform history on these versions, configure the server's global value before applying the workspace. Apply does not change global options or replace the initial pane. On tmux 3.7+, setting the option also updates existing grids. Shell commands are sent as literal text followed by Enter. Both insertion and Enter are dispatch effects: embedded newlines can execute during text insertion. Success proves tmux accepted the dispatch, not that a shell command finished or succeeded. Shell commands can leave effects beyond tmux. An [`ApplyError`]() exposes an immutable [`result`](): completed step IDs, positively identified [`created_refs`](), observed or dispatch-only effects, failed action, uncertainty and cleanup diagnostics. Diagnostics omit command payloads and paths. Lost creation replies stay uncertain; names are never used to guess ownership. A caller may pass `compensate: true` to kill only the positively returned new session on failure, after an atomic tmux guard proves that every current window and pane has a positively identified created reference. Unknown initial entities or borrowed entities moved into that session cause refusal. Cleanup uses a separate 0.5-second budget. Compensation status is explicit and cannot undo shell effects. The default preserves partial state for inspection. Applying or compensating does not close the supplied server binding. ## Command-line interface The gem installs `libtmux-workspace`. `validate` and offline [`plan`]() do not contact tmux. Without a filename, discovery requires exactly one `.tmuxp.yaml`, `.tmuxp.yml` or `.tmuxp.json` in the current directory. Check the installed gem version without reading a configuration or contacting tmux: ```console $ libtmux-workspace --version ``` ```console $ libtmux-workspace validate workspace.yaml ``` Human plans list ordered operations and their effects. `--json` prints the same plan data as `Plan#to_h`, including configured command text and paths. ```console $ libtmux-workspace plan \ --json \ workspace.yaml ``` [`load`]() and `plan --live` require `--socket` for an existing server. This detached creation example uses an explicitly supplied `TMUX_SOCKET` value: ```console $ libtmux-workspace load \ --socket "$TMUX_SOCKET" \ --json \ workspace.yaml ``` `--timeout` bounds each apply, live capture or subsequent switch operation and defaults to 5 seconds. `--compensate` enables guarded cleanup after apply failure. Environment expansion requires both `--expand-environment` and explicit `--env NAME=VALUE` arguments; ambient environment variables are not copied into that mapping. `load --attach` opens the CLI's `/dev/tty` after creation and runs an owned terminal client until the user detaches. It requires a valid `TERM`. Failure to open or attach the terminal retains the successful apply ledger and returns status 3. `load --switch CLIENT` switches the explicit current tmux client selector to the created session after apply, preserving the session's environment. It accepts a current client name, full TTY path or TTY path without `/dev/`; native first-match behavior applies. A missing client fails without fallback and retains the created session and ledger with status 3. Missing or invalid selector arguments fail before creation. Use `--switch=VALUE` for a selector beginning with `-`. The selector is resolved at dispatch; a reconnect matching it is eligible. It is not a captured client reference or proof of terminal ownership. Attach and switch are mutually exclusive. Neither operation infers a latest client, and library `Plan#apply` performs neither operation. | Exit status | Meaning | | --- | --- | | 0 | Validation, planning or apply succeeded; requested attach/switch succeeded | | 1 | Execution failed before known application effects | | 2 | Configuration or arguments are invalid | | 3 | Application was partial or uncertain, or a later attach/switch/cleanup failed | | 130 | Interrupted; available effect ledger is retained | JSON mode writes one result or error object to stdout. Apply errors include `ApplyResult#to_h`; human errors write the diagnostic and any ledger to stderr. Diagnostics omit configuration payloads. Explicit plan rendering and canonical configuration export contain those values by design. --- # Coroutines and flows Source: https://libtmux.org/en/kotlin/latest/guides/coroutines/ > Coroutines and flows: io.github.libtmux:libtmux-kotlin documentation. ## Wrapper classes over the Java handles [`Server`](), [`Session`](), [`Window`](), [`Pane`](), [`Client`](), and [`ControlClient`]() in [`io.github.libtmux.kotlin`]() are hand-written Kotlin classes, not the Java types directly and not extensions on them. A same-named extension is silently shadowed by a Java member with only a compiler warning, so a member on a real wrapper class is what makes a generated suspend mirror safe to add later without an accidental collision. Every operation that may contact tmux is [`suspend`](). Captured state — an id, a name, a size — is a plain, non-suspending property. Query fields live on the handle type's companion ([`Pane.command`]()), never as an instance member, so [`Pane.command`]() (the field) and [`pane.currentCommand`]() (the captured value) never collide. A tmux subsystem an accessor answers — [`Pane.options()`](), [`Server.hooks()`](), [`Server.shell()`](), [`Server.commands()`](), [`Server.buffers()`](), [`Session.environment()`](), [`Server.messageLog()`](), [`Server.prompt()`](), [`Server.keys()`](), [`Server.batch()`](), [`Server.chain()`]() — is wrapped the same way: a small Kotlin class over the Java handle, whose own operations are [`suspend`]() in turn. ```kotlin // Given: config: ServerConfig withServer(config) { server -> val session = server.newSession("guide-demo") session.name // → guide-demo } ``` Each wrapper answers the Java handle it holds as `asJava`, the same object rather than a copy, for a Java API that takes one. [`Server.fromJava`]() goes the other way, over a server opened in Java, such as a test fixture's; closing the wrapper closes that server. The two sets of classes share simple names, so a file that needs both imports one under an alias: `import io.github.libtmux.Server as JavaServer`. ## `ExecutionPolicy`: two independently sized pools [`ExecutionPolicy.commands`]() backs every [`suspend`]() operation this module generates or hand-writes, sized from [`ServerConfig.maxConcurrentCommands()`]() — the transport's real admission bound, not a guessed constant. [`ExecutionPolicy.streamReads`]() backs only what still genuinely blocks a thread: [`Server.liveState`]()'s background pump. [`ControlClient.output`]()/[`events`]() hold no thread from either pool; they are built on the non-blocking [`EventSubscription.poll`]()/[`onReady`]() path, not a parked [`next()`](). [`ExecutionPolicy.default(config)`]() sizes both pools; pass a differently-sized one to [`Server.open`]() or [`withServer`]() when a program opens more than the default 16 concurrent [`liveState`]() watches. ## The cold `Flow` bridge, and why it is not `callbackFlow` [`ControlClient.output`]()/[`events`]() return a plain `flow {}` that calls [`EventSubscription.poll()`]() from the collector itself, suspending on the subscription's one-shot [`onReady`]() callback via `suspendCancellableCoroutine` when nothing is buffered, and [`clearReady()`]() on cancellation. A fresh Java subscription opens per [`collect()`](), so two concurrent collections never share one subscription's buffer or gap accounting. A `callbackFlow` over the same subscription would have its readiness callback drain [`poll()`]() straight into the flow's channel, where a full channel's `trySend` failing discards the polled item with no [`Gap`]() recorded. `flow {}` calls [`poll()`]() only from the collector itself, so an overflow can only happen inside the subscription's own buffer, which is exactly what turns into a [`Gap`](). ## Blocking calls from a coroutine Every libtmux call blocks its thread until tmux answers. This module already wraps each one in [`runInterruptible`](), dispatched on [`ExecutionPolicy.commands`]() or [`.streamReads`](), so cancelling the coroutine interrupts the wait rather than leaving it running past the point nothing is listening for its result. - An ordinary suspend call — [`newSession`](), [`capture`](), `sendLine` — already runs on `policy.commands`, sized from the server's own admission bound. - [`Server.liveState`]()'s background pump runs on [`policy.streamReads`](). - [`ControlClient.output`]()/[`events`]() hold no thread at all; only collecting the returned [`Flow`]() reads. ## The DSL, and the compile error the first draft had `@DslMarker` marks [`SessionBuilder`](), [`WindowBuilder`](), and [`SplitBuilder`]() so an inner block cannot reach an outer block's receiver by accident. Directory is settable at all three levels for exactly this reason: writing `directory = x` inside a nested `split { }` resolves to the innermost builder, and reaching the outer one on purpose needs `this@newSession.directory = x` written out. ```kotlin // Given: config: ServerConfig withServer(config) { server -> val session = server.newSession { name = "layout-demo" window { name = "editor" } window { name = "shell" split { toRight(); percent(30) } } } session.windows.size // → 2 } ``` tmux's [`SplitSpec.Builder`]() spells direction and size as method calls — [`below()`]()/[`above()`]()/[`toRight()`]()/[`toLeft()`](), [`cells(n)`]()/[`percent(n)`]() — not an enum. The DSL forwards to that real vocabulary directly rather than inventing a parallel [`SplitDirection`]()/[`PaneSize`]() type. `env(name, value)` is on [`SessionBuilder`](), [`WindowBuilder`](), and [`SplitBuilder`]() alike, matching the Java [`SessionSpec.Builder`]()/[`WindowSpec.Builder`]()/ [`SplitSpec.Builder`]() each has, and sets a variable in the environment the new session, window, or pane's process starts with. ## Why nothing in Java may depend on this Nothing written in Java may depend on `libtmux-kotlin`, and the build fails if it does. Per the JSpecify specification a class carrying `@kotlin.Metadata` is *not* null-marked, because the Kotlin compiler does not yet emit full nullness into binaries ([KT-47417](https://youtrack.jetbrains.com/projects/KT/issues/KT-47417/Emit-jspecify-annotations-for-types-in-Kotlin-binaries)). A Kotlin-authored API would therefore be worse for a Java caller and invisible to NullAway. The dependency runs one way only. See the [module README](https://libtmux.org/en/kotlin/latest/guides/getting-started/) for the full call-site tour, including the query DSL, the exhaustive `when` over sealed failures, and [`StateFlow`](). --- # Installation and requirements Source: https://libtmux.org/en/scala/latest/guides/overview/ > Installation and requirements: io.github.libtmux:libtmux-scala_3 documentation. **Scala 3 collections and opaque handles over libtmux for Java.** Use Scala collections and explicit effects to inspect and operate tmux through libtmux for Java. The direct-style facade's handles are opaque aliases of the Java ones — lossless by construction, never a hand-copied parallel type — and return immutable [`Vector`]() and [`Option`]() values. The [separate Cats module](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/README.md) supplies scoped effects and FS2 observations. Both retain the original Java handles, targeting rules and command engine. **This project is alpha.** Releases carry an `-alpha` prerelease tag. The API is not settled, and any release may change or remove exported identifiers without a deprecation period. Pin an exact version rather than a range. Not recommended for production. ## Requirements Scala 3.9 and JDK 25 or newer; there is no Scala 2.13 build. tmux 3.2a through 3.7c, which the Java library supports and every tmux lane in CI runs these suites against. See [Compatibility](https://libtmux.org/en/scala/latest/guides/compatibility/). ## Installation ```sbt libraryDependencies += "io.github.libtmux" %% "libtmux-scala" % "" ``` From Gradle or Maven the coordinate is `io.github.libtmux:libtmux-scala_3`. The version is always `libtmux`'s own: the Scala artifacts are on Maven Central and release with the Java ones. Core depends on `libtmux` and the Scala 3 library only; Cats, FS2 and Ox arrive through [`libtmux-scala-cats`](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/) and [`libtmux-scala-ox`](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-ox/). ## Inspect captured panes Start with [a first client](https://libtmux.org/en/scala/latest/guides/getting-started/#a-first-client) to construct [`ServerConfig`]() from your tmux executable, owned socket and configuration file. Here `config` selects an existing server. Opening the client does not create a session. This operation closes its owned client while leaving the daemon running. ```scala import io.github.libtmux.scaladsl.{config => _, *} import scala.util.Using Using.resource(Server.open(config)) { server => val panes = server.panes() val named = panes.filter(_.info.title().nonEmpty) val commands = named.map(_.info.currentCommand()) assert(commands.size <= panes.size) assert(panes.forall(p => p.window.info.context().equals(p.info.context()))) } ``` [`server.panes()`]() acquires state. Reading `info`, traversing `window`, or filtering the captured vector performs no further tmux commands. `refresh()` returns a new capture. A failed acquisition raises the original Java error; it does not become an empty vector. ## Documentation - [Getting started](https://libtmux.org/en/scala/latest/guides/getting-started/): installation, a first owned client, and building from source. - [Queries](https://libtmux.org/en/scala/latest/guides/query/): native collections, the typed field DSL and strict cardinality. - [Ownership](https://libtmux.org/en/scala/latest/guides/ownership/): captured handles, borrowing and cleanup. - [Execution](https://libtmux.org/en/scala/latest/guides/execution/): direct-style calls, bounded effects and command outcomes. - [Streaming](https://libtmux.org/en/scala/latest/guides/streaming/): subscriptions, cancellation and visible loss. - [Compatibility](https://libtmux.org/en/scala/latest/guides/compatibility/): compilers, runtimes and what CI runs. - [Examples](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/examples/): runnable programs, each executed against a real tmux. The [Java guide](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/docs/guide/scala.md) shows direct Java use without the facade. Source contracts live beside [direct-style operations][server] and [Cats resources][cats-server]. For changes to existing APIs, see the repository's [migration notes](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/MIGRATION.md). [server]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Server.scala [cats-server]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/src/main/scala/io/github/libtmux/scaladsl/cats/Server.scala --- # Quick start Source: https://libtmux.org/en/fsharp/latest/guides/quickstart/ > Install the package, capture server state, and choose a read operation. Drive tmux from F#: send keys and wait for what a pane prints, run a command to its exit status, and list and filter sessions, windows, panes and clients with typed filters tmux evaluates itself. Every function works on the [LibTmux](https://www.nuget.org/packages/LibTmux) core objects. The [F# package](https://www.nuget.org/packages/LibTmux.FSharp) and core share a repository, release version, and primary author in the `libtmux` organization. [![build](https://github.com/libtmux/libtmux-dotnet/actions/workflows/dotnet.yml/badge.svg)](https://github.com/libtmux/libtmux-dotnet/actions/workflows/dotnet.yml) [![tmux matrix](https://github.com/libtmux/libtmux-dotnet/actions/workflows/dotnet-tmux.yml/badge.svg)](https://github.com/libtmux/libtmux-dotnet/actions/workflows/dotnet-tmux.yml) [![license](https://img.shields.io/badge/license-MIT-blue)](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/LICENSE) [Run isolated tmux](https://libtmux.org/en/fsharp/latest/guides/quickstart/#quick-start) · [Connect to running tmux](https://libtmux.org/en/fsharp/latest/guides/quickstart/#existing-tmux) · [Send, wait, read](https://libtmux.org/en/fsharp/latest/guides/getting-started/#send-wait-read) · [Query tmux](https://libtmux.org/en/fsharp/latest/guides/queries/) · [Stream events](https://libtmux.org/en/fsharp/latest/guides/streams/) Find a shell, send it keys, wait for its output, and run a command: ```fsharp run open System open System.Threading open LibTmux open LibTmux.FSharp let runInShellAsync (cancellationToken: CancellationToken) (server: Server) = task { // List and filter: tmux narrows the listing, then every row is rechecked. let! shells = server |> Server.panes |> Query.where (PaneFields.currentCommand |> Filter.oneOf [ "bash"; "sh"; "zsh" ]) |> Query.list cancellationToken let pane = shells[0] // Type a command and wait for what it prints, not for its echo. let! ready = pane |> Pane.sendAndWait cancellationToken (TimeSpan.FromSeconds 10.) "echo ready" "ready" // Run a command to its exit status and read what it printed. let! listing = pane |> Pane.run cancellationToken (TimeSpan.FromSeconds 30.) "ls /" return ready.Found, listing.Succeeded, listing.Output } ``` Building a query reads nothing; [`Query.list`]() asks tmux, which drops panes that cannot match, and checks every row it returns. [`Pane.sendAndWait`]() types the line, then waits for a later line to contain the text; the screen before it and the line's own echo do not count. It sleeps on the pane's output instead of polling, and ends early if the program exits. [`Pane.run`]() returns the command's exit status and the lines it printed. The quick start below runs these steps against an isolated tmux server. Alpha API: pin a package version and upgrade deliberately. The walkthrough uses .NET SDK 10 and tmux 3.2a through 3.7c on Linux or macOS. The package targets `net8.0` and `net10.0`. ## Choose a call | Need | F# call | Result | | --- | --- | --- | | List and filter live objects | `Server.panes server \|> Query.where filter \|> Query.list ct` | Task; tmux narrows the listing and every row is rechecked | | Exactly one match | `Query.exactlyOne ct query` | [`Result`]() distinguishing none from several | | Find, or create when absent | `Query.atMostOne ct query` | [`option`](): [`None`]() only when nothing matched; several raise. Publishes under NativeAOT | | A missing live entity | `Server.tryFindPane ct id server` | `Task`; other failures still throw | | Type a line and wait for its output | `Pane.sendAndWait ct timeout line text pane` | [`PaneWaitResult`](); ignores the earlier screen and the line's echo. [`Pane.sendAndWaitFor`]() takes a keys request and patterns | | Wait for output you did not type | `Pane.waitForText ct timeout text pane` | [`PaneWaitResult`](); text already showing answers at once. [Which wait](https://libtmux.org/en/fsharp/latest/guides/getting-started/#which-wait) compares them all | | Wait for a condition over the whole screen | `Pane.waitUntil ct timeout condition pane` | [`PaneWaitResult`](); the condition sees every visible row, including what a full-screen program draws | | Run a command to its exit status | `Pane.run ct timeout command pane` | [`PaneRunResult`]() with the status and printed lines; POSIX shells only | | Create a session with windows and splits | `Server.newSession ct spec server` | The [`Session`](); describe it with [`SessionSpec`](), [`WindowSpec`]() and [`SplitSpec`]() records | | Run several commands in one tmux call | `Chain.start server \|> Chain.newWindow session name \|> … \|> Chain.run ct` | One [`TmuxCommandResult`](); each step acts on what the one before made | | Bound every command a handle sends | `Server.within timeout server` | A handle to the same server; its sessions, windows and panes share the bound | | Read or set an option as its type | `Options.get ct TmuxOptionKey.HistoryLimit session.Options` | The value as the key's type; [`Options.set`]() writes one | | A whole object graph | `Server.capture ct depth server` | Snapshot to traverse and filter locally | | Follow live server state | `Mirror.start ct session` | A [`ServerMirror`]() to `use!`, updated from tmux's announcements; [`Mirror.waitUntil`]() waits for a view | | React to events as they happen | `Control.withSession ct work server`, then [`Control.events`](), [`Control.watchPane`]() or [`Control.watchPanes`]() | Cold [`IAsyncEnumerable`]() for a control client, which [`withSession`]() disposes | | Let an assistant drive the same tmux | The `LibTmux.Mcp` server on a shared socket | [Which F# call each MCP tool matches](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/docs/fsharp/mcp.md) | Captured sessions, windows, panes, and IDs are the core .NET types. A window linked into more than one session has contextual placements; filtering keeps their order and multiplicity. An uncaptured relationship raises [`IncompleteSnapshotException`]() rather than behaving as empty. ## Quick start Install tmux and make sure it is available on `PATH`. Create an F# console project: ```console $ dotnet new console --language F# --framework net8.0 --output tmux-demo ``` Enter it: ```console $ cd tmux-demo ``` Add [LibTmux.FSharp](https://www.nuget.org/packages/LibTmux.FSharp) from NuGet; it brings in the matching `LibTmux` core package and records the selected prerelease version in the project: ```console $ dotnet package add LibTmux.FSharp --prerelease ``` Replace `Program.fs` with this complete program: ```fsharp run open System open System.Threading open LibTmux open LibTmux.FSharp let runAsync () = task { use deadline = new CancellationTokenSource(TimeSpan.FromSeconds 30.) let token = deadline.Token let options = ServerConnectionOptions( SocketName = "fsharp-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = (Environment.GetEnvironmentVariable "LIBTMUX_TMUX" |> Option.ofObj |> Option.defaultValue "tmux") ) use! owned = LibTmux.Server.CreateOwnedAsync(options, token) for name in [ "build"; "web"; "worker" ] do let! _ = owned.Value.CreateSessionAsync(NewSessionRequest(Name = name, Command = "/bin/sh"), token) () let! server = LibTmux.Server.ConnectAsync(options, token) // List and filter: tmux narrows the listing, then every row is rechecked. // atMostOne is None when nothing matches and raises when several do. let! build = server |> Server.sessions |> Query.where (SessionFields.name |> Filter.eq "build") |> Query.atMostOne token let! others = server |> Server.sessions |> Query.where (SessionFields.name |> Filter.ne "build") |> Query.list token printfn "other sessions: %s" (String.Join(", ", [ for session in others -> session.Name ])) match build with | None -> printfn "no build session" | Some session -> let! panes = session |> Session.panes |> Query.list token let pane = panes[0] // Type a command and wait for what it prints, not for its echo. let! started = pane |> Pane.sendAndWait token (TimeSpan.FromSeconds 10.) "echo build started" "build started" // Run a command to its exit status and read what it printed. let! result = pane |> Pane.run token (TimeSpan.FromSeconds 10.) "printf 'ok\\n'; exit 3" printfn "wait found: %b" started.Found printfn "run: exit %d, output %A" result.ExitStatus.Value (List.ofSeq result.Output) } runAsync().GetAwaiter().GetResult() ``` Run it: ```console $ dotnet run ``` It prints: ```text other sessions: web, worker wait found: true run: exit 3, output ["ok"] ``` [`CreateOwnedAsync`]() starts a server on a unique socket and `use!` stops it when the task ends. `ConnectAsync` attaches a second handle to that socket, as an application attaches to a server it did not start. [`Query.atMostOne`]() returns [`None`]() only when no session matched, so the `match` is where a program would create the missing session; several matches raise. The wait succeeds whether the line appeared before or after it began, and the run's exit status comes from the shell, not from reading the screen. The [quickstart source](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/examples/LibTmux.FSharp.Quickstart/Program.fs) is the published block. CI restores only `LibTmux.FSharp` as a direct package reference from freshly packed artifacts, runs this program against real tmux on both target frameworks, and compares what it prints with the block above. ## Existing tmux The quickstart's `ConnectAsync(options, ct)` attaches to a running server by socket name. In an application, use your server's socket name and omit the owned setup. `ConnectAsync` never starts tmux. A bare `ConnectAsync()` resolves the default socket; [socket selection](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/src/LibTmux/README.md#where-a-bare-connect-lands) explains the configuration order. Code running inside a tmux pane can use [`Server.FromEnvironment()`]() to locate that pane's server. ## Keep going - [Send, wait and read; split panes](https://libtmux.org/en/fsharp/latest/guides/getting-started/): owned scopes, waits, runs and live mutation. - [Query tmux](https://libtmux.org/en/fsharp/latest/guides/queries/), [filter captured objects](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/docs/fsharp/filters.md) and [supported fields](https://libtmux.org/en/fsharp/latest/guides/supported-query-fields/): every level, pushdown, screen search, relations and capture depth. - [Choose an execution mode](https://libtmux.org/en/fsharp/latest/guides/modes/) and [stream events](https://libtmux.org/en/fsharp/latest/guides/streams/): scoped clients, cold streams, pane watches, cancellation, and command chains. - [Test code that drives tmux](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/docs/fsharp/testing.md): a private server per test, waits instead of sleeps, and CI setup. - [Call the core from F#](https://libtmux.org/en/fsharp/latest/guides/interop/) and [browse signatures](https://libtmux.org/en/fsharp/latest/reference/). - [Share tmux with an assistant](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/docs/fsharp/mcp.md): the `LibTmux.Mcp` server, a shared socket, and which F# function each tool matches. - [Read benchmark records](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/docs/benchmarks/README.md): measured core execution modes and benchmark methods. ## Compatibility | Area | Contract and verification | | --- | --- | | .NET | Targets .NET 8 and .NET 10 and uses the matching `LibTmux` package version. | | F# | Requires FSharp.Core 8.0.100 or newer, so an application keeps its SDK's FSharp.Core. Required CI builds and runs a consumer with the .NET 8 SDK's F# compiler and implicit FSharp.Core. | | tmux | Required Linux CI runs the repository's F# integration example against tmux 3.2a, 3.3a, 3.4, 3.5, 3.6, 3.7a, 3.7b, and 3.7c on both target frameworks. The README quickstart runs against the runner's tmux in the package workflow. | | Operating systems | Linux is required CI. An advisory macOS arm64 job runs the example with Homebrew tmux on manual dispatch. Native Windows is unsupported: the core marks its tmux calls `[UnsupportedOSPlatform("windows")]`. WSL runs the Linux build, which CI does not exercise separately. | | Trimming and NativeAOT | Portable filters bind fields without reflection. A Linux consumer publishes and runs captured snapshots, a tmux query, portable filters with relations and regex, and native [`Seq`]() predicates under NativeAOT and trimming on both frameworks. | [`Selection.exactlyOne`]() and [`Query.exactlyOne`]() return FSharp.Core's [`Result`](), whose compiler-generated `ToString` formats through `printf`; with FSharp.Core 10.1.302, which the NativeAOT consumer builds with, NativeAOT publication rejects it. Under NativeAOT, read one row with [`Query.atMostOne`](), which still raises on several matches, or with [`Query.tryExactlyOne`]() where none and several may be treated alike. The NativeAOT consumer runs both. --- # Sending keys Source: https://libtmux.org/en/tmux/guides/sending-keys/ > Send literal text or named keys to a tmux pane and distinguish input from completion. `send-keys -l` types literal characters. Without `-l`, tmux recognizes key names such as `Enter`, `C-c`, and [`Up`](). Typing the word `Enter` and pressing Enter are separate operations. ## Literal text, key names, and whether Enter follows This complete script types the word `Enter` into a pane running `cat`, then presses the Enter key. Neither command starts an interactive tmux client. Save it as `send.sh` and run it in a POSIX shell with tmux 3.2a or newer and fractional `sleep` support. ```sh title="send.sh" #!/bin/sh set -eu directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-guide.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! tmux -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || status=$? exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM tmux -S "$socket" -f /dev/null new-session -d -s input 'cat' tmux -S "$socket" send-keys -t input:0.0 -l 'Enter' tmux -S "$socket" send-keys -t input:0.0 Enter attempt=0 while [ "$attempt" -lt 100 ]; do screen=$(tmux -S "$socket" capture-pane -p -t input:0.0) if printf '%s\n' "$screen" | grep -Fqx 'Enter'; then printf '%s\n' "$screen" exit 0 fi attempt=$((attempt + 1)) sleep 0.05 done printf '%s\n' 'Timed out waiting for typed input.' >&2 exit 1 ``` Run the saved script: ```console $ sh send.sh ``` The screen contains `Enter`: the terminal echoes the input, and `cat` writes it back after the newline. The polling loop waits for visible text and fails after 100 unsuccessful checks. Cleanup stops only the private server. Literal input disables tmux's key-name lookup. The application still interprets those characters. In a shell pane, that includes shell quoting, expansions and commands; literal mode does not make shell input safe to compose from arbitrary text. ## The race you can't see from the call site Completing `send-keys` means tmux accepted the input. It does not establish that the application read it or finished a command. Terminal echo can appear before the application processes a line. For a shell command, wait for its distinct output or a completion signal before using the result. [Capture pane output](https://libtmux.org/en/tmux/examples/capture-pane-output/) matches a complete output line so the echoed command cannot satisfy the check. [Capturing output](https://libtmux.org/en/tmux/guides/capturing-output/) explains screen and history capture. ## Use a language library Each port's complete capture program sends a command, waits for its output and cleans up. Use the port dropdown for its input APIs, or open the program: [Python](https://libtmux.org/en/py/latest/examples/capture-pane-output/) · [TypeScript](https://libtmux.org/en/ts/latest/examples/capture-pane-output/) · [Go](https://libtmux.org/en/go/latest/examples/capture-pane-output/) · [Rust](https://libtmux.org/en/rs/latest/examples/capture-pane-output/) · [Java](https://libtmux.org/en/java/latest/examples/capture-pane-output/) · [Kotlin](https://libtmux.org/en/kotlin/latest/examples/capture-pane-output/) · [Scala](https://libtmux.org/en/scala/latest/examples/capture-pane-output/) · [C#](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/) · [F#](https://libtmux.org/en/fsharp/latest/examples/capture-pane-output/) · [C++](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/) · [Swift](https://libtmux.org/en/swift/latest/examples/capture-pane-output/) · [Ruby](https://libtmux.org/en/ruby/latest/examples/capture-pane-output/) · [Lua](https://libtmux.org/en/lua/latest/examples/capture-pane-output/) ## tmux reference The [send-keys reference](https://libtmux.org/en/tmux/latest/manual/send-keys/) describes literal input, key names, and each supported flag. Select your installed tmux version on that page. The [tmux manual](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1) documents these commands and their flags. --- # Sending keys Source: https://libtmux.org/en/csharp/latest/guides/sending-keys/ > Send text and named keys, then wait for the result. [`Pane.SendTextAsync`]() sends text; [`Pane.EnterAsync`]() submits the line. Pass a cancellation token to both operations. The complete program performs these steps separately and waits for its output before treating the task as done. ## Run the complete program [Capture pane output](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/) supplies the full C# program, imports, project setup and run command. It starts a private server, sends a command, checks a complete output line and cleans up. ## Literal text, key names, and whether Enter follows Choose the method and options for the input you mean to send. Literal text still goes to an application: a shell interprets its quoting, expansions and commands. Key-name handling and shell interpretation are separate concerns. ## The race you can't see from the call site A successful send means tmux accepted input. The pane's program may still be starting or processing that input. Wait for the state the next operation needs. Terminal echo alone does not prove command completion. [`Pane.CaptureAsync`]() reads visible pane lines. The complete program passes a cancellation token, compares whole lines and bounds its waits with a [`CancellationTokenSource`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=net-10.0). Its [`OwnedServerScope`]() owns the private server and is disposed with `await using`. ## Where to go next [Capturing output](https://libtmux.org/en/csharp/latest/guides/capturing-output/) covers the output side. [Attaching to tmux](https://libtmux.org/en/csharp/latest/guides/attaching-to-tmux/) connects to a server you already own. --- # Sending keys Source: https://libtmux.org/en/cxx/latest/guides/sending-keys/ > Send text and named keys, then wait for the result. [`Pane::send_text`]() sends literal characters without an added newline. [`Pane::send_key`]() sends a named key such as Enter; [`Pane::send_line`]() sends a complete line. Check each result before proceeding. A failed operation carries its diagnostic in the error value. ## Run the complete program [Capture pane output](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/) supplies the full C++ program, imports, project setup and run command. It starts a private server, sends a command, checks a complete output line and cleans up. ## Literal text, key names, and whether Enter follows Choose the method and options for the input you mean to send. Literal text still goes to an application: a shell interprets its quoting, expansions and commands. Key-name handling and shell interpretation are separate concerns. ## The race you can't see from the call site A successful send means tmux accepted input. The pane's program may still be starting or processing that input. Wait for the state the next operation needs. Terminal echo alone does not prove command completion. [`Pane::capture`]() returns captured text through a result that must be checked. The complete program splits that text into lines and compares a whole line before its deadline. Capture options select history and bound the output size; an exceeded output limit is reported as an error. ## Where to go next [Capturing output](https://libtmux.org/en/cxx/latest/guides/capturing-output/) covers the output side. [Attaching to tmux](https://libtmux.org/en/cxx/latest/guides/attaching-to-tmux/) connects to a server you already own. --- # Sending keys Source: https://libtmux.org/en/go/latest/guides/sending-keys/ > Send text and named keys, then wait for the result. Pass a [`tmux.SendKeysRequest`]() to [`Pane.SendKeys`]() and check the returned error. Set `Literal` to send characters and [`SkipEnter`]() to type without submitting. [`Pane.Enter`]() sends Enter separately. Use a context deadline for operations that must finish within a fixed budget. ## Run the complete program [Capture pane output](https://libtmux.org/en/go/latest/examples/capture-pane-output/) supplies the full Go program, imports, project setup and run command. It starts a private server, sends a command, checks a complete output line and cleans up. ## Literal text, key names, and whether Enter follows Choose the method and options for the input you mean to send. Literal text still goes to an application: a shell interprets its quoting, expansions and commands. Key-name handling and shell interpretation are separate concerns. ## The race you can't see from the call site A successful send means tmux accepted input. The pane's program may still be starting or processing that input. Wait for the state the next operation needs. Terminal echo alone does not prove command completion. [`Pane.Capture`]() takes a [`tmux.CapturePaneRequest`](). Use `Start` and [`End`]() to choose a range; [`tmux.CaptureBoundary`]() reaches the corresponding history or screen boundary. The complete program reads the visible screen, compares full lines and stops when its context expires. ## Where to go next [Capturing output](https://libtmux.org/en/go/latest/guides/capturing-output/) covers the output side. [Attaching to tmux](https://libtmux.org/en/go/latest/guides/attaching-to-tmux/) connects to a server you already own. --- # Sending keys Source: https://libtmux.org/en/java/latest/guides/sending-keys/ > Send text and named keys, then wait for the result. [`Pane.sendLine`]() sends a command line and submits it. The complete program checks the resulting output separately; a successful send does not establish that the shell finished. Configure a timeout through [`ServerConfig`]() and keep exceptions visible. ## Run the complete program [Capture pane output](https://libtmux.org/en/java/latest/examples/capture-pane-output/) supplies the full Java program, imports, project setup and run command. It starts a private server, sends a command, checks a complete output line and cleans up. ## Literal text, key names, and whether Enter follows Choose the method and options for the input you mean to send. Literal text still goes to an application: a shell interprets its quoting, expansions and commands. Key-name handling and shell interpretation are separate concerns. ## The race you can't see from the call site A successful send means tmux accepted input. The pane's program may still be starting or processing that input. Wait for the state the next operation needs. Terminal echo alone does not prove command completion. [`Pane.capture`]() returns visible pane contents as a list of lines. The complete program compares a full line with its expected value and checks a monotonic deadline. A `finally` block kills its private tmux server, while try-with-resources closes the [`Server`]() handle. ## Where to go next [Capturing output](https://libtmux.org/en/java/latest/guides/capturing-output/) covers the output side. [Attaching to tmux](https://libtmux.org/en/java/latest/guides/attaching-to-tmux/) connects to a server you already own. --- # Sending keys Source: https://libtmux.org/en/py/latest/guides/sending-keys/ > Send text and named keys, then wait for the result. [`Pane.send_keys`]() accepts literal text with `literal=True`. It sends Enter by default; use `enter=False` to type without submitting, then call [`Pane.enter`](). The complete example sets literal mode explicitly. ## Run the complete program [Capture pane output](https://libtmux.org/en/py/latest/examples/capture-pane-output/) supplies the full Python program, imports, project setup and run command. It starts a private server, sends a command, checks a complete output line and cleans up. ## Literal text, key names, and whether Enter follows Choose the method and options for the input you mean to send. Literal text still goes to an application: a shell interprets its quoting, expansions and commands. Key-name handling and shell interpretation are separate concerns. ## The race you can't see from the call site A successful send means tmux accepted input. The pane's program may still be starting or processing that input. Wait for the state the next operation needs. Terminal echo alone does not prove command completion. [`Pane.capture_pane`]() returns a list of lines. The complete program compares whole lines, uses a monotonic deadline and closes its private server in [`finally`](). The echoed shell command cannot satisfy its output check. ## Where to go next [Capturing output](https://libtmux.org/en/py/latest/guides/capturing-output/) covers the output side. [Attaching to tmux](https://libtmux.org/en/py/latest/guides/attaching-to-tmux/) connects to a server you already own. --- # Sending keys Source: https://libtmux.org/en/rs/latest/guides/sending-keys/ > Send text and named keys, then wait for the result. [`Pane::send_keys`]() sends literal text without Enter. [`Pane::send_line`]() sends a line and Enter in one dispatch. Use [`Pane::send_key_names`]() for named keys. Await the result and propagate a failed send before attempting the next step. ## Run the complete program [Capture pane output](https://libtmux.org/en/rs/latest/examples/capture-pane-output/) supplies the full Rust program, imports, project setup and run command. It starts a private server, sends a command, checks a complete output line and cleans up. ## Literal text, key names, and whether Enter follows Choose the method and options for the input you mean to send. Literal text still goes to an application: a shell interprets its quoting, expansions and commands. Key-name handling and shell interpretation are separate concerns. ## The race you can't see from the call site A successful send means tmux accepted input. The pane's program may still be starting or processing that input. Wait for the state the next operation needs. Terminal echo alone does not prove command completion. [`Pane::capture`]() reads the visible screen. The complete program compares the returned line bytes with the expected output and uses [`tokio::time::timeout`](https://docs.rs/tokio/latest/tokio/time/fn.timeout.html) to bound the task. It kills its private server and shuts down the client before returning a capture error. ## Where to go next [Capturing output](https://libtmux.org/en/rs/latest/guides/capturing-output/) covers the output side. [Attaching to tmux](https://libtmux.org/en/rs/latest/guides/attaching-to-tmux/) connects to a server you already own. --- # Sending keys Source: https://libtmux.org/en/swift/latest/guides/sending-keys/ > Send text and named keys, then wait for the result. [`Server.run(_:in:)`]() types a command line and presses Enter. Await it with `try await`, then wait separately for the output your next operation needs. The complete program uses an explicit socket and propagates failed operations. ## Run the complete program [Capture pane output](https://libtmux.org/en/swift/latest/examples/capture-pane-output/) supplies the full Swift program, imports, project setup and run command. It starts a private server, sends a command, checks a complete output line and cleans up. ## Literal text, key names, and whether Enter follows Choose the method and options for the input you mean to send. Literal text still goes to an application: a shell interprets its quoting, expansions and commands. Key-name handling and shell interpretation are separate concerns. ## The race you can't see from the call site A successful send means tmux accepted input. The pane's program may still be starting or processing that input. Wait for the state the next operation needs. Terminal echo alone does not prove command completion. `Server.capture` reads pane lines. The complete program compares a whole line, bounds the wait and reports cleanup errors. For repeated reads of changing output, the streaming APIs can track output beyond one screen snapshot; consult this version's API reference for their lifetime and completion rules. ## Where to go next [Capturing output](https://libtmux.org/en/swift/latest/guides/capturing-output/) covers the output side. [Attaching to tmux](https://libtmux.org/en/swift/latest/guides/attaching-to-tmux/) connects to a server you already own. --- # Sending keys Source: https://libtmux.org/en/ts/latest/guides/sending-keys/ > Send text and named keys, then wait for the result. [`Pane.sendKeys`]() sends Enter by default. Use `enter: false` to type without submitting and `literal: true` when characters could be interpreted as key names. Pass an abort signal to bound the operation. ## Run the complete program [Capture pane output](https://libtmux.org/en/ts/latest/examples/capture-pane-output/) supplies the full TypeScript program, imports, project setup and run command. It starts a private server, sends a command, checks a complete output line and cleans up. ## Literal text, key names, and whether Enter follows Choose the method and options for the input you mean to send. Literal text still goes to an application: a shell interprets its quoting, expansions and commands. Key-name handling and shell interpretation are separate concerns. ## The race you can't see from the call site A successful send means tmux accepted input. The pane's program may still be starting or processing that input. Wait for the state the next operation needs. Terminal echo alone does not prove command completion. [`Pane.capture`]() returns captured lines. The complete program uses [`AbortSignal.timeout`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static) for a deadline and matches a whole output line. Its cleanup checks whether the private socket exists, including when startup fails, and reports shutdown errors. ## Where to go next [Capturing output](https://libtmux.org/en/ts/latest/guides/capturing-output/) covers the output side. [Attaching to tmux](https://libtmux.org/en/ts/latest/guides/attaching-to-tmux/) connects to a server you already own. --- # Server bindings Source: https://libtmux.org/en/ruby/latest/guides/core/ > Own a private server or connect to an existing socket. Ruby tmux orchestration core. `Server.open` borrows an existing explicit endpoint. Closing it retires owned clients and preserves the daemon; `kill` explicitly terminates the daemon. `Server.start` creates a private owned foreground daemon whose lifetime ends with its server handle. Owned startup uses Linux and Darwin readiness backends. The [compatibility workflow](https://github.com/libtmux/libtmux-ruby/actions/workflows/compatibility.yml) retains exact per-revision platform and version results. Install the alpha with `gem install libtmux --pre`, then require `libtmux`. Imports do not start tmux, a scheduler or an MCP server. See the repository's contribution guide for local build and verification commands. Handles carry immutable refs bound to one open server binding. IDs and refs are local readers; `list_*`, `snapshot` and command methods perform explicit I/O. Global windows represent unique entities. [`WindowLink`]() retains a session, index and window ID so repeated links stay distinct. Link selection, unlinking, movement, swapping and display check the complete link identity in the same tmux queue turn as their operation. Configured command aliases are avoided using unshadowed builtin spellings. Hook waits before dispatch cannot turn a stale link into its replacement. Concurrent rewriting of command aliases is outside this guarantee; applications must coordinate configuration changes. Typed arguments preserve literal semicolons and distinguish pane text from key names. Pane commands take executable argument arrays. Hook commands, display formats, pipe shell commands and `source_file` configuration are explicit executable inputs. `Server.run` remains the raw tmux escape hatch, including daemon aliases, separators and format semantics. Creation accepts `cwd:` and a String-to-String `environment:` map. Directories resolve from the Ruby caller and are checked before dispatch; concurrent filesystem changes can still trigger tmux's directory fallback. Creation returns tmux-assigned IDs after dispatch, without claiming program readiness or a successful program exit. `new_session(window_name:)` names the initial window; its index can be moved explicitly after creation. [`new_window(index:)`]() refuses an occupied slot. `Pane#split` targets that exact pane, with `size:` as cells or a percentage string. Windows and splits retain focus unless `focus: true` is requested. Typed operations accept `timeout:` and `cancel:`. Composed link and copy operations share one deadline across their preflights and final dispatch. Copy-mode exit uses `cancel_mode: true`; `cancel:` accepts [`LibTmux::Cancellation.new`](). Call the token's [`cancel`]() from another thread to wake a blocked request, join its caller, then `close` the token. See the [plain-Ruby cancellation recipe](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/cancel.rb) and [ownership contract](https://libtmux.org/en/ruby/latest/topics/errors-and-exceptions/). [`Options`]() retains raw bytes, inheritance and sparse array indexes; `OptionValue#as` requests a strict conversion. Hook values remain tmux command strings. The stable tmux option listing uses its escaped representation, including octal bytes; it does not split raw values on line breaks. Option names containing whitespace are currently rejected. Inherited hook listing is not implemented and raises explicitly. Indexed `get` acquires the array and selects locally, so a missing index raises [`NoMatchError`]() while a present empty value remains present. Reading an array without an index raises [`MultipleMatchesError`]() when it has several entries. Append follows tmux's lowest-free-index rule; indexed hooks execute in index order. Empty arrays remain distinct from empty String values. Binary buffers and command results preserve trailing newlines. Capture can join wrapped lines, include attribute escapes, escape nonprintable bytes, preserve trailing spaces and trim unused trailing cells. `mode_screen: true` reads the mode's backing screen (the copy-mode snapshot, without its UI), `alternate: true` reads tmux's saved screen and raises when absent (while an application occupies the alternate screen, this is the saved main screen), and `pending: true` reads an incomplete escape sequence. These three selectors are mutually exclusive. Mode-screen and trailing-cell flags are checked against advertised command usage; unsupported requests raise explicitly. Copy-mode flags are checked against the connected daemon's advertised command usage. Client discovery returns observations. `Server#attach` uses an explicit caller-owned TTY and terminal type, waits for its owned client to exit, and restores the terminal mode. `Server#switch_client(client:, session:)` switches an explicit current native client selector to an exact bound session, keeping the session environment. A missing selector fails without fallback. This operation does not turn a client observation into an incarnation-safe reference; a reconnect matching the selector is eligible at dispatch. Control connections expose bounded event subscriptions and raw guarded replies. `pause_output(pane_id:)` and `resume_output(pane_id:)` return [`GuardedReply`](); they do not establish that an action took effect. Their gap events identify `:pause_requested` or `:resume_requested` when no outside-block native notice was observed, including cancellation after possible dispatch. Native notices use `:pause` and `:resume`. Loss counts are unknown (`dropped_bytes: nil`); resume does not replay skipped output. Guarded notification-looking text stays in its reply body. Close the old control connection, then explicitly call [`server.open_control(session: ref, reconnect: old_connection)`]() to reconnect within the same binding and session. The replacement has a new `generation` and retains `previous_generation`. Every new subscription begins with a `:reconnect` gap containing both generations and an unknown loss count. Old subscriptions stay closed, and requests are never replayed. Event sequences describe one connection's observations, not durable pane history. Typed command coverage includes hierarchy creation/listing; rename, split, resize, swap, join, break, respawn, and layout operations; link operations; options/hooks/environment, capture/send/paste/pipe/buffers, copy commands, display/source-file/wait-for. It does not establish complete flag parity or every compatibility cell; consult the workflow results. RBS validation checks declarations; installed signature consumers check selected real arguments, blocks and return values. [Executable recipes](https://libtmux.org/en/ruby/latest/examples/recipes/) run against installed artifacts; the documentation gate renders YARD and guides and checks local destinations and fragments. The [public method inventory](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/docs/reference/api.md) links exported methods to source and behavioral contracts. These consumer checks do not establish whole-program static typing. --- # Capturing output Source: https://libtmux.org/en/tmux/guides/capturing-output/ > Capture a tmux pane screen or include its scrollback history. `capture-pane -p` prints a pane's visible screen. Add `-S -` to start at the oldest line still present in its scrollback history. Capture is a snapshot of terminal state; it is not a log of every byte the application wrote. ## Visible pane vs. scrollback This example forces output into scrollback: it prints 40 numbered lines in a pane with 10 rows. A normal capture shows the last screenful. Adding `-S -` also retrieves earlier lines, including `row-1`. Save the script as `history.sh`. It needs tmux 3.2a or newer, a POSIX shell and fractional `sleep` support. ```sh title="history.sh" #!/bin/sh set -eu directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-guide.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! tmux -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || status=$? exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM tmux -S "$socket" -f /dev/null new-session -d -s capture -x 80 -y 10 \ 'i=1; while [ "$i" -le 40 ]; do printf "row-%s\n" "$i"; i=$((i + 1)); done; exec cat' tmux -S "$socket" resize-window -t capture:0 -x 80 -y 10 attempt=0 while [ "$attempt" -lt 100 ]; do screen=$(tmux -S "$socket" capture-pane -p -t capture:0.0) if printf '%s\n' "$screen" | grep -Fqx 'row-40'; then printf 'Visible screen:\n%s\n' "$screen" printf '\nScreen and scrollback:\n' tmux -S "$socket" capture-pane -p -S - -t capture:0.0 exit 0 fi attempt=$((attempt + 1)) sleep 0.05 done printf '%s\n' 'Timed out waiting for pane output.' >&2 exit 1 ``` Run the saved script: ```console $ sh history.sh ``` `row-1` appears in the history capture but has already scrolled off the visible screen. `row-40` appears in both. The script cleans up its private server after printing or after any failure. A numeric `-S` chooses a starting row: `0` is the top visible row and negative values reach into history. `-E` selects the final row. `-J` joins wrapped rows; `-e` includes terminal escape sequences for attributes such as color. History is bounded by `history-limit`, so discarded lines cannot be recovered by capture. ## Wait for the expected text Wait for an observable result with a deadline. An immediate capture after [Sending keys](https://libtmux.org/en/tmux/guides/sending-keys/) can race the application. Match a complete output line, as [Capture pane output](https://libtmux.org/en/tmux/examples/capture-pane-output/) does, to avoid treating an echoed command as completed work. A screen may change before the next capture. For continuously consumed output, use a pipe or an attached control-mode client's output events; see [Control mode vs one-shot](https://libtmux.org/en/tmux/concepts/transports/). ## Wait for a completion signal A program that controls its own completion can send `wait-for -S` on a dedicated tmux channel. A matching `wait-for` waits on that server. Use the same socket and a distinct channel for each task, and put a deadline around the wait. [Waiting and retrying](https://libtmux.org/en/tmux/topics/waiting-and-retry/) covers the channel protocol. ## Use a language library The port dropdown opens that language's capture guide. Complete programs with imports and setup are available here: [Python](https://libtmux.org/en/py/latest/examples/capture-pane-output/) · [TypeScript](https://libtmux.org/en/ts/latest/examples/capture-pane-output/) · [Go](https://libtmux.org/en/go/latest/examples/capture-pane-output/) · [Rust](https://libtmux.org/en/rs/latest/examples/capture-pane-output/) · [Java](https://libtmux.org/en/java/latest/examples/capture-pane-output/) · [Kotlin](https://libtmux.org/en/kotlin/latest/examples/capture-pane-output/) · [Scala](https://libtmux.org/en/scala/latest/examples/capture-pane-output/) · [C#](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/) · [F#](https://libtmux.org/en/fsharp/latest/examples/capture-pane-output/) · [C++](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/) · [Swift](https://libtmux.org/en/swift/latest/examples/capture-pane-output/) · [Ruby](https://libtmux.org/en/ruby/latest/examples/capture-pane-output/) · [Lua](https://libtmux.org/en/lua/latest/examples/capture-pane-output/) ## tmux reference The [capture-pane reference](https://libtmux.org/en/tmux/latest/manual/capture-pane/) documents line ranges, scrollback, and output flags for each supported tmux version. See [wait-for](https://libtmux.org/en/tmux/latest/manual/wait-for/) for completion channels. The [tmux manual](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1) documents these commands and their flags. --- # Capturing output Source: https://libtmux.org/en/csharp/latest/guides/capturing-output/ > Read pane output with an explicit completion condition. [`Pane.CaptureAsync`]() reads visible pane lines. The complete program passes a cancellation token, compares whole lines and bounds its waits with a [`CancellationTokenSource`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=net-10.0). Its [`OwnedServerScope`]() owns the private server and is disposed with `await using`. ## Run the complete program [Capture pane output](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/) includes the full C# program, all imports, project files and a run command. The program matches `libtmux capture ready` as a complete line, so the echoed command cannot satisfy the check. It creates and cleans up its own tmux server. ## Visible pane vs. scrollback A capture reads terminal state. Lines that have scrolled beyond retained history are unavailable, and repeated captures can miss intermediate output. Choose the range your task needs and use a stream or completion signal when every output event matters. ## Wait for the expected text Use a deadline and a specific output predicate. The example's short polling pause limits work between checks; it is the observed line that determines completion. [Sending keys](https://libtmux.org/en/csharp/latest/guides/sending-keys/) explains why returning from the input call is not a completion signal. ## Wait for a completion signal A program can also signal a dedicated tmux channel. Use the same server endpoint for the sender and waiter and a new channel name per task. [Waiting and retrying](https://libtmux.org/en/csharp/latest/topics/waiting-and-retry/) documents this port's waiting APIs and failure handling. --- # Capturing output Source: https://libtmux.org/en/cxx/latest/guides/capturing-output/ > Read pane output with an explicit completion condition. [`Pane::capture`]() returns captured text through a result that must be checked. The complete program splits that text into lines and compares a whole line before its deadline. Capture options select history and bound the output size; an exceeded output limit is reported as an error. ## Run the complete program [Capture pane output](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/) includes the full C++ program, all imports, project files and a run command. The program matches `libtmux capture ready` as a complete line, so the echoed command cannot satisfy the check. It creates and cleans up its own tmux server. ## Visible pane vs. scrollback A capture reads terminal state. Lines that have scrolled beyond retained history are unavailable, and repeated captures can miss intermediate output. Choose the range your task needs and use a stream or completion signal when every output event matters. ## Wait for the expected text Use a deadline and a specific output predicate. The example's short polling pause limits work between checks; it is the observed line that determines completion. [Sending keys](https://libtmux.org/en/cxx/latest/guides/sending-keys/) explains why returning from the input call is not a completion signal. ## Wait for a completion signal A program can also signal a dedicated tmux channel. Use the same server endpoint for the sender and waiter and a new channel name per task. [Waiting and retrying](https://libtmux.org/en/cxx/latest/topics/waiting-and-retry/) documents this port's waiting APIs and failure handling. --- # Capturing output Source: https://libtmux.org/en/go/latest/guides/capturing-output/ > Read pane output with an explicit completion condition. [`Pane.Capture`]() takes a [`tmux.CapturePaneRequest`](). Use `Start` and [`End`]() to choose a range; [`tmux.CaptureBoundary`]() reaches the corresponding history or screen boundary. The complete program reads the visible screen, compares full lines and stops when its context expires. ## Run the complete program [Capture pane output](https://libtmux.org/en/go/latest/examples/capture-pane-output/) includes the full Go program, all imports, project files and a run command. The program matches `libtmux capture ready` as a complete line, so the echoed command cannot satisfy the check. It creates and cleans up its own tmux server. ## Visible pane vs. scrollback A capture reads terminal state. Lines that have scrolled beyond retained history are unavailable, and repeated captures can miss intermediate output. Choose the range your task needs and use a stream or completion signal when every output event matters. ## Wait for the expected text Use a deadline and a specific output predicate. The example's short polling pause limits work between checks; it is the observed line that determines completion. [Sending keys](https://libtmux.org/en/go/latest/guides/sending-keys/) explains why returning from the input call is not a completion signal. ## Wait for a completion signal A program can also signal a dedicated tmux channel. Use the same server endpoint for the sender and waiter and a new channel name per task. [Waiting and retrying](https://libtmux.org/en/go/latest/topics/waiting-and-retry/) documents this port's waiting APIs and failure handling. --- # Capturing output Source: https://libtmux.org/en/java/latest/guides/capturing-output/ > Read pane output with an explicit completion condition. [`Pane.capture`]() returns visible pane contents as a list of lines. The complete program compares a full line with its expected value and checks a monotonic deadline. A `finally` block kills its private tmux server, while try-with-resources closes the [`Server`]() handle. ## Run the complete program [Capture pane output](https://libtmux.org/en/java/latest/examples/capture-pane-output/) includes the full Java program, all imports, project files and a run command. The program matches `libtmux capture ready` as a complete line, so the echoed command cannot satisfy the check. It creates and cleans up its own tmux server. ## Visible pane vs. scrollback A capture reads terminal state. Lines that have scrolled beyond retained history are unavailable, and repeated captures can miss intermediate output. Choose the range your task needs and use a stream or completion signal when every output event matters. ## Wait for the expected text Use a deadline and a specific output predicate. The example's short polling pause limits work between checks; it is the observed line that determines completion. [Sending keys](https://libtmux.org/en/java/latest/guides/sending-keys/) explains why returning from the input call is not a completion signal. ## Wait for a completion signal A program can also signal a dedicated tmux channel. Use the same server endpoint for the sender and waiter and a new channel name per task. [Waiting and retrying](https://libtmux.org/en/java/latest/topics/waiting-and-retry/) documents this port's waiting APIs and failure handling. --- # Capturing output Source: https://libtmux.org/en/py/latest/guides/capturing-output/ > Read pane output with an explicit completion condition. [`Pane.capture_pane`]() returns a list of lines. The complete program compares whole lines, uses a monotonic deadline and closes its private server in [`finally`](). The echoed shell command cannot satisfy its output check. ## Run the complete program [Capture pane output](https://libtmux.org/en/py/latest/examples/capture-pane-output/) includes the full Python program, all imports, project files and a run command. The program matches `libtmux capture ready` as a complete line, so the echoed command cannot satisfy the check. It creates and cleans up its own tmux server. ## Visible pane vs. scrollback A capture reads terminal state. Lines that have scrolled beyond retained history are unavailable, and repeated captures can miss intermediate output. Choose the range your task needs and use a stream or completion signal when every output event matters. ## Wait for the expected text Use a deadline and a specific output predicate. The example's short polling pause limits work between checks; it is the observed line that determines completion. [Sending keys](https://libtmux.org/en/py/latest/guides/sending-keys/) explains why returning from the input call is not a completion signal. ## Wait for a completion signal A program can also signal a dedicated tmux channel. Use the same server endpoint for the sender and waiter and a new channel name per task. [Waiting and retrying](https://libtmux.org/en/py/latest/topics/waiting-and-retry/) documents this port's waiting APIs and failure handling. --- # Capturing output Source: https://libtmux.org/en/rs/latest/guides/capturing-output/ > Read pane output with an explicit completion condition. [`Pane::capture`]() reads the visible screen. The complete program compares the returned line bytes with the expected output and uses [`tokio::time::timeout`](https://docs.rs/tokio/latest/tokio/time/fn.timeout.html) to bound the task. It kills its private server and shuts down the client before returning a capture error. ## Run the complete program [Capture pane output](https://libtmux.org/en/rs/latest/examples/capture-pane-output/) includes the full Rust program, all imports, project files and a run command. The program matches `libtmux capture ready` as a complete line, so the echoed command cannot satisfy the check. It creates and cleans up its own tmux server. ## Visible pane vs. scrollback A capture reads terminal state. Lines that have scrolled beyond retained history are unavailable, and repeated captures can miss intermediate output. Choose the range your task needs and use a stream or completion signal when every output event matters. ## Wait for the expected text Use a deadline and a specific output predicate. The example's short polling pause limits work between checks; it is the observed line that determines completion. [Sending keys](https://libtmux.org/en/rs/latest/guides/sending-keys/) explains why returning from the input call is not a completion signal. ## Wait for a completion signal A program can also signal a dedicated tmux channel. Use the same server endpoint for the sender and waiter and a new channel name per task. [Waiting and retrying](https://libtmux.org/en/rs/latest/topics/waiting-and-retry/) documents this port's waiting APIs and failure handling. --- # Capturing output Source: https://libtmux.org/en/swift/latest/guides/capturing-output/ > Read pane output with an explicit completion condition. `Server.capture` reads pane lines. The complete program compares a whole line, bounds the wait and reports cleanup errors. For repeated reads of changing output, the streaming APIs can track output beyond one screen snapshot; consult this version's API reference for their lifetime and completion rules. ## Run the complete program [Capture pane output](https://libtmux.org/en/swift/latest/examples/capture-pane-output/) includes the full Swift program, all imports, project files and a run command. The program matches `libtmux capture ready` as a complete line, so the echoed command cannot satisfy the check. It creates and cleans up its own tmux server. ## Visible pane vs. scrollback A capture reads terminal state. Lines that have scrolled beyond retained history are unavailable, and repeated captures can miss intermediate output. Choose the range your task needs and use a stream or completion signal when every output event matters. ## Wait for the expected text Use a deadline and a specific output predicate. The example's short polling pause limits work between checks; it is the observed line that determines completion. [Sending keys](https://libtmux.org/en/swift/latest/guides/sending-keys/) explains why returning from the input call is not a completion signal. ## Wait for a completion signal A program can also signal a dedicated tmux channel. Use the same server endpoint for the sender and waiter and a new channel name per task. [Waiting and retrying](https://libtmux.org/en/swift/latest/topics/waiting-and-retry/) documents this port's waiting APIs and failure handling. --- # Capturing output Source: https://libtmux.org/en/ts/latest/guides/capturing-output/ > Read pane output with an explicit completion condition. [`Pane.capture`]() returns captured lines. The complete program uses [`AbortSignal.timeout`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static) for a deadline and matches a whole output line. Its cleanup checks whether the private socket exists, including when startup fails, and reports shutdown errors. ## Run the complete program [Capture pane output](https://libtmux.org/en/ts/latest/examples/capture-pane-output/) includes the full TypeScript program, all imports, project files and a run command. The program matches `libtmux capture ready` as a complete line, so the echoed command cannot satisfy the check. It creates and cleans up its own tmux server. ## Visible pane vs. scrollback A capture reads terminal state. Lines that have scrolled beyond retained history are unavailable, and repeated captures can miss intermediate output. Choose the range your task needs and use a stream or completion signal when every output event matters. ## Wait for the expected text Use a deadline and a specific output predicate. The example's short polling pause limits work between checks; it is the observed line that determines completion. [Sending keys](https://libtmux.org/en/ts/latest/guides/sending-keys/) explains why returning from the input call is not a completion signal. ## Wait for a completion signal A program can also signal a dedicated tmux channel. Use the same server endpoint for the sender and waiter and a new channel name per task. [Waiting and retrying](https://libtmux.org/en/ts/latest/topics/waiting-and-retry/) documents this port's waiting APIs and failure handling. --- # Queries Source: https://libtmux.org/en/scala/latest/guides/query/ > Queries: io.github.libtmux:libtmux-scala_3 documentation. Acquire once, then use Scala collections. A handle's captured fields (`.info`, returning the real Java [`PaneState`]()/[`WindowState`]()/[`SessionState`]()/[`ClientState`]() record) describe state as of that capture. A `filter`, `find`, `collect`, sort or comprehension over a [`Vector`]() of handles does not acquire another snapshot. A custom predicate can still perform whatever work its author puts inside it. ## Native predicates `config` identifies the server. Keep the capture while deriving several views of the same data. A view defers local computation; it does not refresh tmux. ```scala import io.github.libtmux.scaladsl.{config => _, *} import scala.util.Using Using.resource(Server.open(config)) { server => val panes = server.panes() val named = panes.filter(_.info.title().nonEmpty) val paths = panes.collect { case pane if pane.info.pid().isPresent => pane.info.currentPath() } val firstActive = panes.find(_.info.active()) val deferred = panes.view.filter(_.info.title().nonEmpty) assert(deferred.toVector == named) assert(paths.size <= panes.size) assert(firstActive.forall(_.info.active())) } ``` Missing metadata answers through the record's own Java accessor ([`Optional`](), [`OptionalLong`]()): a missing PID is different from PID zero, and unavailable floating-pane metadata is different from [`Optional.of(false)`](). ## The typed field DSL and strict cardinality Fields hang on the handle type's own companion ([`Pane.command`](), [`Pane.active`](), ...), generated one-line forwards to Java's own field metamodel ([`Pane_.command()`]()). [`.matching`]() filters a captured [`Vector`]() locally; `&&`, `||` and `!` compose expressions, alongside their named forms [`.and`](), [`.or`]() and [`.not`](). [`.exactlyOne`]()/[`.atMostOne`]() give the strict cardinality `headOption` and `find` do not: both return `Either[CardinalityError, ...]`, mirroring Java's own [`CardinalityException`]() leaves losslessly, including [`MultipleMatches`]()'s [`atLeast`]() count. ```scala import io.github.libtmux.scaladsl.query.* assert(Vector.empty[Int].atMostOne == Right(None)) assert(Vector("selected").exactlyOne == Right("selected")) val ambiguous = Vector(1, 2).atMostOne assert(ambiguous == Left(CardinalityError.MultipleMatches(2))) ``` ## Symbolic and named operators ```scala import io.github.libtmux.scaladsl.{config => _, *} import io.github.libtmux.scaladsl.query._ import scala.util.Using Using.resource(Server.open(config)) { server => val panes = server.panes() val expression = Pane.command.is("cat") && Pane.width.atLeast(1) val selected = panes.matching(expression) val native = panes.filter(p => p.info.currentCommand() == "cat" && p.info.size().width() >= 1) assert(selected == native) } ``` The Cats module reads the same expressions over a captured [`Vector`](), inside the effect's own `map`: `server.panes.map(_.filter(...))` (`Vector[Pane[F]]` does not itself carry [`.matching`]() — apply the predicate to each pane's own `.info` field instead, or to `.underlying.asJava` for a Java expression). This is still local evaluation over a captured vector; it does not run a Java command. An invalid field/operator combination must fail at compilation: ```scala import io.github.libtmux.scaladsl.Pane Pane.active.contains("yes") ``` ## Relationships and identity Java's [`Session_`](), [`Window_`](), [`Pane_`]() and [`Client_`]() expose the canonical fields; the Scala field companions are one-line forwards to them, never a second, hand-copied metamodel. Use their existing [`any`](), `all`, [`none`]() and to-one `is` relations, exposed through [`Fields.ToManyRef`]()/[`Fields.ToOneRef`](). `all` over an empty relation is true. Applying [`any`]() to a conjunction requires one related object satisfying both conditions; conjoining two separate [`any`]() expressions allows two different related objects. Window equality includes its session and index placement. Pane equality is physical, while traversal retains each occurrence's window context. A vector can therefore contain equal pane handles reached through different links. Deduplicate only when that is the intended question, retaining server identity when mixing endpoints. See [ownership](https://libtmux.org/en/scala/latest/guides/ownership/). ## Serialization and regular expressions Opted-in serialization uses the separate Java `libtmux-jackson` artifact and its `libtmux.filter/1` schema, over the raw Java [`FilterExpr`]() an `Expr[T]` wraps (`.asJava`). Keep the canonical Java field and relation objects; rebuilding an accessor with the same name does not establish model authority. Unknown schemas, fields, operators and relations remain errors. Arbitrary Scala closures are not serialized. Java regex matching uses [`java.util.regex.Pattern`]() and substring search through [`Matcher.find`](). Supply a Scala regex's `.pattern` explicitly. Neither the expression adapter nor serialization implies tmux `-f` compilation or an MCP query parameter. --- # Querying and filtering Source: https://libtmux.org/en/fsharp/latest/guides/queries/ > List objects, handle missing matches, and filter captured relations. Describe a listing with [`Server.sessions`](), [`Server.windows`](), [`Server.panes`](), [`Server.clients`](), [`Session.windows`](), [`Session.panes`]() or [`Window.panes`](), narrow it with [`Query.where`](), [`Query.showing`]() or [`Query.whereUnsafe`](), and read it with [`Query.list`](), [`Query.exactlyOne`](), [`Query.atMostOne`]() or [`Query.tryExactlyOne`](). tmux drops rows that cannot match before they are read, and every row is rechecked against the portable filter. Use [`Seq.filter`]() for application predicates over objects you already hold, and [filters](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/docs/fsharp/filters.md) to apply a portable filter to captured objects and their relations. [`Query.atMostOne`]() returns [`None`]() only when nothing matched and raises when several did, so it suits finding an object or creating it when absent; [`Query.tryExactlyOne`](), like FSharp.Core's [`Seq.tryExactlyOne`](), returns [`None`]() for both. In an application published with NativeAOT, use either of them: [`Query.exactlyOne`]() returns FSharp.Core's [`Result`](), whose compiler-generated `ToString` formats through `printf`, and with FSharp.Core 10.1.302 NativeAOT publication rejects it. These complete programs require .NET 8 or 10 and tmux on Linux or macOS. Run the commands from this repository's root. Each block can also replace `Program.fs` in a console project referencing this revision of `LibTmux.FSharp`. Set `LIBTMUX_TMUX` to select a tmux binary outside `PATH`. Each program creates a uniquely named server. Its `use!` bindings dispose the control clients, sessions, and server when the task finishes or fails. Your existing tmux sessions are unaffected. ## At a glance Each binding is one task; its annotation is the type the compiler checks. ```fsharp open System.Collections.Generic open System.Threading open LibTmux open LibTmux.FSharp let queryShapesAsync (ct: CancellationToken) (server: Server) (session: Session) (held: Pane list) = task { // Describing a listing reads nothing. let named = server |> Server.sessions |> Query.where (SessionFields.name |> Filter.startsWith "bu") let! (all: IReadOnlyList) = named |> Query.list ct let! (one: Result) = named |> Query.exactlyOne ct let! (maybe: Session option) = named |> Query.tryExactlyOne ct let! (atMost: Session option) = named |> Query.atMostOne ct let! (inSession: IReadOnlyList) = session |> Session.panes |> Query.list ct let! (showingError: IReadOnlyList) = server |> Server.panes |> Query.showing (ScreenSearch.Text "ERROR:") |> Query.list ct let! (withTail: IReadOnlyList) = server |> Server.sessions |> Query.where (WindowFields.name |> Filter.eq "tail" |> Filter.any SessionFields.windows) |> Query.list ct let! (active: IReadOnlyList) = server |> Server.panes |> Query.whereUnsafe (UnsafeTmuxFilter "#{pane_active}") |> Query.list ct // Objects already in hand are filtered locally. let editors: IReadOnlyList = held |> Query.matching (PaneFields.currentCommand |> Filter.oneOf [ "nvim"; "vim" ]) return all, one, maybe, atMost, inSession, showingError, withTail, active, editors } ``` ## Query every level the same way This program creates a `build` session and a `logs` session whose pane prints an error. It filters sessions by name and by a window they contain, confines a query to one session and one window, finds the pane showing the error, and passes a raw tmux filter through. A filter that reads a relation captures only the sessions tmux keeps. ```console $ dotnet run \ --project examples/LibTmux.FSharp.Examples/LibTmux.FSharp.Examples.fsproj \ --configuration Release \ --framework net10.0 \ -p:ExampleProgram=Queries ``` ```fsharp open System open System.Threading open LibTmux open LibTmux.FSharp let runAsync () = task { use deadline = new CancellationTokenSource(TimeSpan.FromSeconds 10.) let token = deadline.Token let options = ServerConnectionOptions( SocketName = "fsharp-queries-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = (Environment.GetEnvironmentVariable "LIBTMUX_TMUX" |> Option.ofObj |> Option.defaultValue "tmux") ) use! owned = LibTmux.Server.CreateOwnedAsync(options, token) let! build = owned.Value.CreateSessionAsync( NewSessionRequest(Name = "build", WindowName = "make", Command = "/bin/sh"), token ) let! _ = owned.Value.CreateSessionAsync( NewSessionRequest( Name = "logs", WindowName = "tail", Command = "printf 'ERROR: disk full\\n'; exec sleep 60" ), token ) let! server = LibTmux.Server.ConnectAsync(options, token) let! logs = server |> Server.sessions |> Query.where (SessionFields.name |> Filter.eq "logs") |> Query.list token let! logPane = logs[0] |> Session.panes |> Query.list token let! logged = logPane[0] |> Pane.waitForText token (TimeSpan.FromSeconds 5.) "ERROR:" // tmux narrows each listing itself; every row is then rechecked. let! named = server |> Server.sessions |> Query.where (SessionFields.name |> Filter.startsWith "bu") |> Query.exactlyOne token // A relation filter reads only the sessions whose windows can match. let! tailing = server |> Server.sessions |> Query.where (WindowFields.name |> Filter.eq "tail" |> Filter.any SessionFields.windows) |> Query.list token // Session and window scopes use the same functions. let! make = build |> Session.windows |> Query.where (WindowFields.name |> Filter.eq "make") |> Query.tryExactlyOne token // tryExactlyOne is None when no window, or several, matched. let! makePanes = task { match make with | Some window -> let! panes = window |> Window.panes |> Query.list token return Some panes.Count | None -> return None } // tmux searches each pane's visible rows, as find-window does. let! showingErrors = server |> Server.panes |> Query.showing (ScreenSearch.Text "ERROR:") |> Query.list token let! errorRow = showingErrors[0] |> Pane.findOnScreen token (ScreenSearch.Text "disk full") // A raw tmux filter is the escape hatch; nothing rechecks it. let! active = server |> Server.panes |> Query.whereUnsafe (UnsafeTmuxFilter "#{pane_active}") |> Query.list token // Find a session or create it: atMostOne is None only when nothing // matched, and raises when several do. let deploy = server |> Server.sessions |> Query.where (SessionFields.name |> Filter.eq "deploy") let! existing = deploy |> Query.atMostOne token if existing.IsNone then let! _ = owned.Value.CreateSessionAsync(NewSessionRequest(Name = "deploy", Command = "exec sleep 60"), token) () let! found = deploy |> Query.atMostOne token let! several = task { try let! _ = server |> Server.sessions |> Query.atMostOne token return "one or none" with :? InvalidOperationException -> return "refused" } printfn "logged: %b" logged.Found printfn "named: %A" (named |> Result.map (fun session -> session.Name)) printfn "tailing: %A" [ for session in tailing -> session.Name ] printfn "make panes: %A" makePanes printfn "error row: %A" errorRow printfn "active panes: %d" active.Count printfn "deploy: absent %b, then found %b" existing.IsNone found.IsSome printfn "at most one of every session: %s" several } runAsync().GetAwaiter().GetResult() ``` It prints: ```text logged: true named: Ok "build" tailing: ["logs"] make panes: Some 1 error row: Some 1 active panes: 2 deploy: absent true, then found true at most one of every session: refused ``` [`Query.showing`]() and [`Pane.findOnScreen`]() search only the rows on screen, as `find-window -C` does. To search history, capture the pane with [`Pane.capture`]() and filter the lines. tmux evaluates case-sensitive string, flag, identifier and count conditions; case-insensitive and regex conditions are applied only by the recheck. ## List sessions, windows, panes, and clients This program creates two detached sessions, each with one window and pane. The four reads report those objects and an empty client list. A listing captures scalar fields; it does not populate child relations. ```console $ dotnet run \ --project examples/LibTmux.FSharp.Examples/LibTmux.FSharp.Examples.fsproj \ --configuration Release \ --framework net10.0 \ -p:ExampleProgram=ServerListings ``` ```fsharp open System open System.Threading open LibTmux open LibTmux.FSharp let runAsync () = task { use deadline = new CancellationTokenSource(TimeSpan.FromSeconds 10.) let token = deadline.Token let binary = Environment.GetEnvironmentVariable("LIBTMUX_TMUX") |> Option.ofObj |> Option.defaultValue "tmux" let options = ServerConnectionOptions( SocketName = "fsharp-listings-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = binary ) use! owned = LibTmux.Server.CreateOwnedAsync(options, token) use! _demo = owned.Value.CreateOwnedSessionAsync( NewSessionRequest(Name = "demo", WindowName = "shell", Command = "/bin/sh"), token ) use! _worker = owned.Value.CreateOwnedSessionAsync( NewSessionRequest(Name = "worker", WindowName = "jobs", Command = "/bin/sh"), token ) let! server = LibTmux.Server.ConnectAsync(options, token) let! sessions = server |> Server.sessions |> Query.list token let! windows = server |> Server.windows |> Query.list token let! panes = server |> Server.panes |> Query.list token let! clients = server |> Server.clients |> Query.list token for session in sessions do printfn "Session: %s (%O)" session.Name session.Id printfn "Windows: %d; panes: %d; clients: %d" windows.Count panes.Count clients.Count } runAsync().GetAwaiter().GetResult() ``` It prints: ```text Session: demo ($0) Session: worker ($1) Windows: 2; panes: 2; clients: 0 ``` The two sessions each hold one window and one pane, and no client is attached. Window listings preserve placements: a window linked into several sessions can appear several times. ## Look up an object and handle absence Session, window, and pane lookups take typed IDs. Client lookup takes an exact, case-sensitive name. The program attaches a control client so it can exercise successful client lookup without an interactive terminal. ```console $ dotnet run \ --project examples/LibTmux.FSharp.Examples/LibTmux.FSharp.Examples.fsproj \ --configuration Release \ --framework net10.0 \ -p:ExampleProgram=ServerLookups ``` ```fsharp open System open System.Threading open LibTmux open LibTmux.FSharp let runAsync () = task { use deadline = new CancellationTokenSource(TimeSpan.FromSeconds 10.) let token = deadline.Token let binary = Environment.GetEnvironmentVariable("LIBTMUX_TMUX") |> Option.ofObj |> Option.defaultValue "tmux" let options = ServerConnectionOptions( SocketName = "fsharp-lookups-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = binary ) use! owned = LibTmux.Server.CreateOwnedAsync(options, token) use! demo = owned.Value.CreateOwnedSessionAsync( NewSessionRequest(Name = "demo", WindowName = "shell", Command = "/bin/sh"), token ) let! server = LibTmux.Server.ConnectAsync(options, token) let! windows = server |> Server.windows |> Query.list token let! panes = server |> Server.panes |> Query.list token let window = windows |> Seq.exactlyOne let pane = panes |> Seq.exactlyOne use! _control = server |> Control.enter token let! clients = server |> Server.clients |> Query.list token let client = clients |> Seq.exactlyOne let! foundSession = server |> Server.tryFindSession token demo.Value.Id let! foundWindow = server |> Server.tryFindWindow token window.Id let! foundPane = server |> Server.tryFindPane token pane.Id let! foundClient = server |> Server.tryFindClient token client.Name let! missingSession = server |> Server.tryFindSession token (SessionId Int32.MaxValue) let! missingWindow = server |> Server.tryFindWindow token (WindowId Int32.MaxValue) let! missingPane = server |> Server.tryFindPane token (PaneId Int32.MaxValue) let! missingClient = server |> Server.tryFindClient token (client.Name + "-missing") printfn "session: %A" (foundSession |> Option.map (fun found -> found.Name)) printfn "window: %A" (foundWindow |> Option.map (fun found -> found.Name)) printfn "pane: %A" (foundPane |> Option.map (fun found -> found.Id = pane.Id)) printfn "client: %A" (foundClient |> Option.map (fun found -> found.Name = client.Name)) printfn "missing: %A" [ missingSession.IsSome missingWindow.IsSome missingPane.IsSome missingClient.IsSome ] } runAsync().GetAwaiter().GetResult() ``` It prints: ```text session: Some "demo" window: Some "shell" pane: Some true client: Some true missing: [false; false; false; false] ``` Each lookup finds the object it was given, and each lookup of an ID or name that does not exist returns [`None`](). [`None`]() means a successful read found no matching object. Connection failures, command failures, stale server generations, and cancellation propagate as errors. --- # Ownership Source: https://libtmux.org/en/scala/latest/guides/ownership/ > Ownership: io.github.libtmux:libtmux-scala_3 documentation. Opening a Scala server owns a Java client. Closing that client releases its transport and local workers; it does not kill the tmux daemon. [`killServer`]() is an explicit, separate operation. A borrowed facade leaves the original Java client under its existing owner's control. ## Direct-style scopes [`Server.open`][server] returns an opaque [`Server`](), bounded by [`AutoCloseable`](), for [`scala.util.Using.resource`]() or an explicit `try`/`finally` scope — the bound is the type's own, so [`close()`]() needs no forwarding of its own. Its [`close`]() is idempotent. [`Server.fromJava`]() borrows a client instead of owning one; closing that facade closes the Java client too, so a caller who only means to borrow keeps the original owner's [`close()`]() as the one that matters. An opaque handle carries no Scala-side scope state of its own — no owned/closed/parent bookkeeping to keep in sync with Java's. Whether a call through it fails after the owning [`Server`]() closes is exactly Java's own use-after-close contract ([`ServerClosedException`]()), not a second policy this facade adds. ## Effect scopes [`cats.Server.resource`][cats-server] acquires the client when its [`Resource`]() runs. [`cats.Server.fromJava`]() also returns a [`Resource`](), with borrowing semantics. Both scope the operations submitted through the returned facade. Release rejects new work, cancels queued and running operations, waits for their finalizers, and then closes the owned client if there is one. Returning a handle or an unevaluated effect from the resource body does not extend its lifetime. The handle's captured data remains available; executing its effect after release fails. Release cancels operations still running; an operation can finish before that cancellation reaches it. A caller that masks cancellation can receive a scope-closed failure instead of waiting indefinitely for a canceled child operation. Partial acquisition failure and failure in the resource body still release what the resource acquired. Cancellation also waits for cleanup. Borrowing changes which client is closed, not the requirement to release the facade's own work. If an external owner closes a borrowed transport while a request is dispatched, that request can fail with Java's `UNKNOWN` dispatch outcome. The facade preserves that failure; it does not turn owner closure into a successful empty result or an automatic retry. Here `config` selects an existing server with a session. The outer resource owns Java. The inner Scala scope borrows it, and the original client still answers after that scope ends: ```scala import _root_.cats.effect.{IO, Resource} import io.github.libtmux.{Server => JavaServer} import io.github.libtmux.scaladsl.cats.{config => _, *} import io.github.libtmux.scaladsl.cats.{Server => ScalaServer} Resource .make(IO.blocking(JavaServer.open(config)))(java => IO.blocking(java.close())) .use { java => ScalaServer.fromJava[IO](java).use { server => server.sessions().flatMap(values => IO(assert(values.nonEmpty))) }.flatMap(_ => IO.blocking(assert(java.isAlive()))) } ``` ## Java identity and one escape hatch Every direct-style handle is opaque over its Java one — the same object, not a copy — so equality and hash code are Java's own. A pane's identity is physical; a window's identity includes its captured session and window index. Borrowing does not replace that identity by reacquiring the same textual ID. Refresh follows the Java contract and can return a pane through a different window occurrence. `.asJava` is the one escape hatch, on every handle, always public: opaque wrapping is free, so it is a zero-cost coercion, never a copy and never a second, more "unsafe" name to reach for. Code using the raw Java handle must still follow its ownership and threading contract. Reaching `.asJava` from an owned scope does not keep that client open past the Scala facade's own [`close()`](); reaching it from a borrowed scope does not make the Scala facade its owner. ## Control attachments [`Control.attach`][control] on a captured session owns a separate process attachment to that capture's process, started by the session's transport. [`Control.attachUnfenced`]() on a config and session id does not check the process. Releasing either stops its admitted requests before closing the attachment and preserves the daemon. Acquire an output or event subscription inside the attachment's resource and before starting its producer. Release the subscription before the attachment. An [observation][observation] allows one active stream consumer; canceled consumption releases that slot. Releasing the observation closes its Java subscription and discards buffered events. Keep command and observation attachments separate when canceling a command must not end observation. See [execution](https://libtmux.org/en/scala/latest/guides/execution/) for admission bounds, cancellation uncertainty, and the difference between a control acknowledgement and command completion. [server]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Server.scala [cats-server]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/src/main/scala/io/github/libtmux/scaladsl/cats/Server.scala [control]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/src/main/scala/io/github/libtmux/scaladsl/cats/Control.scala [observation]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/src/main/scala/io/github/libtmux/scaladsl/cats/Observation.scala --- # Querying and filtering Source: https://libtmux.org/en/tmux/guides/querying-and-filtering/ > Find an exact tmux session and select one pane using formats and filters. Use an exact target when you know its name, or filter a listing when you need to inspect several objects. A session named `work` and one named `worker` should not become interchangeable targets. ## Require exactly one match Prefix a session target with `=` to require an exact name. `has-session` reports whether it exists; it does not return a pane. This script selects panes in `work` and rejects both zero matches and multiple matches before using an ID. Save the complete script as `query.sh`. It requires tmux 3.2a or newer and a POSIX shell. It creates and cleans up its own server. ```sh title="query.sh" #!/bin/sh set -eu directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-guide.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! tmux -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || status=$? exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM tmux -S "$socket" -f /dev/null new-session -d -s work 'cat' tmux -S "$socket" new-session -d -s worker 'cat' tmux -S "$socket" has-session -t '=work' panes=$(tmux -S "$socket" list-panes -a \ -f '#{==:#{session_name},work}' -F '#{pane_id}') # Pane IDs contain no whitespace; split the rows to count matches. # shellcheck disable=SC2086 set -- $panes if [ "$#" -ne 1 ]; then printf 'Expected one work pane, found %s.\n' "$#" >&2 exit 1 fi tmux -S "$socket" display-message -p -t "$1" '#{session_name}' ``` Run the saved script: ```console $ sh query.sh ``` The output is `work`. The `worker` session remains outside the result. Targeting the returned pane ID avoids repeating name matching when the next command runs. An object can still disappear between commands; keep errors visible. ## Declarative filters `list-panes -a` searches every session. `-f` evaluates a tmux format as a boolean for each pane; here `#{==:#{session_name},work}` keeps only exact session-name matches. `-F` chooses what each returned row contains. Using only `#{pane_id}` keeps the result easy to pass to another tmux command. ## Case-insensitive matching Choose case handling explicitly when a name may vary in capitalization. tmux's `m` format operator supports an `i` modifier for case-insensitive matching. Keep the ordinary `==` comparison when exact case is part of your contract. [Filtering and queries](https://libtmux.org/en/tmux/concepts/queries/) explains the query model. ## Push the filter into tmux, or read once and filter locally A tmux-side filter reduces returned rows. Capturing a listing once and filtering it in your program is useful when several decisions should use the same read. Neither approach reserves the objects. Unknown format names expand to empty values; check an unexpectedly empty result before assuming nothing exists. ## Use a language library The port dropdown opens the language's query guide. These complete programs connect to an existing server, find exactly the `work` session and report its absence: [Python](https://libtmux.org/en/py/latest/guides/attaching-to-tmux/) · [TypeScript](https://libtmux.org/en/ts/latest/guides/attaching-to-tmux/) · [Go](https://libtmux.org/en/go/latest/guides/attaching-to-tmux/) · [Rust](https://libtmux.org/en/rs/latest/guides/attaching-to-tmux/) · [Java](https://libtmux.org/en/java/latest/guides/attaching-to-tmux/) · [Kotlin](https://libtmux.org/en/kotlin/latest/guides/attaching-to-tmux/) · [Scala](https://libtmux.org/en/scala/latest/guides/attaching-to-tmux/) · [C#](https://libtmux.org/en/csharp/latest/guides/attaching-to-tmux/) · [F#](https://libtmux.org/en/fsharp/latest/guides/attaching-to-tmux/) · [C++](https://libtmux.org/en/cxx/latest/guides/attaching-to-tmux/) · [Swift](https://libtmux.org/en/swift/latest/guides/attaching-to-tmux/) · [Ruby](https://libtmux.org/en/ruby/latest/guides/attaching-to-tmux/) · [Lua](https://libtmux.org/en/lua/latest/guides/attaching-to-tmux/) ## tmux reference See [has-session](https://libtmux.org/en/tmux/latest/manual/has-session/), [list-panes](https://libtmux.org/en/tmux/latest/manual/list-panes/), and the [target syntax](https://libtmux.org/en/tmux/latest/manual/full/#COMMANDS). The version selector shows the flags supported by your installed tmux release. The [tmux manual](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1) documents these commands and their flags. --- # Querying and filtering Source: https://libtmux.org/en/csharp/latest/guides/querying-and-filtering/ > Choose a target and handle missing or ambiguous results. [`Server.HasSessionAsync`]() checks whether a session exists. It does not return a selected session object. The complete program checks `work`, reports its absence and leaves the borrowed server running. Use collection filtering when you need handles or must detect several matching objects. ## Require exactly one match [Attaching to tmux](https://libtmux.org/en/csharp/latest/guides/attaching-to-tmux/) provides the complete C# program and its setup. It searches an existing server for `work`, prints the name and reports an absent session. Its launcher checks that the server remains running. For a more general predicate, decide whether zero or several results are valid before indexing a collection. Keep lookup and command failures visible: another client can change the server between a read and the operation using its result. ## Declarative filters [Filtering and queries](https://libtmux.org/en/csharp/latest/concepts/queries/) describes this port's query APIs, accepted fields and result-count contracts. Use that contract when storing a query in configuration. ## Case-insensitive matching Choose case handling explicitly when your query needs it. The attach program uses exact case because the intended session is named `work`. ## Push the filter into tmux, or read once and filter locally A tmux-side filter reduces returned rows; a captured collection can answer several local queries from one read. Neither reserves the result. Check unexpectedly empty format values before assuming that an object does not exist. --- # Querying and filtering Source: https://libtmux.org/en/cxx/latest/guides/querying-and-filtering/ > Choose a target and handle missing or ambiguous results. Check the results from [`Server::at_socket_path`]() and [`Server::sessions`]() before reading either value. The complete program compares [`Session::name`]() with `"work"`, reports an absent session and keeps the existing server running. [`libtmux::exactly_one`]() can enforce a one-element result for a filtered range. ## Require exactly one match [Attaching to tmux](https://libtmux.org/en/cxx/latest/guides/attaching-to-tmux/) provides the complete C++ program and its setup. It searches an existing server for `work`, prints the name and reports an absent session. Its launcher checks that the server remains running. For a more general predicate, decide whether zero or several results are valid before indexing a collection. Keep lookup and command failures visible: another client can change the server between a read and the operation using its result. ## Declarative filters [Filtering and queries](https://libtmux.org/en/cxx/latest/concepts/queries/) describes this port's query APIs, accepted fields and result-count contracts. Use that contract when storing a query in configuration. ## Case-insensitive matching Choose case handling explicitly when your query needs it. The attach program uses exact case because the intended session is named `work`. ## Push the filter into tmux, or read once and filter locally A tmux-side filter reduces returned rows; a captured collection can answer several local queries from one read. Neither reserves the result. Check unexpectedly empty format values before assuming that an object does not exist. --- # Querying and filtering Source: https://libtmux.org/en/go/latest/guides/querying-and-filtering/ > Choose a target and handle missing or ambiguous results. [`Server.SearchSessions`]() accepts a [`tmux.TmuxFilter`](). The complete program uses `#{==:#{session_name},work}` and checks the result count before accepting it. For local collections, [`tmuxq.ExactlyOne`]() distinguishes [`ErrNoMatch`]() from [`ErrMultipleMatches`](); preserve those errors when adding context. ## Require exactly one match [Attaching to tmux](https://libtmux.org/en/go/latest/guides/attaching-to-tmux/) provides the complete Go program and its setup. It searches an existing server for `work`, prints the name and reports an absent session. Its launcher checks that the server remains running. For a more general predicate, decide whether zero or several results are valid before indexing a collection. Keep lookup and command failures visible: another client can change the server between a read and the operation using its result. ## Declarative filters [Filtering and queries](https://libtmux.org/en/go/latest/concepts/queries/) provides complete Go programs for combined predicates, invalid filters, missing and ambiguous results, and related windows. Use that contract when storing a query in configuration. ## Case-insensitive matching Choose case handling explicitly when your query needs it. The attach program uses exact case because the intended session is named `work`. ## Push the filter into tmux, or read once and filter locally A tmux-side filter reduces returned rows; a captured collection can answer several local queries from one read. Neither reserves the result. Check unexpectedly empty format values before assuming that an object does not exist. --- # Querying and filtering Source: https://libtmux.org/en/java/latest/guides/querying-and-filtering/ > Choose a target and handle missing or ambiguous results. [`Server.sessions`]() returns the sessions to inspect. The complete program filters the returned stream using [`Session.name().equals("work")`]() and throws when the session is absent. Session names are unique within one server. Closing that borrowed [`Server`]() handle leaves the tmux process running. ## Require exactly one match [Attaching to tmux](https://libtmux.org/en/java/latest/guides/attaching-to-tmux/) provides the complete Java program and its setup. It searches an existing server for `work`, prints the name and reports an absent session. Its launcher checks that the server remains running. For a more general predicate, decide whether zero or several results are valid before indexing a collection. Keep lookup and command failures visible: another client can change the server between a read and the operation using its result. ## Declarative filters [Filtering and queries](https://libtmux.org/en/java/latest/concepts/queries/) describes this port's query APIs, accepted fields and result-count contracts. Use that contract when storing a query in configuration. ## Case-insensitive matching Choose case handling explicitly when your query needs it. The attach program uses exact case because the intended session is named `work`. ## Push the filter into tmux, or read once and filter locally A tmux-side filter reduces returned rows; a captured collection can answer several local queries from one read. Neither reserves the result. Check unexpectedly empty format values before assuming that an object does not exist. --- # Querying and filtering Source: https://libtmux.org/en/py/latest/guides/querying-and-filtering/ > Choose a target and handle missing or ambiguous results. [`server.sessions.get(session_name="work")`]() selects by exact name and reports an absent result. The complete program below uses that lookup, prints the session name and leaves the existing server running. ## Require exactly one match [Attaching to tmux](https://libtmux.org/en/py/latest/guides/attaching-to-tmux/) provides the complete Python program and its setup. It searches an existing server for `work`, prints the name and reports an absent session. Its launcher checks that the server remains running. For a more general predicate, decide whether zero or several results are valid before indexing a collection. Keep lookup and command failures visible: another client can change the server between a read and the operation using its result. ## Declarative filters [Filtering and queries](https://libtmux.org/en/py/latest/concepts/queries/) describes this port's query APIs, accepted fields and result-count contracts. Use that contract when storing a query in configuration. ## Case-insensitive matching Choose case handling explicitly when your query needs it. The attach program uses exact case because the intended session is named `work`. ## Push the filter into tmux, or read once and filter locally A tmux-side filter reduces returned rows; a captured collection can answer several local queries from one read. Neither reserves the result. Check unexpectedly empty format values before assuming that an object does not exist. --- # Querying and filtering Source: https://libtmux.org/en/rs/latest/guides/querying-and-filtering/ > Choose a target and handle missing or ambiguous results. [`Server::sessions`]() returns session handles. The complete program compares [`Session::name`]() bytes with `b"work"` and reports an absent match. Session names are unique within that server. It shuts down its client while leaving tmux running. ## Require exactly one match [Attaching to tmux](https://libtmux.org/en/rs/latest/guides/attaching-to-tmux/) provides the complete Rust program and its setup. It searches an existing server for `work`, prints the name and reports an absent session. Its launcher checks that the server remains running. For a more general predicate, decide whether zero or several results are valid before indexing a collection. Keep lookup and command failures visible: another client can change the server between a read and the operation using its result. ## Declarative filters [Filtering and queries](https://libtmux.org/en/rs/latest/concepts/queries/) describes this port's query APIs, accepted fields and result-count contracts. Use that contract when storing a query in configuration. ## Case-insensitive matching Choose case handling explicitly when your query needs it. The attach program uses exact case because the intended session is named `work`. ## Push the filter into tmux, or read once and filter locally A tmux-side filter reduces returned rows; a captured collection can answer several local queries from one read. Neither reserves the result. Check unexpectedly empty format values before assuming that an object does not exist. --- # Querying and filtering Source: https://libtmux.org/en/swift/latest/guides/querying-and-filtering/ > Choose a target and handle missing or ambiguous results. [`Server.hasSession`]() checks existence. The complete program passes `"=work"` to require the exact tmux session name, reports an absent session and leaves the server running. An existence check does not return a session handle or reserve the session against changes by another client. ## Require exactly one match [Attaching to tmux](https://libtmux.org/en/swift/latest/guides/attaching-to-tmux/) provides the complete Swift program and its setup. It searches an existing server for `work`, prints the name and reports an absent session. Its launcher checks that the server remains running. For a more general predicate, decide whether zero or several results are valid before indexing a collection. Keep lookup and command failures visible: another client can change the server between a read and the operation using its result. ## Declarative filters [Filtering and queries](https://libtmux.org/en/swift/latest/concepts/queries/) describes this port's query APIs, accepted fields and result-count contracts. Use that contract when storing a query in configuration. ## Case-insensitive matching Choose case handling explicitly when your query needs it. The attach program uses exact case because the intended session is named `work`. ## Push the filter into tmux, or read once and filter locally A tmux-side filter reduces returned rows; a captured collection can answer several local queries from one read. Neither reserves the result. Check unexpectedly empty format values before assuming that an object does not exist. --- # Querying and filtering Source: https://libtmux.org/en/ts/latest/guides/querying-and-filtering/ > Choose a target and handle missing or ambiguous results. Take a snapshot with [`Server.snapshot`](), then use [`snapshot.sessions.one`]() with an exact name predicate. The complete program reports an absent result and leaves the existing tmux server running. A snapshot describes the read that created it; later commands can still fail if an object has disappeared. ## Require exactly one match [Attaching to tmux](https://libtmux.org/en/ts/latest/guides/attaching-to-tmux/) provides the complete TypeScript program and its setup. It searches an existing server for `work`, prints the name and reports an absent session. Its launcher checks that the server remains running. For a more general predicate, decide whether zero or several results are valid before indexing a collection. Keep lookup and command failures visible: another client can change the server between a read and the operation using its result. ## Declarative filters [Filtering and queries](https://libtmux.org/en/ts/latest/concepts/queries/) describes this port's query APIs, accepted fields and result-count contracts. Use that contract when storing a query in configuration. ## Case-insensitive matching Choose case handling explicitly when your query needs it. The attach program uses exact case because the intended session is named `work`. ## Push the filter into tmux, or read once and filter locally A tmux-side filter reduces returned rows; a captured collection can answer several local queries from one read. Neither reserves the result. Check unexpectedly empty format values before assuming that an object does not exist. --- # Streams and cleanup Source: https://libtmux.org/en/fsharp/latest/guides/streams/ > Consume events with bounded lifetimes and cancellation. Captured snapshots are replayable local observations. Control-mode events are live, ordered, destructive observations. They are not a replayable [`seq`](), and a control client has one event stream with one consumer. ## Choose a wait or a stream To wait for one thing a pane prints, use [`Pane.sendAndWait`](), [`Pane.waitForText`](), [`Pane.waitUntil`]() or [`Pane.run`](); each returns a single result, and [which wait](https://libtmux.org/en/fsharp/latest/guides/getting-started/#which-wait) compares them. The waits share one control client per session while any wait on it runs, and [`Pane.run`]() learns its exit status from a private `wait-for` channel. Read a stream when the caller reacts to events as they arrive. ## Streams are cold [`Control.events`]() and [`Control.watchPane`]() return an [`IAsyncEnumerable`](). Nothing is read until a consumer enumerates it, and the consumer supplies the cancellation token. [`Control.foldWhile`]() and [`Control.iter`]() consume a stream, await one callback at a time, dispose only their enumerator, and leave the client open. Any [`IAsyncEnumerable`]() library composes the same streams; `TaskSeq<'T>` in FSharp.Control.TaskSeq is the same type. [`Control.watchPane`]() narrows a client's stream to one pane's output, and ends with [`TmuxPaneGoneEvent`]() once the pane is confirmed gone: ```fsharp run open System open System.Threading open LibTmux open LibTmux.FSharp let readPaneUntilAsync (cancellationToken: CancellationToken) (marker: string) (pane: Pane) (session: IControlModeSession) = session |> Control.watchPane pane |> Control.foldWhile cancellationToken (fun output event -> task { match event with | :? TmuxOutputEvent as printed -> let output = output + printed.Data if output.Contains(marker, StringComparison.Ordinal) then return StreamStep.Stop output else return StreamStep.Continue output | :? TmuxPaneGoneEvent | :? TmuxExitEvent -> return StreamStep.Stop output | _ -> return StreamStep.Continue output }) "" ``` A client has one event stream, so watching two panes with [`Control.watchPane`]() takes two clients. [`Control.watchPanes`]() follows several through one: each output event names its pane, each pane's end arrives as [`TmuxPaneGoneEvent`]() after the output buffered before it went, and the stream ends once every pane is gone. This complete program follows two panes, then their ends: ```fsharp run open System open System.Threading open LibTmux open LibTmux.FSharp let runAsync () = task { use deadline = new CancellationTokenSource(TimeSpan.FromSeconds 20.) let token = deadline.Token let options = ServerConnectionOptions( SocketName = "fsharp-watch-panes-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = (Environment.GetEnvironmentVariable "LIBTMUX_TMUX" |> Option.ofObj |> Option.defaultValue "tmux") ) use! owned = LibTmux.Server.CreateOwnedAsync(options, token) let! session = owned.Value.CreateSessionAsync(NewSessionRequest(Name = "work", Command = "exec sleep 60"), token) // The client buffers everything from the moment it attaches, so the // panes it should see can start afterwards. use! client = session |> Control.enterSession token let! first = session |> Session.panes |> Query.list token let start command = first[0] |> Pane.split token (SplitPaneRequest(Command = command)) let! build = start "printf 'build: ok\\n'; exec sleep 60" let! test = start "printf 'test: ok\\n'; exec sleep 60" // One client, both panes: each output event names its pane. let! printed = client |> Control.watchPanes [ build; test ] |> Control.foldWhile token (fun (printed: Map) event -> task { match event with | :? TmuxOutputEvent as output -> let pane = output.PaneId.ToString() let sofar = printed |> Map.tryFind pane |> Option.defaultValue "" let printed = printed |> Map.add pane (sofar + output.Data) if printed.Count = 2 && printed |> Map.forall (fun _ text -> text.Contains '\n') then return StreamStep.Stop printed else return StreamStep.Continue printed | _ -> return StreamStep.Continue printed }) Map.empty // Each pane's end arrives as TmuxPaneGoneEvent, and the stream ends // once both are gone. do! build.KillAsync(cancellationToken = token) do! test.KillAsync(cancellationToken = token) let! ended = client |> Control.watchPanes [ build; test ] |> Control.foldWhile token (fun ended event -> task { match event with | :? TmuxPaneGoneEvent as gone -> return StreamStep.Continue(ended @ [ gone.PaneId ]) | _ -> return StreamStep.Continue ended }) [] for pane in [ build; test ] do printfn "%s" (printed[pane.Id.ToString()].Trim()) printfn "ended in order given: %b" (ended = [ build.Id; test.Id ]) } runAsync().GetAwaiter().GetResult() ``` It prints: ```text build: ok test: ok ended in order given: true ``` The watch reads the client's only stream, so it consumes and drops events for other panes. Attach the client with [`Control.enterSession`]() to the session that holds the pane. tmux discards output it has not yet sent once a pane's program exits, so the last lines of a program that exits at once may never arrive on any control client. Read final output with [`Pane.run`](), or capture a pane kept with `remain-on-exit`. ## Follow live state [`Mirror.start`]() keeps a current copy of a server's sessions, windows, panes and clients. Each change tmux announces starts a fresh capture, and a capture that finds nothing different publishes nothing, so [`Mirror.waitUntil`]() and [`Mirror.views`]() see each distinct state once. Activity times, cursor positions and history sizes change with every keystroke and do not count. tmux does not announce a pane's running command or working directory, nor a layout change in a session the mirror is not attached to; [`Mirror.startRefreshing`]() also captures whenever the mirror has been quiet for an interval: ```fsharp run open System open System.Threading open LibTmux open LibTmux.FSharp let runAsync () = task { use deadline = new CancellationTokenSource(TimeSpan.FromSeconds 20.) let token = deadline.Token let options = ServerConnectionOptions( SocketName = "fsharp-live-" + Guid.NewGuid().ToString("N"), ConfigurationFile = "/dev/null", TmuxBinaryPath = (Environment.GetEnvironmentVariable "LIBTMUX_TMUX" |> Option.ofObj |> Option.defaultValue "tmux") ) use! owned = LibTmux.Server.CreateOwnedAsync(options, token) let! session = owned.Value.CreateSessionAsync( NewSessionRequest(Name = "work", WindowName = "shell", Command = "/bin/sh"), token ) // Captures again on each change tmux announces, and every 200 ms for // changes it does not, such as the command a pane runs. use! mirror = session |> Mirror.startRefreshing token (TimeSpan.FromMilliseconds 200.) let! _ = session.CreateWindowAsync(NewWindowRequest(Name = "logs", Command = "/bin/sh"), token) let! withLogs = mirror |> Mirror.waitUntil token (TimeSpan.FromSeconds 5.) (fun view -> view.Server.Windows |> Seq.exists (fun window -> window.Name = "logs")) let! panes = session |> Session.panes |> Query.list token do! panes[0] |> Pane.sendKeys token (SendKeysRequest(Text = "exec sleep 30", Literal = true)) let! sleeping = mirror |> Mirror.waitUntil token (TimeSpan.FromSeconds 5.) (fun view -> view.Server.Panes |> Seq.exists (fun pane -> pane.CurrentCommand = "sleep")) printfn "windows: %s" (String.Join(", ", [ for window in withLogs.Server.Windows -> window.Name ])) printfn "sleeping panes: %d" (sleeping.Server.Panes |> Seq.filter (fun pane -> pane.CurrentCommand = "sleep") |> Seq.length) printfn "newer view: %b" (sleeping.Epoch > withLogs.Epoch) } runAsync().GetAwaiter().GetResult() ``` It prints: ```text windows: shell, logs sleeping panes: 1 newer view: true ``` The mirror's control client receives notifications only, never pane output, and does not change window sizes. If its client ends, the mirror attaches again through the anchor session; once that session is gone, the mirror ends and [`Mirror.views`]() raises [`TmuxObjectNotFoundException`](). ## Ownership Use [`Control.withSession`]() to own a client for one task, or pass a client from [`Control.enter`]() or [`Control.enterSession`]() to [`Control.useSession`](). The [control-mode example](https://libtmux.org/en/fsharp/latest/guides/modes/#control-mode) shows both lifetimes. ## Loss, ends and failures A client buffers 512 events by default ([`ServerConnectionOptions.ControlModeEventBufferCapacity`]()). When a reader falls behind, the buffer discards the oldest output of the pane with the most output waiting, so a flooding pane loses its own output rather than a quieter pane's, and notifications about sessions, windows and layout survive it. [`TmuxEventsDroppedEvent`]() reports the loss; its [`OnlyOutput`]() is true when no notification was discarded, so state derived from notifications is still exact. The client then pauses the flooding pane in tmux until the reader catches up: [`TmuxPanePausedEvent`]() and [`TmuxPaneContinuedEvent`]() bracket output the pane printed that the reader never receives, and a client nobody reads keeps the pane paused. The pause is the client's own `refresh-client -A`, sent when its buffer fills; it does not set tmux's age-based `pause-after`, so a reader that keeps up never sees a pause. Capture the pane to read its screen after a gap. [`TmuxExitEvent`]() precedes normal stream completion. A stream fault arrives after buffered events. Cancellation stops waiting and disposes the reader; it does not undo a command tmux already received. When a callback and the enumerator's cleanup both fail, the callback's exception propagates unchanged and [`Control.cleanupFailure`]() returns the cleanup's. The callback's exception keeps its type, so a handler that matches `:? TmuxPaneException` still catches it; an `AggregateException` of both would not be caught there. --- # .NET interoperation Source: https://libtmux.org/en/fsharp/latest/guides/interop/ > Use core operations alongside the F# helpers. The companion is built on [LibTmux](https://github.com/libtmux/libtmux-dotnet/) in the same `libtmux` organization and maintained by the same primary author. It uses the existing entities, IDs, requests, exceptions, snapshots, and query documents. Pass a [`Server`](), [`Session`](), [`Window`](), or [`Pane`]() between F# and C# without conversion. `Task<'T>` remains the default asynchronous contract. Pass the cancellation token to the façade function explicitly and preserve core exceptions. Use [`option`]() only for a completed lookup that found no entity; use [`Selection.exactlyOne`]() when zero and multiple local matches need different outcomes. A task starts when called; an [`Async`]() workflow starts when run. If cancellation details matter, await the core task directly. Passing it through [`Async.AwaitTask`]() and [`Async.StartAsTask`]() can replace [`TmuxOperationCanceledException`]() with [`TaskCanceledException`](), losing [`CommandMayHaveExecuted`]() and `ClientProcessId`. Depending on continuation timing, the outer task can be canceled or faulted. The companion does not expose an [`Async`]() adapter with an unproved cancellation contract. `LibTmux.Query.Json` remains optional. Add it only when a portable filter must cross a process or language boundary. It serializes the core [`QueryDocument`](); the F# package does not define a second format. ## Failures and retries Every [`LibTmuxException`]() says whether its command reached tmux. The [`TmuxFailure`]() patterns match on that. `NotSent` means tmux never saw the command, so running it again repeats nothing. `Ran` means tmux ran it and then reported an error or gave an answer that could not be used. `MayHaveRun` covers a failure or cancellation after which tmux may already have acted. [`Retry.ifNotSent`]() runs an operation again only for `NotSent`, and only when no command the attempt sent before that failure reached tmux: ```fsharp run open System.Threading open LibTmux open LibTmux.FSharp let readSessionNamesAsync (cancellationToken: CancellationToken) (server: Server) = task { try // Runs again only when tmux never received the command. let! sessions = Retry.ifNotSent cancellationToken 2 (fun token -> server.GetSessionsAsync(token)) return Ok [ for session in sessions -> session.Name ] with | TmuxFailure.Ran failure -> return Error $"tmux ran the command, then: {failure.Message}" | TmuxFailure.MayHaveRun failure -> return Error $"tmux may have acted: {failure.Message}" } ``` `NotSent` speaks for one command. An operation that creates a window and then fails to send a second command has already created the window, so [`Retry.ifNotSent`]() counts every command an attempt sends, through whatever it awaits, and repeats the attempt only if none reached tmux. A read that is safe to repeat whatever happened can use any retry policy; a command that changes tmux should be retried only this way. ## Bound how long tmux may take Bound one call with its token: pass `(new CancellationTokenSource(timeout)).Token`. A call cancelled that way raises [`TmuxOperationCanceledException`](), whose [`CommandMayHaveExecuted`]() says whether tmux may already have run it, and which `TmuxFailure.MayHaveRun` matches. Bound every command a handle sends with `Server.within timeout server`. It returns a handle to the same server, over the same connection, whose commands, and those of every session, window and pane taken from it, give tmux that long. A command that outlasts it raises [`TmuxTransportException`]() with an [`Unknown`]() dispatch state. [`ServerConnectionOptions.CommandTimeout`]() sets the same bound for a whole connection. ## Typed options [`Options.get`]() and [`Options.set`]() take a [`TmuxOptionKey`]() that knows its value's type. The named keys, such as [`TmuxOptionKey.HistoryLimit`]() and [`TmuxOptionKey.Mouse`](), have the same type on every supported tmux; declare others with [`TmuxOptionKey.Text`](), [`Number`]() or [`Flag`](). A read returns the value tmux applies, including one inherited from a parent scope, and raises [`TmuxOptionException`]() when tmux reports none or one the key cannot read. ```fsharp run open System.Threading open LibTmux open LibTmux.FSharp let tuneAsync (cancellationToken: CancellationToken) (session: Session) (window: Window) = task { do! session.Options |> Options.set cancellationToken TmuxOptionKey.HistoryLimit 50_000 do! session.Options |> Options.set cancellationToken (TmuxOptionKey.Text "@stage") "build" let! history = session.Options |> Options.get cancellationToken TmuxOptionKey.HistoryLimit let! stage = session.Options |> Options.get cancellationToken (TmuxOptionKey.Text "@stage") // Never set on the window, so this is tmux's inherited default. let! renames = window.Options |> Options.get cancellationToken TmuxOptionKey.AutomaticRename return history, stage, renames } ``` ## Configuration, hooks and formats Core configuration and format APIs remain available on the same handles. This function takes an existing server and session, makes scoped changes, and checks what tmux reports. The [example runner](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/examples/LibTmux.FSharp.Examples/Program.fs) passes handles from an owned tmux hierarchy. ```fsharp run open System open System.Collections.Generic open System.Threading open LibTmux let inspectCoreSettingsAsync (cancellationToken: CancellationToken) (server: Server) (session: Session) = task { // A global value, overridden locally, shows through again once the // local value is unset. let! _ = session.Options.SetAsync(SetOptionRequest("status-keys", "vi", Global = true), cancellationToken) let! _ = session.Options.SetAsync(SetOptionRequest("status-keys", "emacs"), cancellationToken) do! session.Options.UnsetAsync(UnsetOptionRequest("status-keys"), cancellationToken) let! statusKeys = session.Options.GetAsync(GetOptionRequest("status-keys", IncludeInherited = true), cancellationToken) // An array option and a hook keep each entry's index. let! _ = server.Options.SetAsync( SetOptionRequest("command-alias[40]", "fsharp-window=new-window"), cancellationToken ) let! aliases = server.Options.GetAsync(GetOptionRequest("command-alias"), cancellationToken) let entries = Dictionary() entries[3] <- "display-message fsharp-hook" let! hook = server.Hooks.SetAsync(SetHooksRequest("alert-bell", entries, ClearExisting = true), cancellationToken) let! _ = session.Environment.SetAsync("LIBTMUX_FSHARP_EXAMPLE", "ready", cancellationToken = cancellationToken) let! variable = session.Environment.GetAsync("LIBTMUX_FSHARP_EXAMPLE", cancellationToken) let! rendered = server.DisplayMessageAsync( DisplayMessageRequest(Format = "fsharp-#{pid}", ReturnText = true), cancellationToken ) return {| StatusKeys = [ for option in statusKeys -> option.Value.Raw, option.Inherited ] Alias = aliases |> Seq.tryFind (fun alias -> alias.Index = Nullable 40) |> Option.map (fun alias -> alias.Value.Raw) HookIndexes = [ for value in hook.Values -> value.Index ] Variable = variable |> Option.ofObj |> Option.map (fun entry -> entry.Value) Rendered = rendered |> Option.ofObj |> Option.map List.ofSeq |} } ``` ## Core operations Call the core APIs directly for window placement, pane sizing, layouts, buffers, and copy mode. This example uses handles from the [owned tmux example runner](https://github.com/libtmux/libtmux-dotnet/blob/4f1b997b2e4aeb604c4184707e49dcd4dea44fef/examples/LibTmux.FSharp.Examples/Program.fs). `MoveAsync` returns the new window placement; the original link remains after the moved one is unlinked. Layout and resize calls return refreshed handles. The buffer belongs to the server, while copy mode belongs to the pane. ```fsharp run open System.Threading open LibTmux let exerciseCoreOperationsAsync (cancellationToken: CancellationToken) (server: Server) (session: Session) (window: Window) (pane: Pane) = task { // Link the window at index 5 as well, move that placement to 3, // then unlink it; the original placement stays. do! window.LinkAsync( LinkWindowRequest(session.Id.ToString(), TargetIndex = "5", Detach = true), cancellationToken ) let! placements = session.GetWindowsAsync(cancellationToken) let linked = placements |> Seq.find (fun item -> item.Id = window.Id && item.Index = 5) let! moved = linked.MoveAsync(MoveWindowRequest(Destination = "3", NoSelect = true), cancellationToken) do! moved.UnlinkAsync(cancellationToken = cancellationToken) let! remaining = session.GetWindowsAsync(cancellationToken) // Layout and resize return the handle they changed. let! split = window.SplitPaneAsync(cancellationToken = cancellationToken) let! laidOut = window.SelectLayoutAsync(SelectLayoutRequest(Layout = "even-horizontal"), cancellationToken) let! resized = split.ResizeAsync(ResizePaneRequest(Height = "10"), cancellationToken) do! server.Buffers.SetAsync("fsharp-ready", "fsharp-guide", cancellationToken = cancellationToken) let! contents = server.Buffers.GetAsync("fsharp-guide", cancellationToken) do! server.Buffers.DeleteAsync("fsharp-guide", cancellationToken) do! pane.EnterCopyModeAsync(cancellationToken = cancellationToken) let! copying = pane.RefreshAsync(cancellationToken) do! pane.EnterCopyModeAsync(CopyModeRequest(Cancel = true), cancellationToken) let! normal = pane.RefreshAsync(cancellationToken) return {| Moved = moved Remaining = remaining Split = split LaidOut = laidOut Resized = resized Buffer = contents InModeWhileCopying = copying.RawFormatFields["pane_in_mode"] InModeAfter = normal.RawFormatFields["pane_in_mode"] |} } ``` ## Window input Core window creation returns a handle that the F# pane helpers can use directly. A literal `"Enter"` types five characters; a key-name `"Enter"` presses the key. `Enter = true` sends a separate key command after literal text. The example checks those command shapes, sends each form to a temporary window, and kills that window. ```fsharp run open System.Threading open LibTmux open LibTmux.FSharp let exerciseWindowInputAsync (cancellationToken: CancellationToken) (session: Session) = task { let! window = session.CreateWindowAsync( NewWindowRequest(Name = "fsharp-input", Command = "/bin/cat", Attach = false), cancellationToken ) let! panes = window.GetPanesAsync(cancellationToken) let pane = panes[0] // Literal text is typed as written; a key name is pressed. Text // followed by Enter is two commands: the text, then the key. let literal = SendKeysRequest(Text = "Enter", Literal = true, Enter = false) let keyName = SendKeysRequest(Text = "Enter", Literal = false, Enter = false) let textThenEnter = SendKeysRequest(Text = "fsharp-input", Literal = true, Enter = true) do! pane |> Pane.sendKeys cancellationToken literal do! pane |> Pane.sendKeys cancellationToken keyName do! pane |> Pane.sendKeys cancellationToken textThenEnter do! window.KillAsync(cancellationToken = cancellationToken) let arguments (request: SendKeysRequest) = [ for command in request.ToCommands(pane) -> List.ofSeq (command.ToArguments()) ] return {| Window = window Panes = panes.Count Literal = arguments literal KeyName = arguments keyName TextThenEnter = arguments textThenEnter |} } ``` ```fsharp run open LibTmux open LibTmux.FSharp open LibTmux.Query.Json let encodeEditorPaneFilter () = Filter.oneOf [ "nvim"; "vim" ] PaneFields.currentCommand |> Filter.toDocument |> QueryJson.Serialize let decodeFilter json = QueryJson.Deserialize json ``` Validate and apply the decoded document with the core query APIs. A JSON round trip does not turn a portable filter into a tmux format expression. --- # Batch commands with a plan Source: https://libtmux.org/en/rs/latest/guides/batching-commands/ > Record Rust operations, compare planners, inspect outcomes, and retain ownership of partial changes. Use a [`Plan`](https://libtmux.org/en/rs/latest/reference/plan-plan/) when you know the operations before you run them. Recording a plan does not contact tmux. You can inspect its steps, validate its dependencies, then select a planner for execution. This program creates a window and sends two lines to its pane. It repeats that work with three planners, verifies the captured lines, and then checks that a refused command stops a later operation. Each run uses a different window name on its own private server. ## Setup and run Use an empty directory with Git, rustup with the 1.97.1 toolchain installed, tmux 3.2a or newer, and a Unix environment. The program creates a private socket under `/tmp/libtmux-rs-dev`, starts `cat` in its panes, and stops only the server it created. No existing session, socket, or environment variable is required. Save this file as `Cargo.toml`: ```toml title="Cargo.toml" [package] name = "libtmux-batching-example" version = "0.0.0" edition = "2024" publish = false [workspace] exclude = ["libtmux-source"] [dependencies] libtmux = { path = "libtmux-source/crates/libtmux", default-features = false, features = ["plan"] } tempfile = "=3.27.0" tokio = { version = "=1.53.1", features = ["macros", "rt", "time"] } [[bin]] name = "batching" path = "batching.rs" ``` Fetch the library revision used by the example: ```console $ git clone https://github.com/libtmux/libtmux-rs libtmux-source && git -C libtmux-source checkout e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4 ``` Only the [plan][plan-feature] feature is enabled. `control-mode` is unnecessary for these subprocess plans, and the program uses ordinary [`Server`]() construction rather than a testing fixture. Save the complete program as `batching.rs`: ```rust title="batching.rs" use std::error::Error; use std::time::Duration; use libtmux::plan::{NewWindow, Outcome, Plan, Planner, SendKeys}; use libtmux::{NewSessionOptions, Server}; type ExampleError = Box; fn check(condition: bool, message: &str) -> Result<(), ExampleError> { if condition { Ok(()) } else { Err(message.into()) } } async fn demonstrate(server: &Server) -> Result<(), ExampleError> { let session = server .new_session(NewSessionOptions::new("work").command("cat")) .await?; for (name, planner, expected) in [ ("sequential", Planner::Sequential, 3), ("folding", Planner::Folding, 2), ("marked", Planner::Marked, 1), ] { let mut plan = Plan::new(); let window = plan.add( NewWindow::new(session.id().clone()) .name(name) .command("cat") .focus(), ); plan.add(SendKeys::new(window.pane()).text("one").enter()); plan.add(SendKeys::new(window.pane()).text("two").enter()); plan.validate()?; let result = plan.run(server, planner).await?; if !result.is_complete() { return Err(format!("{name} did not complete: {:?}", result.operations()).into()); } check(result.dispatches() == expected, "unexpected dispatch count")?; let windows = session.windows().await?; let created = windows .iter() .find(|window| window.name().as_bytes() == name.as_bytes()) .ok_or("created window is missing")?; let panes = created.panes().await?; let pane = panes.first().ok_or("created window has no pane")?; loop { let lines = pane.capture().await?; if lines.iter().any(|line| line.as_bytes() == b"one") && lines.iter().any(|line| line.as_bytes() == b"two") { break; } tokio::time::sleep(Duration::from_millis(20)).await; } println!("{name}: {} dispatches; one, two", result.dispatches()); } // Index zero is occupied by the session's original window. let mut refused = Plan::new(); refused.add(NewWindow::new(session.id().clone()).index(0)); refused.add(NewWindow::new(session.id().clone()).name("must-not-exist")); let result = refused.run(server, Planner::Sequential).await?; check( !result.is_complete(), "tmux should refuse the occupied index", )?; check( result.operations()[0].outcome() == Outcome::Failed && result.operations()[1].outcome() == Outcome::Skipped, "the failed and skipped operations were not distinguished", )?; check( session .windows() .await? .iter() .all(|window| window.name().as_bytes() != b"must-not-exist"), "the operation after the failure ran", )?; println!("refused plan: failed, skipped"); Ok(()) } #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), ExampleError> { let root = std::path::Path::new("/tmp/libtmux-rs-dev"); std::fs::create_dir_all(root)?; let directory = tempfile::Builder::new() .prefix("docs-batching-") .tempdir_in(root)?; std::fs::write( directory.path().join("owner"), std::process::id().to_string(), )?; let server = Server::builder() .socket_path(directory.path().join("tmux.sock")) .config_file("/dev/null") .default_timeout(Duration::from_secs(5)) .build()?; let outcome = tokio::time::timeout(Duration::from_secs(10), demonstrate(&server)).await; // Stop the owned daemon before closing the client executor. let killed = server.kill().await; let closed = server.shutdown().await; let cleanup_failed = killed.is_err() || closed.is_err(); let mut failures = Vec::new(); match outcome { Ok(Ok(())) => {} Ok(Err(error)) => failures.push(format!("example failed: {error}")), Err(error) => failures.push(format!("example deadline: {error}")), } if let Err(error) = killed { failures.push(format!("daemon cleanup: {error}")); } if let Err(error) = closed { failures.push(format!("executor cleanup: {error}")); } if cleanup_failed { let retained = directory.keep(); failures.push(format!("inspect retained directory {}", retained.display())); } else if let Err(error) = directory.close() { failures.push(format!("directory cleanup: {error}")); } if failures.is_empty() { Ok(()) } else { Err(failures.join("; ").into()) } } ``` ```console $ cargo +1.97.1 run --quiet --bin batching ``` Expected output: ```text sequential: 3 dispatches; one, two folding: 2 dispatches; one, two marked: 1 dispatches; one, two refused plan: failed, skipped ``` ## References to newly created objects [`Plan::add(NewWindow::new(...))`]() returns a window slot, not a live [`Window`](). Its [`Slot::pane`](https://libtmux.org/en/rs/latest/reference/plan-slot-pane/) points to the first pane that operation will create. The later [`SendKeys`]() operations use that typed reference, so the program does not guess an ID or query tmux between recording steps. Slots belong to their creating plan and must refer to an earlier compatible operation. [`validate()`](https://libtmux.org/en/rs/latest/reference/plan-plan-validate/) checks those relationships before execution. `run()` validates them again; a rejected recording dispatches no recorded operation. Some version-sensitive preflight checks may still query metadata. ## Choose the evidence you need | Planner | Grouping | Failure evidence | | --- | --- | --- | | [`Sequential`]() | One invocation per operation | Separate status for each dispatched operation | | [`Folding`]() | Compatible neighboring operations share an invocation | One status for a combined group | | [`Marked`]() | Also combines suitable focused creation with operations using its new pane | A returned created ID proves that creation; other failed group members may remain unknown | The example focuses the new window deliberately: the marked planner can then address the pane created by that step without another process. The three, two, and one counts describe this specific three-operation plan. [`dispatches()`](https://libtmux.org/en/rs/latest/reference/plan-run-planresult/) excludes metadata and preflight probes; it is not a count of every tmux process the application starts. Setup, verification, and cleanup also issue commands. Folding preserves the intended successful work. It reduces how precisely a failed combined invocation can be attributed. Measure real workload latency before selecting it for speed, and do not report a successful plan as proof that a program inside a pane finished. This example separately waits for its expected captured lines. ## Handle refusal and partial effects [`PlanResult::is_complete()`](https://libtmux.org/en/rs/latest/reference/plan-run-planresult-is_complete/) is true only when every operation is known to have completed. A tmux refusal is returned inside [`Ok(PlanResult)`](https://libtmux.org/en/rs/latest/reference/plan-run-planresult/), so checking only the outer [`Result`]() is insufficient. [`operations()`]() retains recording order. | Outcome | What it establishes | | --- | --- | | [`Complete`]() | tmux accepted the operation | | [`Failed`]() | The individually attributable operation was refused | | [`Skipped`]() | The operation was not dispatched or did not run after an earlier failure | | `Unknown` | A failed combined invocation does not identify this member's outcome | The final two operations deliberately try an occupied window index and then create `must-not-exist`. Sequential execution identifies the first as [`Failed`]() and the second as [`Skipped`](); the program also verifies that no later window appeared. A combined failure can instead produce `Unknown` members. Do not silently treat unknown as success or infer that none of the group ran. An invalid plan, unreachable tmux, or transport failure returns [`Err`](https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err) rather than a normal refusal report. Cancellation can leave dispatched operations applied while losing the report. Inspect state before retrying; re-running a plan runs the whole recording again and is not a rollback or resume operation. ## Cleanup and other routes Each command has a five-second limit, and the workload has a ten-second deadline. The program stops its owned daemon and closes its executor even if a plan or assertion fails. A cleanup failure preserves the private directory and reports its path. Plans can also run through control mode when both features are enabled: [`run_over_control_mode(&sender)`]() sends recorded operations over that connection, or `run(&routed, planner)` uses a server returned by [`over_control_mode()`](). Blocking plan [`Pause`]() operations are refused on a control connection before recorded commands are sent. See [Control mode](https://libtmux.org/en/rs/latest/guides/control-mode/) for connection ownership and notification draining. Source contracts: [Plan](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/libtmux/src/plan.rs), [planners](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/libtmux/src/plan/planner.rs), and [execution and outcomes](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/libtmux/src/plan/run.rs) at the displayed library revision. [plan-feature]: https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/libtmux/Cargo.toml#L115 --- # Execution Source: https://libtmux.org/en/scala/latest/guides/execution/ > Execution: io.github.libtmux:libtmux-scala_3 documentation. The direct-style facade runs operations immediately. The Cats facade constructs lazy effects: creating a read or mutation effect performs no tmux I/O, and evaluating it again repeats the operation. Both delegate commands and transport behavior to Java. Choose the [direct-style server][server] for ordinary synchronous code or the [Cats server][cats-server] inside a managed effect scope. Here `config` is a Java [`ServerConfig`]() for an existing tmux server. The same read effect observes the value present at each evaluation: ```scala import _root_.cats.effect.IO import io.github.libtmux.scaladsl.cats.{config => _, *} import io.github.libtmux.scaladsl.cats.{Server => ScalaServer} ScalaServer.resource[IO](config).use { server => val name = "scala-guide-session" val read = server.hasSession(name) for { before <- read _ <- server.newSession(name) after <- read _ <- IO { assert(!before) assert(after) } } yield () } ``` Captured `info`, session windows, window panes, and client attachments are pure reads: generated as plain values in both layers, never wrapped in `F` on the Cats side, since the catalog marks them [`CAPTURED`](). A captured accessor that answers a tmux subsystem instead — [`Server.hooks`](), [`Pane.options`](), [`Server.shell`](), and the rest — is CAPTURED for the same reason, its own construction touches no tmux state, but on the Cats side it answers that subsystem's own wrapper class rather than the raw Java handle direct style still returns; the subsystem's own reads and mutations then run through `F` exactly as every other operation does. Filtering their immutable collections does not refresh them. Listing, refresh, format expansion, pane mode inspection, and mutation perform I/O. [`Pane.awaitText`]() polls captured text. ## Admission and blocking work Cats operations run through an [interruptible blocking boundary][execution], including a server or control client's own acquisition step and every subsystem operation reached through [`Server.hooks`](), [`Pane.options`](), and the rest. An owned server accepts `maxConcurrentCalls` from one through four. A borrowed server accepts a positive bound, but that bound covers only calls through that facade. Its owner must account for other users and the underlying transport's capacity. [`Pane.awaitText`]() and [`Pane.await`]() reserve one facade call for work that can release the wait (`Execution.waiting`), and require capacity of at least two. [`Pane.run`]() uses ordinary admission: its private completion channel is normally signalled by the pane's shell. This bounds admitted calls; it does not make Java I/O thread-free. Waiting operations occupy blocking workers, and process transport uses its own workers to service child processes. The limit does not bound the number of fibers a caller may queue. Use bounded effect traversal when submitting a large collection. Ordered traversal preserves result order, while concurrent tmux mutations can still reach the daemon in a different order. Prompt cancellation depends on a borrowed transport honoring interruption and completing its cleanup. Command timeouts start when Java receives the operation, after Scala admission. An effect timeout can bound admission and execution together, but cancellation still waits for the operation's cleanup. A timeout is not a promise that a dispatched mutation had no effect. ## Failures and cancellation Ordinary failures preserve Java's exception and dispatch certainty: the sealed [`LibTmuxException`]() tree matches directly from Scala (see [errors](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/docs/guide/scala.md)), and `DispatchException#safeToRetry` answers the question a caller usually has without a catalog lookup. A [`NOT_DISPATCHED`]() transport failure differs from `UNKNOWN`: the latter may have changed tmux. Raw [`Server.cmd`]() returns Java's own [`transport.CommandResult`](), so a nonzero exit remains data with its stdout and stderr. Cats cancellation interrupts local work, waits for owned cleanup, and ends in `Outcome.Canceled` whether or not the command reached tmux. Cancellation carries no error, so the facade does not turn it into one. To learn whether a canceled command was dispatched, set an [`OperationObserver`]() on the Java [`ServerConfig`](): the process transport reports `UNKNOWN` for a command it interrupted after starting. Treat a canceled mutation as possibly dispatched; the facade does not retry it, roll it back, or switch transports. A daemon-side shell job can continue after its requesting client is canceled. Closing a borrowed transport from its owner can instead produce an ordinary Java `UNKNOWN` failure. ## Control replies [`Control.acknowledge`]() reports a [protocol reply][control]. [`accepted`]() means a successful reply frame arrived; deferred tmux work can still be running. Use a separate completion signal for that work. Canceling an active control request can close its attachment and affect queued requests and observations, so use separate attachments when their lifetimes must be independent. [`Control.isAlive`]() reports whether that process is still running. [`Control.standardError`]() is the text that process wrote to its error stream, at most 4096 bytes. [`standardErrorTruncated`]() says the stream continued past that bound. [`Control.watch`]() asks tmux to push a format when its value changes, and [`unwatch`]() removes that name. A target that is not a pane or window id watches the attached session. [server]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala/src/main/scala/io/github/libtmux/scaladsl/Server.scala [cats-server]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/src/main/scala/io/github/libtmux/scaladsl/cats/Server.scala [execution]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/src/main/scala/io/github/libtmux/scaladsl/cats/Execution.scala [control]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/src/main/scala/io/github/libtmux/scaladsl/cats/Control.scala --- # Testing with libtmux Source: https://libtmux.org/en/csharp/latest/guides/testing-with-libtmux/ > Use an isolated server and check cleanup failures. [`LibTmux.Testing`]() is a separate package. [`TmuxTestFactory`]() creates a temporary hierarchy whose scope is disposed with `await using`. Use a bounded predicate wait for state assertions. The complete capture program shows ownership with [`Server.CreateOwnedAsync`]() and a cancellation token in a standalone executable. ## Run a complete example [Capture pane output](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/) includes a complete .NET executable, imports, dependency setup and cleanup. Its output check fails when the expected line does not arrive before the deadline. Start with that program when adapting the pattern to your own test runner. ## Keep server ownership explicit Give each test a private socket and a known tmux configuration. Stop the server the test creates, including when startup or an assertion fails. Preserve the original failure and report cleanup errors so a leaked server remains visible. A connection to an existing server has a different lifetime. The [attach program](https://libtmux.org/en/csharp/latest/guides/attaching-to-tmux/) leaves that server running and lets its launcher own cleanup. ## Wait for the state you assert Wait for the actual output or completion condition with a deadline. [Sending keys](https://libtmux.org/en/csharp/latest/guides/sending-keys/) returning successfully does not establish that the application finished. [Capturing output](https://libtmux.org/en/csharp/latest/guides/capturing-output/) explains the difference between a screen snapshot and a stream of output. --- # Testing with libtmux Source: https://libtmux.org/en/cxx/latest/guides/testing-with-libtmux/ > Use an isolated server and check cleanup failures. The complete capture program uses [`libtmux::test::ScopedTmuxServer`]() to own a private server and report teardown failures. It includes the public testing header and links the testing library explicitly in its CMake setup. This fixture is temporary example scaffolding. In an application, use the regular [`Server`](https://libtmux.org/en/cxx/latest/reference/libtmux-server/) connected to the server you manage. Future versions of that example will use the regular server object directly. ## Run a complete example [Capture pane output](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/) includes a complete C++ executable, imports, dependency setup and cleanup. Its output check fails when the expected line does not arrive before the deadline. Start with that program when adapting the pattern to your own test runner. ## Keep server ownership explicit Give each test a private socket and a known tmux configuration. Stop the server the test creates, including when startup or an assertion fails. Preserve the original failure and report cleanup errors so a leaked server remains visible. A connection to an existing server has a different lifetime. The [attach program](https://libtmux.org/en/cxx/latest/guides/attaching-to-tmux/) leaves that server running and lets its launcher own cleanup. ## Wait for the state you assert Wait for the actual output or completion condition with a deadline. [Sending keys](https://libtmux.org/en/cxx/latest/guides/sending-keys/) returning successfully does not establish that the application finished. [Capturing output](https://libtmux.org/en/cxx/latest/guides/capturing-output/) explains the difference between a screen snapshot and a stream of output. --- # Testing with libtmux Source: https://libtmux.org/en/go/latest/guides/testing-with-libtmux/ > Use an isolated server and check cleanup failures. [`tmuxtest.NewServer`]() gives a test its own server and cleanup. Call [`tmuxtest.Main`]() from `TestMain` before using the package's helpers. [`WaitForShellReady`]() waits for shell startup; [`WaitForLine`]() waits for a complete output line. The complete capture program shows the corresponding explicit server ownership and context deadline outside a test suite. ## Run a complete example [Capture pane output](https://libtmux.org/en/go/latest/examples/capture-pane-output/) includes a complete Go executable, imports, dependency setup and cleanup. Its output check fails when the expected line does not arrive before the deadline. Start with that program when adapting the pattern to your own test runner. ## Keep server ownership explicit Give each test a private socket and a known tmux configuration. Stop the server the test creates, including when startup or an assertion fails. Preserve the original failure and report cleanup errors so a leaked server remains visible. A connection to an existing server has a different lifetime. The [attach program](https://libtmux.org/en/go/latest/guides/attaching-to-tmux/) leaves that server running and lets its launcher own cleanup. ## Wait for the state you assert Wait for the actual output or completion condition with a deadline. [Sending keys](https://libtmux.org/en/go/latest/guides/sending-keys/) returning successfully does not establish that the application finished. [Capturing output](https://libtmux.org/en/go/latest/guides/capturing-output/) explains the difference between a screen snapshot and a stream of output. --- # Testing with libtmux Source: https://libtmux.org/en/java/latest/guides/testing-with-libtmux/ > Use an isolated server and check cleanup failures. `libtmux-junit5` supplies a [`TmuxExtension`]() and a running [`Server`]() for each test. Request a [`TmuxSocketPath`]() when the code under test accepts a path instead. For a standalone executable, the complete capture program demonstrates explicit [`ServerConfig`]() setup, output assertions and cleanup. The port's `docs` module compiles Java fences from READMEs and guides, then runs them against `libtmux-junit5` servers. A `` directive can instead require a named exception, a compile failure, or an explicit skip reason. Source: [`docs/README.md`](). A setup added by a test fixture is still needed when copying a fragment into a new project; the linked program includes all imports and its entry point. ## Run a complete example [Capture pane output](https://libtmux.org/en/java/latest/examples/capture-pane-output/) includes a complete Java executable, imports, dependency setup and cleanup. Its output check fails when the expected line does not arrive before the deadline. Start with that program when adapting the pattern to your own test runner. ## Keep server ownership explicit Give each test a private socket and a known tmux configuration. Stop the server the test creates, including when startup or an assertion fails. Preserve the original failure and report cleanup errors so a leaked server remains visible. A connection to an existing server has a different lifetime. The [attach program](https://libtmux.org/en/java/latest/guides/attaching-to-tmux/) leaves that server running and lets its launcher own cleanup. ## Wait for the state you assert Wait for the actual output or completion condition with a deadline. [Sending keys](https://libtmux.org/en/java/latest/guides/sending-keys/) returning successfully does not establish that the application finished. [Capturing output](https://libtmux.org/en/java/latest/guides/capturing-output/) explains the difference between a screen snapshot and a stream of output. --- # Testing with libtmux Source: https://libtmux.org/en/py/latest/guides/testing-with-libtmux/ > Use an isolated server and check cleanup failures. The pytest plugin supplies `server` and `session` fixtures. A session fixture also creates its server. Use [`session_params`]() for fixture setup options. For a standalone program, the complete capture example uses an explicit private socket and [`finally`]() cleanup. ## Run a complete example [Capture pane output](https://libtmux.org/en/py/latest/examples/capture-pane-output/) includes a complete Python executable, imports, dependency setup and cleanup. Its output check fails when the expected line does not arrive before the deadline. Start with that program when adapting the pattern to your own test runner. ## Keep server ownership explicit Give each test a private socket and a known tmux configuration. Stop the server the test creates, including when startup or an assertion fails. Preserve the original failure and report cleanup errors so a leaked server remains visible. A connection to an existing server has a different lifetime. The [attach program](https://libtmux.org/en/py/latest/guides/attaching-to-tmux/) leaves that server running and lets its launcher own cleanup. ## Wait for the state you assert Wait for the actual output or completion condition with a deadline. [Sending keys](https://libtmux.org/en/py/latest/guides/sending-keys/) returning successfully does not establish that the application finished. [Capturing output](https://libtmux.org/en/py/latest/guides/capturing-output/) explains the difference between a screen snapshot and a stream of output. --- # Testing with libtmux Source: https://libtmux.org/en/rs/latest/guides/testing-with-libtmux/ > Use an isolated server and check cleanup failures. The `test-support` feature exposes [`TestServer`]() and asynchronous wait helpers. [`TestServer`]() is acceptable in examples for now. Application examples will move to the regular [`Server`](https://libtmux.org/en/rs/latest/reference/server-server/) object. The complete capture program already uses [`Server::builder`]() with an explicit private socket and performs its own shutdown. ## Run a complete example [Capture pane output](https://libtmux.org/en/rs/latest/examples/capture-pane-output/) includes a complete Rust executable, imports, dependency setup and cleanup. Its output check fails when the expected line does not arrive before the deadline. Start with that program when adapting the pattern to your own test runner. ## Keep server ownership explicit Give each test a private socket and a known tmux configuration. Stop the server the test creates, including when startup or an assertion fails. Preserve the original failure and report cleanup errors so a leaked server remains visible. A connection to an existing server has a different lifetime. The [attach program](https://libtmux.org/en/rs/latest/guides/attaching-to-tmux/) leaves that server running and lets its launcher own cleanup. ## Wait for the state you assert Wait for the actual output or completion condition with a deadline. [Sending keys](https://libtmux.org/en/rs/latest/guides/sending-keys/) returning successfully does not establish that the application finished. [Capturing output](https://libtmux.org/en/rs/latest/guides/capturing-output/) explains the difference between a screen snapshot and a stream of output. --- # Testing with libtmux Source: https://libtmux.org/en/swift/latest/guides/testing-with-libtmux/ > Use an isolated server and check cleanup failures. [TmuxFixture](https://github.com/libtmux/libtmux-swift/tree/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Tests/TmuxFixture) is a separate package product. [`withTmuxServer`]() supplies a private server with a bootstrap session for the body of a test. Use a bounded wait for output assertions. The complete capture program demonstrates explicit server setup and cleanup outside a testing fixture. ## Run a complete example [Capture pane output](https://libtmux.org/en/swift/latest/examples/capture-pane-output/) includes a complete Swift executable, imports, dependency setup and cleanup. Its output check fails when the expected line does not arrive before the deadline. Start with that program when adapting the pattern to your own test runner. ## Keep server ownership explicit Give each test a private socket and a known tmux configuration. Stop the server the test creates, including when startup or an assertion fails. Preserve the original failure and report cleanup errors so a leaked server remains visible. A connection to an existing server has a different lifetime. The [attach program](https://libtmux.org/en/swift/latest/guides/attaching-to-tmux/) leaves that server running and lets its launcher own cleanup. ## Wait for the state you assert Wait for the actual output or completion condition with a deadline. [Sending keys](https://libtmux.org/en/swift/latest/guides/sending-keys/) returning successfully does not establish that the application finished. [Capturing output](https://libtmux.org/en/swift/latest/guides/capturing-output/) explains the difference between a screen snapshot and a stream of output. --- # Testing with libtmux Source: https://libtmux.org/en/ts/latest/guides/testing-with-libtmux/ > Use an isolated server and check cleanup failures. The repository's internal test harness is not a published API. For an external test, create a [`Server`]() with a private socket and register cleanup in your test framework. The complete capture program demonstrates startup checks, a bounded output wait and visible cleanup failures. ## Run a complete example [Capture pane output](https://libtmux.org/en/ts/latest/examples/capture-pane-output/) includes a complete TypeScript executable, imports, dependency setup and cleanup. Its output check fails when the expected line does not arrive before the deadline. Start with that program when adapting the pattern to your own test runner. ## Keep server ownership explicit Give each test a private socket and a known tmux configuration. Stop the server the test creates, including when startup or an assertion fails. Preserve the original failure and report cleanup errors so a leaked server remains visible. A connection to an existing server has a different lifetime. The [attach program](https://libtmux.org/en/ts/latest/guides/attaching-to-tmux/) leaves that server running and lets its launcher own cleanup. ## Wait for the state you assert Wait for the actual output or completion condition with a deadline. [Sending keys](https://libtmux.org/en/ts/latest/guides/sending-keys/) returning successfully does not establish that the application finished. [Capturing output](https://libtmux.org/en/ts/latest/guides/capturing-output/) explains the difference between a screen snapshot and a stream of output. --- # Testing with tmux Source: https://libtmux.org/en/tmux/guides/testing-with-libtmux/ > Test on a private tmux server and preserve errors during cleanup. Give each test its own tmux socket. Start it with a known configuration, assert the state your program needs, and stop only the server the test owns. This keeps a test run separate from your interactive sessions. ## Run an isolated test This complete shell test creates a session and a window, checks their names, and prints `tmux fixture passed` on success. It requires tmux 3.2a or newer and a POSIX shell. Save it as `test-tmux.sh`. ```sh title="test-tmux.sh" #!/bin/sh set -eu directory=$(mktemp -d "${TMPDIR:-/tmp}/libtmux-guide.XXXXXX") socket="$directory/tmux.sock" cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$socket" ] && ! tmux -S "$socket" kill-server; then printf 'Cannot stop tmux; kept %s\n' "$directory" >&2 exit 1 fi rm -rf "$directory" || status=$? exit "$status" } trap cleanup 0 trap 'exit 1' HUP INT TERM tmux -S "$socket" -f /dev/null new-session -d -s fixture -n main 'cat' tmux -S "$socket" new-window -t fixture: -n worker 'cat' name=$(tmux -S "$socket" display-message -p -t fixture:worker '#{session_name}') if [ "$name" != fixture ]; then printf 'Expected fixture, got %s.\n' "$name" >&2 exit 1 fi windows=$(tmux -S "$socket" list-windows -t '=fixture' -F '#{window_name}') if ! printf '%s\n' "$windows" | grep -Fqx worker; then printf '%s\n' 'The worker window was not created.' >&2 exit 1 fi printf '%s\n' 'tmux fixture passed' ``` Run the saved script: ```console $ sh test-tmux.sh ``` The trap preserves a failed assertion's exit status and also reports cleanup failures. If the server cannot be stopped, its socket directory stays available for inspection. Each invocation gets a fresh directory from `mktemp`. ## Wait for the state you assert A successful `send-keys` call establishes that tmux accepted input, not that the application finished processing it. For output assertions, use a bounded wait such as the [complete capture example](https://libtmux.org/en/tmux/examples/capture-pane-output/). A fixed pause alone cannot establish that the result arrived. ## Use a language test fixture Language ports have different fixture and lifetime APIs. Select a port from the dropdown for its testing guidance. The complete programs below demonstrate creating a private server, checking a result and cleaning up through that port: [Python](https://libtmux.org/en/py/latest/examples/capture-pane-output/) · [TypeScript](https://libtmux.org/en/ts/latest/examples/capture-pane-output/) · [Go](https://libtmux.org/en/go/latest/examples/capture-pane-output/) · [Rust](https://libtmux.org/en/rs/latest/examples/capture-pane-output/) · [Java](https://libtmux.org/en/java/latest/examples/capture-pane-output/) · [Kotlin](https://libtmux.org/en/kotlin/latest/examples/capture-pane-output/) · [Scala](https://libtmux.org/en/scala/latest/examples/capture-pane-output/) · [C#](https://libtmux.org/en/csharp/latest/examples/capture-pane-output/) · [F#](https://libtmux.org/en/fsharp/latest/examples/capture-pane-output/) · [C++](https://libtmux.org/en/cxx/latest/examples/capture-pane-output/) · [Swift](https://libtmux.org/en/swift/latest/examples/capture-pane-output/) · [Ruby](https://libtmux.org/en/ruby/latest/examples/capture-pane-output/) · [Lua](https://libtmux.org/en/lua/latest/examples/capture-pane-output/) ## Where to go next [Attaching to tmux](https://libtmux.org/en/tmux/guides/attaching-to-tmux/) connects to a server that should remain running. [Querying and filtering](https://libtmux.org/en/tmux/guides/querying-and-filtering/) selects an exact target, and [Capturing output](https://libtmux.org/en/tmux/guides/capturing-output/) reads its screen. ## tmux reference See [new-session](https://libtmux.org/en/tmux/latest/manual/new-session/), [new-window](https://libtmux.org/en/tmux/latest/manual/new-window/), and [kill-server](https://libtmux.org/en/tmux/latest/manual/kill-server/) for the commands used by the fixture. The [global options](https://libtmux.org/en/tmux/latest/manual/full/#DESCRIPTION) describe socket selection and configuration files. The [tmux manual](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1) documents these commands and their flags. --- # Execution modes Source: https://libtmux.org/en/fsharp/latest/guides/modes/ > Choose commands, control mode, or bounded concurrent reads. The F# companion forwards task-based core operations. The caller chooses the subprocess, control client, or command chain. Use one-shot core operations when one task describes the work. Use a control client when tmux must report work that nobody explicitly requested. A command chain remains an explicit core value. ## Control mode [`Control.withSession`]() opens and owns a core control client. It ends the client after its task finishes. `readUntilTerminalAsync` borrows a client, so it disposes only its event enumerator. [`Control.enter`]() returns an owned client when its lifetime must extend beyond one function, and [`Control.enterSession`]() attaches one to a chosen session; pass either to [`Control.useSession`]() to transfer ownership to a task scope. ```fsharp run open System.Threading open LibTmux open LibTmux.FSharp let readUntilTerminalAsync (cancellationToken: CancellationToken) (session: IControlModeSession) = session |> Control.events |> Control.foldWhile cancellationToken (fun events event -> task { let retained = event :: events match event with | :? TmuxEventsDroppedEvent | :? TmuxExitEvent -> return StreamStep.Stop(List.rev retained) | _ -> return StreamStep.Continue retained }) [] let observeUntilTerminalAsync cancellationToken server = server |> Control.withSession cancellationToken (readUntilTerminalAsync cancellationToken) ``` [`Control.events`]() is the client's event stream; nothing is read until a consumer enumerates it. [`Control.foldWhile`]() reads and awaits one folder call at a time. It stops before reading another event when the folder returns [`StreamStep.Stop`](). It preserves unknown event types. [`TmuxEventsDroppedEvent`]() means the caller must resynchronize from a capture; when its [`OnlyOutput`]() is true, only pane output was lost and every notification arrived. The example returns it to the caller and stops. [`TmuxExitEvent`]() is a normal terminal event. A failed control stream raises after its buffered events. [`Control.iter`]() is the same borrowed-client pattern when no accumulator is needed. It completes when the stream ends or propagates the handler, stream, and cancellation errors unchanged. When a handler and the enumerator's cleanup both fail, the handler's exception propagates and [`Control.cleanupFailure`]() returns the cleanup's. ## Command chains A chain is a core [`TmuxChain`](), which F# can build directly or through the [`Chain`]() module below. Building it makes no I/O; one `ExecuteAsync` dispatches the commands in order and returns their combined output. ```fsharp run open System.Threading open LibTmux let readChainOutputAsync (cancellationToken: CancellationToken) (server: Server) = task { // Each typed request becomes one command of the chain. let print text = DisplayMessageRequest(Format = text, ReturnText = true).ToCommand(server) let chain = server.Chain().Then(print "fsharp-chain-first").Then(print "fsharp-chain-second") let! result = chain.ExecuteAsync(cancellationToken) return result.StandardOutputLines |> Seq.toList } ``` Forty request types, such as [`SendKeysRequest`](), [`SplitPaneRequest`]() and [`CapturePaneRequest`](), convert to a command with `ToCommand`, so a chain keeps their validation; [`Then(name, arguments)`]() takes any other command as text. The [`Chain`]() module builds the same chain as a pipeline, with named steps that act on what the step before made: [`Chain.newWindow`](), [`Chain.splitLeftRight`](), [`Chain.splitTopBottom`](), [`Chain.sendLine`]() and [`Chain.arrange`](), then [`Chain.run`](); [`Chain.add`]() appends a typed request's command. The [session program](https://libtmux.org/en/fsharp/latest/guides/getting-started/#describe-a-session) uses one. Use a chain for a known batch. It returns one [`TmuxCommandResult`](), not a typed object for every step. Use one-shot operations when each step needs a refreshed entity handle. ## Bounded concurrent reads [`Task.WhenAll`]() starts all inputs. Supply a bound when the input size can grow; this helper holds at most `maximumConcurrency` pane captures at once and returns results in input order. ```fsharp run open System open System.Threading open System.Threading.Tasks open LibTmux open LibTmux.FSharp let boundedMapAsync maximumConcurrency (cancellationToken: CancellationToken) (work: CancellationToken -> 'Input -> Task<'Output>) (inputs: 'Input list) = if maximumConcurrency < 1 then invalidArg "maximumConcurrency" "Maximum concurrency must be positive." task { use gate = new SemaphoreSlim(maximumConcurrency) let run index input = task { do! gate.WaitAsync(cancellationToken) try let! output = work cancellationToken input return index, output finally gate.Release() |> ignore } let! indexed = inputs |> List.mapi run |> Task.WhenAll return indexed |> Array.sortBy fst |> Array.map snd |> Array.toList } let capturePanesBoundedAsync maximumConcurrency cancellationToken (panes: seq) = panes |> Seq.toList |> boundedMapAsync maximumConcurrency cancellationToken (fun token pane -> pane |> Pane.capture token (CapturePaneRequest())) ``` Cancellation reaches waiting and active reads. The gate is released when an operation succeeds, fails, or is canceled. --- # Send commands over control mode Source: https://libtmux.org/en/rs/latest/guides/control-mode/ > Route typed Rust calls over a persistent tmux connection, drain notifications, and close it with explicit ownership. Use [`ControlMode::attach`](https://libtmux.org/en/rs/latest/reference/control-controlmode-attach/) to open a persistent connection to an existing session. Use [`Server::over_control_mode`](https://libtmux.org/en/rs/latest/reference/server-server-over_control_mode/) to obtain a handle whose typed commands use that connection. The original server handle keeps its subprocess route. This program creates its own session, sends a line through a routed pane, checks captured output, and observes the attached client. It drains events while waiting for command results, closes the connection, verifies that tmux is still alive, and finally stops its owned daemon. ## Setup and run Use an empty directory with Git, rustup with the 1.97.1 toolchain installed, tmux 3.2a or newer, and a Unix environment. The program creates a private socket under `/tmp/libtmux-rs-dev`, starts `cat` in its panes, and stops only the server it created. No existing session, socket, or environment variable is required. Save this file as `Cargo.toml`: ```toml title="Cargo.toml" [package] name = "libtmux-control-example" version = "0.0.0" edition = "2024" publish = false [workspace] exclude = ["libtmux-source"] [dependencies] libtmux = { path = "libtmux-source/crates/libtmux", default-features = false, features = ["control-mode"] } tempfile = "=3.27.0" tokio = { version = "=1.53.1", features = ["macros", "rt", "time"] } [[bin]] name = "control" path = "control.rs" ``` Fetch the library revision used by the example: ```console $ git clone https://github.com/libtmux/libtmux-rs libtmux-source && git -C libtmux-source checkout e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4 ``` Only the `control-mode` feature is enabled. It does not require [plan][plan-feature], [`query`](), or `test-support`. Save the complete program as `control.rs`: ```rust title="control.rs" use std::error::Error; use std::time::Duration; use libtmux::control::ControlMode; use libtmux::{NewSessionOptions, Server}; type ExampleError = Box; fn check(condition: bool, message: &str) -> Result<(), ExampleError> { if condition { Ok(()) } else { Err(message.into()) } } async fn demonstrate(server: &Server) -> Result<(), ExampleError> { let host = server .new_session(NewSessionOptions::new("work").command("cat")) .await?; let control = ControlMode::attach(server, host.id()) .await? .reply_timeout(Duration::from_secs(3)); let (sender, mut events) = control.split(); let operation = async { let routed = server.over_control_mode(&sender).await?; let sessions = routed.sessions().await?; check(sessions.len() == 1, "expected one session")?; let panes = sessions[0].panes().await?; let pane = panes.first().ok_or("the session has no pane")?; pane.send_line("hello from control").await?; loop { let lines = pane.capture().await?; if lines .iter() .any(|line| line.as_bytes() == b"hello from control") { break; } tokio::time::sleep(Duration::from_millis(20)).await; } println!("captured: hello from control"); // This original handle still uses subprocesses. check( server.clients().await?.len() == 1, "control client is missing", )?; println!("attached control clients: 1"); Ok::<(), ExampleError>(()) }; // Drain notifications while commands wait for their replies. let outcome = tokio::select! { result = tokio::time::timeout(Duration::from_secs(10), operation) => { match result { Ok(result) => result, Err(error) => Err(Box::new(error) as ExampleError), } } error = async { loop { match events.next_event().await { Some(Ok(_event)) => {} Some(Err(error)) => break Box::new(error) as ExampleError, None => break "control connection closed early".into(), } } } => Err(error), }; let closed = events.shutdown().await; drop(sender); let mut failures = Vec::new(); if let Err(error) = outcome { failures.push(format!("control operation: {error}")); } if let Err(error) = closed { failures.push(format!("control cleanup: {error}")); } if !failures.is_empty() { return Err(failures.join("; ").into()); } server.check_alive().await?; check( server.clients().await?.is_empty(), "control client remained attached", )?; println!("connection closed; server still running"); Ok(()) } #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), ExampleError> { let root = std::path::Path::new("/tmp/libtmux-rs-dev"); std::fs::create_dir_all(root)?; let directory = tempfile::Builder::new() .prefix("docs-control-") .tempdir_in(root)?; std::fs::write( directory.path().join("owner"), std::process::id().to_string(), )?; let server = Server::builder() .socket_path(directory.path().join("tmux.sock")) .config_file("/dev/null") .default_timeout(Duration::from_secs(5)) .build()?; let outcome = tokio::time::timeout(Duration::from_secs(20), demonstrate(&server)).await; // Stop the owned daemon before closing the client executor. let killed = server.kill().await; let closed = server.shutdown().await; let cleanup_failed = killed.is_err() || closed.is_err(); let mut failures = Vec::new(); match outcome { Ok(Ok(())) => {} Ok(Err(error)) => failures.push(format!("example failed: {error}")), Err(error) => failures.push(format!("example deadline: {error}")), } if let Err(error) = killed { failures.push(format!("daemon cleanup: {error}")); } if let Err(error) = closed { failures.push(format!("executor cleanup: {error}")); } if cleanup_failed { let retained = directory.keep(); failures.push(format!("inspect retained directory {}", retained.display())); } else if let Err(error) = directory.close() { failures.push(format!("directory cleanup: {error}")); } if failures.is_empty() { Ok(()) } else { Err(failures.join("; ").into()) } } ``` ```console $ cargo +1.97.1 run --quiet --bin control ``` Expected output: ```text captured: hello from control attached control clients: 1 connection closed; server still running ``` ## Route the handles you use [`attach()`]() returns after the control client has attached. A successfully started child process alone would not establish that the connection is ready. The session must already exist; this program creates it through the ordinary subprocess server first. The routed [`Server`](), sessions it lists, and panes obtained from those sessions all share the connection. An older [`Session`]() or [`Pane`]() from the original server keeps its original route. Opening a control connection does not rewrite all existing handles. The routing method checks that sender and server refer to the same endpoint and can probe the tmux version during setup. ## Drain events while awaiting replies `split()` separates a command sender from an event receiver. The program uses [`tokio::select!`](https://docs.rs/tokio/1.53.1/tokio/macro.select.html) to keep polling [`next_event()`](https://libtmux.org/en/rs/latest/reference/control-controlevents-next_event/) while the command future runs. It discards ordinary notifications because its task only needs command results, but it reports a terminal event error or unexpected closure. The event queue is bounded. Leaving an event receiver alive without consuming it can stop the connection from reading tmux and prevent command progress. Dropping the event receiver is an option when no notifications are needed; retaining and draining it, as here, also gives explicit shutdown and terminal error reporting. For an observer application, handle the event variants your task needs. Pane output is byte data, not necessarily UTF-8 or complete lines. A notification stream does not by itself supply a prior screen snapshot; obtain one explicitly when needed. [`watch_only()`]() can narrow pane output, but muting can affect tmux's reading of a pane's pseudo-terminal, so it is not merely a local filter over received events. ## What a successful reply proves Typed object methods interpret the command result for their documented task. The lower-level [`ControlSender::send`](https://libtmux.org/en/rs/latest/reference/control-controlsender-send/) returns a [`BlockResult`](). A tmux `%error` block is a received result, not a transport [`Err`](https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err); inspect [`succeeded()`]() before using its output. A reply marks a command boundary, not arbitrary work completing inside a pane. The example explicitly waits for the captured line. Use the original process server for queue-blocking operations such as `wait-for` or foreground `run-shell`, and for arguments containing bytes that the UTF-8 control command protocol cannot represent. ## Timeouts and shutdown The server's five-second default bounds subprocess commands and attaching. The connected sender's three-second `reply_timeout` bounds an entire command round trip, including time spent queued or writing. The program also gives its routed operation ten seconds and its overall demonstration twenty seconds. A timeout may follow a committed command; inspect state before retrying a mutation. [`ControlEvents::shutdown`](https://libtmux.org/en/rs/latest/reference/control-controlevents-shutdown/) stops the connection, drains unread notifications for cleanup, and reports an undelivered terminal error. It succeeds while other sender handles still exist. The program records both an operation error and any shutdown error, then verifies the client detached without killing the daemon. The outer cleanup kills this program's private server and shuts down the executor. An application connected to someone else's server should close its clients and leave that daemon running. A failed cleanup here reports and retains the socket directory for inspection. See [Command transports](https://libtmux.org/en/rs/latest/concepts/transports/) for the default process route and [Batching commands](https://libtmux.org/en/rs/latest/guides/batching-commands/) for recorded plans. The pinned [control connection contract](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/libtmux/src/control.rs) and [typed routing contract](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/libtmux/src/server.rs) describe the source revision used by the program. [plan-feature]: https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/libtmux/Cargo.toml#L115 --- # Streaming Source: https://libtmux.org/en/scala/latest/guides/streaming/ > Streaming: io.github.libtmux:libtmux-scala_3 documentation. The Cats module adapts Java control subscriptions to FS2. Acquire an attachment, then an observation, then start the producer. An observation has one active stream consumer; use FS2's explicit broadcast operations if several consumers need the same values. Starting another reader on the same observation fails. ## Observe a state change Here `config` selects an existing server with a session. The subscription is registered before the rename. Evaluating the returned [`IO`]() performs the work; constructing it alone does not. ```scala import _root_.cats.effect.IO import io.github.libtmux.control.Notification import io.github.libtmux.scaladsl.cats.{config => _, *} import scala.concurrent.duration._ Server.resource[IO](config).use { server => server.sessions().flatMap { sessions => val session = sessions.head Control.attach[IO](session).use { control => control.events(8).use { observation => for { renamed <- session.rename("scala-streamed") event <- observation.stream .map(Observation.value) .unNone .map(_.notification()) .collect { case value: Notification.SessionRenamed => value } .filter(_.name() == renamed.info.name()) .take(1) .compile.lastOrError.timeout(5.seconds) drops <- observation.droppedCount _ <- IO { assert(event.session().value() == session.info.id().value()) assert(drops == 0L) } } yield () } } } } ``` [`events`]() retains Java's typed notifications and its unknown notification variant. [`output`]() yields pane-attributed [`PaneOutput`]() values. Their `data` is decoded terminal text, not exact bytes or a captured screen. A marker may span several values; retain the necessary suffix while matching it. ## Loss and state reconciliation Each subscription has a bounded queue. Overflow drops the oldest buffered value. The stream then emits a [`Delivery.Gap`]() ahead of what survived. [`Observation.value`]() drops that gap, so a pipeline that keeps only values cannot see where the loss sat. [`Observation.kept`]() fails the read instead. [`droppedCount`]() is the cumulative total. Closing a subscription discards queued values without counting them as overflow. FS2 demand does not make tmux obey backpressure, and the facade never mutes pane output to imitate it. Read the counter when completeness matters. If it increases, reacquire a snapshot before making decisions about current object state. A snapshot cannot reconstruct the dropped terminal output. The [ObserveChanges example](https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/examples/src/main/scala/io/github/libtmux/scaladsl/examples/ObserveChanges.scala) demonstrates the live view's own reconciliation over a real rename. ## Cancellation and closure The Cats stream suspends the *fiber*, not a platform thread, while idle: it polls first — nothing suspends when a step is already buffered — and only arms the subscription's one-shot readiness callback ([`onReady`]()) when nothing is, disarming it ([`clearReady`]()) if the fiber is cancelled first. No [`ExecutionContext`]() sized for blocking stream reads is needed, and no thread is parked per subscription. Canceling a reader releases its consumer slot. Releasing the observation closes its subscription and disarms any pending wakeup. Deliberate Scala observation or attachment closure ends the stream. If the control client ends the subscription, the stream fails with that cause. [`Observation.UnknownCause`]() is only the remaining case: the subscription ended, this side did not close it, and Java recorded no cause. Do not label every unexpected end as a timeout or a server crash. The direct-style module reads the same subscription through its own `Observation`, blocking in Java's [`next()`]() per read and guarding against a second, overlapping [`read`]() on the same instance with a scoped CAS — the direct-style analogue of the Cats module's stream ownership. Raw [`Control.acknowledge`]() calls use bounded, supervised admission. Their timeout begins after Scala admission. Canceling a genuinely dispatched request can close the attachment and affect queued requests and observations. Use a separate attachment when an observation must survive command cancellation. An accepted reply is an acknowledgement, not proof that deferred tmux work finished. See [execution](https://libtmux.org/en/scala/latest/guides/execution/) for completion signals and uncertainty. The [Control source][control] and [Observation source][observation] specify the resource and stream boundaries. [control]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/src/main/scala/io/github/libtmux/scaladsl/cats/Control.scala [observation]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux-scala-cats/src/main/scala/io/github/libtmux/scaladsl/cats/Observation.scala --- # Compatibility Source: https://libtmux.org/en/scala/latest/guides/compatibility/ > Compatibility: io.github.libtmux:libtmux-scala_3 documentation. The Scala facades build, test and publish with the rest of the repository, so they meet the same gates the Java library does. ## Compilers and runtimes Scala 3.9 only — there is no 2.13 build — compiled to JDK 25 bytecode. CI runs the facades' unit suites, their real-tmux suites, the documented Scala examples and the runnable programs on JDK 25 and 27 on Linux, and on macOS. Every lane of the [tmux matrix][tmux-matrix] runs the real-tmux suites against its own tmux: `3.2a`, `3.3`, `3.3a`, `3.4`, `3.5`, `3.6`, `3.7`, `3.7a`, `3.7b` and `3.7c`. The Scala fixture takes the lane's tmux the same way the Java one does. ## Artifacts - **`libtmux-scala_3`** — direct-style operations and the typed query DSL. - **`libtmux-scala-cats_3`** — Cats Effect resources and FS2 observations. - **`libtmux-scala-ox_3`** — an Ox [`Flow`]() over subscriptions and live views. Core's runtime dependencies are the Scala 3 library and `libtmux`. Cats Effect and FS2 belong to `libtmux-scala-cats`, Ox to `libtmux-scala-ox`. None depends on Jackson, JUnit, Kotlin, MCP or the workspace packages. The Scala artifacts release with the Java ones, at the same version, in the same Central deployment, signed and attested alike. `libtmux-bom` manages them too, so one BOM version selects a matching Java and Scala set. ## The generated and handwritten surface Every direct-style extension method and Cats per-operation forward that reaches tmux is generated from the operation catalog `libtmux` ships, by [`ScalaOperationGenerator`][generator] — never hand-copied per method, so it cannot drift from what Java exposes. [`WAIT`](), [`STREAM`]() and [`LIFECYCLE`]() operations are written by hand, for their cancellation or resource scoping: [`Server.open`]()/`fromJava`/[`within`]()/[`control`](), [`Pane.awaitText`]()/`run`/`await`, [`LiveView`](), [`LiveServer`](), and both modules' `Observation`. Both facades generate from the same catalog through the same owner-and-kind branching, and the [generator's tests][generator-tests] hold the two to it: a captured operation forwards purely on both, and a mutation is effect-wrapped on the Cats side only. Nothing Scala has shipped yet, so there is no earlier release for MiMa or `tasty-mima` to compare against. ## Inherited feature boundaries The facade preserves Java's version guards. [Named buffer deletion][buffers] rejects tmux before 3.4 because those versions can delete the wrong buffer. [`Shell.capturing`][java-shell] rejects tmux 3.3a and 3.4, which lose the requested output. Java's tmux matrix asserts these unsupported results rather than skip the contract or substitute an empty successful result. Capture and buffer reads retain Java's normalized text, including its handling of trailing empty lines. Observations retain decoded text chunks. These APIs do not promise arbitrary-byte round trips. Sparse hook listings preserve command order without inventing their original indices. Basic copy-mode entry, inspection, and exit are wrapped; advanced commands use explicit raw access. See [execution](https://libtmux.org/en/scala/latest/guides/execution/) for control acknowledgement limits, and [ownership](https://libtmux.org/en/scala/latest/guides/ownership/) for resource lifetimes. [generator]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/build-logic/codegen/src/main/kotlin/io/github/libtmux/codegen/scala/ScalaOperationGenerator.kt [generator-tests]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/build-logic/codegen/src/test/kotlin/io/github/libtmux/codegen/scala/ScalaOperationGeneratorTest.kt [tmux-matrix]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/build-logic/conventions/src/main/kotlin/libtmux.tmux-matrix.gradle.kts [java-options]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux/src/main/java/io/github/libtmux/Options.java [buffers]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux/src/main/java/io/github/libtmux/Buffers.java [java-shell]: https://github.com/libtmux/libtmux-java/blob/be1d62fbaa1aa634c687e1c50bceeb09ef0b8a15/libtmux/src/main/java/io/github/libtmux/Shell.java --- # Query fields Source: https://libtmux.org/en/fsharp/latest/guides/supported-query-fields/ > Browse the fields supported by typed filters. [`LibTmux.FSharp.Filter`]() creates version-one [`QueryDocument`]() values. These are the descriptors it exposes. [`Query.matching`]() is local and materialized; it does not send a native tmux filter. The fields below are checked against documents generated by the F# descriptors and the optional `LibTmux.Query.Json` serializer. Parent links, layouts, active flags and placement data remain native captured-object properties. They have no portable descriptor. ## Sessions ### `SessionFields.name` - Core property: [`Session.Name`]() - Wire name: `session_name` - Value type: [`string`]() - Operators: [`eq`](), [`ne`](), [`eqIgnoreCase`](), [`isNull`](), [`startsWith`](), [`startsWithIgnoreCase`](), [`endsWith`](), [`endsWithIgnoreCase`](), [`contains`](), [`containsIgnoreCase`](), [`matches`](), [`matchesIgnoreCase`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Sessions`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-sessions/) - Schema version: `1` ### `SessionFields.id` - Core property: [`Session.Id`]() - Wire name: `session_id` - Value type: [`SessionId`]() - Operators: [`eq`](), [`ne`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Sessions`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-sessions/) - Schema version: `1` ### `SessionFields.attached` - Core property: [`Session.Attached`]() - Wire name: `session_attached` - Value type: [`bool`]() - Operators: [`eq`](), [`ne`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Sessions`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-sessions/) - Schema version: `1` ### `SessionFields.windowCount` - Core property: [`Session.Windows`]() - Wire name: `session_windows` - Value type: [`int`]() - Operators: [`eq`](), [`ne`](), [`lt`](), [`le`](), [`gt`](), [`ge`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Windows`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-windows/) - Schema version: `1` ### `SessionFields.windows` - Core property: [`Session.Windows`]() - Wire name: `session_windows` - Value type: `Relation` - Operators: [`any`](), [`all`](), [`none`]() - Required depth: [`Windows`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-windows/) - Schema version: `1` ## Windows ### `WindowFields.name` - Core property: [`Window.Name`]() - Wire name: `window_name` - Value type: [`string`]() - Operators: [`eq`](), [`ne`](), [`eqIgnoreCase`](), [`isNull`](), [`startsWith`](), [`startsWithIgnoreCase`](), [`endsWith`](), [`endsWithIgnoreCase`](), [`contains`](), [`containsIgnoreCase`](), [`matches`](), [`matchesIgnoreCase`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Windows`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-windows/) - Schema version: `1` ### `WindowFields.id` - Core property: [`Window.Id`]() - Wire name: `window_id` - Value type: [`WindowId`]() - Operators: [`eq`](), [`ne`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Windows`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-windows/) - Schema version: `1` ### `WindowFields.index` - Core property: [`Window.Index`]() - Wire name: `window_index` - Value type: [`int`]() - Operators: [`eq`](), [`ne`](), [`lt`](), [`le`](), [`gt`](), [`ge`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Windows`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-windows/) - Schema version: `1` ### `WindowFields.width` - Core property: [`Window.Width`]() - Wire name: `window_width` - Value type: [`int`]() - Operators: [`eq`](), [`ne`](), [`lt`](), [`le`](), [`gt`](), [`ge`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Windows`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-windows/) - Schema version: `1` ### `WindowFields.height` - Core property: [`Window.Height`]() - Wire name: `window_height` - Value type: [`int`]() - Operators: [`eq`](), [`ne`](), [`lt`](), [`le`](), [`gt`](), [`ge`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Windows`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-windows/) - Schema version: `1` ### `WindowFields.paneCount` - Core property: [`Window.Panes`]() - Wire name: `window_panes` - Value type: [`int`]() - Operators: [`eq`](), [`ne`](), [`lt`](), [`le`](), [`gt`](), [`ge`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `WindowFields.panes` - Core property: [`Window.Panes`]() - Wire name: `window_panes` - Value type: `Relation` - Operators: [`any`](), [`all`](), [`none`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ## Panes ### `PaneFields.currentCommand` - Core property: [`Pane.CurrentCommand`]() - Wire name: `pane_command` - Value type: [`string`]() - Operators: [`eq`](), [`ne`](), [`eqIgnoreCase`](), [`isNull`](), [`startsWith`](), [`startsWithIgnoreCase`](), [`endsWith`](), [`endsWithIgnoreCase`](), [`contains`](), [`containsIgnoreCase`](), [`matches`](), [`matchesIgnoreCase`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.id` - Core property: [`Pane.Id`]() - Wire name: `pane_id` - Value type: [`PaneId`]() - Operators: [`eq`](), [`ne`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.index` - Core property: [`Pane.Index`]() - Wire name: `pane_index` - Value type: [`int`]() - Operators: [`eq`](), [`ne`](), [`lt`](), [`le`](), [`gt`](), [`ge`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.title` - Core property: [`Pane.Title`]() - Wire name: `pane_title` - Value type: [`string`]() - Operators: [`eq`](), [`ne`](), [`eqIgnoreCase`](), [`isNull`](), [`startsWith`](), [`startsWithIgnoreCase`](), [`endsWith`](), [`endsWithIgnoreCase`](), [`contains`](), [`containsIgnoreCase`](), [`matches`](), [`matchesIgnoreCase`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.currentPath` - Core property: [`Pane.CurrentPath`]() - Wire name: `pane_current_path` - Value type: [`string`]() - Operators: [`eq`](), [`ne`](), [`eqIgnoreCase`](), [`isNull`](), [`startsWith`](), [`startsWithIgnoreCase`](), [`endsWith`](), [`endsWithIgnoreCase`](), [`contains`](), [`containsIgnoreCase`](), [`matches`](), [`matchesIgnoreCase`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.width` - Core property: [`Pane.Width`]() - Wire name: `pane_width` - Value type: [`int`]() - Operators: [`eq`](), [`ne`](), [`lt`](), [`le`](), [`gt`](), [`ge`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.height` - Core property: [`Pane.Height`]() - Wire name: `pane_height` - Value type: [`int`]() - Operators: [`eq`](), [`ne`](), [`lt`](), [`le`](), [`gt`](), [`ge`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.left` - Core property: [`Pane.Left`]() - Wire name: `pane_left` - Value type: [`int`]() - Operators: [`eq`](), [`ne`](), [`lt`](), [`le`](), [`gt`](), [`ge`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.top` - Core property: [`Pane.Top`]() - Wire name: `pane_top` - Value type: [`int`]() - Operators: [`eq`](), [`ne`](), [`lt`](), [`le`](), [`gt`](), [`ge`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.atTop` - Core property: [`Pane.AtTop`]() - Wire name: `pane_at_top` - Value type: [`bool`]() - Operators: [`eq`](), [`ne`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.atBottom` - Core property: [`Pane.AtBottom`]() - Wire name: `pane_at_bottom` - Value type: [`bool`]() - Operators: [`eq`](), [`ne`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.atLeft` - Core property: [`Pane.AtLeft`]() - Wire name: `pane_at_left` - Value type: [`bool`]() - Operators: [`eq`](), [`ne`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ### `PaneFields.atRight` - Core property: [`Pane.AtRight`]() - Wire name: `pane_at_right` - Value type: [`bool`]() - Operators: [`eq`](), [`ne`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Panes`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-panes/) - Schema version: `1` ## Clients ### `ClientFields.name` - Core property: [`Client.Name`]() - Wire name: `client_name` - Value type: [`string`]() - Operators: [`eq`](), [`ne`](), [`eqIgnoreCase`](), [`isNull`](), [`startsWith`](), [`startsWithIgnoreCase`](), [`endsWith`](), [`endsWithIgnoreCase`](), [`contains`](), [`containsIgnoreCase`](), [`matches`](), [`matchesIgnoreCase`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Sessions`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-sessions/) - Schema version: `1` ### `ClientFields.controlMode` - Core property: [`Client.IsControlClient`]() - Wire name: `client_control_mode` - Value type: [`bool`]() - Operators: [`eq`](), [`ne`](), [`oneOf`](), [`notOneOf`]() - Required depth: [`Sessions`](https://libtmux.org/en/csharp/latest/reference/libtmux-snapshotdepth-sessions/) - Schema version: `1` ## Limits The core wire catalog also reserves `client_id`. The core client model has no typed client ID, so the F# façade does not invent one. `session_windows` and `window_panes` appear as typed relations; the façade does not expose a count descriptor because its controlled translator input is the captured relation. `allOf []` matches everything, and `anyOf []`, `oneOf []` match nothing; `notOneOf []` matches everything. Each is a Boolean constant predicate, which serializes and travels like any other document. --- # Connect a Ruby MCP client Source: https://libtmux.org/en/ruby/latest/mcp/guides/connect-client/ > Launch a pinned Ruby MCP server on its own private tmux socket, inspect the default tools, and close it with the client. Let your MCP client launch the Ruby server on a private tmux socket. The launcher below creates one `mcp-example` session, offers capability discovery and metadata snapshots, and stops its owned tmux daemon when the client closes the connection. ## Prepare the project Use Ruby 4.0.7 with its development headers, Bundler, Git, a C compiler and Make, and tmux 3.2a or newer on a Unix host. The bundle includes native extensions such as `io-event`, `json`, and `fiddle`. This recipe uses the source revision whose MCP contract is documented here; it does not assume that a newer checkout and an installed prerelease have identical APIs. Create an empty directory: ```console $ mkdir ruby-mcp-client && cd ruby-mcp-client ``` Fetch the source: ```console $ git clone https://github.com/libtmux/libtmux-ruby libtmux-source ``` Select the documented revision: ```console $ git -C libtmux-source checkout 9b1545562a112353c2c893a1d3e8c0d9b4b51f8d ``` Install the dependencies from its lockfile: ```console $ BUNDLE_FROZEN=true BUNDLE_GEMFILE=./libtmux-source/Gemfile bundle install ``` This installs the source checkout's core and MCP gems together. Keep the checkout beside the launcher so the client's working directory does not affect which gems it loads. ## Save the launcher Save this complete program as `run-mcp.rb` in the project directory: ```ruby title="run-mcp.rb" # frozen_string_literal: true ENV["BUNDLE_GEMFILE"] = File.expand_path("libtmux-source/Gemfile", __dir__) require "bundler/setup" require "libtmux/mcp/cli" def describe_failure(error) details = ["#{error.class}: #{error.message}"] if error.is_a?(LibTmux::Error) details.concat(error.cleanup_errors.map { |message| "Cleanup: #{message}" }) end details.join("\n") end server = nil failures = [] begin server = LibTmux::Server.start(timeout: 5.0) server.new_session(name: "mcp-example", command: ["/bin/cat"], timeout: 5.0) status = LibTmux::MCP::CLI.run([ "--socket", server.endpoint.socket_path, "--endpoint", "docs", "--timeout", "5" ]) failures << "MCP stopped with status #{status}" unless status.zero? rescue StandardError => error failures << describe_failure(error) ensure begin server&.close rescue StandardError => error failures << "Cleanup failed: #{describe_failure(error)}" end end abort failures.join("\n") unless failures.empty? ``` `Server.start` owns a new socket directory and foreground daemon with an empty tmux configuration. It starts no session by itself; `new_session` creates the example's pane running `cat`. Closing this owned server stops its daemon. The MCP command borrows that endpoint and closes its own clients when stdin ends. The outer launcher then closes the daemon it created. The five-second startup deadline, five-second session-creation deadline, and five-second MCP request deadline govern separate operations. The server keeps serving while the client remains connected. Diagnostics go to stderr; stdout contains MCP messages only. Operation and cleanup failures are both reported. Run it directly to check startup: ```console $ ruby -W:no-experimental run-mcp.rb ``` It waits for a client. Send EOF to close it. The Ruby option suppresses the runtime's experimental [`IO::Buffer`](https://docs.ruby-lang.org/en/4.0/IO/Buffer.html) warning; it does not suppress exceptions. ## Configure a client For a client that accepts an `mcpServers` configuration, generate the entry using this project's absolute launcher path and the current Ruby executable: ```console $ ruby -rjson -rrbconfig -e ' puts JSON.pretty_generate( "mcpServers" => { "tmux-ruby" => { "command" => RbConfig.ruby, "args" => ["-W:no-experimental", File.expand_path("run-mcp.rb")] } } ) ' ``` Add that entry to the client's existing configuration and reconnect. Other clients ask for a command and argument list separately; use the same values. The client needs tmux available on its process `PATH`. If its environment cannot find the intended executable, give the launcher an absolute `executable:` argument in `Server.start` and pass that same path with the MCP CLI's `--tmux` option. ## Verify the connection List the tools. The default catalog contains exactly `tmux_capabilities` and `tmux_snapshot`. Capture, wait, create, send, close, and authored-run tools are absent until explicitly enabled. Call `tmux_capabilities` with an empty argument object. Its successful `structuredContent` has `ok: true`; `data.endpoint` is `docs`. That alias labels discovery and resource URIs. The `--socket` argument selects the actual daemon. Call `tmux_snapshot` with this argument object: ```json {"entity": "session"} ``` The successful result has one item in [`structuredContent.data.items`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_snapshot/). Its `fields.name` is `mcp-example`, and its `ref` includes the session identity and server generation. Check `ok` before reading successful data; a JSON-RPC response alone does not establish that the tool succeeded. Close the MCP connection. The launcher exits, stops its private daemon, and removes its owned socket directory. Reconnecting runs the launcher again and creates a fresh session, so do not reuse references from the previous server. ## Connect to a server your application owns When the application already owns a tmux daemon, use the installed `libtmux-mcp` executable with one explicit `--socket PATH` or `--socket-name NAME` selector. It borrows the daemon: EOF closes the MCP clients without stopping that daemon. The application's lifecycle remains responsible for it. [Tool reference](https://libtmux.org/en/ruby/latest/mcp/tools/) describes the argument and result schemas. [Source-owned MCP guide](https://libtmux.org/en/ruby/latest/mcp/source-guide/) explains policy, observation and shell enrollment. The pinned [CLI implementation](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/cli.rb) and [owned-server implementation](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux/lib/libtmux/owned.rb) define these lifecycle boundaries. --- # Connect an MCP client Source: https://libtmux.org/en/csharp/latest/mcp/guides/connect-client/ > Install the .NET tool, select its tmux endpoint, and verify discovery and ownership. Configure your MCP client to launch `libtmux-mcp`. The executable selects one tmux socket and its tools at startup, then serves MCP over stdin and stdout. Use Linux, macOS, or WSL with tmux 3.2a or newer and a compatible .NET runtime. The examples here use the [published package](https://www.nuget.org/packages/LibTmux.Mcp/0.0.0-alpha.20) and its [source contract](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/README.md). ## Install the tool Install the pinned alpha release with the .NET SDK: ```console $ dotnet tool install \ --global \ --version 0.0.0-alpha.20 \ LibTmux.Mcp ``` The package targets .NET 8 and .NET 10. It installs the `libtmux-mcp` executable; `dotnet add package` is not the installation method for this tool. The client's launch environment must include the .NET tools directory on `PATH`, normally [`$HOME/.dotnet/tools`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-tool-install#global-tools) on a POSIX host. For a project-local installation and a complete C# client, use [List sessions through MCP](https://libtmux.org/en/csharp/latest/mcp/examples/inspect-sessions/). ## Connect to an existing server This client configuration selects the existing socket named `docs-agent` and enables inspection tools: ```json { "mcpServers": { "tmux": { "command": "libtmux-mcp", "env": { "LIBTMUX_SOCKET": "docs-agent", "LIBTMUX_TOOLSETS": "inspect" } } } } ``` Use the name of the server you intend to inspect. A socket name corresponds to tmux's `-L` option. `LIBTMUX_SOCKET_PATH` instead selects one absolute socket path, corresponding to `-S`. Set only one of these variables. The selection is not taken from an inherited `TMUX` value. `TMUX_PANE` can identify the calling pane when the client runs inside the selected server; discovery and mutation tools use that context to avoid inappropriate input to the caller. Explicitly selecting a socket still requires checking that it is the server you intend to control. Ask the connected client to list tools, read `tmux://capabilities`, and call [`list_sessions`](https://libtmux.org/en/csharp/latest/mcp/tools/list_sessions/). Check the reported socket and session names before sending input. The capability resource records the startup selection; use [`get_server_info`](https://libtmux.org/en/csharp/latest/mcp/tools/get_server_info/) and the hierarchy tools for current state. ## Use the dedicated server Omit both socket variables to select the dedicated `libtmux-mcp` socket. When that endpoint is absent, the launcher can create it using its bundled minimal tmux configuration. A newly created dedicated endpoint defaults to all four toolsets. Select `inspect` explicitly when that is all the client needs. An existing or explicitly selected endpoint defaults to `inspect`, `manage`, and `execute`; teardown requires an explicit selection. An explicit `LIBTMUX_TMUX_CONFIG` must be an absolute, nonempty path. Using your own configuration also affects the launcher's ownership classification and default tool selection. Read the capability report instead of inferring ownership from the socket's name. On shutdown, the MCP process stops only a dedicated daemon whose launch marker still matches that process. It leaves borrowed and replaced daemons running. Closing an MCP client does not promise to stop work already running in a borrowed pane. ## Diagnose startup Read stderr in the client's server log. Keep stdout exclusively for protocol messages; a shell startup message on stdout can break the connection. - If `libtmux-mcp` is not found, check the client's `PATH` or configure the installed executable's absolute path. - If the tool cannot locate .NET, set `DOTNET_ROOT` to the runtime installation used by that client. Desktop launchers may not inherit a version manager's shell setup. - Use `LIBTMUX_TMUX` to select a particular tmux executable. It is resolved when the MCP server starts. - Set either `LIBTMUX_SOCKET` or `LIBTMUX_SOCKET_PATH`, and use an absolute path for the latter. The executable takes no positional socket argument. - Check toolset and tool names against [Tool selection](https://libtmux.org/en/csharp/latest/mcp/topics/tool-selection/). Unknown names and malformed comma-separated lists stop startup. - Remove `LIBTMUX_SAFETY` if it is present. This release rejects the retired variable instead of treating it as an additional policy. Restart the MCP connection after changing its environment. Changing a terminal's environment does not reconfigure a server process already running inside another client. The [startup implementation](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/McpStartup.cs) defines socket selection and ownership. The [tool-selection implementation](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilitySelection.cs) defines registration and filter precedence. --- # Connect an MCP client Source: https://libtmux.org/en/go/latest/mcp/guides/connect-client/ > Install libtmux-mcp, choose its tmux server, and diagnose startup and shutdown. An MCP client starts `libtmux-mcp` and exchanges protocol messages over stdin and stdout. The executable selects one tmux server at startup. Its diagnostics go to stderr, which the client should retain in its server log. ## Install the command Use Go 1.26 or newer and tmux 3.2a or newer on Linux, macOS, or WSL. Install the [published MCP module](https://github.com/libtmux/libtmux-go/tree/6e7420927f4cb717fe089a710328e44e8d551025/mcp): ```console $ go install \ github.com/libtmux/libtmux-go/mcp/cmd/libtmux-mcp@v0.0.1-alpha.12 ``` Make the Go installation directory available in the MCP client's `PATH`, or set its command to the installed executable's absolute path. `GOBIN` selects the installation directory; when unset, Go uses `bin` under its `GOPATH`. Check the executable the client will launch: ```console $ libtmux-mcp -version ``` The installed release reports `libtmux-mcp v0.0.1-alpha.12`. The [complete SDK example](https://libtmux.org/en/go/latest/mcp/examples/inspect-sessions/) installs this same release into a local `.tools` directory and supplies the client code. ## Choose a server Without a socket selector, the launcher uses a dedicated socket named `libtmux-mcp` and a minimal tmux configuration. This is separate from tmux's ordinary default socket. A client using an `mcpServers` configuration can launch an inspection-only instance with: ```json title="mcp.json" { "mcpServers": { "tmux-go": { "command": "libtmux-mcp", "args": [], "env": { "LIBTMUX_TOOLSETS": "inspect" } } } } ``` For an existing named server, set `args` to `["-socket-name", "docs-agent"]`. Here, `docs-agent` must be the socket name you chose when starting that server. For an absolute socket path, use `-socket-path` instead. The executable also accepts `LIBTMUX_SOCKET` for a name and `LIBTMUX_SOCKET_PATH` for an absolute path. Select one endpoint; conflicting selectors fail startup. Use `-binary` or `LIBTMUX_TMUX_BIN` to select the tmux executable. If you set `LIBTMUX_TMUX_CONFIG`, supply a nonempty absolute configuration path. Reconnect after changing the socket, executable, configuration, or tool selection. ## Inspect the selection Report the tools selected by the same executable and environment: ```console $ LIBTMUX_TOOLSETS=inspect libtmux-mcp -tools ``` This command probes the selected socket without starting a tmux server. The result describes the tools a server started now would advertise; its defaults depend on whether that socket already has a server. Read `tmux://capabilities` through a connected client to inspect its frozen endpoint and tool selection. The [tool-selection topic](https://libtmux.org/en/go/latest/mcp/topics/tool-selection/) explains how to add individual tools and how exclusions affect batch operations. ## Diagnose startup Run the doctor's check against the dedicated socket: ```console $ libtmux-mcp -doctor -socket-name libtmux-mcp ``` The report describes the endpoint, tmux version, topology, and caller context. Use the same socket and binary options as the client's configuration. A shell and an MCP client may have different `PATH`, locale, and socket variables. If the client cannot start the executable, check its command path first. If the process starts and exits before connecting, inspect stderr for an old tmux binary, conflicting socket settings, invalid configuration paths, unknown tools, or malformed lists. An explicitly empty toolset selects no tools; `none` is not a toolset name. Keep stdout reserved for MCP messages. A process waiting silently on stdin can be healthy. On client shutdown, a `terminated signal received` diagnostic can reflect the client's ordinary termination of its subprocess. ## Shutdown and ownership Closing the MCP transport ends its client connection. Do not use client shutdown as proof that an application command stopped or an existing tmux server was destroyed. The complete examples create and stop their own daemon, with [separate cleanup deadlines](https://libtmux.org/en/go/latest/mcp/examples/inspect-sessions/#shutdown). The [launcher source](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/cmd/libtmux-mcp/main.go) handles configuration and startup. The [instance lifecycle](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/instance_lifecycle.go) closes client sessions and their scoped work. --- # Connect an MCP client Source: https://libtmux.org/en/rs/latest/mcp/guides/connect-client/ > Install the Rust MCP server, choose its tmux socket, and inspect the tools your client can call. `tmux-mcp` connects an MCP client to one tmux server. The client launches the executable and exchanges JSON-RPC messages over stdin and stdout. The launcher writes diagnostics to stderr. Use Rust 1.88 or newer, Git, and tmux 3.2a or newer on Linux or macOS. The command below uses the tested Rust 1.97.1 toolchain and installs the source revision used by this documentation's MCP reference. Cargo's binary directory must be on the path available to your MCP client. ## Install and connect ```console $ cargo +1.97.1 install \ --git https://github.com/libtmux/libtmux-rs \ --rev a6fc2a65674177b92b17fa380757155d2ba150fd \ --locked \ tmux-mcp ``` Check that the installed command runs: ```console $ tmux-mcp --version ``` Expected output: ```text tmux-mcp 0.1.0-alpha.16 ``` For a client that accepts `mcpServers`, add this entry to its configuration: ```json { "mcpServers": { "tmux-rust": { "command": "tmux-mcp", "env": { "LIBTMUX_TOOLSETS": "inspect" } } } } ``` Restart the connection after changing its environment. The server chooses its socket and tools once at startup. Running `tmux-mcp` in a terminal waits for protocol input; it does not open an interactive tmux client. This configuration offers inspection tools. They read metadata and terminal output, and include bounded observation through [`wait_for_text`](https://libtmux.org/en/rs/latest/mcp/tools/wait_for_text/). They do not send pane input or create sessions. See [Tool selection](https://libtmux.org/en/rs/latest/mcp/topics/tool-selection/) to add those operations deliberately. ## Check the connection Ask your client to list the available tools, then read `tmux://capabilities`. Its connection fields identify the resolved socket, whether a daemon already existed, and what the launcher knows about its configuration. Its effective tool list should match discovery. Call [`list_sessions`](https://libtmux.org/en/rs/latest/mcp/tools/list_sessions/) with this MCP `tools/call` params object: ```json { "name": "list_sessions", "arguments": {} } ``` Use the returned IDs for subsequent calls. An empty list is normal on a new daemon: connecting the MCP client does not create a session. Without a socket selector, the launcher uses the dedicated `libtmux-mcp` socket. If `LIBTMUX_TMUX_CONFIG` is also unset, it starts a missing daemon with its shipped minimal configuration. An existing daemon keeps its configuration. An explicit configuration disables this automatic startup. The launcher does not choose the socket from `TMUX`. ## Connect to an existing server To work with a named tmux server, use the same name in the client entry: ```json { "mcpServers": { "tmux-rust": { "command": "tmux-mcp", "args": ["--socket-name", "work"], "env": { "LIBTMUX_TOOLSETS": "inspect" } } } } ``` The `work` daemon must already exist for inspection calls to succeed. Selecting an absent explicit socket does not start a daemon during connection. Read the startup connection report and distinguish that case from an existing daemon with no sessions. Use `--socket` with an absolute socket path instead when the server was started with `tmux -S`. Do not combine the two socket flags. `LIBTMUX_SOCKET` and `LIBTMUX_SOCKET_PATH` supply the corresponding environment settings; an explicit command-line selector takes precedence. Socket selection limits which tmux objects the process can address. Commands sent to panes still run with the tmux user's filesystem, network, and process access. Tool selection describes the callable interface, not an operating-system permission boundary. ## Stop the connection Closing the client's protocol input ends the MCP process. It leaves an explicitly selected daemon running. For the default dedicated daemon, the process that created it stops it only when no other MCP process still holds a connection lease. If the creating process exits while another connection remains, it leaves the daemon running. The remaining process did not create that daemon, so its later exit does not stop it either. Inspect the selected socket before stopping a daemon manually. ## Diagnose startup failures Read the client's server log for stderr. An unknown tool name, malformed selection, conflicting socket settings, or an empty or relative `LIBTMUX_TMUX_CONFIG` value stops startup. Correct the setting before reconnecting. If the executable cannot be found, configure the client with the installed binary's absolute path. If a tool is missing, compare discovery with `tmux://capabilities` and the [selection rules](https://libtmux.org/en/rs/latest/mcp/topics/tool-selection/). For a missing session or pane, list the objects again before choosing another target. [Launcher source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/bin/tmux-mcp.rs) defines socket selection and shutdown. --- # Install and load a workspace Source: https://libtmux.org/en/csharp/latest/workspace/guides/installation/ > Build the workspace command and load a session on a private tmux socket. Build the documented `tmux-workspace` revision, then load a small session on a private socket. Use a Unix shell with tmux 3.2a or newer on `PATH`. ## Build the command Fetch the documented source revision, then build from its repository root. Keep the exported `PATH` in this shell for the rest of the walkthrough. ```console $ git clone --filter=blob:none https://github.com/libtmux/libtmux-dotnet.git ``` ```console $ cd libtmux-dotnet ``` ```console $ git fetch --depth=1 origin f77fe776ba67a04abb20ddbbc26cf4a000d63b74 ``` ```console $ git checkout --detach FETCH_HEAD ``` Use the .NET 10 SDK to build the command: ```console $ dotnet build src/LibTmux.Workspace.Cli/LibTmux.Workspace.Cli.csproj --configuration Release ``` ```console $ WORKSPACE_BIN="$(mktemp -d)" ``` ```console $ ln -s "$PWD/src/LibTmux.Workspace.Cli/bin/Release/net10.0/LibTmux.Workspace.Cli" "$WORKSPACE_BIN/tmux-workspace" ``` ```console $ export PATH="$WORKSPACE_BIN:$PATH" ``` Keep the build directory and the matching .NET runtime available when using this launcher. ```console $ tmux-workspace --help ``` ## Create the input Keep this shell open. Create a temporary working directory on a filesystem that supports Unix sockets, then enter it: ```console $ WORKSPACE_TMP="$(mktemp -d)" ``` ```console $ cd "$WORKSPACE_TMP" ``` Save this as `workspace.yaml`: ```yaml title="workspace.yaml" session_name: workspace-guide windows: - window_name: editor layout: even-horizontal panes: [null, null] ``` ## Load and inspect ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-d` leaves the session detached. Inspect its panes using the same socket: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-guide:editor' ``` Attach interactively with `tmux -S "$WORKSPACE_TMP/tmux.sock" attach-session -t '=workspace-guide'`. Detach with your tmux detach binding before continuing. ## Capture and clean up ```console $ tmux-workspace freeze -S "$WORKSPACE_TMP/tmux.sock" --json workspace-guide ``` Try [export and reload](https://libtmux.org/en/csharp/latest/workspace/guides/export-session/) before cleanup. Capture cannot recover original scripts, command history or application state. Remove only the session created by this walkthrough when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-guide' ``` The configuration remains in the temporary directory. Keep the session running when following guides that continue this example. ## Continue [Configuration](https://libtmux.org/en/csharp/latest/workspace/configuration/) describes execution fields; [discovery](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/) finds saved files. Read the [load reference](https://libtmux.org/en/csharp/latest/workspace/cli/load/) and [automation](https://libtmux.org/en/csharp/latest/workspace/guides/automation/) for attachment, output and failure handling. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Install and load a workspace Source: https://libtmux.org/en/cxx/latest/workspace/guides/installation/ > Build the workspace command and load a session on a private tmux socket. Build the documented `tmux-workspace` revision, then load a small session on a private socket. Use a Unix shell with tmux 3.2a or newer on `PATH`. ## Build the command Fetch the documented source revision, then build from its repository root. Keep the exported `PATH` in this shell for the rest of the walkthrough. ```console $ git clone --filter=blob:none https://github.com/libtmux/libtmux-cxx.git ``` ```console $ cd libtmux-cxx ``` ```console $ git fetch --depth=1 origin 9c8c6a264114277df84c9f6819855093adae5c6e ``` ```console $ git checkout --detach FETCH_HEAD ``` Use the compiler and CMake requirements in the repository's `cxx-dev` preset: ```console $ cmake --preset cxx-dev \ -DLIBTMUX_BUILD_TESTS=OFF \ -DLIBTMUX_BUILD_EXAMPLES=OFF \ -DLIBTMUX_BUILD_MCP_SERVER=OFF ``` ```console $ cmake --build --preset cxx-dev --target tmux-workspace -j2 ``` ```console $ export PATH="$PWD/build/cxx-dev/apps/workspace:$PATH" ``` ```console $ tmux-workspace --help ``` ## Create the input Keep this shell open. Create a temporary working directory on a filesystem that supports Unix sockets, then enter it: ```console $ WORKSPACE_TMP="$(mktemp -d)" ``` ```console $ cd "$WORKSPACE_TMP" ``` Save this as `workspace.yaml`: ```yaml title="workspace.yaml" session_name: workspace-guide windows: - window_name: editor layout: even-horizontal panes: [null, null] ``` ## Load and inspect ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-d` leaves the session detached. Inspect its panes using the same socket: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-guide:editor' ``` Attach interactively with `tmux -S "$WORKSPACE_TMP/tmux.sock" attach-session -t '=workspace-guide'`. Detach with your tmux detach binding before continuing. ## Capture and clean up ```console $ tmux-workspace freeze -S "$WORKSPACE_TMP/tmux.sock" --json workspace-guide ``` Try [export and reload](https://libtmux.org/en/cxx/latest/workspace/guides/export-session/) before cleanup. Capture cannot recover original scripts, command history or application state. Remove only the session created by this walkthrough when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-guide' ``` The configuration remains in the temporary directory. Keep the session running when following guides that continue this example. ## Continue [Configuration](https://libtmux.org/en/cxx/latest/workspace/configuration/) describes execution fields; [discovery](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/) finds saved files. Read the [load reference](https://libtmux.org/en/cxx/latest/workspace/cli/load/) and [automation](https://libtmux.org/en/cxx/latest/workspace/guides/automation/) for attachment, output and failure handling. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Install and load a workspace Source: https://libtmux.org/en/go/latest/workspace/guides/installation/ > Build the workspace command and load a session on a private tmux socket. Build the documented `tmux-workspace` revision, then load a small session on a private socket. Use a Unix shell with tmux 3.2a or newer on `PATH`. ## Build the command Fetch the documented source revision, then build from its repository root. Keep the exported `PATH` in this shell for the rest of the walkthrough. ```console $ git clone --filter=blob:none https://github.com/libtmux/libtmux-go.git ``` ```console $ cd libtmux-go ``` ```console $ git fetch --depth=1 origin bb06e26e116e941813ca40bf45e7e3a47d38f52a ``` ```console $ git checkout --detach FETCH_HEAD ``` Use Go 1.26 or newer. Building from the repository root selects its workspace modules: ```console $ go build -o tmux-workspace ./workspace/cmd/tmux-workspace ``` ```console $ export PATH="$PWD:$PATH" ``` ```console $ tmux-workspace --help ``` ## Create the input Keep this shell open. Create a temporary working directory on a filesystem that supports Unix sockets, then enter it: ```console $ WORKSPACE_TMP="$(mktemp -d)" ``` ```console $ cd "$WORKSPACE_TMP" ``` Save this as `workspace.yaml`: ```yaml title="workspace.yaml" session_name: workspace-guide windows: - window_name: editor layout: even-horizontal panes: [null, null] ``` ## Load and inspect ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-d` leaves the session detached. Inspect its panes using the same socket: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-guide:editor' ``` Attach interactively with `tmux -S "$WORKSPACE_TMP/tmux.sock" attach-session -t '=workspace-guide'`. Detach with your tmux detach binding before continuing. ## Capture and clean up ```console $ tmux-workspace freeze -S "$WORKSPACE_TMP/tmux.sock" --json workspace-guide ``` Try [export and reload](https://libtmux.org/en/go/latest/workspace/guides/export-session/) before cleanup. Capture cannot recover original scripts, command history or application state. Remove only the session created by this walkthrough when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-guide' ``` The configuration remains in the temporary directory. Keep the session running when following guides that continue this example. ## Continue [Configuration](https://libtmux.org/en/go/latest/workspace/configuration/) describes execution fields; [discovery](https://libtmux.org/en/go/latest/workspace/guides/discovery/) finds saved files. Read the [load reference](https://libtmux.org/en/go/latest/workspace/cli/load/) and [automation](https://libtmux.org/en/go/latest/workspace/guides/automation/) for attachment, output and failure handling. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Install and load a workspace Source: https://libtmux.org/en/java/latest/workspace/guides/installation/ > Build the workspace command and load a session on a private tmux socket. Build the documented `tmux-workspace` revision, then load a small session on a private socket. Use a Unix shell with tmux 3.2a or newer on `PATH`. ## Build the command Fetch the documented source revision, then build from its repository root. Keep the exported `PATH` in this shell for the rest of the walkthrough. ```console $ git clone --filter=blob:none https://github.com/libtmux/libtmux-java.git ``` ```console $ cd libtmux-java ``` ```console $ git fetch --depth=1 origin 3e5b20d22af3890ae5f7f52842e4b05d170a983f ``` ```console $ git checkout --detach FETCH_HEAD ``` Use JDK 25 or newer and the repository's Gradle wrapper: ```console $ ./gradlew --no-daemon --max-workers=2 :libtmux-workspace-cli:installDist ``` ```console $ export PATH="$PWD/libtmux-workspace-cli/build/install/tmux-workspace/bin:$PATH" ``` Keep the distribution's `bin` and `lib` directories together. Set `JAVA_HOME` to the JDK if Java is not already on `PATH`. ```console $ tmux-workspace --help ``` ## Create the input Keep this shell open. Create a temporary working directory on a filesystem that supports Unix sockets, then enter it: ```console $ WORKSPACE_TMP="$(mktemp -d)" ``` ```console $ cd "$WORKSPACE_TMP" ``` Save this as `workspace.yaml`: ```yaml title="workspace.yaml" session_name: workspace-guide windows: - window_name: editor layout: even-horizontal panes: [null, null] ``` ## Load and inspect ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-d` leaves the session detached. Inspect its panes using the same socket: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-guide:editor' ``` Attach interactively with `tmux -S "$WORKSPACE_TMP/tmux.sock" attach-session -t '=workspace-guide'`. Detach with your tmux detach binding before continuing. ## Capture and clean up ```console $ tmux-workspace freeze -S "$WORKSPACE_TMP/tmux.sock" --json workspace-guide ``` Try [export and reload](https://libtmux.org/en/java/latest/workspace/guides/export-session/) before cleanup. Capture cannot recover original scripts, command history or application state. Remove only the session created by this walkthrough when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-guide' ``` The configuration remains in the temporary directory. Keep the session running when following guides that continue this example. ## Continue [Configuration](https://libtmux.org/en/java/latest/workspace/configuration/) describes execution fields; [discovery](https://libtmux.org/en/java/latest/workspace/guides/discovery/) finds saved files. Read the [load reference](https://libtmux.org/en/java/latest/workspace/cli/load/) and [automation](https://libtmux.org/en/java/latest/workspace/guides/automation/) for attachment, output and failure handling. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Install and load a workspace Source: https://libtmux.org/en/py/latest/workspace/guides/installation/ > Build the workspace command and load a session on a private tmux socket. The runnable terminal loader is the separate Python application tmuxp. Its documented prerequisites are Python 3.10 or newer and tmux 3.2 or newer. Install it in an isolated tool environment with uv: ```console $ uv tool install tmuxp ``` The tool environment owns tmuxp's Python dependencies, including libtmux. ## Create the input Save this file as [`workspace.yaml`](https://libtmux.org/en/py/latest/workspace/guides/installation/#create-the-input) in a writable directory: ```yaml session_name: workspace-guide windows: - window_name: editor layout: even-horizontal panes: - echo ready - echo second ``` Load the session detached. Reserve the socket name for this walkthrough: ```console $ tmuxp load \ -L workspace-guide \ -d \ workspace.yaml ``` Inspect the two panes: ```console $ tmux -L workspace-guide list-panes -t '=workspace-guide:editor' ``` Attach when ready: ```console $ tmux -L workspace-guide attach-session -t '=workspace-guide' ``` Detach with your configured tmux detach binding. Before cleanup, optionally try [export and reload](https://libtmux.org/en/py/latest/workspace/guides/export-session/). Remove only this walkthrough's session when finished: ```console $ tmux -L workspace-guide kill-session -t '=workspace-guide' ``` ## Continue [Discovery](https://libtmux.org/en/py/latest/workspace/guides/discovery/) explains project files and saved names. [Configuration](https://libtmux.org/en/py/latest/workspace/configuration/) describes accepted fields, and [load](https://libtmux.org/en/py/latest/workspace/cli/load/) documents all flags. [tmuxp reference source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Install and load a workspace Source: https://libtmux.org/en/rs/latest/workspace/guides/installation/ > Build the workspace command and load a session on a private tmux socket. Build the documented `tmux-workspace` revision, then load a small session on a private socket. Use a Unix shell with tmux 3.2a or newer on `PATH`. ## Build the command Fetch the documented source revision, then build from its repository root. Keep the exported `PATH` in this shell for the rest of the walkthrough. ```console $ git clone --filter=blob:none https://github.com/libtmux/libtmux-rs.git ``` ```console $ cd libtmux-rs ``` ```console $ git fetch --depth=1 origin e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4 ``` ```console $ git checkout --detach FETCH_HEAD ``` Use the Rust toolchain selected by [`rust-toolchain.toml`](): ```console $ cargo build --locked -p tmux-workspace --bin tmux-workspace ``` ```console $ export PATH="$PWD/target/debug:$PATH" ``` ```console $ tmux-workspace --help ``` ## Create the input Keep this shell open. Create a temporary working directory on a filesystem that supports Unix sockets, then enter it: ```console $ WORKSPACE_TMP="$(mktemp -d)" ``` ```console $ cd "$WORKSPACE_TMP" ``` Save this as `workspace.yaml`: ```yaml title="workspace.yaml" session_name: workspace-guide windows: - window_name: editor layout: even-horizontal panes: [null, null] ``` ## Load and inspect ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-d` leaves the session detached. Inspect its panes using the same socket: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-guide:editor' ``` Attach interactively with `tmux -S "$WORKSPACE_TMP/tmux.sock" attach-session -t '=workspace-guide'`. Detach with your tmux detach binding before continuing. ## Capture and clean up ```console $ tmux-workspace freeze -S "$WORKSPACE_TMP/tmux.sock" --json workspace-guide ``` Try [export and reload](https://libtmux.org/en/rs/latest/workspace/guides/export-session/) before cleanup. Capture cannot recover original scripts, command history or application state. Remove only the session created by this walkthrough when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-guide' ``` The configuration remains in the temporary directory. Keep the session running when following guides that continue this example. ## Continue [Configuration](https://libtmux.org/en/rs/latest/workspace/configuration/) describes execution fields; [discovery](https://libtmux.org/en/rs/latest/workspace/guides/discovery/) finds saved files. Read the [load reference](https://libtmux.org/en/rs/latest/workspace/cli/load/) and [automation](https://libtmux.org/en/rs/latest/workspace/guides/automation/) for attachment, output and failure handling. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Install and load a workspace Source: https://libtmux.org/en/swift/latest/workspace/guides/installation/ > Build the workspace command and load a session on a private tmux socket. Build the documented `tmux-workspace` revision, then load a small session on a private socket. Use a Unix shell with tmux 3.2a or newer on `PATH`. ## Build the command Fetch the documented source revision, then build from its repository root. Keep the exported `PATH` in this shell for the rest of the walkthrough. ```console $ git clone --filter=blob:none https://github.com/libtmux/libtmux-swift.git ``` ```console $ cd libtmux-swift ``` ```console $ git fetch --depth=1 origin 53c67947879f4976ddf2c43f3c8df7c7671c5b19 ``` ```console $ git checkout --detach FETCH_HEAD ``` Use Swift 6.2 and enable YAML decoding for this walkthrough: ```console $ swift build --force-resolved-versions --traits YAMLWorkspaces --product tmux-workspace ``` ```console $ export PATH="$PWD/.build/debug:$PATH" ``` A Linux executable still needs its Swift runtime libraries. Keep the matching toolchain available when running it. ```console $ tmux-workspace --help ``` ## Create the input Keep this shell open. Create a temporary working directory on a filesystem that supports Unix sockets, then enter it: ```console $ WORKSPACE_TMP="$(mktemp -d)" ``` ```console $ cd "$WORKSPACE_TMP" ``` Save this as `workspace.yaml`: ```yaml title="workspace.yaml" session_name: workspace-guide windows: - window_name: editor layout: even-horizontal panes: [null, null] ``` ## Load and inspect ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-d` leaves the session detached. Inspect its panes using the same socket: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-guide:editor' ``` Attach interactively with `tmux -S "$WORKSPACE_TMP/tmux.sock" attach-session -t '=workspace-guide'`. Detach with your tmux detach binding before continuing. ## Capture and clean up ```console $ tmux-workspace freeze -S "$WORKSPACE_TMP/tmux.sock" --json workspace-guide ``` Try [export and reload](https://libtmux.org/en/swift/latest/workspace/guides/export-session/) before cleanup. Capture cannot recover original scripts, command history or application state. Remove only the session created by this walkthrough when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-guide' ``` The configuration remains in the temporary directory. Keep the session running when following guides that continue this example. ## Continue [Configuration](https://libtmux.org/en/swift/latest/workspace/configuration/) describes execution fields; [discovery](https://libtmux.org/en/swift/latest/workspace/guides/discovery/) finds saved files. Read the [load reference](https://libtmux.org/en/swift/latest/workspace/cli/load/) and [automation](https://libtmux.org/en/swift/latest/workspace/guides/automation/) for attachment, output and failure handling. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Install and load a workspace Source: https://libtmux.org/en/ts/latest/workspace/guides/installation/ > Build the workspace command and load a session on a private tmux socket. Build the documented `tmux-workspace` revision, then load a small session on a private socket. Use a Unix shell with tmux 3.2a or newer on `PATH`. ## Build the command Fetch the documented source revision, then build from its repository root. Keep the exported `PATH` in this shell for the rest of the walkthrough. ```console $ git clone --filter=blob:none https://github.com/libtmux/libtmux-ts.git ``` ```console $ cd libtmux-ts ``` ```console $ git fetch --depth=1 origin f36d692552bb9a373b45338bb5fece854e57cc3d ``` ```console $ git checkout --detach FETCH_HEAD ``` Use Bun and Node.js 22 or newer. Install the locked dependencies and build the core package before the CLI: ```console $ bun install --frozen-lockfile ``` ```console $ bun run --cwd packages/libtmux build ``` ```console $ bun run --cwd packages/workspace-cli build ``` ```console $ WORKSPACE_BIN="$(mktemp -d)" ``` ```console $ ln -s "$PWD/packages/workspace-cli/dist/main.js" "$WORKSPACE_BIN/tmux-workspace" ``` ```console $ export PATH="$WORKSPACE_BIN:$PATH" ``` The launcher runs the built JavaScript using Node. Keep the source directory in place while using it. ```console $ tmux-workspace --help ``` ## Create the input Keep this shell open. Create a temporary working directory on a filesystem that supports Unix sockets, then enter it: ```console $ WORKSPACE_TMP="$(mktemp -d)" ``` ```console $ cd "$WORKSPACE_TMP" ``` Save this as `workspace.yaml`: ```yaml title="workspace.yaml" session_name: workspace-guide windows: - window_name: editor layout: even-horizontal panes: [null, null] ``` ## Load and inspect ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -f /dev/null \ -d \ --json \ workspace.yaml ``` `-d` leaves the session detached. Inspect its panes using the same socket: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-guide:editor' ``` Attach interactively with `tmux -S "$WORKSPACE_TMP/tmux.sock" attach-session -t '=workspace-guide'`. Detach with your tmux detach binding before continuing. ## Capture and clean up ```console $ tmux-workspace freeze -S "$WORKSPACE_TMP/tmux.sock" --json workspace-guide ``` Try [export and reload](https://libtmux.org/en/ts/latest/workspace/guides/export-session/) before cleanup. Capture cannot recover original scripts, command history or application state. Remove only the session created by this walkthrough when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-guide' ``` The configuration remains in the temporary directory. Keep the session running when following guides that continue this example. ## Continue [Configuration](https://libtmux.org/en/ts/latest/workspace/configuration/) describes execution fields; [discovery](https://libtmux.org/en/ts/latest/workspace/guides/discovery/) finds saved files. Read the [load reference](https://libtmux.org/en/ts/latest/workspace/cli/load/) and [automation](https://libtmux.org/en/ts/latest/workspace/guides/automation/) for attachment, output and failure handling. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Find saved workspaces Source: https://libtmux.org/en/csharp/latest/workspace/guides/discovery/ > Resolve explicit files, project directories and saved workspace names. Use an explicit path, such as [`./workspace.yaml`](https://libtmux.org/en/csharp/latest/workspace/guides/installation/#create-the-input), to select one document. Pass a project directory such as `.` to use its [`.tmuxp.yaml`](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/#list-available-files), [`.tmuxp.yml`](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/#list-available-files) or [`.tmuxp.json`](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/#list-available-files) configuration. A bare saved name uses the global workspace directory. ## List available files ```console $ tmux-workspace ls --json ``` Discovery includes project configurations in the current directory and its parents, plus saved global workspaces. The first existing global directory wins, in this order: 1. `TMUXP_CONFIGDIR`. 2. `$XDG_CONFIG_HOME/tmuxp`, with [`~/.config`](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/#list-available-files) as the XDG default. 3. [`~/.tmuxp`](https://libtmux.org/en/csharp/latest/workspace/guides/discovery/#list-available-files). An existing empty directory remains selected. A missing directory does not override an existing fallback merely because its environment variable is set. ## Search by content ```console $ tmux-workspace search --json window:editor ``` Use [search](https://libtmux.org/en/csharp/latest/workspace/cli/search/) for field prefixes and pattern rules. Use [edit](https://libtmux.org/en/csharp/latest/workspace/cli/edit/) to open a discovered workspace, or [load](https://libtmux.org/en/csharp/latest/workspace/cli/load/) with an explicit path when a name is ambiguous. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Find saved workspaces Source: https://libtmux.org/en/cxx/latest/workspace/guides/discovery/ > Resolve explicit files, project directories and saved workspace names. Use an explicit path, such as [`./workspace.yaml`](https://libtmux.org/en/cxx/latest/workspace/guides/installation/#create-the-input), to select one document. Pass a project directory such as `.` to use its [`.tmuxp.yaml`](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/#list-available-files), [`.tmuxp.yml`](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/#list-available-files) or [`.tmuxp.json`](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/#list-available-files) configuration. A bare saved name uses the global workspace directory. ## List available files ```console $ tmux-workspace ls --json ``` Discovery includes project configurations in the current directory and its parents, plus saved global workspaces. The first existing global directory wins, in this order: 1. `TMUXP_CONFIGDIR`. 2. `$XDG_CONFIG_HOME/tmuxp`, with [`~/.config`](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/#list-available-files) as the XDG default. 3. [`~/.tmuxp`](https://libtmux.org/en/cxx/latest/workspace/guides/discovery/#list-available-files). An existing empty directory remains selected. A missing directory does not override an existing fallback merely because its environment variable is set. ## Search by content ```console $ tmux-workspace search --json window:editor ``` Use [search](https://libtmux.org/en/cxx/latest/workspace/cli/search/) for field prefixes and pattern rules. Use [edit](https://libtmux.org/en/cxx/latest/workspace/cli/edit/) to open a discovered workspace, or [load](https://libtmux.org/en/cxx/latest/workspace/cli/load/) with an explicit path when a name is ambiguous. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Find saved workspaces Source: https://libtmux.org/en/go/latest/workspace/guides/discovery/ > Resolve explicit files, project directories and saved workspace names. Use an explicit path, such as [`./workspace.yaml`](https://libtmux.org/en/go/latest/workspace/guides/installation/#create-the-input), to select one document. Pass a project directory such as `.` to use its [`.tmuxp.yaml`](https://libtmux.org/en/go/latest/workspace/guides/discovery/#list-available-files), [`.tmuxp.yml`](https://libtmux.org/en/go/latest/workspace/guides/discovery/#list-available-files) or [`.tmuxp.json`](https://libtmux.org/en/go/latest/workspace/guides/discovery/#list-available-files) configuration. A bare saved name uses the global workspace directory. ## List available files ```console $ tmux-workspace ls --json ``` Discovery includes project configurations in the current directory and its parents, plus saved global workspaces. The first existing global directory wins, in this order: 1. `TMUXP_CONFIGDIR`. 2. `$XDG_CONFIG_HOME/tmuxp`, with [`~/.config`](https://libtmux.org/en/go/latest/workspace/guides/discovery/#list-available-files) as the XDG default. 3. [`~/.tmuxp`](https://libtmux.org/en/go/latest/workspace/guides/discovery/#list-available-files). An existing empty directory remains selected. A missing directory does not override an existing fallback merely because its environment variable is set. ## Search by content ```console $ tmux-workspace search --json window:editor ``` Use [search](https://libtmux.org/en/go/latest/workspace/cli/search/) for field prefixes and pattern rules. Use [edit](https://libtmux.org/en/go/latest/workspace/cli/edit/) to open a discovered workspace, or [load](https://libtmux.org/en/go/latest/workspace/cli/load/) with an explicit path when a name is ambiguous. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Find saved workspaces Source: https://libtmux.org/en/java/latest/workspace/guides/discovery/ > Resolve explicit files, project directories and saved workspace names. Use an explicit path, such as [`./workspace.yaml`](https://libtmux.org/en/java/latest/workspace/guides/installation/#create-the-input), to select one document. Pass a project directory such as `.` to use its [`.tmuxp.yaml`](https://libtmux.org/en/java/latest/workspace/guides/discovery/#list-available-files), [`.tmuxp.yml`](https://libtmux.org/en/java/latest/workspace/guides/discovery/#list-available-files) or [`.tmuxp.json`](https://libtmux.org/en/java/latest/workspace/guides/discovery/#list-available-files) configuration. A bare saved name uses the global workspace directory. ## List available files ```console $ tmux-workspace ls --json ``` Discovery includes project configurations in the current directory and its parents, plus saved global workspaces. The first existing global directory wins, in this order: 1. `TMUXP_CONFIGDIR`. 2. `$XDG_CONFIG_HOME/tmuxp`, with [`~/.config`](https://libtmux.org/en/java/latest/workspace/guides/discovery/#list-available-files) as the XDG default. 3. [`~/.tmuxp`](https://libtmux.org/en/java/latest/workspace/guides/discovery/#list-available-files). An existing empty directory remains selected. A missing directory does not override an existing fallback merely because its environment variable is set. ## Search by content ```console $ tmux-workspace search --json window:editor ``` Use [search](https://libtmux.org/en/java/latest/workspace/cli/search/) for field prefixes and pattern rules. Use [edit](https://libtmux.org/en/java/latest/workspace/cli/edit/) to open a discovered workspace, or [load](https://libtmux.org/en/java/latest/workspace/cli/load/) with an explicit path when a name is ambiguous. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Find saved workspaces Source: https://libtmux.org/en/py/latest/workspace/guides/discovery/ > Resolve explicit files, project directories and saved workspace names. Use an explicit YAML or JSON file path when you need an unambiguous input. A directory resolves its project configuration, and a saved name resolves through the tmuxp configuration roots. ## Global directories An existing `TMUXP_CONFIGDIR` takes precedence, followed by the XDG configuration directory and then the legacy [`~/.tmuxp`](https://libtmux.org/en/py/latest/workspace/guides/discovery/) directory. A nonexistent explicit directory does not automatically win discovery. See [environment](https://libtmux.org/en/py/latest/workspace/configuration/environment/) for the relevant variables. ## Project files Project discovery walks from the current directory toward its ancestors, stopping at home or the filesystem root. It selects at most one candidate per directory, preferring [`.tmuxp.yaml`](), then [`.tmuxp.yml`](https://libtmux.org/en/py/latest/workspace/guides/discovery/), then [`.tmuxp.json`](https://libtmux.org/en/py/latest/workspace/guides/discovery/). Nearer directories come first. It does not recursively enumerate child projects. Load the current project's configuration: ```console $ tmuxp load . ``` The normal command can attach or prompt. Use `-d` when you want detached execution and select `-L` or `-S` for an isolated server. [ls](https://libtmux.org/en/py/latest/workspace/cli/ls/), [search](https://libtmux.org/en/py/latest/workspace/cli/search/), and [edit](https://libtmux.org/en/py/latest/workspace/cli/edit/) use the same discovery concepts with their own result and error behavior. [tmuxp reference source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Find saved workspaces Source: https://libtmux.org/en/rs/latest/workspace/guides/discovery/ > Resolve explicit files, project directories and saved workspace names. Use an explicit path, such as [`./workspace.yaml`](https://libtmux.org/en/rs/latest/workspace/guides/installation/#create-the-input), to select one document. Pass a project directory such as `.` to use its [`.tmuxp.yaml`](https://libtmux.org/en/rs/latest/workspace/guides/discovery/#list-available-files), [`.tmuxp.yml`](https://libtmux.org/en/rs/latest/workspace/guides/discovery/#list-available-files) or [`.tmuxp.json`](https://libtmux.org/en/rs/latest/workspace/guides/discovery/#list-available-files) configuration. A bare saved name uses the global workspace directory. ## List available files ```console $ tmux-workspace ls --json ``` Discovery includes project configurations in the current directory and its parents, plus saved global workspaces. The first existing global directory wins, in this order: 1. `TMUXP_CONFIGDIR`. 2. `$XDG_CONFIG_HOME/tmuxp`, with [`~/.config`](https://libtmux.org/en/rs/latest/workspace/guides/discovery/#list-available-files) as the XDG default. 3. [`~/.tmuxp`](https://libtmux.org/en/rs/latest/workspace/guides/discovery/#list-available-files). An existing empty directory remains selected. A missing directory does not override an existing fallback merely because its environment variable is set. ## Search by content ```console $ tmux-workspace search --json window:editor ``` Use [search](https://libtmux.org/en/rs/latest/workspace/cli/search/) for field prefixes and pattern rules. Use [edit](https://libtmux.org/en/rs/latest/workspace/cli/edit/) to open a discovered workspace, or [load](https://libtmux.org/en/rs/latest/workspace/cli/load/) with an explicit path when a name is ambiguous. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Find saved workspaces Source: https://libtmux.org/en/swift/latest/workspace/guides/discovery/ > Resolve explicit files, project directories and saved workspace names. Use an explicit path, such as [`./workspace.yaml`](https://libtmux.org/en/swift/latest/workspace/guides/installation/#create-the-input), to select one document. Pass a project directory such as `.` to use its [`.tmuxp.yaml`](https://libtmux.org/en/swift/latest/workspace/guides/discovery/#list-available-files), [`.tmuxp.yml`](https://libtmux.org/en/swift/latest/workspace/guides/discovery/#list-available-files) or [`.tmuxp.json`](https://libtmux.org/en/swift/latest/workspace/guides/discovery/#list-available-files) configuration. A bare saved name uses the global workspace directory. ## List available files ```console $ tmux-workspace ls --json ``` Discovery includes project configurations in the current directory and its parents, plus saved global workspaces. The first existing global directory wins, in this order: 1. `TMUXP_CONFIGDIR`. 2. `$XDG_CONFIG_HOME/tmuxp`, with [`~/.config`](https://libtmux.org/en/swift/latest/workspace/guides/discovery/#list-available-files) as the XDG default. 3. [`~/.tmuxp`](https://libtmux.org/en/swift/latest/workspace/guides/discovery/#list-available-files). An existing empty directory remains selected. A missing directory does not override an existing fallback merely because its environment variable is set. ## Search by content ```console $ tmux-workspace search --json window:editor ``` Use [search](https://libtmux.org/en/swift/latest/workspace/cli/search/) for field prefixes and pattern rules. Use [edit](https://libtmux.org/en/swift/latest/workspace/cli/edit/) to open a discovered workspace, or [load](https://libtmux.org/en/swift/latest/workspace/cli/load/) with an explicit path when a name is ambiguous. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Find saved workspaces Source: https://libtmux.org/en/ts/latest/workspace/guides/discovery/ > Resolve explicit files, project directories and saved workspace names. Use an explicit path, such as [`./workspace.yaml`](https://libtmux.org/en/ts/latest/workspace/guides/installation/#create-the-input), to select one document. Pass a project directory such as `.` to use its [`.tmuxp.yaml`](https://libtmux.org/en/ts/latest/workspace/guides/discovery/#list-available-files), [`.tmuxp.yml`](https://libtmux.org/en/ts/latest/workspace/guides/discovery/#list-available-files) or [`.tmuxp.json`](https://libtmux.org/en/ts/latest/workspace/guides/discovery/#list-available-files) configuration. A bare saved name uses the global workspace directory. ## List available files ```console $ tmux-workspace ls --json ``` Discovery includes project configurations in the current directory and its parents, plus saved global workspaces. The first existing global directory wins, in this order: 1. `TMUXP_CONFIGDIR`. 2. `$XDG_CONFIG_HOME/tmuxp`, with [`~/.config`](https://libtmux.org/en/ts/latest/workspace/guides/discovery/#list-available-files) as the XDG default. 3. [`~/.tmuxp`](https://libtmux.org/en/ts/latest/workspace/guides/discovery/#list-available-files). An existing empty directory remains selected. A missing directory does not override an existing fallback merely because its environment variable is set. ## Search by content ```console $ tmux-workspace search --json window:editor ``` Use [search](https://libtmux.org/en/ts/latest/workspace/cli/search/) for field prefixes and pattern rules. Use [edit](https://libtmux.org/en/ts/latest/workspace/cli/edit/) to open a discovered workspace, or [load](https://libtmux.org/en/ts/latest/workspace/cli/load/) with an explicit path when a name is ambiguous. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Automate workspace operations Source: https://libtmux.org/en/csharp/latest/workspace/guides/automation/ > Run detached commands with explicit inputs and machine-readable results. Give automation an explicit file, endpoint and attachment choice. Continue the [installation walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/) with this detached operation: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ workspace.yaml ``` Check the process exit status, parse its JSON result, then inspect any reported partial effects. A failed later input does not imply that earlier sessions were removed. Keep stderr separate from the result stream. ## Follow progress Use NDJSON when the caller needs records while a load is running: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --ndjson \ workspace.yaml ``` Parse one complete JSON value per line. Treat a closed stream or missing final result as incomplete work. Do not infer success from an earlier creation event. ## Make retries deliberate Use a unique session name for independent jobs. Reusing a name follows the loader's existing-session policy; it is not a request to reset that session. Capture IDs and retained effects from the result before deciding what to clean up or retry. Remove only sessions the job owns. Read [output](https://libtmux.org/en/csharp/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/csharp/latest/workspace/reference/exit-codes/) for the command's machine interface. A pane's process can outlive the CLI and can fail after successful command delivery. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Automate workspace operations Source: https://libtmux.org/en/cxx/latest/workspace/guides/automation/ > Run detached commands with explicit inputs and machine-readable results. Give automation an explicit file, endpoint and attachment choice. Continue the [installation walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/) with this detached operation: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ workspace.yaml ``` Check the process exit status, parse its JSON result, then inspect any reported partial effects. A failed later input does not imply that earlier sessions were removed. Keep stderr separate from the result stream. ## Follow progress Use NDJSON when the caller needs records while a load is running: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --ndjson \ workspace.yaml ``` Parse one complete JSON value per line. Treat a closed stream or missing final result as incomplete work. Do not infer success from an earlier creation event. ## Make retries deliberate Use a unique session name for independent jobs. Reusing a name follows the loader's existing-session policy; it is not a request to reset that session. Capture IDs and retained effects from the result before deciding what to clean up or retry. Remove only sessions the job owns. Read [output](https://libtmux.org/en/cxx/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/cxx/latest/workspace/reference/exit-codes/) for the command's machine interface. A pane's process can outlive the CLI and can fail after successful command delivery. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Automate workspace operations Source: https://libtmux.org/en/go/latest/workspace/guides/automation/ > Run detached commands with explicit inputs and machine-readable results. Give automation an explicit file, endpoint and attachment choice. Continue the [installation walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/) with this detached operation: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ workspace.yaml ``` Check the process exit status, parse its JSON result, then inspect any reported partial effects. A failed later input does not imply that earlier sessions were removed. Keep stderr separate from the result stream. ## Follow progress Use NDJSON when the caller needs records while a load is running: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --ndjson \ workspace.yaml ``` Parse one complete JSON value per line. Treat a closed stream or missing final result as incomplete work. Do not infer success from an earlier creation event. ## Make retries deliberate Use a unique session name for independent jobs. Reusing a name follows the loader's existing-session policy; it is not a request to reset that session. Capture IDs and retained effects from the result before deciding what to clean up or retry. Remove only sessions the job owns. Read [output](https://libtmux.org/en/go/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/go/latest/workspace/reference/exit-codes/) for the command's machine interface. A pane's process can outlive the CLI and can fail after successful command delivery. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Automate workspace operations Source: https://libtmux.org/en/java/latest/workspace/guides/automation/ > Run detached commands with explicit inputs and machine-readable results. Give automation an explicit file, endpoint and attachment choice. Continue the [installation walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/) with this detached operation: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ workspace.yaml ``` Check the process exit status, parse its JSON result, then inspect any reported partial effects. A failed later input does not imply that earlier sessions were removed. Keep stderr separate from the result stream. ## Follow progress Use NDJSON when the caller needs records while a load is running: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --ndjson \ workspace.yaml ``` Parse one complete JSON value per line. Treat a closed stream or missing final result as incomplete work. Do not infer success from an earlier creation event. ## Make retries deliberate Use a unique session name for independent jobs. Reusing a name follows the loader's existing-session policy; it is not a request to reset that session. Capture IDs and retained effects from the result before deciding what to clean up or retry. Remove only sessions the job owns. Read [output](https://libtmux.org/en/java/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/java/latest/workspace/reference/exit-codes/) for the command's machine interface. A pane's process can outlive the CLI and can fail after successful command delivery. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Automate workspace operations Source: https://libtmux.org/en/py/latest/workspace/guides/automation/ > Run detached commands with explicit inputs and machine-readable results. Pass an explicit workspace file, dedicated socket and `-d` when running tmuxp from a script. `--yes` answers confirmations; it does not supply every missing choice. ```console $ tmuxp load -L workspace-guide -d workspace.yaml ``` Use `ls --json` to read discovered workspace records: ```console $ tmuxp ls --json ``` The output is an object with a `workspaces` array. Search has different empty output and error behavior; read [search](https://libtmux.org/en/py/latest/workspace/cli/search/) and [exit codes](https://libtmux.org/en/py/latest/workspace/reference/exit-codes/) before building a pipeline. Use [export and reload](https://libtmux.org/en/py/latest/workspace/guides/export-session/) to capture a session. Review the resulting commands and paths rather than treating capture as a complete backup. --- # Automate workspace operations Source: https://libtmux.org/en/rs/latest/workspace/guides/automation/ > Run detached commands with explicit inputs and machine-readable results. Give automation an explicit file, endpoint and attachment choice. Continue the [installation walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/) with this detached operation: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ workspace.yaml ``` Check the process exit status, parse its JSON result, then inspect any reported partial effects. A failed later input does not imply that earlier sessions were removed. Keep stderr separate from the result stream. ## Follow progress Use NDJSON when the caller needs records while a load is running: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --ndjson \ workspace.yaml ``` Parse one complete JSON value per line. Treat a closed stream or missing final result as incomplete work. Do not infer success from an earlier creation event. ## Make retries deliberate Use a unique session name for independent jobs. Reusing a name follows the loader's existing-session policy; it is not a request to reset that session. Capture IDs and retained effects from the result before deciding what to clean up or retry. Remove only sessions the job owns. Read [output](https://libtmux.org/en/rs/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/rs/latest/workspace/reference/exit-codes/) for the command's machine interface. A pane's process can outlive the CLI and can fail after successful command delivery. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Automate workspace operations Source: https://libtmux.org/en/swift/latest/workspace/guides/automation/ > Run detached commands with explicit inputs and machine-readable results. Give automation an explicit file, endpoint and attachment choice. Continue the [installation walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/) with this detached operation: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ workspace.yaml ``` Check the process exit status, parse its JSON result, then inspect any reported partial effects. A failed later input does not imply that earlier sessions were removed. Keep stderr separate from the result stream. ## Follow progress Use NDJSON when the caller needs records while a load is running: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --ndjson \ workspace.yaml ``` Parse one complete JSON value per line. Treat a closed stream or missing final result as incomplete work. Do not infer success from an earlier creation event. ## Make retries deliberate Use a unique session name for independent jobs. Reusing a name follows the loader's existing-session policy; it is not a request to reset that session. Capture IDs and retained effects from the result before deciding what to clean up or retry. Remove only sessions the job owns. Read [output](https://libtmux.org/en/swift/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/swift/latest/workspace/reference/exit-codes/) for the command's machine interface. A pane's process can outlive the CLI and can fail after successful command delivery. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Automate workspace operations Source: https://libtmux.org/en/ts/latest/workspace/guides/automation/ > Run detached commands with explicit inputs and machine-readable results. Give automation an explicit file, endpoint and attachment choice. Continue the [installation walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/) with this detached operation: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ workspace.yaml ``` Check the process exit status, parse its JSON result, then inspect any reported partial effects. A failed later input does not imply that earlier sessions were removed. Keep stderr separate from the result stream. ## Follow progress Use NDJSON when the caller needs records while a load is running: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --ndjson \ workspace.yaml ``` Parse one complete JSON value per line. Treat a closed stream or missing final result as incomplete work. Do not infer success from an earlier creation event. ## Make retries deliberate Use a unique session name for independent jobs. Reusing a name follows the loader's existing-session policy; it is not a request to reset that session. Capture IDs and retained effects from the result before deciding what to clean up or retry. Remove only sessions the job owns. Read [output](https://libtmux.org/en/ts/latest/workspace/reference/output/) and [errors](https://libtmux.org/en/ts/latest/workspace/reference/exit-codes/) for the command's machine interface. A pane's process can outlive the CLI and can fail after successful command delivery. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Export and reload a session Source: https://libtmux.org/en/csharp/latest/workspace/guides/export-session/ > Capture a running session, inspect the document and load a second copy. Capture the session created by the [installation walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/) to a new YAML file: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to workspace-export.yaml \ workspace-guide ``` Review the saved commands, directories and layout. Capture reads current tmux state; it cannot recover original arguments, shell history, scripts, comments or application state. A captured command may need editing before replay. ## Load a second copy Use a fresh session name on the same private server: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ -s workspace-replayed \ --json \ workspace-export.yaml ``` Inspect the second copy's panes: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-replayed' ``` Remove that copy when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-replayed' ``` [Capture](https://libtmux.org/en/csharp/latest/workspace/cli/freeze/) explains destination handling. [Conversion](https://libtmux.org/en/csharp/latest/workspace/cli/convert/) changes file encoding without proving the document can be loaded. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Export and reload a session Source: https://libtmux.org/en/cxx/latest/workspace/guides/export-session/ > Capture a running session, inspect the document and load a second copy. Capture the session created by the [installation walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/) to a new YAML file: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to workspace-export.yaml \ workspace-guide ``` Review the saved commands, directories and layout. Capture reads current tmux state; it cannot recover original arguments, shell history, scripts, comments or application state. A captured command may need editing before replay. ## Load a second copy Use a fresh session name on the same private server: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ -s workspace-replayed \ --json \ workspace-export.yaml ``` Inspect the second copy's panes: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-replayed' ``` Remove that copy when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-replayed' ``` [Capture](https://libtmux.org/en/cxx/latest/workspace/cli/freeze/) explains destination handling. [Conversion](https://libtmux.org/en/cxx/latest/workspace/cli/convert/) changes file encoding without proving the document can be loaded. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Export and reload a session Source: https://libtmux.org/en/go/latest/workspace/guides/export-session/ > Capture a running session, inspect the document and load a second copy. Capture the session created by the [installation walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/) to a new YAML file: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to workspace-export.yaml \ workspace-guide ``` Review the saved commands, directories and layout. Capture reads current tmux state; it cannot recover original arguments, shell history, scripts, comments or application state. A captured command may need editing before replay. ## Load a second copy Use a fresh session name on the same private server: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ -s workspace-replayed \ --json \ workspace-export.yaml ``` Inspect the second copy's panes: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-replayed' ``` Remove that copy when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-replayed' ``` [Capture](https://libtmux.org/en/go/latest/workspace/cli/freeze/) explains destination handling. [Conversion](https://libtmux.org/en/go/latest/workspace/cli/convert/) changes file encoding without proving the document can be loaded. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Export and reload a session Source: https://libtmux.org/en/java/latest/workspace/guides/export-session/ > Capture a running session, inspect the document and load a second copy. Capture the session created by the [installation walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/) to a new YAML file: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to workspace-export.yaml \ workspace-guide ``` Review the saved commands, directories and layout. Capture reads current tmux state; it cannot recover original arguments, shell history, scripts, comments or application state. A captured command may need editing before replay. ## Load a second copy Use a fresh session name on the same private server: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ -s workspace-replayed \ --json \ workspace-export.yaml ``` Inspect the second copy's panes: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-replayed' ``` Remove that copy when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-replayed' ``` [Capture](https://libtmux.org/en/java/latest/workspace/cli/freeze/) explains destination handling. [Conversion](https://libtmux.org/en/java/latest/workspace/cli/convert/) changes file encoding without proving the document can be loaded. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Export and reload a session Source: https://libtmux.org/en/py/latest/workspace/guides/export-session/ > Capture a running session, inspect the document and load a second copy. Use the session created by the [installation walkthrough](https://libtmux.org/en/py/latest/workspace/guides/installation/). Capture it to a new YAML destination: ```console $ tmuxp freeze \ -L workspace-guide \ --workspace-format yaml \ --save-to captured-workspace.yaml \ --yes \ workspace-guide ``` Review the output file. Capture cannot reconstruct original scripts, shell history, plugin decisions, comments, or every application's state. Compare window and pane topology, directories, layouts, environment, and options explicitly. Replay under a new name on the same dedicated server: ```console $ tmuxp load \ -L workspace-guide \ -d \ -s workspace-replay \ captured-workspace.yaml ``` Inspect the replay: ```console $ tmux -L workspace-guide list-panes -t '=workspace-replay' ``` Remove the replay when finished: ```console $ tmux -L workspace-guide kill-session -t '=workspace-replay' ``` The [freeze reference](https://libtmux.org/en/py/latest/workspace/cli/freeze/) explains prompts and overwrite behavior. [convert](https://libtmux.org/en/py/latest/workspace/cli/convert/) changes document representation without validating whether a workspace can be loaded. [tmuxp reference source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Export and reload a session Source: https://libtmux.org/en/rs/latest/workspace/guides/export-session/ > Capture a running session, inspect the document and load a second copy. Capture the session created by the [installation walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/) to a new YAML file: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to workspace-export.yaml \ workspace-guide ``` Review the saved commands, directories and layout. Capture reads current tmux state; it cannot recover original arguments, shell history, scripts, comments or application state. A captured command may need editing before replay. ## Load a second copy Use a fresh session name on the same private server: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ -s workspace-replayed \ --json \ workspace-export.yaml ``` Inspect the second copy's panes: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-replayed' ``` Remove that copy when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-replayed' ``` [Capture](https://libtmux.org/en/rs/latest/workspace/cli/freeze/) explains destination handling. [Conversion](https://libtmux.org/en/rs/latest/workspace/cli/convert/) changes file encoding without proving the document can be loaded. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Export and reload a session Source: https://libtmux.org/en/swift/latest/workspace/guides/export-session/ > Capture a running session, inspect the document and load a second copy. Capture the session created by the [installation walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/) to a new YAML file: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to workspace-export.yaml \ workspace-guide ``` Review the saved commands, directories and layout. Capture reads current tmux state; it cannot recover original arguments, shell history, scripts, comments or application state. A captured command may need editing before replay. ## Load a second copy Use a fresh session name on the same private server: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ -s workspace-replayed \ --json \ workspace-export.yaml ``` Inspect the second copy's panes: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-replayed' ``` Remove that copy when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-replayed' ``` [Capture](https://libtmux.org/en/swift/latest/workspace/cli/freeze/) explains destination handling. [Conversion](https://libtmux.org/en/swift/latest/workspace/cli/convert/) changes file encoding without proving the document can be loaded. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Export and reload a session Source: https://libtmux.org/en/ts/latest/workspace/guides/export-session/ > Capture a running session, inspect the document and load a second copy. Capture the session created by the [installation walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/) to a new YAML file: ```console $ tmux-workspace freeze \ -S "$WORKSPACE_TMP/tmux.sock" \ --json \ --workspace-format yaml \ --save-to workspace-export.yaml \ workspace-guide ``` Review the saved commands, directories and layout. Capture reads current tmux state; it cannot recover original arguments, shell history, scripts, comments or application state. A captured command may need editing before replay. ## Load a second copy Use a fresh session name on the same private server: ```console $ tmux-workspace load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ -s workspace-replayed \ --json \ workspace-export.yaml ``` Inspect the second copy's panes: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" list-panes -t '=workspace-replayed' ``` Remove that copy when finished: ```console $ tmux -S "$WORKSPACE_TMP/tmux.sock" kill-session -t '=workspace-replayed' ``` [Capture](https://libtmux.org/en/ts/latest/workspace/cli/freeze/) explains destination handling. [Conversion](https://libtmux.org/en/ts/latest/workspace/cli/convert/) changes file encoding without proving the document can be loaded. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Troubleshoot a workspace Source: https://libtmux.org/en/csharp/latest/workspace/guides/troubleshooting/ > Find the failed stage before retrying a workspace operation. Start with the error message and exit status. A partially completed load can leave sessions or windows running; inspect its result before retrying or cleaning up. ## Confirm the command and input ```console $ tmux-workspace debug-info --json ``` Check the executable version, selected tmux binary and workspace directories. Use an explicit file path to bypass saved-name lookup. Verify the socket matches the one used for inspection and capture. ## Common failures | Symptom | Next check | | --- | --- | | Workspace not found | Explicit path, file extension and global discovery directory | | Unsupported field | CLI configuration fields and the reported field path | | tmux unavailable | Executable path, permissions and selected socket | | Existing session mismatch | Running window names and the requested document | | Layout rejected | Layout name, pane capacity and the selected tmux version | | File already exists | Select a new output path or authorize replacement with `--force` | | Script failed | Child status, captured output and working directory | | Interactive context required | Use `load -d` for automation; provide a terminal for interactive work | ## Record a load Continue the [installation walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/) and append diagnostic records to a local file: ```console $ tmux-workspace --log-level debug load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ --log-file workspace-load.log \ workspace.yaml ``` Logs may include script output and local paths. Inspect them before sharing a bug report. Include the command, versions, minimal configuration, exit status and relevant result; remove private values. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Troubleshoot a workspace Source: https://libtmux.org/en/cxx/latest/workspace/guides/troubleshooting/ > Find the failed stage before retrying a workspace operation. Start with the error message and exit status. A partially completed load can leave sessions or windows running; inspect its result before retrying or cleaning up. ## Confirm the command and input ```console $ tmux-workspace debug-info --json ``` Check the executable version, selected tmux binary and workspace directories. Use an explicit file path to bypass saved-name lookup. Verify the socket matches the one used for inspection and capture. ## Common failures | Symptom | Next check | | --- | --- | | Workspace not found | Explicit path, file extension and global discovery directory | | Unsupported field | CLI configuration fields and the reported field path | | tmux unavailable | Executable path, permissions and selected socket | | Existing session mismatch | Running window names and the requested document | | Layout rejected | Layout name, pane capacity and the selected tmux version | | File already exists | Select a new output path or authorize replacement with `--force` | | Script failed | Child status, captured output and working directory | | Interactive context required | Use `load -d` for automation; provide a terminal for interactive work | ## Record a load Continue the [installation walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/) and append diagnostic records to a local file: ```console $ tmux-workspace --log-level debug load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ --log-file workspace-load.log \ workspace.yaml ``` Logs may include script output and local paths. Inspect them before sharing a bug report. Include the command, versions, minimal configuration, exit status and relevant result; remove private values. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Troubleshoot a workspace Source: https://libtmux.org/en/go/latest/workspace/guides/troubleshooting/ > Find the failed stage before retrying a workspace operation. Start with the error message and exit status. A partially completed load can leave sessions or windows running; inspect its result before retrying or cleaning up. ## Confirm the command and input ```console $ tmux-workspace debug-info --json ``` Check the executable version, selected tmux binary and workspace directories. Use an explicit file path to bypass saved-name lookup. Verify the socket matches the one used for inspection and capture. ## Common failures | Symptom | Next check | | --- | --- | | Workspace not found | Explicit path, file extension and global discovery directory | | Unsupported field | CLI configuration fields and the reported field path | | tmux unavailable | Executable path, permissions and selected socket | | Existing session mismatch | Running window names and the requested document | | Layout rejected | Layout name, pane capacity and the selected tmux version | | File already exists | Select a new output path or authorize replacement with `--force` | | Script failed | Child status, captured output and working directory | | Interactive context required | Use `load -d` for automation; provide a terminal for interactive work | ## Record a load Continue the [installation walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/) and append diagnostic records to a local file: ```console $ tmux-workspace --log-level debug load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ --log-file workspace-load.log \ workspace.yaml ``` Logs may include script output and local paths. Inspect them before sharing a bug report. Include the command, versions, minimal configuration, exit status and relevant result; remove private values. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Troubleshoot a workspace Source: https://libtmux.org/en/java/latest/workspace/guides/troubleshooting/ > Find the failed stage before retrying a workspace operation. Start with the error message and exit status. A partially completed load can leave sessions or windows running; inspect its result before retrying or cleaning up. ## Confirm the command and input ```console $ tmux-workspace debug-info --json ``` Check the executable version, selected tmux binary and workspace directories. Use an explicit file path to bypass saved-name lookup. Verify the socket matches the one used for inspection and capture. ## Common failures | Symptom | Next check | | --- | --- | | Workspace not found | Explicit path, file extension and global discovery directory | | Unsupported field | CLI configuration fields and the reported field path | | tmux unavailable | Executable path, permissions and selected socket | | Existing session mismatch | Running window names and the requested document | | Layout rejected | Layout name, pane capacity and the selected tmux version | | File already exists | Select a new output path or authorize replacement with `--force` | | Script failed | Child status, captured output and working directory | | Interactive context required | Use `load -d` for automation; provide a terminal for interactive work | ## Record a load Continue the [installation walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/) and append diagnostic records to a local file: ```console $ tmux-workspace --log-level debug load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ --log-file workspace-load.log \ workspace.yaml ``` Logs may include script output and local paths. Inspect them before sharing a bug report. Include the command, versions, minimal configuration, exit status and relevant result; remove private values. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Troubleshoot a workspace Source: https://libtmux.org/en/py/latest/workspace/guides/troubleshooting/ > Find the failed stage before retrying a workspace operation. Start by identifying the failing stage. A parser error happens before a workspace is loaded. A missing file is a discovery problem. An accepted document can still fail during tmux creation, shell startup, command dispatch, or a plugin callback. ## Arguments and files Use the [command reference](https://libtmux.org/en/py/latest/workspace/cli/) for local flag meanings. Place root `--color` and `--log-level` before the command. Keep multiple load filenames together. Both importer children require a source argument. Confirm an explicit file works before investigating saved-name discovery. ## Configuration and commands Check the [configuration reference](https://libtmux.org/en/py/latest/workspace/configuration/) and the [example gallery](https://libtmux.org/en/py/latest/workspace/examples/gallery/). YAML parsing alone does not validate keys or prove builder support. A missing shell executable, directory, plugin package, SSH target, or application can prevent an otherwise valid workspace from behaving as intended. Commands are sent into panes and can require shell readiness. `enter: false` intentionally leaves text unsubmitted. Delays are measured in seconds; explicit zero and omission differ. See [commands](https://libtmux.org/en/py/latest/workspace/configuration/commands/) and [hooks](https://libtmux.org/en/py/latest/workspace/configuration/hooks/). ## Diagnostics and remaining state ```console $ tmuxp debug-info --json ``` Inspect raw tmux values before sharing diagnostics. Use the same `-L` or `-S` endpoint when inspecting a failed load. A partial build can leave sessions, windows, and panes behind; inspect them before cleanup. Do not assume rollback or kill an unrelated default server. [tmuxp reference source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Troubleshoot a workspace Source: https://libtmux.org/en/rs/latest/workspace/guides/troubleshooting/ > Find the failed stage before retrying a workspace operation. Start with the error message and exit status. A partially completed load can leave sessions or windows running; inspect its result before retrying or cleaning up. ## Confirm the command and input ```console $ tmux-workspace debug-info --json ``` Check the executable version, selected tmux binary and workspace directories. Use an explicit file path to bypass saved-name lookup. Verify the socket matches the one used for inspection and capture. ## Common failures | Symptom | Next check | | --- | --- | | Workspace not found | Explicit path, file extension and global discovery directory | | Unsupported field | CLI configuration fields and the reported field path | | tmux unavailable | Executable path, permissions and selected socket | | Existing session mismatch | Running window names and the requested document | | Layout rejected | Layout name, pane capacity and the selected tmux version | | File already exists | Select a new output path or authorize replacement with `--force` | | Script failed | Child status, captured output and working directory | | Interactive context required | Use `load -d` for automation; provide a terminal for interactive work | ## Record a load Continue the [installation walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/) and append diagnostic records to a local file: ```console $ tmux-workspace --log-level debug load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ --log-file workspace-load.log \ workspace.yaml ``` Logs may include script output and local paths. Inspect them before sharing a bug report. Include the command, versions, minimal configuration, exit status and relevant result; remove private values. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Troubleshoot a workspace Source: https://libtmux.org/en/swift/latest/workspace/guides/troubleshooting/ > Find the failed stage before retrying a workspace operation. Start with the error message and exit status. A partially completed load can leave sessions or windows running; inspect its result before retrying or cleaning up. ## Confirm the command and input ```console $ tmux-workspace debug-info --json ``` Check the executable version, selected tmux binary and workspace directories. Use an explicit file path to bypass saved-name lookup. Verify the socket matches the one used for inspection and capture. ## Common failures | Symptom | Next check | | --- | --- | | Workspace not found | Explicit path, file extension and global discovery directory | | Unsupported field | CLI configuration fields and the reported field path | | tmux unavailable | Executable path, permissions and selected socket | | Existing session mismatch | Running window names and the requested document | | Layout rejected | Layout name, pane capacity and the selected tmux version | | File already exists | Select a new output path or authorize replacement with `--force` | | Script failed | Child status, captured output and working directory | | Interactive context required | Use `load -d` for automation; provide a terminal for interactive work | ## Record a load Continue the [installation walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/) and append diagnostic records to a local file: ```console $ tmux-workspace --log-level debug load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ --log-file workspace-load.log \ workspace.yaml ``` Logs may include script output and local paths. Inspect them before sharing a bug report. Include the command, versions, minimal configuration, exit status and relevant result; remove private values. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Troubleshoot a workspace Source: https://libtmux.org/en/ts/latest/workspace/guides/troubleshooting/ > Find the failed stage before retrying a workspace operation. Start with the error message and exit status. A partially completed load can leave sessions or windows running; inspect its result before retrying or cleaning up. ## Confirm the command and input ```console $ tmux-workspace debug-info --json ``` Check the executable version, selected tmux binary and workspace directories. Use an explicit file path to bypass saved-name lookup. Verify the socket matches the one used for inspection and capture. ## Common failures | Symptom | Next check | | --- | --- | | Workspace not found | Explicit path, file extension and global discovery directory | | Unsupported field | CLI configuration fields and the reported field path | | tmux unavailable | Executable path, permissions and selected socket | | Existing session mismatch | Running window names and the requested document | | Layout rejected | Layout name, pane capacity and the selected tmux version | | File already exists | Select a new output path or authorize replacement with `--force` | | Script failed | Child status, captured output and working directory | | Interactive context required | Use `load -d` for automation; provide a terminal for interactive work | ## Record a load Continue the [installation walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/) and append diagnostic records to a local file: ```console $ tmux-workspace --log-level debug load \ -S "$WORKSPACE_TMP/tmux.sock" \ -d \ --json \ --log-file workspace-load.log \ workspace.yaml ``` Logs may include script output and local paths. Inspect them before sharing a bug report. Include the command, versions, minimal configuration, exit status and relevant result; remove private values. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Inspect a workspace through MCP Source: https://libtmux.org/en/csharp/latest/workspace/guides/inspect-with-mcp/ > Connect the development C# MCP server to a session loaded by its native workspace CLI. Inspect the session you loaded with the C# workspace CLI by pointing its MCP server at the same tmux socket. The loaded windows and panes are ordinary tmux objects; discovery returns their existing IDs. **This guide uses development `workspace-cli` source.** Continue the [installation walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/#load-and-inspect) through its detached load, keeping that shell and `WORKSPACE_TMP` available. Leave the `workspace-guide` session running. Build both executables from the same native repository checkout; released package instructions may describe different MCP contracts. ## Build the MCP server Run from the native repository root with the installation walkthrough's toolchain and dependencies. ```console $ dotnet build \ --configuration Release \ --framework net10.0 \ -m:2 \ src/LibTmux.Mcp/LibTmux.Mcp.csproj ``` Use the repository's SDK and a compatible .NET 10 runtime. Keep the complete build output beside the DLL, including its runtime and dependency metadata. ## Select the same socket Configure an MCP client to launch the following command with the shown environment. The client owns the process's standard input and output for JSON-RPC messages. ```console $ LIBTMUX_TOOLSETS=inspect \ LIBTMUX_SOCKET_PATH="$WORKSPACE_TMP/tmux.sock" \ dotnet src/LibTmux.Mcp/bin/Release/net10.0/LibTmux.Mcp.dll ``` In a client's configuration file, use absolute executable or script paths and expand `WORKSPACE_TMP` to its actual value. Configuration files do not perform shell variable expansion. Retain the environment used to build and run the native executable. For a workspace loaded with `-L NAME`, set `LIBTMUX_SOCKET=NAME` instead of `LIBTMUX_SOCKET_PATH`. Do not set both. If you selected a tmux executable with `LIBTMUX_TMUX`, supply that same setting to the MCP process. ## Inspect and wait 1. Discover tools with `tools/list` and read the `tmux://capabilities` resource. Confirm that its resolved endpoint matches the loaded socket. 2. Call [list_sessions][mcp-source], then [list_windows][mcp-source] with `session: "workspace-guide"`, and [list_panes][mcp-source]. Retain the returned session, window and pane IDs. 3. Select one returned pane ID for capture or a bounded text wait. Use the argument names below; discover the full schema before adding options. | Tool | Arguments | | --- | --- | | [capture_pane][mcp-source] | `"paneId"`, `"maxLines"` | | [wait_for_text][mcp-source] | `"paneId"`, regex `"patterns"`, `"timeoutSeconds"` in seconds | Set `"timeoutSeconds"` to `10` for a ten-second wait. A pending wait permits other inspection calls on the same connection. To check that behavior, start a wait for text absent from the pane, then request [list_panes][mcp-source] before its deadline. Client cancellation uses `notifications/cancelled` with the outstanding request ID; the connection remains usable for inspection. Capture returns a bounded `"lines"` array inside `"content"` with trailing empty rows removed; interior blank lines remain. [snapshot_pane][mcp-source] adds cursor and viewport state. The first [capture_since][mcp-source] call establishes an opaque cursor without returning content; pass that cursor to subsequent calls. If discovery does not show `workspace-guide`, compare the resolved socket in capabilities with the CLI's `-S` path. A different socket selects a different daemon even when session names match. ## Close the connection Close the MCP connection's standard input to stop the server and release pending work. This separately loaded workspace remains running. When you finish the walkthrough, remove only its session on the same socket: ```console $ tmux \ -S "$WORKSPACE_TMP/tmux.sock" \ kill-session \ -t '=workspace-guide' ``` The configuration remains in the temporary directory until you remove it. See the verified [native workspace workflow][workspace-source] and [development MCP reference][mcp-source] for this source contract. The site's released MCP pages retain their version-pinned contracts. [workspace-source]: https://github.com/libtmux/libtmux-dotnet/blob/95df228cfbe33cd3672bebb2d9a1c4b7f02f58f2/src/LibTmux.Workspace.Cli/README.md [mcp-source]: https://github.com/libtmux/libtmux-dotnet/blob/95df228cfbe33cd3672bebb2d9a1c4b7f02f58f2/docs/mcp/tools.md --- # Inspect a workspace through MCP Source: https://libtmux.org/en/cxx/latest/workspace/guides/inspect-with-mcp/ > Connect the development C++ MCP server to a session loaded by its native workspace CLI. Inspect the session you loaded with the C++ workspace CLI by pointing its MCP server at the same tmux socket. The loaded windows and panes are ordinary tmux objects; discovery returns their existing IDs. **This guide uses development `workspace-cli` source.** Continue the [installation walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/#load-and-inspect) through its detached load, keeping that shell and `WORKSPACE_TMP` available. Leave the `workspace-guide` session running. Build both executables from the same native repository checkout; released package instructions may describe different MCP contracts. ## Build the MCP server Run from the native repository root with the installation walkthrough's toolchain and dependencies. ```console $ cmake --preset cxx-dev \ -DLIBTMUX_BUILD_WORKSPACE_CLI=ON \ -DLIBTMUX_BUILD_MCP_SERVER=ON ``` Build the MCP executable; the target also copies its minimal configuration: ```console $ cmake --build --preset cxx-dev \ --target libtmux_mcp_server \ --parallel 2 ``` ## Select the same socket Configure an MCP client to launch the following command with the shown environment. The client owns the process's standard input and output for JSON-RPC messages. ```console $ LIBTMUX_TOOLSETS=inspect \ build/cxx-dev/apps/mcp/libtmux-mcp-server \ --socket-path "$WORKSPACE_TMP/tmux.sock" ``` In a client's configuration file, use absolute executable or script paths and expand `WORKSPACE_TMP` to its actual value. Configuration files do not perform shell variable expansion. Retain the environment used to build and run the native executable. For a workspace loaded with `-L NAME`, use MCP's `--socket-name NAME` instead. Keep the same tmux executable on `PATH` for both processes. ## Inspect and wait 1. Discover tools with `tools/list` and read the `tmux://capabilities` resource. Confirm that its resolved endpoint matches the loaded socket. 2. Call [list_sessions][mcp-source], then [list_windows][mcp-source] with `session: "workspace-guide"`, and [list_panes][mcp-source]. Retain the returned session, window and pane IDs. 3. Select one returned pane ID for capture or a bounded text wait. Use the argument names below; discover the full schema before adding options. | Tool | Arguments | | --- | --- | | [capture_pane][mcp-source] | `"paneId"` | | [wait_for_text][mcp-source] | `"target"`, literal `"text"`, `"timeout_ms"` in milliseconds | Set `"timeout_ms"` to `10000` for a ten-second wait. A pending wait permits other inspection calls on the same connection. To check that behavior, start a wait for text absent from the pane, then request [list_panes][mcp-source] before its deadline. Client cancellation uses `notifications/cancelled` with the outstanding request ID; the connection remains usable for inspection. [capture_pane][mcp-source] returns visible text. Use [snapshot_pane][mcp-source] for structured screen state and [capture_since][mcp-source] for incremental observation. If discovery does not show `workspace-guide`, compare the resolved socket in capabilities with the CLI's `-S` path. A different socket selects a different daemon even when session names match. ## Close the connection Close the MCP connection's standard input to stop the server and release pending work. This separately loaded workspace remains running. When you finish the walkthrough, remove only its session on the same socket: ```console $ tmux \ -S "$WORKSPACE_TMP/tmux.sock" \ kill-session \ -t '=workspace-guide' ``` The configuration remains in the temporary directory until you remove it. See the verified [native workspace workflow][workspace-source] and [development MCP reference][mcp-source] for this source contract. The site's released MCP pages retain their version-pinned contracts. [workspace-source]: https://github.com/libtmux/libtmux-cxx/blob/ef40c60dceafa890fc32b85ff7ee0c24baf84440/apps/workspace/README.md [mcp-source]: https://github.com/libtmux/libtmux-cxx/blob/ef40c60dceafa890fc32b85ff7ee0c24baf84440/apps/mcp/README.md --- # Inspect a workspace through MCP Source: https://libtmux.org/en/go/latest/workspace/guides/inspect-with-mcp/ > Connect the development Go MCP server to a session loaded by its native workspace CLI. Inspect the session you loaded with the Go workspace CLI by pointing its MCP server at the same tmux socket. The loaded windows and panes are ordinary tmux objects; discovery returns their existing IDs. **This guide uses development `workspace-cli` source.** Continue the [installation walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/#load-and-inspect) through its detached load, keeping that shell and `WORKSPACE_TMP` available. Leave the `workspace-guide` session running. Build both executables from the same native repository checkout; released package instructions may describe different MCP contracts. ## Build the MCP server Run from the native repository root with the installation walkthrough's toolchain and dependencies. ```console $ GOMAXPROCS=2 go build \ -p 2 \ -o libtmux-mcp \ ./mcp/cmd/libtmux-mcp ``` ## Select the same socket Configure an MCP client to launch the following command with the shown environment. The client owns the process's standard input and output for JSON-RPC messages. ```console $ LIBTMUX_TOOLSETS=inspect ./libtmux-mcp \ -socket-path "$WORKSPACE_TMP/tmux.sock" ``` In a client's configuration file, use absolute executable or script paths and expand `WORKSPACE_TMP` to its actual value. Configuration files do not perform shell variable expansion. Retain the environment used to build and run the native executable. For a workspace loaded with `-L NAME`, use MCP's `-socket-name NAME` instead. These MCP options use a single dash. Keep the same tmux executable on `PATH` for both processes. ## Inspect and wait 1. Discover tools with `tools/list` and read the `tmux://capabilities` resource. Confirm that its resolved endpoint matches the loaded socket. 2. Call [list_sessions][mcp-source], then [list_windows][mcp-source] with `session: "workspace-guide"`, and [list_panes][mcp-source]. Retain the returned session, window and pane IDs. 3. Select one returned pane ID for capture or a bounded text wait. Use the argument names below; discover the full schema before adding options. | Tool | Arguments | | --- | --- | | [capture_pane][mcp-source] | `"pane_id"`, `"max_lines"`; optional `"history"` | | [wait_for_text][mcp-source] | `"pane_id"`, `"patterns"`, `"timeout"` in seconds | Set `"timeout"` to `10` for a ten-second wait. A pending wait permits other inspection calls on the same connection. To check that behavior, start a wait for text absent from the pane, then request [list_panes][mcp-source] before its deadline. Client cancellation uses `notifications/cancelled` with the outstanding request ID; the connection remains usable for inspection. Use returned pane IDs for capture and snapshots. [wait_for_text][mcp-source] treats its patterns as literal text unless you enable its `"regex"` option. Discover the current schema before using cursor or history options. If discovery does not show `workspace-guide`, compare the resolved socket in capabilities with the CLI's `-S` path. A different socket selects a different daemon even when session names match. ## Close the connection Close the MCP connection's standard input to stop the server and release pending work. This separately loaded workspace remains running. When you finish the walkthrough, remove only its session on the same socket: ```console $ tmux \ -S "$WORKSPACE_TMP/tmux.sock" \ kill-session \ -t '=workspace-guide' ``` The configuration remains in the temporary directory until you remove it. See the verified [native workspace workflow][workspace-source] and [development MCP reference][mcp-source] for this source contract. The site's released MCP pages retain their version-pinned contracts. [workspace-source]: https://github.com/libtmux/libtmux-go/blob/56e30d41f0dc0eb32d582b581860d2b07a3c0ddb/workspace/CLI.md [mcp-source]: https://github.com/libtmux/libtmux-go/blob/56e30d41f0dc0eb32d582b581860d2b07a3c0ddb/mcp/TOOLS.md --- # Inspect a workspace through MCP Source: https://libtmux.org/en/java/latest/workspace/guides/inspect-with-mcp/ > Connect the development Java MCP server to a session loaded by its native workspace CLI. Inspect the session you loaded with the Java workspace CLI by pointing its MCP server at the same tmux socket. The loaded windows and panes are ordinary tmux objects; discovery returns their existing IDs. **This guide uses development `workspace-cli` source.** Continue the [installation walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/#load-and-inspect) through its detached load, keeping that shell and `WORKSPACE_TMP` available. Leave the `workspace-guide` session running. Build both executables from the same native repository checkout; released package instructions may describe different MCP contracts. ## Build the MCP server Run from the native repository root with the installation walkthrough's toolchain and dependencies. ```console $ ./gradlew :libtmux-mcp:installDist \ --max-workers=2 \ --no-parallel ``` Keep the installed distribution intact: its launcher loads the JARs in the adjacent `lib` directory. Use the JDK from the installation walkthrough. ## Select the same socket Configure an MCP client to launch the following command with the shown environment. The client owns the process's standard input and output for JSON-RPC messages. ```console $ LIBTMUX_TOOLSETS=inspect \ libtmux-mcp/build/install/libtmux-mcp/bin/libtmux-mcp \ --socket "$WORKSPACE_TMP/tmux.sock" ``` In a client's configuration file, use absolute executable or script paths and expand `WORKSPACE_TMP` to its actual value. Configuration files do not perform shell variable expansion. Retain the environment used to build and run the native executable. For a workspace loaded with `-L NAME`, use MCP's `--socket-name NAME` instead. The path option is `--socket`, not the workspace CLI's `-S`. If the CLI used a tmux executable outside `PATH`, pass the same executable with MCP's `--tmux` option. ## Inspect and wait 1. Discover tools with `tools/list` and read the `tmux://capabilities` resource. Confirm that its resolved endpoint matches the loaded socket. 2. Call [list_sessions][mcp-source], then [list_windows][mcp-source] with `session: "workspace-guide"`, and [list_panes][mcp-source]. Retain the returned session, window and pane IDs. 3. Select one returned pane ID for capture or a bounded text wait. Use the argument names below; discover the full schema before adding options. | Tool | Arguments | | --- | --- | | [capture_pane][mcp-source] | `"pane_id"`, `"max_lines"` | | [wait_for_text][mcp-source] | `"pane_id"`, `"patterns"`, `"timeout"` in seconds | Set `"timeout"` to `10` for a ten-second wait. A pending wait permits other inspection calls on the same connection. To check that behavior, start a wait for text absent from the pane, then request [list_panes][mcp-source] before its deadline. Client cancellation uses `notifications/cancelled` with the outstanding request ID; the connection remains usable for inspection. Capture omits trailing empty rows. Use [snapshot_pane][mcp-source] for structured pane state and [capture_since][mcp-source] for incremental observation; their budgets and cursor fields are described in the discovered schemas. If discovery does not show `workspace-guide`, compare the resolved socket in capabilities with the CLI's `-S` path. A different socket selects a different daemon even when session names match. ## Close the connection Close the MCP connection's standard input to stop the server and release pending work. This separately loaded workspace remains running. When you finish the walkthrough, remove only its session on the same socket: ```console $ tmux \ -S "$WORKSPACE_TMP/tmux.sock" \ kill-session \ -t '=workspace-guide' ``` The configuration remains in the temporary directory until you remove it. See the verified [native workspace workflow][workspace-source] and [development MCP reference][mcp-source] for this source contract. The site's released MCP pages retain their version-pinned contracts. [workspace-source]: https://github.com/libtmux/libtmux-java/blob/7a3aa4c8cf520d886f9877936c41fd07e7d4754d/workspace-cli/README.md [mcp-source]: https://github.com/libtmux/libtmux-java/blob/7a3aa4c8cf520d886f9877936c41fd07e7d4754d/libtmux-mcp/README.md --- # Inspect a workspace through MCP Source: https://libtmux.org/en/rs/latest/workspace/guides/inspect-with-mcp/ > Connect the development Rust MCP server to a session loaded by its native workspace CLI. Inspect the session you loaded with the Rust workspace CLI by pointing its MCP server at the same tmux socket. The loaded windows and panes are ordinary tmux objects; discovery returns their existing IDs. **This guide uses development `workspace-cli` source.** Continue the [installation walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/#load-and-inspect) through its detached load, keeping that shell and `WORKSPACE_TMP` available. Leave the `workspace-guide` session running. Build both executables from the same native repository checkout; released package instructions may describe different MCP contracts. ## Build the MCP server Run from the native repository root with the installation walkthrough's toolchain and dependencies. ```console $ cargo build \ --locked \ --package tmux-mcp \ --release \ --jobs 2 ``` ## Select the same socket Configure an MCP client to launch the following command with the shown environment. The client owns the process's standard input and output for JSON-RPC messages. ```console $ LIBTMUX_TOOLSETS=inspect target/release/tmux-mcp \ -S "$WORKSPACE_TMP/tmux.sock" ``` In a client's configuration file, use absolute executable or script paths and expand `WORKSPACE_TMP` to its actual value. Configuration files do not perform shell variable expansion. Retain the environment used to build and run the native executable. For a workspace loaded with `-L NAME`, pass the same `-L NAME` to MCP. The MCP server also accepts `LIBTMUX_SOCKET` for a name or `LIBTMUX_SOCKET_PATH` for a path. Keep the same tmux executable on `PATH` for both processes. ## Inspect and wait 1. Discover tools with `tools/list` and read the `tmux://capabilities` resource. Confirm that its resolved endpoint matches the loaded socket. 2. Call [list_sessions][mcp-source], [list_windows][mcp-source] and [list_panes][mcp-source] without arguments. Select `workspace-guide` from the results and retain its session, window and pane IDs. 3. Select one returned pane ID for capture or a bounded text wait. Use the argument names below; discover the full schema before adding options. | Tool | Arguments | | --- | --- | | [capture_pane][mcp-source] | `"pane"` | | [wait_for_text][mcp-source] | `"pane"`, `"patterns"`, `"seconds"` in seconds | Set `"seconds"` to `10` for a ten-second wait. A pending wait permits other inspection calls on the same connection. To check that behavior, start a wait for text absent from the pane, then request [list_panes][mcp-source] before its deadline. Client cancellation uses `notifications/cancelled` with the outstanding request ID; the connection remains usable for inspection. [capture_pane][mcp-source] selects a pane through `"pane"`. Use [snapshot_pane][mcp-source] when you need structured state and its optional `"max_lines"` budget. These spellings differ from ports that use `"paneId"` or `"pane_id"`. If discovery does not show `workspace-guide`, compare the resolved socket in capabilities with the CLI's `-S` path. A different socket selects a different daemon even when session names match. ## Close the connection Close the MCP connection's standard input to stop the server and release pending work. This separately loaded workspace remains running. When you finish the walkthrough, remove only its session on the same socket: ```console $ tmux \ -S "$WORKSPACE_TMP/tmux.sock" \ kill-session \ -t '=workspace-guide' ``` The configuration remains in the temporary directory until you remove it. See the verified [native workspace workflow][workspace-source] and [development MCP reference][mcp-source] for this source contract. The [released MCP guide](https://libtmux.org/en/rs/latest/mcp/guides/) documents its pinned source, including `--safety` and `tmux://server`. This development workflow uses `LIBTMUX_TOOLSETS` and `tmux://capabilities`; use the tool schema from the executable you launch. [workspace-source]: https://github.com/libtmux/libtmux-rs/blob/1ef17b9c1b3a1a8e54a4cf306bd91799beee1338/crates/tmux-workspace/README.md [mcp-source]: https://github.com/libtmux/libtmux-rs/blob/1ef17b9c1b3a1a8e54a4cf306bd91799beee1338/crates/tmux-mcp/README.md --- # Inspect a workspace through MCP Source: https://libtmux.org/en/swift/latest/workspace/guides/inspect-with-mcp/ > Connect the development Swift MCP server to a session loaded by its native workspace CLI. Inspect the session you loaded with the Swift workspace CLI by pointing its MCP server at the same tmux socket. The loaded windows and panes are ordinary tmux objects; discovery returns their existing IDs. **This guide uses development `workspace-cli` source.** Continue the [installation walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/#load-and-inspect) through its detached load, keeping that shell and `WORKSPACE_TMP` available. Leave the `workspace-guide` session running. Build both executables from the same native repository checkout; released package instructions may describe different MCP contracts. ## Build the MCP server Run from the native repository root with the installation walkthrough's toolchain and dependencies. ```console $ swift build \ --configuration release \ --jobs 2 \ --force-resolved-versions \ --product libtmux-mcp ``` Use the Swift toolchain from the installation walkthrough. On Linux, the executable also needs that toolchain's runtime libraries. ## Select the same socket Configure an MCP client to launch the following command with the shown environment. The client owns the process's standard input and output for JSON-RPC messages. ```console $ LIBTMUX_TOOLSETS=inspect \ LIBTMUX_SOCKET_PATH="$WORKSPACE_TMP/tmux.sock" \ .build/release/libtmux-mcp ``` In a client's configuration file, use absolute executable or script paths and expand `WORKSPACE_TMP` to its actual value. Configuration files do not perform shell variable expansion. Retain the environment used to build and run the native executable. For a workspace loaded with `-L NAME`, set `LIBTMUX_SOCKET=NAME` instead of `LIBTMUX_SOCKET_PATH`. Do not set both. If you selected a tmux executable with `LIBTMUX_TMUX_BIN`, supply that same setting to the MCP process. ## Inspect and wait 1. Discover tools with `tools/list` and read the `tmux://capabilities` resource. Confirm that its resolved endpoint matches the loaded socket. 2. Call [list_sessions][mcp-source], then [list_windows][mcp-source] with `session: "workspace-guide"`, and [list_panes][mcp-source]. Retain the returned session, window and pane IDs. 3. Select one returned pane ID for capture or a bounded text wait. Use the argument names below; discover the full schema before adding options. | Tool | Arguments | | --- | --- | | [capture_pane][mcp-source] | `"paneId"`, `"maxLines"` | | [wait_for_text][mcp-source] | `"paneId"`, `"patterns"`, `"timeoutMs"` in milliseconds | Set `"timeoutMs"` to `10000` for a ten-second wait. A pending wait permits other inspection calls on the same connection. To check that behavior, start a wait for text absent from the pane, then request [list_panes][mcp-source] before its deadline. Client cancellation uses `notifications/cancelled` with the outstanding request ID; the connection remains usable for inspection. Use [snapshot_pane][mcp-source] for structured pane state and [capture_since][mcp-source] for incremental observation. Bound capture with `"maxLines"`; read the discovered schemas for cursor and history options. If discovery does not show `workspace-guide`, compare the resolved socket in capabilities with the CLI's `-S` path. A different socket selects a different daemon even when session names match. ## Close the connection Close the MCP connection's standard input to stop the server and release pending work. This separately loaded workspace remains running. When you finish the walkthrough, remove only its session on the same socket: ```console $ tmux \ -S "$WORKSPACE_TMP/tmux.sock" \ kill-session \ -t '=workspace-guide' ``` The configuration remains in the temporary directory until you remove it. See the verified [native workspace workflow][workspace-source] and [development MCP reference][mcp-source] for this source contract. The site's released MCP pages retain their version-pinned contracts. [workspace-source]: https://github.com/libtmux/libtmux-swift/blob/d08c1f527cb6c04ab755b54d37c2b4882be15b6e/Sources/TmuxWorkspaceCLI/README.md [mcp-source]: https://github.com/libtmux/libtmux-swift/blob/d08c1f527cb6c04ab755b54d37c2b4882be15b6e/Sources/libtmux-mcp/README.md --- # Inspect a workspace through MCP Source: https://libtmux.org/en/ts/latest/workspace/guides/inspect-with-mcp/ > Connect the development TypeScript MCP server to a session loaded by its native workspace CLI. Inspect the session you loaded with the TypeScript workspace CLI by pointing its MCP server at the same tmux socket. The loaded windows and panes are ordinary tmux objects; discovery returns their existing IDs. **This guide uses development `workspace-cli` source.** Continue the [installation walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/#load-and-inspect) through its detached load, keeping that shell and `WORKSPACE_TMP` available. Leave the `workspace-guide` session running. Build both executables from the same native repository checkout; released package instructions may describe different MCP contracts. ## Build the MCP server Run from the native repository root with the installation walkthrough's toolchain and dependencies. ```console $ bun run --cwd packages/mcp build ``` The installation walkthrough has already installed the frozen dependencies and built the local core package. Keep the MCP output chunks, workspace packages and installed dependencies available to Node. ## Select the same socket Configure an MCP client to launch the following command with the shown environment. The client owns the process's standard input and output for JSON-RPC messages. ```console $ LIBTMUX_TOOLSETS=inspect \ LIBTMUX_SOCKET_PATH="$WORKSPACE_TMP/tmux.sock" \ node packages/mcp/dist/server.js ``` In a client's configuration file, use absolute executable or script paths and expand `WORKSPACE_TMP` to its actual value. Configuration files do not perform shell variable expansion. Retain the environment used to build and run the native executable. For a workspace loaded with `-L NAME`, set `LIBTMUX_SOCKET=NAME` instead of `LIBTMUX_SOCKET_PATH`. Do not set both. If the CLI selected a binary through `TMUX_BIN`, give that same path to MCP through `LIBTMUX_TMUX_BIN`. ## Inspect and wait 1. Discover tools with `tools/list` and read the `tmux://capabilities` resource. Confirm that its resolved endpoint matches the loaded socket. 2. Call [list_sessions][mcp-source], then [list_windows][mcp-source] with `session: "workspace-guide"`, and [list_panes][mcp-source]. Retain the returned session, window and pane IDs. 3. Select one returned pane ID for capture or a bounded text wait. Use the argument names below; discover the full schema before adding options. | Tool | Arguments | | --- | --- | | [capture_pane][mcp-source] | `"paneId"`, `"maxLines"` | | [wait_for_text][mcp-source] | `"paneId"`, `"patterns"`, `"timeoutMs"` in milliseconds | Set `"timeoutMs"` to `10000` for a ten-second wait. A pending wait permits other inspection calls on the same connection. To check that behavior, start a wait for text absent from the pane, then request [list_panes][mcp-source] before its deadline. Client cancellation uses `notifications/cancelled` with the outstanding request ID; the connection remains usable for inspection. Capture omits trailing empty rows. Use [snapshot_pane][mcp-source] for structured pane state and [capture_since][mcp-source] for incremental observation; their budgets and cursor fields are described in the discovered schemas. If discovery does not show `workspace-guide`, compare the resolved socket in capabilities with the CLI's `-S` path. A different socket selects a different daemon even when session names match. ## Close the connection Close the MCP connection's standard input to stop the server and release pending work. This separately loaded workspace remains running. When you finish the walkthrough, remove only its session on the same socket: ```console $ tmux \ -S "$WORKSPACE_TMP/tmux.sock" \ kill-session \ -t '=workspace-guide' ``` The configuration remains in the temporary directory until you remove it. See the verified [native workspace workflow][workspace-source] and [development MCP reference][mcp-source] for this source contract. The site's released MCP pages retain their version-pinned contracts. [workspace-source]: https://github.com/libtmux/libtmux-ts/blob/3db812d1aaca4501e26b1cff7551d28ab1fdf530/packages/workspace-cli/README.md [mcp-source]: https://github.com/libtmux/libtmux-ts/blob/3db812d1aaca4501e26b1cff7551d28ab1fdf530/packages/mcp/README.md --- # Capture server state Source: https://libtmux.org/en/lua/latest/guides/snapshots/ > Capture server state: libtmux documentation. Use [`runtime:connect(options):await()`]() to bind a borrowed tmux daemon, then [`server:snapshot(options):await()`]() to capture its state. Every live operation returns a Request. The [snapshot example](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/examples/snapshot.lua) prints each unique pane and its window ID using the public API. Pass an absolute [`binary`]() and explicit absolute `socket_path` to [`connect`](). Optional [`config_path`]() defaults to `/dev/null`. Connection options are copied before dispatch. The library does not select a default server or start one. Importing the library and inspecting captured records perform no I/O. Connection setup reads the actual daemon's version and identity. Linux socket binding creates a private socket alias in the selected socket's parent directory; that directory must permit creation and hard links. Each command checks the original socket and alias, reads bounded daemon evidence, and disables tmux autostart. A restart, replaced socket or uncertain connection invalidates the handle. Reconnect explicitly; old references do not bind to reused IDs. Tests currently cover Linux under WSL2. Native Linux and macOS remain separate unverified platform lanes. [`server:close():await()`]() closes the handle and its owned connections. It leaves the borrowed daemon running. The runtime also closes handles when its root scope finishes. Keep live work inside that scope; returning a handle from [`adapter.run`]() does not keep its runtime alive. ## Collections and projections Snapshots contain [`sessions`](), [`windows`](), `panes`, `window_links`, [`clients`]() and [`buffers`]() as [native selections](https://libtmux.org/en/lua/latest/guides/query/). Canonical entity collections deduplicate identity; [`snapshot.raw`]() preserves contextual listing rows and their order. A window linked twice has two link rows and one canonical window. Relationships refer only to captured data. Clients are the attached clients that tmux exposes through `list-clients`. Window links own `session_id`, `window_id`, `index` and active context. Pane and window IDs remain tmux strings; Lua positions are not tmux indexes. A daemon with no sessions can still have buffers. Capture reads them without creating a session. By default, capture loads every supported field in the [catalog](https://libtmux.org/en/lua/latest/topics/format-token-fields/). The `fields` option maps collection names to nonempty field-name sequences; omitted collections keep their default projection. Required identity and relationship fields are added. [`requested_projections`]() records the caller's selection; `projections` records effective fields, including for empty collections. Both maps use singular entity names such as `pane` and [`window_link`](). `capabilities.fields` records availability for the observed daemon version; it does not claim every tmux command is supported. Refresh by calling `snapshot` again. It returns fresh records. Tables remain mutable, so do not edit them during traversal. Editing a record does not refresh the server, another snapshot or its private identity index. Create a handle with [`server:handle(snapshot, record)`](). The record's kind picks the handle's class: a [`SnapshotPane`]() gives a [`libtmux.Pane`](), a [`SnapshotSession`]() a [`libtmux.Session`](), and so on, so LuaLS offers only the methods tmux accepts for that kind. It copies the record's private identity, so edits to exposed `id` or `ref` fields cannot redirect it. `handle:reference()` returns a separate reference table without I/O. `handle:snapshot():await()` explicitly captures fresh state and returns the matching record. A missing link/index, client/TTY or buffer name returns `target_missing`; stale server generations fail before capture. Same-name client or buffer reuse cannot establish continuous object identity. ## Consistency and limits Capture spans multiple commands. `acquisition.started` and `finished` are monotonic milliseconds. Normal capture reports observed relationship races in `races` and sets `complete` to false. Transport failures return an error. Set `strict = true` for one additional identity/topology verification pass. It compares membership and link context, ignoring listing order and volatile scalar values. A mismatch returns `inconsistent_snapshot` with the original snapshot in [`err.partial`](); capture never retries to manufacture consistency. [`verification`]() records the pass and its result. Equal observations do not make capture atomic, prove continuous identity, or detect objects created and removed between reads. Replacing a named buffer can preserve every catalog field while changing its contents. Each pass permits at most [`max_rows`]() raw rows (default 65,536) across all collections, before deduplication. `max_bytes` (default 16 MiB) limits both total encoded output and retained scalar/key bytes per pass. Strict mode adds one bounded pass. Accumulated rows and the graph copy also consume the runtime's byte budget; exhaustion returns `queue_full`. These counters bound data, not exact Lua heap allocation. `timeout` defaults to 750 milliseconds per listing command. Endpoint evidence checks have a separate bounded 750-millisecond deadline. Whole capture has a finite command count; cancel its Request for an earlier stop. Closing the server during capture prevents a successful current-reference result. Cancellation retires owned clients; it does not kill the daemon. Run the example against an explicitly selected existing server: ```console $ TMUX_BIN=/usr/bin/tmux TMUX_SOCKET=/tmp/example-tmux.sock lua examples/snapshot.lua ``` The package gate runs this file from installed core and luv outside the checkout, checks exact output, and verifies cleanup. Core-only installation still has no luv dependency; this standalone example selects it explicitly. --- # Compatibility targets Source: https://libtmux.org/en/lua/latest/guides/compatibility/ > Compatibility targets: libtmux documentation. The Lua port is under development. The following versions define required acceptance tests; they are not a published support promise. A source declaration, successful import, or sibling-port result does not establish live compatibility. | Component | Required versions | | --- | --- | | PUC Lua | 5.1.5, 5.2.4, 5.3.6, 5.4.9, 5.5.1 | | LuaJIT | v2.1 at c6ffc141a8762b41703f9287d63d93622a13dd8f | | Standalone adapter | luv 1.52.1-0 built for each runtime ABI | | Neovim | 0.10.0, 0.10.4, 0.11.7, 0.12.5 | | tmux | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | | Platforms | Linux x86_64, macOS arm64; WSL2 recorded separately | Pure-core tests run once per runtime/platform. Standalone and embedded live tests cover floor/current tmux for each runtime or host. The full tmux sweep uses PUC Lua 5.5.1 and current Neovim. Consumer imports and pure validation cover each runtime; floor/current combinations also run interoperability and workspace failure tests. Client/daemon version mismatches must report protocol failures truthfully instead of inferring daemon capabilities from the client executable. macOS x86_64 and native Windows transport are outside the initial platform matrix. Local tmux 3.7d and 3.8-rc results are diagnostic evidence and cannot replace released-version checks. Neovim's LuaJIT results do not prove stock PUC Lua 5.1 yield behavior. A Neovim build using PUC Lua is a separate host gate. Named buffer deletion requires tmux 3.4 or later. The typed API refuses older releases because a missing target can delete another buffer. The older-release deletion parity requirement remains open; see [buffers](https://libtmux.org/en/lua/latest/guides/buffers/). Exact operating-system images, binary hashes, compiler and module ABI identities belong with each result. Missing and skipped cells remain unverified. No complete product compatibility cell has passed yet. Current local implementation evidence comes from Ubuntu 24.04 under WSL2 on x86_64. Record it in the WSL2 lane; it does not close the native Linux or macOS gates. Selected PUC, LuaJIT, Neovim and tmux foundation tests have passed there while the complete product is still being implemented. The [CI workflow](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/.github/workflows/ci.yml) covers Linux unit runtimes, floor/current outer gates and the released-tmux integration sweep. Its [setup and coverage](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/.github/CONTRIBUTING.md#github-actions) use the same local gate commands. A passing run establishes those implemented checks at its tested revision; macOS, additional host/runtime combinations and unfinished product requirements remain open. Version evidence comes from [Lua's version history](https://www.lua.org/versions.html), [LuaJIT's release policy](https://luajit.org/status.html), the [luv release](https://github.com/luvit/luv/releases/tag/1.52.1-0), [Neovim's Lua contract](https://neovim.io/doc/user/lua/#lua-compat), and [tmux releases](https://github.com/tmux/tmux/releases). --- # Create sessions, windows and panes Source: https://libtmux.org/en/lua/latest/guides/creation/ > Create sessions, windows and panes: libtmux documentation. [`Server:new_session`](), [`Session:new_window`]() and [`Pane:split`]() return a `Request`. Await inside the adapter's managed coroutine, or register [`on_complete(value, err)`](). See [connections](https://libtmux.org/en/lua/latest/guides/snapshots/) and [runtime ownership](https://libtmux.org/en/lua/latest/guides/runtime/) for setup and cancellation. The receipt contains `session`, `window`, `pane` and [`window_link`]() handles made from tmux's returned IDs. Its `created` sequence names the objects this operation created: all four for a session, window/pane/link for a window, and only the pane for a split. Other handles describe the containing context. Creating a pane proves neither application readiness nor command success. ## Commands and literal values Pass `argv` for a literal command, or `shell` for explicitly authored tmux shell text. They are mutually exclusive. Multiple arguments use tmux's native argument execution. A singleton executable uses `/usr/bin/env --` to avoid tmux's single-argument shell interpretation; it requires that utility and rejects executable names containing `=`. Use explicit shell text for that case. Omitting both fields uses tmux's configured default command or shell. Names, directories and environment values stay literal, including tmux format-looking text. Session names reject `:`, `.`, and control bytes because tmux would otherwise change them. `environment` maps portable variable names to string values and applies to the created session or pane process through tmux's `-e` semantics. It does not change the caller's environment. An explicit `cwd` must be an absolute existing directory. The asynchronous preflight rejects a missing directory before sending the creation command. Filesystem changes after validation remain possible. Input is copied and validated before dispatch, including nested process options. ## Placement and selection Sessions start detached and accept `name`, [`window_name`](), `width` and `height`. Windows accept `name`, an optional nonnegative `index`, and `select`; their parent is the Session handle's exact ID. A supplied occupied index fails rather than replacing the existing window. Splits accept `direction` (`left`, `right`, `up` or `down`), optional positive `size` in cells or `percent` from 1 through 99, `full_size`, and `select`. The default direction is down. New windows and splits leave selection unchanged unless `select=true`. Handle references cannot be edited to redirect an operation. ## Errors and limits `process` accepts `timeout`, `deadline`, `max_output_bytes`, `kill_timeout` and `drain_timeout`; see [command completion](https://libtmux.org/en/lua/latest/guides/commands/). It cannot replace the bound socket, process environment, input stream or working directory. Creation accepts at most 1024 argv items, 128 environment entries and one MiB of encoded input, subject to the runtime's shared byte capacity. Errors preserve whether the command was not sent, may have taken effect, or completed. A malformed receipt reports `invalid_result` with completed effect and retained command output. Canceling the tmux client cannot undo a creation already accepted by the daemon. Creation does not retry or remove partial state. Closing the Server connection leaves created sessions running. The [public creation fixture](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/tests/integration/domain.lua) exercises the same API through luv and Neovim with literal arguments, environment and directory values, returned IDs, explicit shell text and missing directories. --- # Execute tmux commands Source: https://libtmux.org/en/lua/latest/guides/commands/ > Execute tmux commands: libtmux documentation. After [connecting](https://libtmux.org/en/lua/latest/guides/snapshots/), [`server:command(argv, options)`]() submits literal tmux arguments and returns a Request. It preserves raw stdout/stderr bytes, exit code and signal, and waits for the owned client and its pipes to retire. A completed nonzero exit is returned as result data. Spawn, timeout, output-limit and incomplete-drain failures return `nil, err`. No shell parses argv. tmux still parses its own command syntax; the library protects literal separator arguments. A tmux command that explicitly accepts shell text, such as `run-shell`, retains that command's shell semantics. Native command aliases apply even to full built-in names, including commands used by typed domain methods. Hooks can run additional commands and affect state. The library does not change borrowed server configuration or promise that aliases preserve built-in semantics. A preliminary configuration check cannot prevent an alias from changing before a later command is parsed. Use [`server:group(commands, options)`]() for an explicit ordered tmux command group. Its result is aggregate output and exit status. Parse failure can reject the whole group, immediate execution failure skips later commands, and delayed WAIT-command failures can still allow later commands. A group provides neither transactions nor independently attributed member results. Output routing also follows tmux: `run-shell` without a pane target writes job output to pane view mode on tmux 3.3–3.4; tmux 3.2a and 3.5 onward write it to the waiting client's stdout. An explicit `-t` pane target selects pane output. Without `-b`, client completion still waits for the job, and a control-mode `%end` marker can precede that completion. See the upstream [stdout restoration](https://github.com/tmux/tmux/commit/fb37d52ddeccb603b0932b81cff3a6228f1fd83d). Use `server:batch(commands, { concurrency = n, process = options })` for independent commands. Concurrency defaults to one and is bounded at 128; runtime capacity can reduce the active pool. The result is an input-indexed array of `completed`, `failed`, [`unknown`]() or `skipped` outcomes, each with `effect` and optional `value`/[`error`](). Nonzero exits are failed outcomes with their actual result in [`error.partial`](). Other commands continue. A canceled batch exposes a frozen `err.partial.outcomes` receipt; it preserves completed results and distinguishes started work from work never sent. All commands and process options are validated and copied before dispatch. One submission accepts at most 1,024 commands, 4,096 total arguments and 16 MiB of input. NUL is rejected in argv and environment entries; raw stdin can contain it. Never retry mutations automatically, especially after an unknown effect. Canceling a client does not prove daemon work stopped. Process options include [`stdin`](), `cwd`, explicit [`env`]() entries, `timeout`, monotonic `deadline`, `max_output_bytes` (default 1 MiB), `drain_timeout` (250 ms), and `kill_timeout` (100 ms). Timeout/deadline apply to the client operation; pinned endpoint evidence uses a separate bounded check. Output limits and runtime byte admission remain distinct. Excess batch output is reported with byte counts and truncation metadata; it is not silently kept. The raw API is an escape hatch. Named domain operations, owned command completion and observation APIs are still under development. A successful `send-keys` process does not report the exit of a pane application. --- # Observing a session Source: https://libtmux.org/en/lua/latest/guides/control/ > Observing a session: libtmux documentation. [`server:observe(session, options)`]() returns a Request for an observation lease. Pass a session handle from that Server's snapshot or creation result. Concurrent leases for the same session share one owned persistent client. General commands use the [process command API](https://libtmux.org/en/lua/latest/guides/commands/). Opening verifies the pinned daemon before spawning and checks daemon evidence again through the new connection. Every client uses `-N`; a missing session fails without creating a session or linking a window. Each endpoint owns at most eight observation clients. The observation offers: - [`watch_pane(pane, options)`]() returns a ready pane-output watch for a pane handle. - [`watch_notifications(options)`]() returns a ready notification watch, preserving unknown events and raw lines. - [`subscribe_format(pane, field_names, options)`]() returns a typed native format watch using generated pane fields. - [`coverage()`]() returns copied session/pane coverage and connection generation. - `close()` closes this lease's watches; final close waits for native cleanup. Handles must belong to the same Server. Their copied private identities select targets; overwriting a public `reference` method cannot redirect observation. Options are copied on submission. Shared connection limits must agree across leases; conflicting options return `option_conflict`. Separate Server handles have independent pools even when their socket paths match. Canceling acquisition releases only that caller's claim. Startup continues for remaining callers; canceling the final claim closes its client. Acquisition during final cleanup returns `closing`. Await final `close()` before reopening; a new connection has a distinct generation and requires new watches. A failed startup also retains its pool entry until native cleanup finishes. A new acquisition on a failed shared connection returns its recorded loss error. Close the old leases before opening a fresh connection. Watch creation installs its local receiver before a same-connection `list-panes` coverage check. A pane outside that session returns `uncovered_pane`. Topology changes invalidate reported coverage and close affected pane watches with `observation_gap`; opening a new watch performs another bounded check. These checks are observations, not a topology transaction. Capture remains a separate operation with no claimed lossless handoff to the stream. ## Reading and closing `watch:next({ timeout = milliseconds })` returns a Request for one event. An absolute monotonic `deadline` is also supported. Only one read may be pending on a watch; another returns `concurrent_read`. Canceling a read detaches that waiter and leaves the watch usable. [`watch:close()`]() is explicit and idempotent. An explicitly closed watch returns `nil, nil`; connection failure or loss returns `nil, err`. Pane events carry `kind = "output"`, `pane`, [`data`](), [`sequence`](), `generation` and [`server_generation`](). [`data`]() is a Lua byte string, including NUL and non-UTF-8 bytes. Extended output also preserves its decimal [`age`]() and [`metadata`](). A sequence identifies ordering within one connection; it does not imply complete pane history or application completion. Format events carry `kind = "format"`, a typed `value`, and explicit `session_id`, `window_id`, window-link `index` and `pane` context. Only catalog field names are accepted. Unknown or unsupported fields fail before writes; caller text cannot introduce a format expression. Registration acknowledgement establishes readiness. Native values arrive on tmux's [one-second sampling timer](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/control.c), so readiness does not wait for the first sample. Native title normalization and other daemon field behavior remain visible in the returned values. Closing a format watch unregisters its subscription. ## Bounds and ownership Defaults are 128 pending housekeeping replies, 128 watches, 4 MiB of retained connection data, and 1 MiB or 1,024 events per watch. Each observation claim, shared attachment and public watch consumes a runtime resource slot; the default runtime limit is 128 resources in total. Runtime byte and logical request limits also apply. Watch byte accounting includes event metadata; subscription projections and queued encoded commands are charged before deferred work begins. Overflow closes the affected watch with `observation_gap`. Its partial result reports discarded event count and decoded pane-byte count. Other watches and the shared reader continue. Native `%pause` also invalidates pane continuity. There is no silent drop policy, output coalescing, or claim that tmux pause is lossless backpressure. The reader parses bounded slices independently of watch consumption. Completion callbacks run through the runtime scheduler; application callbacks must not block the shared Lua event loop. A persistent connection occupies a resource lease, not an active process slot. A pending `next` uses the separate bounded logical-request lane. The serialized writer accepts only private housekeeping operations. Arguments are encoded for tmux's control-line parser. Bootstrap has its own response; subsequent replies use FIFO attribution and matching guard tuples. A request canceled after a possible write leaves a connection-owned tombstone until its reply drains. A write or framing failure closes the connection and fails pending callers. No command or pane input is retried or replayed. Normal root return closes resource leases after owned requests retire. Endpoint close or generation invalidation also closes its observation clients. Native cleanup waits for exit, pipe closure and pending write callbacks. Post-exit pipe drain is bounded at 250 ms. Explicit close first ends stdin; after 100 ms it signals only the owned client, escalating after another 100 ms. It never signals the tmux daemon or a pane program. ## Attachment effects The client uses `attach-session -E -f ignore-size,active-pane` with an exact session ID. It issues no shared pane/window selection, resizing, detachment or session-environment updates. Native client listings, attachment state, focus hooks and configured lifecycle policy remain observable. Hooks may themselves change state; preservation fixtures use neutral hooks. `focus-events` stays unchanged. Disabling it cannot suppress every attachment focus hook, and tmux provides no supported client flag for that guarantee. The transport does not create hidden sessions or change window links. It omits `-r`: on tmux 3.7 and 3.7c, a read-only observer can make independent process-lane `send-keys` fail with "client is read-only". The private writer restricts observation commands without that flag. Closing an observer removes its attached client. Native policy such as `destroy-unattached` can then destroy its session. A startup check cannot guarantee lifetime preservation when options or other clients can change. The library does not rewrite borrowed options or retain hidden clients to prevent that policy. Housekeeping assumes the server's native command semantics. Aliases and hooks can change even builtin commands; control framing does not authenticate server output. This transport does not enable general command acceleration. Automatic reconnect and subscription replay are not implemented. Opening a new connection creates a distinct generation; callers must establish new watches and treat the interval between connections as a gap. --- # Pane operations Source: https://libtmux.org/en/lua/latest/guides/panes/ > Pane operations: libtmux documentation. Pane handles perform explicit asynchronous operations through the pinned PROCESS endpoint. Each method returns a Request; await it inside a managed runtime task or use its completion callback. Snapshot records remain plain captured data. Obtain a handle from a creation receipt or [`server:handle`](). ```lua local capture = assert(pane:capture({ history_lines = 20 }):await()) local text = assert(capture:text()) assert(pane:send_text("printf '%s\\n' ready"):await()) assert(pane:send_keys({ "Enter" }):await()) ``` The executable [integration fixture](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/tests/integration/pane.lua) includes connection setup, creation, output barriers and teardown. ## Capture and text [`capture()`]() returns `{ bytes, target }` with a pure `text()` method. `bytes` preserves tmux's stdout, including its terminal newline and invalid UTF-8. `text()` validates UTF-8 strictly and returns the same string; invalid input returns `nil, err` with `invalid_utf8`. It performs no replacement, trimming, newline conversion or tmux I/O. Ordinary capture reads rendered screen/history cells. It does not recover the original PTY byte stream, prove application completion, or establish an ordered handoff to observation. It does not enter, exit or navigate copy mode. The default captures the visible terminal screen. `history_lines = N` adds up to N history rows, bounded at 1,000,000. Alternatively, [`start_line`]() and [`end_line`]() accept integer row offsets or `"-"`: zero is the first visible row, negative offsets refer to history, `start_line = "-"` selects all retained history and `end_line = "-"` selects the visible screen's end. Explicit ranges cannot be combined with [`history_lines`](). tmux clamps ranges to available data. | Option | Native behavior | Availability | | --- | --- | --- | | [`join_lines`]() | Join wrapped rows and preserve trailing spaces (`-J`). | 3.2a+ | | [`preserve_spaces`]() | Preserve trailing spaces (`-N`). | 3.2a+ | | [`escape_sequences`]() | Include text/background attribute sequences (`-e`). | 3.2a+ | | [`escape_nonprintable`]() | Request native octal escaping (`-C`). | 3.2a+ | | [`alternate_screen`]() | Select tmux's alternate grid (`-a`); missing grid errors. | 3.2a+ | | [`trim_empty_cells`]() | Omit trailing empty cells (`-T`). | 3.4+ | | [`mode_screen`]() | Capture the active mode screen when available (`-M`). | 3.6+ | | [`ignore_missing_alternate`]() | With [`alternate_screen`](), return one newline if the grid is missing (`-q`). | 3.2a+ | | [`pending_escape_sequences`]() | Capture incomplete input held by tmux's parser (`-P`). | 3.2a+ | | [`hyperlinks_only`]() | List native hyperlink URLs instead of cell text (`-H`). | 3.7+ | | [`line_numbers`]() | Prefix rows with offsets relative to the visible screen (`-L`). | 3.7+ | | [`line_flags`]() | Prefix rows with native grid flags (`-F`). | 3.7+ | [`alternate_screen`]() cannot be combined with history, explicit ranges or [`mode_screen`](). Unsupported version flags fail before dispatch. [`pending_escape_sequences`]() selects parser input instead of screen cells. Only [`escape_nonprintable`]() and process limits apply; other enabled capture options are rejected. For example, a pending ESC followed by `[` produces `"\027[\n"`, or `"\\033[\n"` with native octal escaping. The final newline belongs to tmux's print output, not the pending input. [`hyperlinks_only`]() preserves tmux's URL listing, including native deduplication and spacing. It does not guarantee an exhaustive URL inventory: tmux limits the number of distinct links collected to the grid width. Screen/range selection, joined rows and line metadata still apply. Attribute sequences, octal escaping, preserved spaces and empty-cell trimming are rejected because tmux ignores them in this mode. No matches produce one newline. [`line_numbers`]() and [`line_flags`]() preserve native prefixes; with both enabled, the number precedes the flags. Flags include `D`, `H`, `O`, `P`, `W` and `X` for dead, hyperlink, output-start, prompt-start, wrapped and extended rows; `-` means none. The result remains bytes, not parsed row records. The executable [capture fixture](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/tests/integration/capture.lua) demonstrates the supported capture modes with output barriers and cleanup. [`capture_to_buffer(name, options)`]() writes directly to an explicit named buffer and returns `true` when the native command completes. It accepts the same capture options and [buffer creation names](https://libtmux.org/en/lua/latest/guides/buffers/#storage-and-identity). Nonempty capture replaces the current slot. Empty capture leaves an existing buffer unchanged and does not create a missing buffer; this includes empty pending input and quiet missing alternate grids. Buffer capture stores native bytes without adding the print newline. A pending ESC followed by `[` is stored as `"\027["`, whereas [`capture()`]() returns `"\027[\n"`. Another client may replace the buffer before a subsequent read. Process output limits bound client output, not storage inside the tmux daemon; use a capture range to limit the selected rows. ## Clear history [`clear_history()`]() clears the pane's retained history and exits all its modes, including copy mode. It leaves visible screen cells intact. This is an explicit shared-state mutation; cancellation of an unrelated Request never calls it. `clear_history({ clear_hyperlinks = true })` also clears hyperlink storage, including links referenced by visible cells. This option requires tmux 3.4; older versions return `unsupported` before changing history or mode state. Success returns `true` under the same process, generation and error contracts as the other Pane mutations. ## Text, keys and copy mode [`send_text(text)`]() sends bounded NUL-free UTF-8 with native `send-keys -l`. It appends no Enter. A CR or LF already present in the argument remains explicit caller input. It accepts at most 65,536 bytes; arbitrary binary input is not part of this method. [`send_keys(names, options)`]() accepts a dense sequence of up to 1,024 names. Supported names include Enter, Escape, Tab, BTab, Space, BSpace, arrows, Home/End, Insert/Delete and their IC/DC aliases, PageUp/PageDown aliases, F1–F12 and numeric keypad names. C-, M- and S- modifiers may prefix these names or one printable ASCII character. Names are bounded at 64 bytes. [`repeat_count`]() is an integer from 1 to 1,000. Typos return `invalid_key`; recognized deferred native categories such as mouse and user-defined keys return `unsupported`. Unmodified literal characters belong in [`send_text`](). Both methods preserve native mode and `synchronize-panes` behavior. Modes can intercept input; synchronization can copy it to sibling panes. Dead or input-disabled panes can accept a command without delivering input. Success means tmux processed the operation, not that an application consumed it. The library does not change these policies or infer shell-command success. `copy_mode({ page_up = true })` explicitly enters copy mode. [`copy_command`]() sends one validated action through `send-keys -X`, with optional arguments and [`repeat_count`](). Entry, navigation and cancellation affect shared pane UI. No automatic cleanup exits a mode that another client may be using. The initial action subset includes cursor/word/paragraph/page/history navigation, selection marking, rectangle modes, refresh, search and jumps. For example: ```lua assert(pane:copy_mode():await()) assert(pane:copy_command("search-forward-text", { "ready" }):await()) assert(pane:copy_command("page-up", {}, { repeat_count = 2 }):await()) assert(pane:copy_command("cancel"):await()) ``` Unknown actions or incorrect argument counts return `invalid_copy_command`. Recognized deferred actions return `unsupported`, including copy/append, clipboard/pipe actions and newer navigation commands. This subset does not claim complete native copy-mode parity. Native command completion does not guarantee a search match or cursor movement. ## Resize, kill and respawn `resize({ width = N, height = N })` requests absolute dimensions; `resize({ direction = "left", amount = N })` adjusts one direction. Forms are mutually exclusive, dimensions/amount are 1–65,535 and adjustment defaults to one. Native layout constraints can clamp the result, resize neighbors and unzoom the window. Obtain a fresh snapshot when the resulting geometry matters. `kill()` targets only the handle's pane ID. Native removal of the last pane also destroys its window and can remove links or empty sessions elsewhere. This is an explicit mutation; canceling another Request never calls it. `respawn(options)` reuses the same pane identity. Without `kill = true`, an active pane produces a native error. Omitted `argv`/`shell` reuses its previous program; explicit launch options follow [creation](https://libtmux.org/en/lua/latest/guides/creation/), including absolute `cwd`, environment and separate literal argv/shell forms. Respawn resets the terminal screen and mode. It can terminate the old program before a later spawn failure, and tmux success does not prove executable startup. These methods return `true` on successful native completion. They preserve typed errors and partial command output on failure, with no automatic retry. All options must be plain records. The nested `process` record accepts timeout, deadline, output limit and drain/kill timeouts as described in [commands](https://libtmux.org/en/lua/latest/guides/commands/). Generation validation and runtime byte limits apply before dispatch; native completion still waits for client exit and both EOFs. ## Selection, titles and swaps `select()` changes the window's shared active pane. It unzooms when changing panes unless `keep_zoom = true`. This explicit mutation affects other clients and can run native focus and selection hooks. [`set_title(text)`]() sends format-literal UTF-8: `#{pane_id}` stays text. NUL, ASCII control bytes and DEL are rejected before dispatch because native tmux can silently ignore them. The limit is 65,536 bytes. Exact tmux 3.7 also silently ignores empty titles, so that combination returns `unsupported`. Other accepted releases allow clearing the title. tmux's native name cleaning still applies; from 3.7, backslashes can be doubled. Completion does not promise byte-exact storage for every accepted title. `swap(other_pane, options)` swaps two explicit, different panes from the same Server. Their stable IDs follow them into their new windows. The default uses native `-d`: across windows, an active pane moved out is replaced at its old position. Within one window, an active source pane can remain selected after moving positions. Neither active identity nor active position is preserved in every case. `select = true` uses native selection of the swapped panes. `keep_zoom = true` preserves each window's zoom. Swaps change inherited window options and the pane relationships visible through every linked window. These methods return `true` on native completion and share the process limits above. Missing targets retain the native failure and its partial receipt. See [topology operations](https://libtmux.org/en/lua/latest/guides/topology/) for Session and Window mutations. --- # Query captured data Source: https://libtmux.org/en/lua/latest/guides/query/ > Query captured data: libtmux documentation. [`libtmux.query`]() filters ordinary Lua records without contacting tmux, starting a loop, or loading a codec. Supply a schema for an ordinary sequence, including an empty one. [The native query example](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/examples/native_query.lua) shows both structured criteria and a Lua predicate over the same records. [`query.select(rows, schema)`]() copies the sequence and retains the record objects. The result is a dense one-based Lua table: indexing, `#` and `ipairs` behave normally. `:where(criteria)` and `:filter(predicate)` return new selections. They preserve input order, duplicate records and shared record references. The input and returned tables remain mutable; they are not live views. | Operation | Result | | --- | --- | | `:first()` | First record, or nil | | `:one()` | Record, or `nil, no_match/multiple_matches` error | | `:one_or_nil()` | Zero or one record; multiple matches return an error | | `:exists()` / `:count()` | Whether any records exist / sequence length | | `:iter()` | Fresh local iterator yielding records | | `:to_table()` | Shallow sequence copy without selection methods | Free functions accept the sequence first and its schema last. A selection carries its schema. [`query.compile(schema, criteria)`]() returns a compiled handle or `nil, err`; [`query.where(rows, compiled)`]() uses that handle's schema for ordinary rows. Compilation copies the schema and criteria. Mutating their original tables cannot change the compiled query. Convenience validation errors raise structured error tables; [`compile`]() and cardinality errors return them. Trusted predicates run as ordinary Lua and their errors propagate unchanged. ## Criteria and projections Schema fields declare [`string`](), [`number`]() or [`boolean`](), with optional `nullable` and `supported` booleans. Relations declare `cardinality = "one"` or `"many"` and a child [`schema`](). To-many arrays must describe the complete relationship. Scalar criteria are equality shorthand; `false` is a value. Operators are [`eq`](), [`ne`](), [`one_of`](), [`none_of`](), [`lt`](), [`lte`](), [`gt`](), [`gte`](), [`contains`](), [`starts_with`](), [`ends_with`]() and [`is_null`](). Strings compare literal bytes. [`AND`]()/[`OR`]() contain dense arrays of criteria; [`NOT`]() contains one criterion. Multiple fields and operators imply AND. To-many relations use [`some`](), [`every`]() or [`none`](); to-one relations use [`is`]() or [`is_not`]() with criteria or [`query.NULL`](). [`query.NULL`]() represents a loaded absent nullable value or to-one relation. A missing key is unloaded. Unloaded and unsupported data produce errors even inside branches that would otherwise short-circuit. The entire grammar is validated first, then every required projection, then matching begins. Invalid criteria fail even when the input is empty. Empty criteria and [`AND`]() match; empty [`OR`]() and [`one_of`]() do not; empty [`none_of`]() matches. On empty relationships, [`some`]() is false and [`every`]()/[`none`]() are true. For an absent to-one relation, `is = criteria` is false, `is_not = criteria` is true, `is = NULL` is true, and `is_not = NULL` is false. Criteria reject metatables, functions, cycles and non-finite numbers. Limits are depth 32, 4,096 copied nodes, 1,024 members per membership operator, 65,536 aggregate string/key bytes and a conservative 524,288-byte encoding estimate. These limits bound criteria validation. Local row traversal and arbitrary caller predicates are synchronous CPU work. ## Versioned JSON criteria [`query.encode_json(schema, criteria, codec)`]() returns a JSON string or `nil, err`. [`query.decode_json(schema, text, codec)`]() returns new plain criteria tables or `nil, err`. Both validate the complete grammar against the supplied local schema. The wire does not supply its own schema or executable predicates. Pass the consumer's codec explicitly. The supported interface is lunajson 1.2.3's `encode(value, null)` and `newparser(text, callbacks)` SAX API; an ordinary JSON `decode` function cannot preserve evidence of duplicate keys. Core imports and ordinary queries require only Lua. Codec functions are trusted synchronous code; the library does not load a codec automatically. ```lua local query = require("libtmux.query") local json = require("lunajson") local schema = { fields = { active = { type = "boolean" } } } local text = assert(query.encode_json(schema, { active = false, AND = {} }, json)) local criteria = assert(query.decode_json(schema, text, json)) ``` This Lua API's versioned profile has exactly two envelope members: ```json {"version":"libtmux.where/v1","where":{"active":false,"AND":[]}} ``` Profile compatibility is scoped to this Lua API; cross-port conformance has not been established. Wire operators retain their Lua spelling, including uppercase [`AND`](), [`OR`]() and [`NOT`](). Unknown members and versions are rejected. Schema positions determine array versus object encoding: empty [`AND`](), [`OR`](), [`one_of`]() and [`none_of`]() use `[]`; empty criteria use `{}`. Decode rejects a container of the wrong kind, including an empty object in an array position. [`query.NULL`]() becomes JSON null and decodes back to the same sentinel. False remains false. Encoding marks arrays only in private copies and leaves caller criteria and schemas unchanged. The decoder rejects duplicate decoded keys, trailing non-whitespace, malformed Unicode, invalid UTF-8 and non-finite numbers. Wire numbers have magnitude at most 9,007,199,254,740,991; nonzero number tokens that underflow to zero are rejected. Numbers otherwise use the host's floating-point representation. Strings containing arbitrary non-UTF-8 bytes remain usable in local criteria and require a separate binary representation at a consumer boundary. Input is capped at 524,288 bytes before constructing the SAX parser. Parsing checks depth 32, 4,096 nodes and 65,536 aggregate decoded string/key bytes as events arrive. Membership remains capped at 1,024 values. Encoding applies the same wire budgets and output-byte cap. Envelope members and keys count toward wire limits, so criteria at a local limit may exceed a wire limit. Errors retain `code`, `operation`, `message` and `path`. `invalid_json` covers syntax and scalar encoding failures, `invalid_wire` covers envelope/container shape, and `unsupported_wire_version` rejects another profile version. `invalid_codec` and `codec_error` report absent or failing injected codecs. Existing grammar errors and `query_limit` remain structured errors as well. ## Query live state explicitly [`server:query_panes(options)`]() returns a `Request>`. [`server:query(options)`]() accepts `kind` for session, window, pane, window_link, client or buffer records. Both return [`rows`](), a canonical Selection, plus the captured `snapshot`, executed [`plan`](), acquisition interval, `complete` flag and detected `races`. Collection methods on these results remain local. Pass structured `where` criteria and choose a `pushdown` mode: | Mode | Behavior | | --- | --- | | `never` | Capture the graph and evaluate all criteria locally. | | `auto` | Also apply supported necessary pane predicates at the source. | | `require` | Reject an incomplete native translation before any listing. | Native translation currently supports bounded equality tests on selected pane IDs, booleans and integer fields. Other criteria remain local. AND can supply necessary source predicates; partial OR, NOT and relationship predicates cannot. All entity kinds support local evaluation. `require` for another entity kind reports `unsupported_pushdown`. [`server:explain_panes(options)`]() and [`server:explain(options)`]() return Requests with the ordered command phases, projections, relation hydration paths, pushed predicates and residual reasons. Explaining performs no tmux I/O. Inputs and projections validate before any live dispatch and are copied so later caller mutation cannot change the query. The `snapshot` option accepts [snapshot acquisition options](https://libtmux.org/en/lua/latest/guides/snapshots/). Required criterion fields are added to explicit projections. The current implementation captures the whole relationship graph before an optional native candidate listing. It preserves canonical order and linked-window context; filtering candidate IDs never removes children from quantified relationships. This establishes semantics, not a performance advantage. The graph and candidate listing cover different moments. `candidate_missing` reports a candidate absent from the captured graph; `candidate_changed` reports disagreement with a pushed predicate. `complete=true` means no known inconsistency, not an atomic view. [`snapshot.strict`]() adds its one topology verification pass; it cannot freeze state across the later candidate listing. The acquisition interval covers both phases. Snapshot and candidate listing each apply the requested row/byte limits; retained data also shares the runtime byte budget. Expert `native_filter` accepts an explicit pane format, up to 16 KiB. It is mutually exclusive with `where` and `pushdown`. It uses tmux's format language as supplied, has no equivalent local predicate, and receives no portability guarantee. Use structured criteria for untrusted data. The [public live-query fixture](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/tests/integration/live_query.lua) exercises linked-window duplicates, projected fields, relationship quantifiers and an expert filter through both adapters. --- # Read and paste named buffers Source: https://libtmux.org/en/lua/latest/guides/buffers/ > Read and paste named buffers: libtmux documentation. Buffers hold bytes in the tmux daemon. Use an explicit name for every read, write, deletion and paste; these methods never infer the most recent buffer. Each live operation returns a Request through the PROCESS endpoint. ```lua assert(server:set_buffer("build-output", "one\000two\n"):await()) local content = assert(server:show_buffer("build-output"):await()) assert(content.bytes == "one\000two\n") assert(pane:paste_buffer("build-output", { bytes = "raw", linefeed_separator = true, }):await()) ``` The executable [integration fixture](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/tests/integration/buffer.lua) includes connection setup, owned pane readers, output barriers and teardown. ## Storage and identity [`server:set_buffer(name, bytes)`]() replaces the current value at that name. Input accepts one byte through one MiB, including NUL, invalid UTF-8 and trailing newlines. It uses native stdin loading, so no shell or argv decoder processes the value. Empty input is rejected with `invalid_argument`: tmux would accept it without creating or clearing a buffer. Delete explicitly to remove the value. New names must be nonempty UTF-8, at most 4,096 bytes, without NUL, ASCII controls, DEL or backslash. The excluded creation forms return `unsupported_name`; some tmux releases accept them, while newer name cleaning can change their stored key. Further native name validation still applies. Spaces, leading dashes and `#{...}` are literal. Buffer names do not undergo tmux format expansion. Use [`pane:capture_to_buffer(name, options)`](https://libtmux.org/en/lua/latest/guides/panes/#capture-and-text) to store a native pane capture directly. It uses these creation-name rules; empty capture leaves the named slot unchanged. Native buffer capture does not add the newline used by capture's printed output. [`server:show_buffer(name)`]() returns `{ name, bytes }` with a pure `text()` method. `bytes` preserves exact stdout. `text()` requires valid UTF-8 and performs no trimming, replacement or newline normalization. Invalid UTF-8 returns `nil, err` with `invalid_utf8`. Mutating this returned record changes neither the daemon's value nor future Requests. [`server:delete_buffer(name)`]() removes the current value on tmux 3.4 and later. It returns `unsupported` before dispatch on 3.2a, 3.3 and 3.3a: those releases can delete the most recent buffer when the requested name is missing. Checking existence first would still race with other clients. This limitation does not affect [`paste_buffer`]() with [`delete_after`](), whose native lookup rejects missing names before deletion. Read, delete and paste accept broader exact observed names: nonempty NUL-free strings up to 4,096 bytes. On supported operations, a missing buffer retains tmux's error and native receipt. A name identifies a current slot, not a persistent buffer incarnation. Another client can replace its value after a snapshot or read. These methods operate on the value present when tmux executes them; no preflight or transaction claim hides that possibility. ## Paste behavior [`pane:paste_buffer(name, options)`]() targets the handle's exact pane ID and adds no Enter. Completion means the native command finished; it does not prove an application received or consumed the bytes. | Option | Behavior | | --- | --- | | `bytes = "native"` | Default: preserve the connected daemon's native policy. tmux 3.7+ sanitizes control and invalid UTF-8 bytes; earlier releases paste raw bytes. | | `bytes = "raw"` | Disable that sanitization with `-S` on 3.7+; earlier releases already behave this way. Newline conversion remains separately controlled. | | `linefeed_separator = true` | Preserve LF. By default, tmux changes each LF to CR. | | `separator = text` | Replace each LF with this bounded NUL-free string, including empty. Excludes [`linefeed_separator`](), even explicit false. | | `bracket = true` | Add native bracketed-paste wrappers only when the pane has enabled that terminal mode. | | `delete_after = true` | Remove the named buffer after native paste processing. | Input-disabled panes can accept paste without receiving bytes, including a successful [`delete_after`](). Paste does not use the send-keys dispatcher; do not assume its copy-mode or synchronized-pane routing. Native aliases and hooks remain observable as described in [command execution](https://libtmux.org/en/lua/latest/guides/commands/). ## Bounds and effects Options must be plain records and are copied before dispatch. The nested `process` options accept timeout, deadline, output limit and drain/kill limits from [Pane operations](https://libtmux.org/en/lua/latest/guides/panes/). Buffer output defaults to one MiB and cannot be raised above that bound. Overflow returns an error with available partial output, never a successful truncated BufferValue. Runtime input and output reservations remain charged through delivery. Closed or stale generations reject new work; continuity lost after native success preserves `effect = "completed"` and the receipt. Cancellation after dispatch can have an unknown effect and never retries the mutation or kills the target pane. Binary append, buffer renaming and explicit file load/save remain pending typed APIs. No read-concatenate-write operation is presented as atomic. --- # Switch and detach clients Source: https://libtmux.org/en/lua/latest/guides/clients/ > Switch and detach clients: libtmux documentation. Use an explicit client name and TTY from a snapshot. A selector addresses the current attachment at that name, including a replacement that attached after the snapshot. Client records do not prove attachment continuity. Inside a [runtime task](https://libtmux.org/en/lua/latest/guides/runtime/), with a connected `server`, choose the client and destination session by their observed names: ```lua local snapshot = assert(server:snapshot():await()) local observed = snapshot.clients:where({ name = "/dev/pts/7" }):one() local record = snapshot.sessions:where({ name = "work" }):one() local destination = assert(server:handle(snapshot, record)) local selector = { name = observed.name, tty = observed.tty } assert(server:switch_client(selector, destination):await()) ``` [`switch_client`]() requires a Session handle from the same Server. Its private session ID determines the destination; changing a returned reference cannot redirect the request. By default, switching preserves the destination's environment. Set `{ update_environment = true }` to apply the client's native `update-environment` values. Switching still triggers tmux's attachment, selection, sizing, focus and lifecycle effects. [`server:detach_client(selector)`]() detaches that current client. It neither detaches all clients nor requests a parent-process signal or shell command. Success means the native detach command completed; it does not mean the borrowed terminal process was reaped. Closing the library connection leaves other attached clients running. Both methods return Requests that resolve to `true` on native completion. The [owned-terminal fixture](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/tests/integration/test_client.py) runs these [public API operations](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/tests/integration/client.lua) through standalone Lua and Neovim, including same-process reconnection and environment updates. ## Selection and failure The selector must be a plain record containing only `name` and `tty`. Both are exact NUL-free byte strings of at most 4,096 bytes. `name` must be nonempty; `tty` may be empty for a client without a terminal. No implicit current client or abbreviated name is selected. A fresh listing checks the complete name/TTY pair and native lookup aliases. Missing pairs return `missing_target`; multiple native matches return `ambiguous_target`. Neither dispatches a mutation. The listing and mutation are separate commands: another attachment can replace the selected client between them. No PID or timestamp check can prove continuity across native detach/exec/reconnect. Use these methods only when addressing the current attachment is the intended operation. Selectors and options are copied before I/O. Closed handles and stale daemon generations reject work. A failure before mutation dispatch has `effect = "not_sent"`; cancellation after dispatch may have an unknown effect. Continuity loss after success retains the native receipt and `effect = "completed"`. Mutations are never retried automatically. Native aliases and hooks follow the [command execution contract](https://libtmux.org/en/lua/latest/guides/commands/). The `process` options accept `timeout`, `deadline`, `max_output_bytes`, `drain_timeout` and `kill_timeout`. The output cap defaults to one MiB and cannot exceed it. Each subprocess has its own timeout; an absolute deadline also bounds later subprocesses. Preflight accepts at most 1,024 client rows. Malformed or oversized listings fail without mutating a target. Runtime byte capacity covers input, listing data and native receipts through delivery. ## Interactive attachment [`session:attach()`]() returns `unsupported_tty` before spawning: the current luv and Neovim adapters do not own an interactive terminal. It does not borrow the editor's terminal or turn a control observation into an interactive attachment. Interactive terminal ownership, client navigation, key tables and read-only toggles remain pending capabilities. --- # tmux option and hook reference Source: https://libtmux.org/en/lua/latest/guides/options/ > tmux option and hook reference: libtmux documentation. This generated catalog records every canonical built-in option and hook in the 13 released tmux versions listed below. It describes native types and storage scopes; it does not establish runtime or platform compatibility. Edit [the catalog](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/data/tmux-options.json), then regenerate: ```console $ python scripts/generate_options.py ``` Check generated Lua metadata and this reference without changing files: ```console $ python scripts/generate_options.py --check ``` Both commands run offline with Python and the pinned StyLua formatter. `--verify-source` additionally accepts a local tmux Git checkout and checks every release tag, pinned source digest, definition and line anchor. It does not download sources, build tmux or start a server. ## Values and scopes Built-in names select their native storage scope; command flags alone do not enforce the caller's intended scope. Session and window defaults are separate global stores. Pane-capable options also support window storage; there is no global pane store. Unknown release strings require new source evidence: the private catalog does not fall back to the latest version. Flags use booleans, numbers use exact bounded integers, and choices use literal strings, including numeric-looking choices such as `"24"`. Keys, colours, styles and commands retain their native string grammars. A command value is tmux command-list source, not shell argv. Native grammar validation and remote conditions such as shell suitability still require tmux. Arrays retain native zero-based sparse indices and their element type. The separator is a set of splitting characters, not a reversible codec. An omitted array separator means space/comma; an empty separator preserves one complete command-list entry. Indexed assignment avoids splitting. All built-in hooks are command arrays; a scalar command option is not a hook. User options beginning with `@` are separate string scalars. Global built-in unset restores the default; local unset removes an override. Native aliases, prefix matching, default values and descriptive option text are outside this catalog. Source integer limits assume the supported target ABIs' 32-bit `int` and 16-bit `short`; the largest bound is 4294967295. ## Source releases | Release | Built-ins, including hooks | Hooks | | --- | ---: | ---: | | [3.2a](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c) | 165 | 61 | | [3.3](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c) | 181 | 65 | | [3.3a](https://github.com/tmux/tmux/blob/0b355ae8114511e1ff6359272b164f1cdf718e80/options-table.c) | 181 | 65 | | [3.4](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/options-table.c) | 186 | 65 | | [3.5](https://github.com/tmux/tmux/blob/ac44566c9c7e3e94d23be6def4c7ae83472543f5/options-table.c) | 190 | 66 | | [3.5a](https://github.com/tmux/tmux/blob/549c35b06165f6ae023115eb76f83f2cbf945395/options-table.c) | 190 | 66 | | [3.6](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c) | 210 | 68 | | [3.6a](https://github.com/tmux/tmux/blob/cc117b5048f77a4842820f8ebbe3a86e5c077224/options-table.c) | 210 | 68 | | [3.6b](https://github.com/tmux/tmux/blob/0623d1e968423ad0c192e0d8debf1258671063d5/options-table.c) | 210 | 68 | | [3.7](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c) | 221 | 68 | | [3.7a](https://github.com/tmux/tmux/blob/0e418b62d259ce8da8970f75732cc6632ee4c3a0/options-table.c) | 221 | 68 | | [3.7b](https://github.com/tmux/tmux/blob/e802909de06012a4df6209d55e86487c56223163/options-table.c) | 221 | 68 | | [3.7c](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/options-table.c) | 221 | 68 | Full commit identities, hashes for `options-table.c`, `options.c` and `tmux.h`, and per-entry source anchors are recorded in the source catalog. Repeated release labels below mean the extracted metadata is identical, not that defaults or other native behavior are identical. ## Options | Name | Releases | Scope | Value | Array separator | | --- | --- | --- | --- | --- | | [`activity-action`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L346) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | [`none`](), [`any`](), `current`, `other` | — | | [`aggressive-resize`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L753) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | flag | — | | [`allow-passthrough`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L804) | 3.3, 3.3a | window, pane | flag | — | | [`allow-passthrough`](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/options-table.c#L859) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | `off`, `on`, `all` | — | | [`allow-rename`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L763) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | flag | — | | [`allow-set-title`](https://github.com/tmux/tmux/blob/ac44566c9c7e3e94d23be6def4c7ae83472543f5/options-table.c#L900) | 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | flag | — | | [`alternate-screen`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L771) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | flag | — | | [`assume-paste-time`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L354) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 0..2147483647 | — | | [`automatic-rename`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L779) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | flag | — | | [`automatic-rename-format`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L786) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`backspace`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L193) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | key | — | | [`base-index`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L365) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 0..2147483647 | — | | [`bell-action`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L374) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | [`none`](), [`any`](), `current`, `other` | — | | [`buffer-limit`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L200) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | 1..2147483647 | — | | [`clock-mode-colour`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L794) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | colour | — | | [`clock-mode-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L801) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a | window | `12`, `24` | — | | [`clock-mode-style`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1093) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | `12`, `24`, `12-with-seconds`, `24-with-seconds` | — | | [`codepoint-widths`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L306) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | string; sparse array | `","` | | [`command-alias`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L210) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | string; sparse array | `","` | | [`copy-command`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L225) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | string | — | | [`copy-mode-current-line-number-style`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L1208) | 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`copy-mode-current-match-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L818) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`copy-mode-line-number-style`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L1217) | 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`copy-mode-line-numbers`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L1226) | 3.7, 3.7a, 3.7b, 3.7c | window | `off`, `default`, `absolute`, `relative`, `hybrid` | — | | [`copy-mode-mark-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L827) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`copy-mode-match-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L809) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`copy-mode-position-format`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1128) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | string | — | | [`copy-mode-position-style`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1140) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`copy-mode-selection-style`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1149) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`cursor-colour`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L245) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | colour | — | | [`cursor-style`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L252) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | `default`, `blinking-block`, `block`, `blinking-underline`, `underline`, `blinking-bar`, `bar` | — | | [`default-client-command`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L338) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | command | — | | [`default-command`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L382) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string | — | | [`default-shell`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L390) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string | — | | [`default-size`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L397) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string | — | | [`default-terminal`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L233) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | string | — | | [`destroy-unattached`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L405) | 3.2a, 3.3, 3.3a | session | flag | — | | [`destroy-unattached`](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/options-table.c#L488) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `off`, `on`, `keep-last`, `keep-group` | — | | [`detach-on-destroy`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L413) | 3.2a, 3.3, 3.3a | session | `off`, `on`, `no-detached` | — | | [`detach-on-destroy`](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/options-table.c#L497) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `off`, `on`, `no-detached`, [`previous`](), `next` | — | | [`display-panes-active-colour`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L422) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | colour | — | | [`display-panes-colour`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L429) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | colour | — | | [`display-panes-time`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L436) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 1..2147483647 | — | | [`display-time`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L446) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 0..2147483647 | — | | [`editor`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L240) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | string | — | | [`escape-time`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L247) | 3.2a | server | 0..2147483647 | — | | [`escape-time`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L274) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | 0..2147483647 | — | | [`exit-empty`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L256) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | flag | — | | [`exit-unattached`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L263) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | flag | — | | [`extended-keys`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L271) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | `off`, `on`, `always` | — | | [`extended-keys-format`](https://github.com/tmux/tmux/blob/ac44566c9c7e3e94d23be6def4c7ae83472543f5/options-table.c#L320) | 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | `csi-u`, `xterm` | — | | [`fill-character`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L885) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`focus-events`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L280) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | flag | — | | [`focus-follows-mouse`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L670) | 3.7, 3.7a, 3.7b, 3.7c | session | flag | — | | [`get-clipboard`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L414) | 3.7, 3.7a, 3.7b, 3.7c | server | `off`, `buffer`, `request`, `both` | — | | [`history-file`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L287) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | string | — | | [`history-limit`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L456) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 0..2147483647 | — | | [`initial-repeat-time`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L664) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 0..2000000 | — | | [`input-buffer-size`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L416) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | 1048576..4294967295 | — | | [`key-table`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L468) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string | — | | [`lock-after-time`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L476) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 0..2147483647 | — | | [`lock-command`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L486) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string | — | | [`main-pane-height`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L836) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`main-pane-width`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L844) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`menu-border-lines`](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/options-table.c#L359) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | `single`, [`double`](), `heavy`, `simple`, `rounded`, `padded`, [`none`]() | — | | [`menu-border-style`](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/options-table.c#L350) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`menu-selected-style`](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/options-table.c#L341) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`menu-style`](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/options-table.c#L332) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`message-command-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L493) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | style string | — | | [`message-format`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L736) | 3.7, 3.7a, 3.7b, 3.7c | session | string | — | | [`message-limit`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L295) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | 0..2147483647 | — | | [`message-line`](https://github.com/tmux/tmux/blob/9ae69c3795ab5ef6b4d760f6398cd9281151f632/options-table.c#L587) | 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `0`, `1`, `2`, `3`, `4` | — | | [`message-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L503) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | style string | — | | [`mode-keys`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L852) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | `emacs`, `vi` | — | | [`mode-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L860) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`monitor-activity`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L869) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | flag | — | | [`monitor-bell`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L876) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | flag | — | | [`monitor-silence`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L883) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | 0..2147483647 | — | | [`mouse`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L512) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | flag | — | | [`other-pane-height`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L894) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`other-pane-width`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L902) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`pane-active-border-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L910) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | window | style string | — | | [`pane-active-border-style`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L1315) | 3.7, 3.7a, 3.7b, 3.7c | window, pane | style string | — | | [`pane-base-index`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L919) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | 0..65535 | — | | [`pane-border-format`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L928) | 3.2a | window | string | — | | [`pane-border-format`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L984) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | string | — | | [`pane-border-indicators`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L992) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | `off`, `colour`, `arrows`, `both` | — | | [`pane-border-lines`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L936) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a | window | `single`, [`double`](), `heavy`, `simple`, [`number`]() | — | | [`pane-border-lines`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1274) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | `single`, [`double`](), `heavy`, `simple`, [`number`](), `spaces` | — | | [`pane-border-status`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L944) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | `off`, `top`, `bottom` | — | | [`pane-border-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L952) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | window | style string | — | | [`pane-border-style`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L1374) | 3.7, 3.7a, 3.7b, 3.7c | window, pane | style string | — | | [`pane-colours`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1027) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | colour; sparse array | `" ,"` | | [`pane-scrollbars`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1308) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | `off`, `modal`, `on` | — | | [`pane-scrollbars-position`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1325) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | `right`, `left` | — | | [`pane-scrollbars-style`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1316) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | style string | — | | [`pane-status-current-style`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L924) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`pane-status-style`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L933) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`popup-border-lines`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1053) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | `single`, [`double`](), `heavy`, `simple`, `rounded`, `padded`, [`none`]() | — | | [`popup-border-style`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1044) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`popup-style`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1035) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`prefix`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L521) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | key | — | | [`prefix-timeout`](https://github.com/tmux/tmux/blob/ac44566c9c7e3e94d23be6def4c7ae83472543f5/options-table.c#L388) | 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | 0..2147483647 | — | | [`prefix2`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L528) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | key | — | | [`prompt-command-cursor-style`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L997) | 3.7, 3.7a, 3.7b, 3.7c | session | `default`, `blinking-block`, `block`, `blinking-underline`, `underline`, `blinking-bar`, `bar` | — | | [`prompt-cursor-colour`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L943) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | colour | — | | [`prompt-cursor-style`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L950) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `default`, `blinking-block`, `block`, `blinking-underline`, `underline`, `blinking-bar`, `bar` | — | | [`prompt-history-limit`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L332) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | 0..2147483647 | — | | [`remain-on-exit`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L961) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b | window, pane | `off`, `on`, `failed` | — | | [`remain-on-exit`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L1443) | 3.7, 3.7a, 3.7b, 3.7c | window, pane | `off`, `on`, `failed`, `key` | — | | [`remain-on-exit-format`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1071) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | string | — | | [`renumber-windows`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L535) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | flag | — | | [`repeat-time`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L543) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a | session | 0..32767 | — | | [`repeat-time`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L759) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 0..2000000 | — | | [`scroll-on-clear`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1084) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | flag | — | | [`session-status-current-style`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L958) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`session-status-style`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L967) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`set-clipboard`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L304) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | `off`, `external`, `on` | — | | [`set-titles`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L554) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | flag | — | | [`set-titles-string`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L561) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string | — | | [`silence-action`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L568) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | [`none`](), [`any`](), `current`, `other` | — | | [`status`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L576) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `off`, `on`, `2`, `3`, `4`, `5` | — | | [`status-bg`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L584) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | colour | — | | [`status-fg`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L592) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | colour | — | | [`status-format`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L600) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string; sparse array | `" ,"` | | [`status-interval`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L612) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 0..2147483647 | — | | [`status-justify`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L622) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `left`, `centre`, `right`, `absolute-centre` | — | | [`status-keys`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L630) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `emacs`, `vi` | — | | [`status-left`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L638) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string | — | | [`status-left-length`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L645) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 0..32767 | — | | [`status-left-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L654) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | style string | — | | [`status-position`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L663) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `top`, `bottom` | — | | [`status-right`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L671) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string | — | | [`status-right-length`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L681) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | 0..32767 | — | | [`status-right-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L690) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | style string | — | | [`status-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L699) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | style string | — | | [`synchronize-panes`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L970) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | flag | — | | [`terminal-features`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L323) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | string; sparse array | `","` | | [`terminal-overrides`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L314) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | string; sparse array | `","` | | [`tiled-layout-max-columns`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1397) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | 0..65535 | — | | [`tree-mode-preview-format`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L1491) | 3.7, 3.7a, 3.7b, 3.7c | window, pane | string | — | | [`tree-mode-preview-style`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L1500) | 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`update-environment`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L708) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string; sparse array | `" ,"` | | [`user-keys`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L334) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | string; sparse array | `","` | | [`variation-selector-always-wide`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L532) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | server | flag | — | | [`visual-activity`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L718) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `off`, `on`, `both` | — | | [`visual-bell`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L727) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `off`, `on`, `both` | — | | [`visual-silence`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L736) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | `off`, `on`, `both` | — | | [`window-active-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L977) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | style string | — | | [`window-pane-current-status-format`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L1522) | 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`window-pane-status-format`](https://github.com/tmux/tmux/blob/81f88f8517c9fc5371b56cf117530c6b477c96ac/options-table.c#L1529) | 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`window-size`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L986) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | [`largest`](), [`smallest`](), `manual`, `latest` | — | | [`window-status-activity-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1007) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`window-status-bell-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1016) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`window-status-current-format`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1025) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`window-status-current-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1032) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`window-status-format`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1041) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`window-status-last-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1049) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`window-status-separator`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1058) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | string | — | | [`window-status-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1065) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | style string | — | | [`window-style`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L998) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | style string | — | | [`word-separators`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L745) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | string | — | | [`wrap-search`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1075) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | flag | — | | [`xterm-keys`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1083) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | flag | — | ## Hooks | Name | Releases | Scope | Value | Array separator | | --- | --- | --- | --- | --- | | [`after-bind-key`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1092) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-capture-pane`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1093) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-copy-mode`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1094) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-display-message`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1095) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-display-panes`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1096) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-kill-pane`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1097) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-list-buffers`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1098) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-list-clients`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1099) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-list-keys`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1100) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-list-panes`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1101) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-list-sessions`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1102) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-list-windows`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1103) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-load-buffer`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1104) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-lock-server`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1105) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-new-session`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1106) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-new-window`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1107) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-paste-buffer`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1108) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-pipe-pane`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1109) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-queue`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1110) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-refresh-client`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1111) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-rename-session`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1112) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-rename-window`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1113) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-resize-pane`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1114) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-resize-window`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1115) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-save-buffer`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1116) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-select-layout`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1117) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-select-pane`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1118) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-select-window`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1119) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-send-keys`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1120) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-set-buffer`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1121) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-set-environment`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1122) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-set-hook`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1123) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-set-option`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1124) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-show-environment`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1125) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-show-messages`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1126) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-show-options`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1127) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-split-window`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1128) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`after-unbind-key`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1129) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`alert-activity`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1130) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`alert-bell`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1131) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`alert-silence`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1132) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`client-active`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1255) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`client-attached`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1133) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`client-dark-theme`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1571) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`client-detached`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1134) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`client-focus-in`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1258) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`client-focus-out`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1259) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`client-light-theme`](https://github.com/tmux/tmux/blob/0dac7fe434d029a4f0b819cba8eb7963df291990/options-table.c#L1570) | 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`client-resized`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1135) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`client-session-changed`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1136) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`command-error`](https://github.com/tmux/tmux/blob/ac44566c9c7e3e94d23be6def4c7ae83472543f5/options-table.c#L1350) | 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`pane-died`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1137) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | command; sparse array | empty | | [`pane-exited`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1138) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | command; sparse array | empty | | [`pane-focus-in`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1139) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | command; sparse array | empty | | [`pane-focus-out`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1140) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | command; sparse array | empty | | [`pane-mode-changed`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1141) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | command; sparse array | empty | | [`pane-set-clipboard`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1142) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | command; sparse array | empty | | [`pane-title-changed`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1143) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window, pane | command; sparse array | empty | | [`session-closed`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1144) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`session-created`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1145) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`session-renamed`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1146) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`session-window-changed`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1147) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`window-layout-changed`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1148) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | command; sparse array | empty | | [`window-linked`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1149) | 3.2a | window | command; sparse array | empty | | [`window-linked`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1274) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | | [`window-pane-changed`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1150) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | command; sparse array | empty | | [`window-renamed`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1151) | 3.2a, 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | command; sparse array | empty | | [`window-resized`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1277) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | window | command; sparse array | empty | | [`window-unlinked`](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/options-table.c#L1152) | 3.2a | window | command; sparse array | empty | | [`window-unlinked`](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/options-table.c#L1278) | 3.3, 3.3a, 3.4, 3.5, 3.5a, 3.6, 3.6a, 3.6b, 3.7, 3.7a, 3.7b, 3.7c | session | command; sparse array | empty | --- # Topology operations Source: https://libtmux.org/en/lua/latest/guides/topology/ > Topology operations: libtmux documentation. Session, Window, Pane and WindowLink handles perform explicit mutations through the PROCESS endpoint. Each operation returns a Request that resolves to `true` when tmux successfully processes it. Refresh or capture a snapshot explicitly to inspect the resulting state; existing records do not change in place. ```lua assert(session:rename("build"):await()) assert(window:resize({ width = 120, height = 40 }):await()) assert(window:layout({ named = "tiled" }):await()) ``` The [integration fixture](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/tests/integration/topology.lua) includes setup, native-state assertions and cleanup through both runtime adapters. ## Names and removal [`session:rename(name)`]() and [`window:rename(name)`]() use their stable native IDs. Names are nonempty NUL-free strings up to 1,024 bytes. Session names also exclude dots, colons, ASCII controls and DEL. Format markers remain literal; native name validation and cleaning still apply. Releases differ in accepted bytes and escaping, so success does not promise byte-exact storage. Exact tmux 3.7 also rejects dots and colons in Window names. Renaming a Window turns off its automatic rename option. [`session:kill()`]() destroys that session and its links. A linked window can survive in another session. [`window:kill()`]() destroys the window and **every** link to it, potentially removing sessions left without windows. Neither method targets all other sessions or windows. Use these only for intended mutations; Request cancellation never implies either operation. ## Window navigation [`session:navigate_window(direction)`]() accepts `"next"`, `"previous"` or `"last"`. Next/previous support `activity = true` to select a window with a native alert. Last rejects the `activity` option, including explicit false. Navigation changes the session's active window and follows native hooks and grouped-session behavior. [`session:renumber_windows()`]() renumbers from the session's `base-index` option. It preserves Window IDs but invalidates captured link indices. It is a separate operation from moving one window. ## Window placements A WindowLink identifies one placement by session, index and Window ID. Use [`creation.window_link`]() or a handle from [`snapshot.window_links`]() when an operation needs that exact placement, including duplicate links in one session. `link:select()` selects its index within its session. `link:link(destination)` creates another placement; [`link:move(destination)`]() also removes this source placement. Destinations accept one of these plain records: - `{ session = session, index = 5 }` chooses an explicit index. Omitting `index` requests a native free index from `base-index`, not append. - `{ link = anchor, position = "before"|"after" }` inserts relative to an existing placement and may shift indices. - `{ link = victim, position = "at" }` requires `{ replace = true }` as the operation options. Replacement can destroy the victim Window if it has no other links. A numeric index alone never authorizes replacement. Both operations default to `select = false`. Removal of an active source or replacement of an active destination can still force native selection. Occupied numeric destinations return native errors; the library never searches for a different destination or retries. `link:swap(other)` exchanges the Windows in two placements. By default, selected **slots** remain selected, although their Window identities change. `select = true` selects the destination slot, and the source slot when the sessions differ. Swapping two placements of the same Window is a native no-op. [`link:unlink()`]() removes only this placement and refuses native last-link destruction. `kill_if_last = true` permits that destruction. Grouped sessions retain tmux's synchronization and last-link rules. Native refusal is not rollback: insertion can shift indices before a later grouped-session error. Each operation checks the stored source tuple, and any destination link tuple, in the native command queue immediately before the mutation. A recognized mismatch returns `stale_target`, `effect = "not_sent"`, and the native receipt. Old handles never rebind automatically after index reuse, movement or swapping. Recreating the identical tuple cannot be distinguished from continuous identity; native command aliases can also change these checks. The [native-command contract](https://libtmux.org/en/lua/latest/guides/commands/) applies to the generated guards and their mutation branches. They are not a transaction or an unconditional compare-and-swap guarantee. Success returns `true`; capture a new snapshot explicitly to find resulting placements. No predicted index or hidden post-mutation read constructs a new WindowLink handle. ## Window size and layout [`window:resize(options)`]() accepts exactly one form: - `width` and/or `height`, integers from 1 to 10,000. - `direction = "left"|"right"|"up"|"down"`, with `amount` from 1 to 10,000, defaulting to one. - `largest = true` or `smallest = true`, using tmux's native client-size rule. Native resizing sets `window-size` to manual. Layout constraints and available client sizes can affect the result; the command's success is not a dimensions oracle. Resizing affects every link to the Window. [`window:layout(options)`]() also accepts exactly one form: - [`named`](): `even-horizontal`, `even-vertical`, `main-horizontal`, `main-vertical` or `tiled`. The mirrored main layouts require tmux 3.5+. - `layout`: an exported native layout string with a four-digit hexadecimal checksum, comma and body, bounded at 65,536 bytes. - `next = true`, `previous = true` or `restore = true`. Malformed custom-layout headers return `invalid_layout` before dispatch. This avoids faulty error handling in tmux 3.3/3.3a and short-header reads in older native parsers. Use [`named`]() for standard layout names. Layout operations unzoom before native checksum and body validation. A rejected layout can therefore change zoom state. A nonzero native exit carries its receipt and `effect = "completed"`; it does not establish rollback. Custom layout syntax is tmux's grammar and is not evaluated as Lua or shell text. ## Restart a window `window:respawn({ context = link, ... })` requires a WindowLink naming this Window. Its session supplies the native launch context, including inherited environment. The link is checked in the native queue before respawn; the method never chooses an arbitrary session from a global Window ID. Launch options match [creation](https://libtmux.org/en/lua/latest/guides/creation/): literal `argv` or explicit `shell`, absolute `cwd` and a per-process `environment` map. Omitting launch text reuses the previous command. Working-directory validation is asynchronous and completes before dispatch. `kill = true` permits replacement of running processes; otherwise tmux refuses an active window. Respawn retains the Window ID and its first Pane, removes sibling panes, and resets layout through every link to the Window. It can fail after destructive preparation; a native error does not establish rollback. Existing sibling Pane handles do not become references to the restarted first Pane. ## Move a pane [`pane:move_to(target, options)`]() moves the same Pane into the target Pane's Window. It defaults to a vertical split with `select = false`. Choose `direction = "horizontal"`, `size` from 1 to 10,000 cells, or `percent` from 1 to 100. Size and percent exclude one another. `before = true` changes native geometry; it does not promise a matching pane-index order. `full_size = true` extends the split across the Window. `select = true` requires `target_link = link`, identifying the exact placement whose session and index will be selected. An optional target link also checks membership when selection is disabled. The library checks that placement and the target Pane's current Window separately in the native queue, then submits the compound target. A moved target Pane produces `stale_target`; a target that tmux cannot resolve can instead retain its native command error. Movement changes global pane membership through all Window links. Moving the last Pane destroys the old Window and all its placements. Native layout and selection changes can happen before a later error. Moving a Pane preserves its ID and running process; it does not restart that process. ## Break a pane into a window [`pane:break_out(source_link, destination, options)`]() requires the Pane's exact source WindowLink. Destinations accept a Session with an optional numeric index, or an anchor WindowLink with `position = "before"|"after"`, as described under [window placements](https://libtmux.org/en/lua/latest/guides/topology/#window-placements). Replacement is not supported; an occupied numeric destination returns the native error. The source placement and current Pane membership are checked in the native queue, along with any destination anchor. The operation preserves the Pane ID and running process. With multiple panes, tmux creates a new Window and keeps the source Window's links. With one pane, it moves the specified placement of the existing Window; other links to that Window survive. `select` defaults to false, though removal of an active placement can force native selection. `name` follows the Window name rules above. Omitting it preserves native naming: a singleton retains its existing Window name and options; a newly created Window takes the native default name and inherited options. An explicit name disables automatic rename for the resulting Window. Exact tmux 3.7 has a native multi-pane naming defect. The library supplies a placeholder when no name is requested, avoiding the faulty native null-name path. For a named multi-pane break, it follows the break with a rename of the same Pane's Window. This repair fires native rename notifications and `after-rename-window` hooks. Singleton breaks and other releases need no repair. A repair failure can occur after the Pane has moved; it is not rollback. ## Effects and boundaries Options are copied before dispatch and must be plain records. These methods accept the same nested `process` limits as [Pane operations](https://libtmux.org/en/lua/latest/guides/panes/). Input is bounded at one MiB per operation. A stale generation or invalid target fails before dispatch. If continuity is lost after successful native completion, the error preserves `effect = "completed"` and that receipt. Mutations are never retried automatically. Native [aliases and hooks](https://libtmux.org/en/lua/latest/guides/commands/) remain observable. These APIs do not promise transactions or protection against aliases that replace a built-in command. --- # C# workspace internals Source: https://libtmux.org/en/csharp/latest/workspace/internals/ > Architecture and development interfaces of the C# workspace builder. Build and inspect tmux sessions from application code with the workspace library. To load files from a terminal, start with the [native CLI walkthrough](https://libtmux.org/en/csharp/latest/workspace/guides/installation/). ## Builder pipeline [`WorkspaceFile.Parse`]() validates the YAML. [`WorkspaceBuilder.BuildAsync`]() creates the session through a supplied core [`Server`]() and returns its materialized objects. The caller supplies file reading, cancellation, command-line handling, attachment, and server lifetime. ## Read the implementation - [Guides](https://libtmux.org/en/csharp/latest/workspace/internals/guides/) show builder setup and application code. - [Topics](https://libtmux.org/en/csharp/latest/workspace/internals/topics/) explain configuration, behavior, and failures. - [Examples](https://libtmux.org/en/csharp/latest/workspace/internals/examples/) exercise the builder through the language API. - [API](https://libtmux.org/en/csharp/latest/workspace/reference/) links the configuration and construction interfaces. ## Implementation scope [`LibTmux.Workspace`]() reads a YAML file and builds its session through LibTmux. It returns the session, materialized windows, and any layouts that tmux rejected while leaving their windows usable. Use it from a launcher or another .NET application that already controls a tmux server. The package adds YAML parsing separately from the core client. ## Package and runtime The package targets .NET 8 and .NET 10 and uses YamlDotNet. tmux must run on the host. Pin the prerelease selected by your package manager because public contracts can change between alpha versions. The parser rejects unknown fields. The caller reads the file and selects the server; parsing does not search configuration directories or load extensions. [Package documentation](https://github.com/libtmux/libtmux-dotnet/blob/6656a563ec9e07ab52e0c3ac96f7704fc94cc0c0/src/LibTmux.Workspace/README.md) --- # C++ workspace internals Source: https://libtmux.org/en/cxx/latest/workspace/internals/ > Architecture and development interfaces of the C++ workspace builder. Build and inspect tmux sessions from application code with the workspace library. To load files from a terminal, start with the [native CLI walkthrough](https://libtmux.org/en/cxx/latest/workspace/guides/installation/). ## Builder pipeline [`parse_tmuxp`]() converts YAML into typed workspace data. [`build`]() applies that data through a core [`Server`](). The `workspace_builder` target keeps YAML parsing separate from the core library. Its executables exercise parsing and builder tests; they do not load workspace files as a user application. ## Read the implementation - [Guides](https://libtmux.org/en/cxx/latest/workspace/internals/guides/) show builder setup and application code. - [Topics](https://libtmux.org/en/cxx/latest/workspace/internals/topics/) explain configuration, behavior, and failures. - [Examples](https://libtmux.org/en/cxx/latest/workspace/internals/examples/) exercise the builder through the language API. - [API](https://libtmux.org/en/cxx/latest/workspace/reference/) links the configuration and construction interfaces. ## Implementation scope The C++ repository includes a workspace consumer that builds a described tmux session and reads YAML. It exercises libtmux's public API from a separate target. The workspace headers and parser belong to `examples/workspace`. They are not installed with the core libtmux package. Use the consumer from a source checkout or adapt it into your own application with its dependencies. ## Dependencies The workspace builder uses the core C++ API. Reading YAML adds yaml-cpp to the consumer target; the core library does not acquire that dependency. Building and exercising the consumer requires the repository's CMake toolchain and tmux on a supported host. The consumer creates a new session. It does not converge an existing session or export a live session back to a workspace file. [Consumer documentation](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/README.md) --- # Go workspace internals Source: https://libtmux.org/en/go/latest/workspace/internals/ > Architecture and development interfaces of the Go workspace builder. Build and inspect tmux sessions from application code with the workspace library. To load files from a terminal, start with the [native CLI walkthrough](https://libtmux.org/en/go/latest/workspace/guides/installation/). ## Builder pipeline [`Parse`]() validates the YAML before tmux construction begins. [`Build`]() creates the session and owns a temporary control connection for construction; [`BuildInto`]() uses an existing session connection. The caller supplies file reading, deadlines, command-line handling, and attachment. ## Read the implementation - [Guides](https://libtmux.org/en/go/latest/workspace/internals/guides/) show builder setup and application code. - [Topics](https://libtmux.org/en/go/latest/workspace/internals/topics/) explain configuration, behavior, and failures. - [Examples](https://libtmux.org/en/go/latest/workspace/internals/examples/) exercise the builder through the language API. - [API](https://libtmux.org/en/go/latest/workspace/reference/) links the configuration and construction interfaces. ## Implementation scope The [`workspace`]() module parses YAML and builds a session through libtmux's Go API. It is a separate module, so applications using only the core client do not acquire a YAML dependency. Parsing validates the whole document before construction. Building returns the created session, including a session handle alongside an error when later operations fail and leave a partial workspace. ## Package and runtime Import [`github.com/libtmux/libtmux-go/workspace`](https://pkg.go.dev/github.com/libtmux/libtmux-go/workspace) together with the core [`tmux`]() package. Building requires tmux on the host. Parsing and configuration validation do not start a tmux server. The module accepts windows, panes, commands, options, environment variables and working directories. Plugin declarations and `before_script` are rejected. Check the [configuration contract](https://libtmux.org/en/go/latest/workspace/internals/topics/) before loading an existing file. [Workspace module documentation](https://github.com/libtmux/libtmux-go/blob/5f808882015a975a65acc7f9da5b3ff0d5cbdc91/workspace/README.md) --- # Java workspace internals Source: https://libtmux.org/en/java/latest/workspace/internals/ > Architecture and development interfaces of the Java workspace builder. Build and inspect tmux sessions from application code with the workspace library. To load files from a terminal, start with the [native CLI walkthrough](https://libtmux.org/en/java/latest/workspace/guides/installation/). ## Builder pipeline The public [`WorkspaceBuilder`]() facade reads or parses YAML into immutable configuration records, then builds through a supplied core [`Server`](). Parsing and applying use separate package-private helpers. The caller owns command-line handling, attachment, and the server connection. ## Read the implementation - [Guides](https://libtmux.org/en/java/latest/workspace/internals/guides/) show builder setup and application code. - [Topics](https://libtmux.org/en/java/latest/workspace/internals/topics/) explain configuration, behavior, and failures. - [Examples](https://libtmux.org/en/java/latest/workspace/internals/examples/) exercise the builder through the language API. - [API](https://libtmux.org/en/java/latest/workspace/reference/) links the configuration and construction interfaces. ## Implementation scope `libtmux-workspace` builds a new tmux session from a YAML description. It uses libtmux's Java API and returns the session after capturing the completed window and pane structure. The module accepts session names, windows, layouts, panes and ordered shell commands. It rejects unknown configuration fields instead of accepting a larger file with missing behavior. ## Package and runtime Use the [`io.github.libtmux:libtmux-workspace`](https://central.sonatype.com/artifact/io.github.libtmux/libtmux-workspace) artifact with the libtmux BOM. The module targets Java 21 and requires tmux on the host for building. Parsing YAML does not create a session. [Module documentation](https://github.com/libtmux/libtmux-java/blob/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-workspace/README.md) --- # Python workspace internals Source: https://libtmux.org/en/py/latest/workspace/internals/ > How tmuxp loads configuration and builds sessions through libtmux. These pages describe tmuxp's internal implementation for contributors and extension authors. The Python interfaces have no stability guarantee and may change between releases. Use [tmuxp load](https://libtmux.org/en/py/latest/workspace/guides/) to launch a workspace from the terminal. ## Builder pipeline The CLI reads YAML or JSON, expands shorthand and variables, applies inherited defaults, and passes the result to a workspace builder. The builder uses libtmux to create the session, windows, and panes. The CLI then handles attachment or client switching. - [Topics](https://libtmux.org/en/py/latest/workspace/internals/topics/) explain the loader pipeline and builder extension points. - [Examples](https://libtmux.org/en/py/latest/workspace/internals/examples/) show expansion and building on an isolated server. - [API](https://libtmux.org/en/py/latest/workspace/reference/) links the internal loading, building, and freezing interfaces. The upstream [Internals documentation](https://tmuxp.git-pull.com/internals/) contains the full architecture and module reference. Use the [libtmux Python API](https://libtmux.org/en/py/latest/reference/) for general tmux programming. --- # Rust workspace internals Source: https://libtmux.org/en/rs/latest/workspace/internals/ > Architecture and development interfaces of the Rust workspace builder. Build and inspect tmux sessions from application code with the workspace library. To load files from a terminal, start with the [native CLI walkthrough](https://libtmux.org/en/rs/latest/workspace/guides/installation/). ## Builder pipeline [`Workspace::from_yaml`]() parses the description. [`WorkspaceBuilder`]() turns it into a command plan or builds a new session through a borrowed [`Server`](). [`freeze`]() reads a session back into workspace data. The caller supplies file reading, the async runtime, command-line handling, and attachment. ## Read the implementation - [Guides](https://libtmux.org/en/rs/latest/workspace/internals/guides/) show builder setup and application code. - [Topics](https://libtmux.org/en/rs/latest/workspace/internals/topics/) explain configuration, behavior, and failures. - [Examples](https://libtmux.org/en/rs/latest/workspace/internals/examples/) exercise the builder through the language API. - [API](https://libtmux.org/en/rs/latest/workspace/reference/) links the configuration and construction interfaces. ## Implementation scope `tmux-workspace` creates a tmux session from a YAML description. The crate uses the public libtmux API and returns a typed session handle. A separate [`freeze`]() operation records an existing session as workspace data. Building creates a new session. It refuses an already existing session with the requested name, so repeated builds require a new name or explicit cleanup. ## Package and runtime Add `tmux-workspace` separately from the core crate. Workspace creation and freezing are asynchronous and require a running Tokio runtime and tmux on the host. Pin a prerelease explicitly; a stable-only Cargo requirement does not select an alpha release. The parser records unknown keys in `unsupported_keys`. Review those lists before building: an unrecognized field does not configure the created session. [Crate documentation](https://github.com/libtmux/libtmux-rs/blob/9331cdf556ea7a1f2589e9c3e6cece6ccdc7765c/crates/tmux-workspace/README.md) --- # Swift workspace internals Source: https://libtmux.org/en/swift/latest/workspace/internals/ > Architecture and development interfaces of the Swift workspace builder. Build and inspect tmux sessions from application code with the workspace library. To load files from a terminal, start with the [native CLI walkthrough](https://libtmux.org/en/swift/latest/workspace/guides/installation/). ## Builder pipeline [`Workspace`]() holds typed configuration or decodes JSON and optional YAML. [`WorkspaceBuilder.build`]() applies that description through an async core [`Server`](). The caller supplies file reading, server startup, command-line handling, and attachment. ## Read the implementation - [Guides](https://libtmux.org/en/swift/latest/workspace/internals/guides/) show builder setup and application code. - [Topics](https://libtmux.org/en/swift/latest/workspace/internals/topics/) explain configuration, behavior, and failures. - [Examples](https://libtmux.org/en/swift/latest/workspace/internals/examples/) exercise the builder through the language API. - [API](https://libtmux.org/en/swift/latest/workspace/reference/) links the configuration and construction interfaces. ## Implementation scope `TmuxWorkspace` builds a tmux session from Swift values or a file configuration. It is a SwiftPM library product beside the core [`LibTmux`](https://libtmux.org/en/swift/latest/reference/) product. Swift and JSON descriptions work without a YAML dependency. Enable the `YAMLWorkspaces` package trait to add YAML decoding. Building uses the same async core server API under either format. ## Existing sessions and versions The builder refuses an existing session with the requested name. On a later failure, it attempts to remove the exact session it created and reports both errors if cleanup also fails. These pages describe the current source API. The port distinguishes its unreleased source examples from the released alpha package. Use a matching source revision for these examples, or consult the release's own README when pinning a published version. [Product and version guidance](https://github.com/libtmux/libtmux-swift/blob/f02a4668570e1cc5198c941413750e021f42c214/README.md) --- # TypeScript workspace internals Source: https://libtmux.org/en/ts/latest/workspace/internals/ > Architecture and development interfaces of the TypeScript workspace builder. Build and inspect tmux sessions from application code with the workspace library. To load files from a terminal, start with the [native CLI walkthrough](https://libtmux.org/en/ts/latest/workspace/guides/installation/). ## Builder pipeline [`parseWorkspace`]() validates input data. [`planWorkspace`]() inspects the target session and reports proposed topology changes; [`applyWorkspace`]() performs the changes through a caller-owned [`Server`](). The caller supplies file reading, command-line handling, attachment, and application lifetime. ## Read the implementation - [Guides](https://libtmux.org/en/ts/latest/workspace/internals/guides/) show builder setup and application code. - [Topics](https://libtmux.org/en/ts/latest/workspace/internals/topics/) explain configuration, behavior, and failures. - [Examples](https://libtmux.org/en/ts/latest/workspace/internals/examples/) exercise the builder through the language API. - [API](https://libtmux.org/en/ts/latest/workspace/reference/) links the configuration and construction interfaces. ## Implementation scope `@libtmux/workspace` applies a declared session layout to a libtmux [`Server`](). Describe windows, panes, working directories, and shell commands as data. Applying the same description again reuses matching objects. The package manages tmux structure. It does not supervise processes or restart commands that have exited. Commands run only in newly created panes by default. ## Package and runtime Use `@libtmux/workspace` alongside `libtmux`. The published package supports Node and Bun; its YAML convenience parser requires Bun. You can use validated JavaScript objects under either runtime. Real tmux control requires tmux on the host. The package documents Linux as its supported runtime platform. Read the [configuration and convergence rules](https://libtmux.org/en/ts/latest/workspace/internals/topics/) before applying a description. The caller supplies input data; the library does not discover files or load runtime extensions. [Package documentation](https://github.com/libtmux/libtmux-ts/blob/f85b8de551353f746d50eaf36bf0112f4fe5a528/packages/workspace/README.md) --- # C# workspace builder behavior Source: https://libtmux.org/en/csharp/latest/workspace/internals/topics/ > Internal configuration, application, and failure contracts of the C# workspace builder. [`WorkspaceFile.Parse`]() produces immutable configuration before building begins. It rejects duplicate or unknown keys, wrong value shapes, multiple YAML documents, and inputs over 1 MiB. Missing session names and empty window lists are rejected before any session is created. ## Supported fields The package supports session names, working directories, scalar options, windows, panes, layouts, focus, and scalar or ordered shell commands. Working directory values remain unchanged after parsing. Call [`WorkspaceFile.Resolve`]() with the document's directory to resolve relative paths before planning. Neither parsing nor resolution contacts tmux or checks directory existence. The default plan refuses an existing session. [`WorkspacePlanOptions`]() can instead select [`Reuse`](), [`Append`](), or [`Replace`](). Reuse returns the inspected session unchanged; append adds windows; replace targets the inspected session while preserving its daemon. These choices do not reconcile arbitrary live state with the declaration. ## Pane readiness The default [`WorkspaceReadiness.Immediate`]() sends commands without waiting for shell readiness or completion. Choose [`Cooperative`]() only when the pane's startup can acknowledge that it accepts input. Each application supplies a fresh `LIBTMUX_WORKSPACE_READY` value to each pane. Startup signals that channel with tmux's `wait-for -S` command. A signal sent before the wait is preserved. The builder closes its waits and stops input to a pane whose readiness timeout expires. This is an explicit startup contract. The builder does not infer readiness from a cursor or prompt, and a startup signal does not acknowledge completion of a later workspace command. ## Construction and failures Inspect [`WorkspacePlan.Actions`]() before calling [`ApplyAsync`](). Planning records creation, input, readiness, host-script, final-capture, and conditional-cleanup actions. Application rechecks the observed daemon and session before running them. Planning observes an interval rather than a transaction; concurrent changes can invalidate its preconditions. Rejected layouts appear in [`WorkspaceResult.Unsupported`](); their windows remain available. Other tmux failures raise [`WorkspaceBuildException`](), whose `PartialResult` identifies materialized state when available. The action journal includes failures, uncertain outcomes, and actions never started. Cancellation during application raises [`WorkspaceOperationCanceledException`]() with the same partial state and journals. `CompensateOnFailure` requests cleanup of resources proven to have been created by that application, under a separate cleanup timeout. Its journal retains cleanup failures. Neither cancellation nor a thrown exception proves rollback; inspect the result and live state before retrying. [Validation and build behavior](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Workspace/README.md) --- # C++ workspace builder behavior Source: https://libtmux.org/en/cxx/latest/workspace/internals/topics/ > Internal configuration, application, and failure contracts of the C++ workspace builder. The consumer separates parsing from application. [`parse_tmuxp`]() reads a YAML document into a [`Workspace`](); [`build`]() applies the typed description through a core [`Server`](). ## Supported data Configuration covers session and window names, working directories, environment values, options, layouts, focus, window indexes, and pane commands. The YAML reader rejects keys outside its supported subset and returns a document path and reason. A [`Command`]() holds text, whether to press Enter, pauses before and after sending, and history suppression. A command with `enter: false` leaves text at the prompt. Pauses delay construction; they do not check application readiness. History suppression adds a leading space, whose effect depends on the shell's history configuration. ## Build ordering Open the core server handle after its tmux socket exists. A handle opened before daemon startup can become stale when the builder creates the first session. The consumer tests use a running isolated fixture before connecting. The builder creates all described windows and panes before delivering pane commands. It addresses panes by their actual IDs, so a configured `pane-base-index` does not redirect input to the wrong pane. Window options are applied before layouts. [`options_after`]() is applied once panes exist, which allows settings such as synchronized input to take effect after creation. Focus choices are applied after the corresponding objects exist. ## Failure effects The requested session must be new. A failure returns [`BuildError`]() with a window position and diagnostic reason. Operations completed before the failure remain in tmux; there is no rollback or attached partial-session handle in the error. Inspect the dedicated server before retrying or removing a session. The parser has its own [`ParseError`](), with a path through the YAML document. Keep parsing errors separate from tmux failures when reporting a problem to someone editing the workspace file. [Build and command contracts](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/include/libtmux_consumers/workspace.hpp); [Parsing contract](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/include/libtmux_consumers/tmuxp.hpp). --- # Go workspace builder behavior Source: https://libtmux.org/en/go/latest/workspace/internals/topics/ > Internal configuration, application, and failure contracts of the Go workspace builder. [`Parse`]() rejects unknown fields and gathers validation problems with their source lines. Parse and validation failures match [`ErrInvalidWorkspace`](). Errors from tmux while building use the core tmux package's error categories. ## Connection ownership [`Build`]() creates the first session with a temporary control connection, uses that connection for construction, and closes it before returning an ordinary session handle. That connection is a tmux client while it exists: it appears in client listings, changes attachment counts, and can trigger client hooks. [`BuildInto`]() uses a session supplied by the caller. The caller owns the connection and its lifetime. [`InitialSessionRequest`]() lets you create the initial session with the workspace's settings before populating it. A returned session from creation does not contain a fresh graph of relations. Take a server snapshot or use the search operations to inspect the windows and panes that were built. ## Failures and directories Building is not transactional. Earlier objects remain if a later operation fails. Check both the returned session and the error, then decide whether to inspect or remove the partial session. The builder uses strict errors even when the supplied server has another error policy. A missing `start_directory` may make tmux start the pane in its home directory without failing. [`Workspace.MissingDirectories`]() reports absent paths before construction; callers decide whether that is an error or something setup commands will resolve. ## Format differences Plugin declarations and `before_script` are rejected. `${VAR}` interpolation is not performed before building; render such configuration yourself if needed. `sleep_before` and `sleep_after` are seconds and pause construction between command deliveries. Environment entries at every configuration level are written to the session. If several entries set the same name, the last value remains for later processes. Global options are applied after the first session exists, so its first window cannot inherit options that were set later. [Workspace contracts](https://github.com/libtmux/libtmux-go/blob/5f808882015a975a65acc7f9da5b3ff0d5cbdc91/workspace/README.md) --- # Java workspace builder behavior Source: https://libtmux.org/en/java/latest/workspace/internals/topics/ > Internal configuration, application, and failure contracts of the Java workspace builder. A [`Workspace`]() is an immutable description of a session. [`read`]() and [`parse`]() create that description. [`build`]() is the operation that changes tmux. ## Supported configuration The root accepts `session_name` and `windows`. Windows carry names, layouts, and panes. A pane can be a command string, a list of commands, or a mapping with `shell_command`. An omitted pane list still produces tmux's initial pane. Unknown keys and unsupported value shapes are rejected. Layout names and layout descriptions are checked before construction; support for a named layout is checked against the target tmux version before creating objects. Session names containing `.` or `:` are rejected because those characters conflict with tmux target syntax. ## Construction and commands The builder creates a uniquely named staging session and renames that exact session to the requested name. It does not take over an existing session with the same name. All windows and panes are created before pane commands are sent, and layouts are applied before those commands run. Completion returns a refreshed [`Session`](). It establishes that the builder's tmux operations completed; it does not establish that a server launched by a pane command is ready to serve requests. ## Failure cleanup When construction fails, the builder attempts to kill the exact session it created. If the initial creation did not produce a usable handle, it targets the unique staging name. This keeps cleanup scoped to the new workspace. Cleanup can also fail. The builder preserves that failure as a suppressed exception on the original exception. Inspect suppressed exceptions before assuming the partial session was removed. Removing tmux objects cannot undo external effects already produced by shell commands. [Construction and cleanup](https://github.com/libtmux/libtmux-java/blob/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-workspace/src/main/java/io/github/libtmux/workspace/WorkspaceApplier.java); [YAML validation](https://github.com/libtmux/libtmux-java/blob/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-workspace/src/main/java/io/github/libtmux/workspace/WorkspaceParser.java). --- # Python workspace builder behavior Source: https://libtmux.org/en/py/latest/workspace/internals/topics/ > tmuxp's internal configuration pipeline, builder selection, and session handling. The CLI separates configuration processing, construction, and attachment. These Python implementation interfaces have no stability guarantee. ## Expand before building The loader reads YAML or JSON, expands command shorthand, variables, and paths, then applies inherited defaults. The builder expects the expanded configuration. The [internal example](https://libtmux.org/en/py/latest/workspace/internals/examples/) shows this sequence with an isolated libtmux server. ## Select a builder [`ClassicWorkspaceBuilder`]() is the default builder. `workspace_builder` selects an importable class or a registered entry point; `workspace_builder_paths` adds explicitly configured import directories. Plugins and custom builders run inside the Python process. Those extension imports are not portable workspace data for the other language ports. The classic builder accepts an optional existing session and an append choice. Failure handling depends on the operation and CLI path; a workspace build does not have universal transactional rollback. The CLI owns its existing-session prompts and the attachment or client-switching workflow. See the upstream [custom builder guide](https://tmuxp.git-pull.com/topics/custom-workspace-builders/) for extension configuration and the [API](https://libtmux.org/en/py/latest/workspace/reference/) for interface contracts. [Configuration loader](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [Classic builder](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py). --- # Rust workspace builder behavior Source: https://libtmux.org/en/rs/latest/workspace/internals/topics/ > Internal configuration, application, and failure contracts of the Rust workspace builder. A Rust workspace describes a new session. Parsing reads the description; planning builds an inert sequence of operations; building executes it on a server. ## Configuration [`Workspace::from_yaml`]() accepts session, window and pane data. The configuration supports working directories, commands, environment variables, options, focus, and layouts. Unknown keys are listed in `unsupported_keys` and ignored. Review `unsupported_keys` before building so an unrecognized field does not leave the session missing an expected setting. A pane's working directory overrides its window's directory, which overrides the workspace's directory. The parser and builder own the supported configuration fields. ## Preview and execution [`WorkspaceBuilder::plan`]() does not contact tmux. Its [`preview`]() exposes the commands and references to objects that later operations will create. This is a construction plan, not a reconciliation of an existing session. [`build`]() checks the requested session name and returns [`BuildError::SessionExists`]() when it is already present. A later tmux error can leave objects already created. The builder does not roll back the session, so inspect the dedicated server and decide whether to keep or remove that partial result. ## Freeze a running session [`freeze`]() captures windows, panes, working directories, and focus into a [`Workspace`](). [`to_yaml`]() serializes that description, and [`from_yaml`]() reads it back. This recovers structure rather than a process checkpoint: tmux cannot recover the original command line from the current foreground program alone. Review exported commands before using the file as a launcher. Freezing does not preserve application memory, terminal history, or files on disk. [Builder implementation](https://github.com/libtmux/libtmux-rs/blob/9331cdf556ea7a1f2589e9c3e6cece6ccdc7765c/crates/tmux-workspace/src/lib.rs); [Freeze implementation](https://github.com/libtmux/libtmux-rs/blob/9331cdf556ea7a1f2589e9c3e6cece6ccdc7765c/crates/tmux-workspace/src/freeze.rs). --- # Swift workspace builder behavior Source: https://libtmux.org/en/swift/latest/workspace/internals/topics/ > Internal configuration, application, and failure contracts of the Swift workspace builder. [`Workspace`](), [`WindowPlan`](), and [`PanePlan`]() are Swift values that describe the objects to create. Their Codable keys use tmuxp's field spelling. ## Supported format JSON decoding is always available. YAML decoding is compiled only when the package enables `YAMLWorkspaces`, which brings in Yams. Unknown keys are ignored by decoding. Validate field names against the model before loading a configuration. The model covers names, directories, layouts and pane commands. A window directory overrides the workspace directory. A split pane can provide its own directory; the initial pane is created with its window's directory. Commands can request Enter or leave literal text unsubmitted. A successful build means the builder delivered its operations, not that a program launched in a pane is ready or has finished. ## Values and observation The returned [`Session`]() is a captured value, not a live object that refreshes its properties. The builder creates additional windows after obtaining the initial session value. Ask the server for a fresh snapshot when inspecting the completed window and pane membership. Encoding a [`Workspace`]() serializes the description you already hold. It is not a live-session freeze operation and does not export the current state of tmux. ## Existing names and failure cleanup The builder refuses an existing session name. If a later operation fails, it attempts cleanup using the exact created session, with an independent bounded cleanup task. Cancellation of the build does not itself cancel that cleanup. [`WorkspaceBuilderError.rollbackFailed`]() carries the original error and the cleanup error. Inspect both before deciding whether a partial session remains. Removing a session cannot undo external effects already caused by its commands. [Configuration model](https://github.com/libtmux/libtmux-swift/blob/f02a4668570e1cc5198c941413750e021f42c214/Sources/TmuxWorkspace/Workspace.swift); [Builder and rollback](https://github.com/libtmux/libtmux-swift/blob/f02a4668570e1cc5198c941413750e021f42c214/Sources/TmuxWorkspace/WorkspaceBuilder.swift). --- # TypeScript workspace builder behavior Source: https://libtmux.org/en/ts/latest/workspace/internals/topics/ > Internal configuration, application, and failure contracts of the TypeScript workspace builder. Applying a workspace reconciles the requested structure with a named session. It can create missing objects, rename windows, and remove eligible surplus objects. It returns the resulting [`Session`](). ## Ownership and shared objects A session created by the package carries the reserved `@libtmux-workspace` option. The default `prune: "owned"` removes surplus only from a session with that ownership stamp. Applying to a session created elsewhere adds the missing structure and preserves its surplus windows and panes. `prune: "never"` disables removals. `prune: "always"` authorizes removals for that call without stamping persistent ownership. Inspect a fresh plan before using that policy on an existing session. Windows match by position rather than numeric tmux index. A linked surplus window is unlinked from this session. Grouped sessions retain surplus windows, and shared windows retain surplus panes, because removing those objects would affect their other placements. ## Commands and options The default `commands: "create-only"` sends setup and pane commands only in panes created by the current apply. `commands: "always"` replays them in reused panes too. Completion means workspace operations finished; it does not mean a long-running command is ready to accept requests. Named options are applied each time. Removing a key from the description does not unset its current tmux value. Working directories inherit from workspace to window to pane, with the most specific value winning. ## Plans and failures [`planWorkspace`]() describes topology changes without applying them. The plan contains object identities and retention reasons; it does not describe option, layout, focus, or command changes. Another tmux client can change the session after planning, so the plan is advisory. [`WorkspaceApplyError`]() reports completed milestones, the failed stage, and the underlying cause. Its [`requiresReplan`]() flag requires a fresh inspection after failure. There is no rollback, and a transport failure may leave command delivery uncertain. Do not infer that replaying the same command is safe from a failed apply alone. [Workspace behavior](https://github.com/libtmux/libtmux-ts/blob/f85b8de551353f746d50eaf36bf0112f4fe5a528/packages/workspace/README.md) --- # Develop the C++ workspace consumer Source: https://libtmux.org/en/cxx/latest/workspace/internals/guides/ > Build and exercise the source-only C++ workspace consumer. Try the workspace consumer from the libtmux C++ source checkout. It is built as a repository target, so installing the core package alone does not provide its headers or YAML reader. ## Build the consumer Use the repository's prepared development toolchain and install tmux. From the checkout root, configure the development preset: ```console $ cmake --preset cxx-dev ``` Build the workspace test executable: ```console $ cmake --build --preset cxx-dev --target workspace_builder_test ``` Run the consumer tests against their isolated tmux fixtures: ```console $ ctest --preset cxx-dev -R consumer.workspace --output-on-failure ``` The tests exercise both YAML parsing and typed configuration. The [example](https://libtmux.org/en/cxx/latest/workspace/internals/examples/) shows the session shape used by the builder test. ## Use it in an application The `workspace_builder` CMake target provides the consumer include directory, links the core [`libtmux::libtmux`](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/CMakeLists.txt) target publicly, and keeps yaml-cpp private to the YAML reader. If you adapt the consumer, preserve those dependency boundaries and include the parser implementation when using [`parse_tmuxp`](). Parse first and inspect [`ParseError`]() before contacting tmux. Start the target tmux server before opening its core handle, as the test fixture does. Pass a core [`Server`]() and the parsed description to [`build`](). Check the returned expected value before reading its session; after failure, inspect the target server because earlier operations may remain. There is no separate installed workspace product in this source tree. Do not expect core package managers to expose [`libtmux_consumers/workspace.hpp`](). [Consumer build targets](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/CMakeLists.txt) --- # Use the C# workspace builder Source: https://libtmux.org/en/csharp/latest/workspace/internals/guides/ > Parse a workspace, build it on an owned server, and handle partial failures. Use [`WorkspaceFile.Parse`]() to read workspace YAML and [`WorkspaceBuilder.BuildAsync`]() to create its session, windows, and panes. Parsing needs no running tmux server; building requires tmux on a Unix host. Start with the [complete workspace example](https://libtmux.org/en/csharp/latest/workspace/internals/examples/). It includes the program, project file, dependency checkout, and run command for the .NET 10 SDK. The example creates a private server and removes it when the owned scope ends. ## Create an isolated workspace Parse the YAML before opening the server. Create an owned scope with [`Server.CreateOwnedAsync`](), passing a [`ServerConnectionOptions`]() object with the fresh socket name and configuration file. Pass the scope's server to [`WorkspaceBuilder`](), then await [`BuildAsync`]() with a cancellation token. Use `await using` so the scope is disposed even when building throws. The returned [`WorkspaceResult`]() identifies the session and its windows. Inspect [`Unsupported`]() for layouts that tmux rejected after creating their windows. Keep the owned scope alive while your application uses the workspace; disposing it removes its server and the sessions on that server. ## Read a file and handle errors Read the YAML file as text and pass it to [`WorkspaceFile.Parse`](). Resolve relative working directories yourself if they should be based on that file's location. For an existing application server, pass its handle to [`WorkspaceBuilder`]() instead of creating an owned scope. A failed build can leave a partial session. Inspect [`WorkspaceBuildException.PartialResult`]() and decide what to remove; the builder does not roll back changes automatically. The [builder source](https://github.com/libtmux/libtmux-dotnet/blob/320dc64f4b8b7815842471327a5e6b84a1499bf8/src/LibTmux.Workspace/WorkspaceBuilder.cs) describes the build result and partial-failure behavior. See [owned server lifetime](https://github.com/libtmux/libtmux-dotnet/blob/320dc64f4b8b7815842471327a5e6b84a1499bf8/src/LibTmux/Server.Lifecycle.cs) for scope cleanup. --- # Use the Go workspace builder Source: https://libtmux.org/en/go/latest/workspace/internals/guides/ > Use the in-development Go workspace builder from application code. Use [`Parse`]() to validate YAML, then [`Build`]() to create the described session. Start in a Go module and add the workspace dependency: ```console $ go get github.com/libtmux/libtmux-go/workspace ``` Pin the resolved version in your module files. The module's current source requires Go 1.26 and uses a separate core libtmux dependency. tmux must be available for construction. ## Parse before building The [executable examples](https://libtmux.org/en/go/latest/workspace/internals/examples/) provide a complete program-shaped test with imports, a deadline, a dedicated socket, and cleanup. Its central calls are [`workspace.Parse(document)`]() followed by [`workspace.Build(ctx, server, described)`](). Save a description like this as `project.yaml`: ```yaml session_name: project windows: - window_name: editor panes: - shell_command: echo ready - window_name: tests panes: - shell_command: echo ready ``` Read the file with [`os.ReadFile`]() and handle that error before parsing. Handle parse errors before opening a server. If a build fails, retain its returned session handle long enough to inspect or clean up any partial result. ## Retain a connection Choose [`BuildInto`]() when the application already owns a session connection. Call [`described.InitialSessionRequest`](), create a session connection with that request, then pass its session to [`BuildInto`](). Close the connection when the caller is done; the workspace function does not transfer ownership. ## Inspect the result Use [`Session.SearchWindows`]() or a fresh server snapshot to inspect membership. Do not expect the handle returned by a creation call to contain populated relations. Review missing working directories before building if falling back to the home directory would make the workspace run in the wrong location. [Complete build examples](https://github.com/libtmux/libtmux-go/blob/5f808882015a975a65acc7f9da5b3ff0d5cbdc91/workspace/example_test.go); [Module requirements](https://github.com/libtmux/libtmux-go/blob/5f808882015a975a65acc7f9da5b3ff0d5cbdc91/workspace/go.mod). --- # Use the Java workspace builder Source: https://libtmux.org/en/java/latest/workspace/internals/guides/ > Use the in-development Java workspace builder from application code. Add the workspace module to a Java 21 project. The BOM selects compatible libtmux modules: ```kotlin title="build.gradle.kts" dependencies { implementation(platform("io.github.libtmux:libtmux-bom:0.0.1-alpha.10")) implementation("io.github.libtmux:libtmux-workspace") } ``` Install tmux on the host before running the builder. ## Create and inspect This program builds on a dedicated socket, prints the resulting session name, and removes the session after inspection. Save it in your application's Java sources and run it through your existing Gradle application task. ```java import io.github.libtmux.Server; import io.github.libtmux.ServerEndpoint; import io.github.libtmux.Session; import io.github.libtmux.workspace.Workspace; import io.github.libtmux.workspace.WorkspaceBuilder; import java.util.UUID; public class WorkspaceGuide { public static void main(String[] args) { Workspace workspace = WorkspaceBuilder.parse(""" session_name: guide windows: - window_name: editor panes: - echo ready - echo ready """); try (Server server = Server.builder() .endpoint(ServerEndpoint.namedSocket( "workspace-" + UUID.randomUUID())) .build()) { Session session = WorkspaceBuilder.build(server, workspace); try { System.out.println(session.name()); } finally { session.kill(); } } } } ``` ## Read a file Use [`WorkspaceBuilder.read(Path)`]() to parse YAML from disk. It reports file read failures as [`UncheckedIOException`](); invalid configuration raises [`IllegalArgumentException`](). Handle those before calling [`build`](). For an application that keeps the workspace running, keep the session rather than calling `kill`. Closing the Java server handle releases its transport; it does not serve as workspace removal. If construction fails, inspect the exception and its suppressed cleanup failures. [Topics](https://libtmux.org/en/java/latest/workspace/internals/topics/) describes the builder's cleanup scope. [Dependency and workspace usage](https://github.com/libtmux/libtmux-java/blob/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-workspace/README.md); [Server lifetime API](https://github.com/libtmux/libtmux-java/blob/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux/src/main/java/io/github/libtmux/Server.java). --- # Use the Rust workspace builder Source: https://libtmux.org/en/rs/latest/workspace/internals/guides/ > Use the in-development Rust workspace builder from application code. Build a workspace by parsing its YAML and passing it to [`WorkspaceBuilder`](). Install tmux first, then add the crate to a Rust project: ```console $ cargo add tmux-workspace ``` The runnable [example](https://libtmux.org/en/rs/latest/workspace/internals/examples/) also uses libtmux's isolated test server. Enable its `test-support` feature: ```console $ cargo add libtmux --features test-support ``` Add the Tokio runtime used by the example: ```console $ cargo add tokio --features macros,rt-multi-thread ``` ## Describe the session Save this description as `dev.yaml`: ```yaml session_name: dev windows: - window_name: editor panes: [/bin/sh, /bin/sh] ``` In an async application, read the file with [`std::fs::read_to_string`](https://doc.rust-lang.org/std/fs/fn.read_to_string.html), parse it with [`Workspace::from_yaml`](), and construct [`WorkspaceBuilder::new(&server)`]() using your libtmux server handle. [`build(&workspace).await`]() returns the newly created session. ## Preview before creating Call [`plan(&workspace)`]() on the builder before execution. Iterate over the plan's [`preview()`]() if you need to show the commands to an operator. Planning itself does not test current session-name availability or execute commands. If the requested session already exists, choose another name or explicitly remove a session you own. Do not treat the error as a request to adopt it. After a partial build failure, inspect the server before retrying. ## Save a live layout Use [`freeze(&session).await`]() to produce a new [`Workspace`](), then write its [`to_yaml()`]() output to a file. Review the resulting command descriptions before loading the file later. [Topics](https://libtmux.org/en/rs/latest/workspace/internals/topics/) explains what the export can recover. [Crate usage and dependencies](https://github.com/libtmux/libtmux-rs/blob/9331cdf556ea7a1f2589e9c3e6cece6ccdc7765c/crates/tmux-workspace/README.md) --- # Use the Swift workspace builder Source: https://libtmux.org/en/swift/latest/workspace/internals/guides/ > Build a workspace, inspect its current layout, and choose its lifetime. Start with the [complete runnable example](https://libtmux.org/en/swift/latest/workspace/internals/examples/). It includes the SwiftPM manifest, a pinned library dependency, imports, an executable entry point, a private tmux server, and cleanup. ## Describe the layout A [`Workspace`]() contains ordered windows. Each [`WindowPlan`]() describes a window's name, layout and panes. Its [`PanePlan`]() values describe commands to send and an optional starting directory. The example keeps panes open with `/bin/cat`, so it needs no editor, application or log file. Replace those choices with commands appropriate for the workspace before using it as an application launcher. ## Build on a running server [`WorkspaceBuilder.build(_:on:)`]() checks the server's sessions before creating its workspace. Start a private bootstrap session first, or pass a running server whose lifetime the application owns. The builder rejects an existing session with the requested name. After a creation failure, it attempts to remove the session it created. Inspect [`WorkspaceBuilderError.rollbackFailed`]() when both the operation and its rollback fail; that error preserves both causes. The example's final cleanup stops its whole private server, including the bootstrap session. An application that wants the workspace to remain open should retain its selected server and stop it when the application is done. ## Inspect the completed layout Request a fresh [`Server.snapshot()`]() after building. The returned session value was captured when the first window was created; it does not become a live view as later windows are added. Use the snapshot's [`windows(of:)`]() and [`panes(of:)`]() methods to inspect membership. The complete example asserts the final window and pane counts before printing its result. ## Read configuration [`Workspace.decode(json:)`]() reads Foundation [`Data`](). The accepted model uses `session_name`, [`windows`](), `window_name` and [`panes`](); unknown keys are ignored. YAML input additionally requires the dependency's `YAMLWorkspaces` trait and [`Workspace.decode(yaml:)`](). Enable that trait on the package dependency when using YAML. A dependency trait does not define the same compilation condition inside a consumer package, so do not wrap the consumer call in an `#if YAMLWorkspaces` guard. Swift values and JSON need no YAML dependency. The [workspace model](https://github.com/libtmux/libtmux-swift/blob/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Sources/TmuxWorkspace/Workspace.swift) and [build contract](https://github.com/libtmux/libtmux-swift/blob/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Sources/TmuxWorkspace/WorkspaceBuilder.swift) describe the accepted fields and failure behavior. --- # Use the TypeScript workspace builder Source: https://libtmux.org/en/ts/latest/workspace/internals/guides/ > Apply a workspace, review planned changes, and handle partial failures. Apply a workspace to create or reconcile its session, windows, and panes. Start with the [complete TypeScript example](https://libtmux.org/en/ts/latest/workspace/internals/examples/): it includes imports, project setup, the selected library source, run commands, and private-server cleanup. ## Create a session [`applyWorkspace`]() accepts a [`Server`]() and workspace configuration. Await it to receive the resulting session. Pane commands can still be running when it returns. The complete example uses a private socket and registers cleanup before applying the workspace. A failed apply can leave a session or some of its windows in place. For a workspace you want to keep, choose the intended server explicitly and retain the returned session. ## Read configuration [`parseWorkspace`]() from `@libtmux/workspace/config` validates an object produced by your chosen JSON or YAML parser. [`parseWorkspaceYaml`]() uses Bun's YAML parser. Unknown fields fail validation. With another runtime, parse the document first and pass the resulting object to [`parseWorkspace`](). ## Review changes and failures [`planWorkspace`]() reads the server and reports planned structural creation, removal, retention, and window renames. Options, layouts, focus, and command effects are outside that plan. Review removals and retained entries, then apply promptly. Replan after an outside change. When an apply fails after mutation may have started, [`WorkspaceApplyError`]() records completed milestones and the failed stage. Its [`requiresReplan`]() flag is true; rediscover the current structure before retrying. Completed command effects remain part of the application's recovery decision. [Topics](https://libtmux.org/en/ts/latest/workspace/internals/topics/) explains command replay and pruning policies. The [configuration parser](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/workspace/src/config.ts) and [builder contracts](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/workspace/src/builder.ts) cover these entry points. --- # C# workspace builder examples Source: https://libtmux.org/en/csharp/latest/workspace/internals/examples/ > Internal examples for building and inspecting workspaces through the C# API. Build a two-window workspace, print its size, and remove its private tmux server. Use a POSIX host with tmux on `PATH` and the .NET 10 SDK. ## Create the project In a new directory, fetch the source revision used by this documentation: ```console $ mkdir dotnet-workspace-example $ cd dotnet-workspace-example $ git init -q libtmux-source $ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-dotnet.git $ git -C libtmux-source fetch --depth=1 origin 320dc64f4b8b7815842471327a5e6b84a1499bf8 $ git -C libtmux-source checkout --detach FETCH_HEAD ``` Save the following project file. The project reference builds the workspace package and its core dependency from that checkout. ```xml title="WorkspaceExample.csproj" Exe net10.0 disable enable false ``` ## Build and inspect Save this complete program as `Program.cs` beside the project file: ```csharp title="Program.cs" using System; using System.Threading; using System.Threading.Tasks; using LibTmux; using LibTmux.Workspace; internal static class Program { private static async Task Main() { if (OperatingSystem.IsWindows()) throw new PlatformNotSupportedException("This example requires POSIX tmux."); using var deadline = new CancellationTokenSource(TimeSpan.FromSeconds(30)); WorkspaceFile workspace = WorkspaceFile.Parse(""" session_name: built options: default-shell: /bin/sh windows: - window_name: editor panes: - shell_command: echo editing - shell_command: echo watching - window_name: server panes: - shell_command: echo serving """); await using var owned = await Server.CreateOwnedAsync( new ServerConnectionOptions { SocketName = $"workspace-{Guid.NewGuid():N}", ConfigurationFile = "/dev/null", }, deadline.Token); WorkspaceResult result = await new WorkspaceBuilder(owned.Value) .BuildAsync(workspace, deadline.Token); Console.WriteLine($"{result.Session.Name}: {result.Windows.Count} windows"); foreach (string unsupported in result.Unsupported) Console.WriteLine(unsupported); } } ``` Build and run it from the example directory: ```console $ dotnet run --project WorkspaceExample.csproj --configuration Release ``` The program prints `built: 2 windows`. The owned scope removes the server on success or failure. Its unique socket and empty tmux configuration keep the example separate from an existing server. The deadline bounds construction; owned-scope cleanup uses its own lifetime. [`BuildAsync`]() returns after creating the workspace and sending its commands. That does not establish completion of programs running in the panes. A build failure can leave partial results; the owned server scope removes them here. [Workspace API source](https://github.com/libtmux/libtmux-dotnet/tree/320dc64f4b8b7815842471327a5e6b84a1499bf8/src/LibTmux.Workspace) --- # C++ workspace builder examples Source: https://libtmux.org/en/cxx/latest/workspace/internals/examples/ > Internal examples for building and inspecting workspaces through the C++ API. Build an editor window with two panes and a logs window with one pane on a private tmux server. This walkthrough uses a POSIX host with tmux, CMake 3.25 or newer, Clang 18, and the libc++ 18 development libraries. ## Create the project In a new directory, fetch the source revision used by this documentation: ```console $ mkdir cxx-workspace-example $ cd cxx-workspace-example $ git init -q libtmux-source $ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-cxx.git $ git -C libtmux-source fetch --depth=1 origin 393d4b0ad666f18a6581f1eb281741a75a7503f0 $ git -C libtmux-source checkout --detach FETCH_HEAD ``` Save the following build file. The typed builder is a source header; this example does not use the optional YAML reader. The public testing library supplies private-server startup and cleanup. [`ScopedTmuxServer`]() is temporary example scaffolding. In an application, use a [`Server`](https://libtmux.org/en/cxx/latest/reference/libtmux-server/) connected to the tmux server you manage. Future versions of this example will use that regular server object directly. ```cmake title="CMakeLists.txt" cmake_minimum_required(VERSION 3.25) project(workspace_example LANGUAGES CXX) set(LIBTMUX_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(LIBTMUX_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) set(LIBTMUX_BUILD_TESTING_LIBRARY ON CACHE BOOL "" FORCE) add_subdirectory(libtmux-source) add_executable(workspace-example main.cpp) target_compile_features(workspace-example PRIVATE cxx_std_23) target_include_directories(workspace-example PRIVATE libtmux-source/examples/workspace/include) target_link_libraries(workspace-example PRIVATE libtmux::libtmux libtmux::testing) ``` ## Build and inspect Save this complete program as `main.cpp`: ```cpp title="main.cpp" #include #include #include #include "libtmux/server.hpp" #include "libtmux/testing/scoped_server.hpp" #include "libtmux_consumers/workspace.hpp" int main() { auto cleanup = std::make_shared(); bool complete = false; try { auto owned = libtmux::test::ScopedTmuxServer::start({.teardown_report = cleanup}); if (!owned) throw std::runtime_error(owned.error()); auto server = libtmux::Server::at_socket_path(owned->socket_path().string()); if (!server) throw std::runtime_error(server.error().diagnostic); namespace workspace = libtmux::workspace; const workspace::Workspace description{ .session_name = "built", .windows = {{.name = "editor", .panes = {{.shell = "/bin/cat"}, {.shell = "/bin/cat"}}}, {.name = "logs", .panes = {{.shell = "/bin/cat"}}}}}; const auto built = workspace::build(*server, description); if (!built) throw std::runtime_error(built.error().reason); const auto windows = built->windows(); if (!windows) throw std::runtime_error(windows.error().diagnostic); const auto panes = windows->front().panes(); if (!panes) throw std::runtime_error(panes.error().diagnostic); std::cout << built->name() << ": " << windows->size() << " windows\n"; std::cout << "editor: " << panes->size() << " panes\n"; complete = true; } catch (const std::exception& error) { std::cerr << error.what() << '\n'; } for (const auto& message : cleanup->messages) { if (message != "server teardown complete") { std::cerr << message << '\n'; complete = false; } } return complete ? 0 : 1; } ``` Configure, build and run from the example directory: ```console $ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_CXX_FLAGS=-stdlib=libc++ $ cmake --build build --parallel 2 --target workspace-example $ ./build/workspace-example ``` The program prints `built: 2 windows` and `editor: 2 panes`. The owned fixture creates a private socket and removes its server and temporary files when the scope ends, including during exception handling. Each pane runs `/bin/cat`, which waits for input without loading an interactive shell configuration. This header belongs to the source consumer. Installing the core package alone does not supply the workspace include directory. For YAML input, the separate consumer build also needs its parser and yaml-cpp dependency. [Workspace builder source](https://github.com/libtmux/libtmux-cxx/blob/393d4b0ad666f18a6581f1eb281741a75a7503f0/examples/workspace/include/libtmux_consumers/workspace.hpp) --- # Go workspace builder examples Source: https://libtmux.org/en/go/latest/workspace/internals/examples/ > Build and inspect a workspace from YAML on a private tmux server with Go. Read a workspace file, create two windows and three panes, then stop the private tmux server. The `/bin/cat` commands keep panes open without another application or log file. ## Prepare the project Use Go 1.26, Git, and tmux 3.2a or newer on Unix. Create an empty project and fetch the source revision used by this example: ```console $ mkdir go-workspace-example && cd go-workspace-example ``` ```console $ git init libtmux-source && \ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-go.git && \ git -C libtmux-source fetch --depth=1 origin bb06e26e116e941813ca40bf45e7e3a47d38f52a && \ git -C libtmux-source checkout --detach FETCH_HEAD ``` Create the module file. Both replacements select that checkout, so the core and workspace libraries use the same source revision: ```go title="go.mod" module example.com/workspace go 1.26.0 require ( github.com/libtmux/libtmux-go v0.0.1-alpha.9 github.com/libtmux/libtmux-go/workspace v0.0.0 ) require go.yaml.in/yaml/v3 v3.0.5 // indirect replace github.com/libtmux/libtmux-go => ./libtmux-source replace github.com/libtmux/libtmux-go/workspace => ./libtmux-source/workspace ``` Create the workspace file in the same directory: ```yaml title="workspace.yaml" session_name: workspace-example windows: - window_name: editor layout: even-horizontal panes: [/bin/cat, /bin/cat] - window_name: logs panes: [/bin/cat] ``` ## Build a session Create the complete program below. It reads and validates the YAML before creating a private socket directory. [`Parse`]() rejects unknown configuration fields; a misspelled key fails before the example starts tmux. ```go title="main.go" package main import ( "context" "errors" "fmt" "os" "path/filepath" "time" "github.com/libtmux/libtmux-go/tmux" "github.com/libtmux/libtmux-go/workspace" ) func main() { if err := run(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func run() (err error) { document, err := os.ReadFile("workspace.yaml") if err != nil { return err } described, err := workspace.Parse(document) if err != nil { return err } directory, err := os.MkdirTemp("/tmp", "libtmux-go-workspace-") if err != nil { return err } config := filepath.Join(directory, "tmux.conf") if err = os.WriteFile(config, []byte("set -g default-shell /bin/sh\n"+ "set-environment -g ENV /dev/null\n"+ "set-environment -g BASH_ENV /dev/null\n"), 0600); err != nil { return errors.Join(err, os.RemoveAll(directory)) } socket := filepath.Join(directory, "s") server, err := tmux.NewServer(tmux.ServerOptions{ SocketPath: socket, ConfigFile: config, }) if err != nil { return errors.Join(err, os.RemoveAll(directory)) } defer func() { cleanup, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if cleanupErr := server.Kill(cleanup); cleanupErr != nil { err = errors.Join(err, fmt.Errorf("stop private server at %s: %w", socket, cleanupErr)) return } err = errors.Join(err, os.RemoveAll(directory)) }() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() session, err := workspace.Build(ctx, server, described) if err != nil { return fmt.Errorf("build workspace: %w", err) } windows, err := session.SearchWindows(ctx, nil) if err != nil { return err } panes, err := server.Panes(ctx) if err != nil { return err } if len(windows) != 2 || len(panes) != 3 { return fmt.Errorf("expected two windows and three panes, got %d and %d", len(windows), len(panes)) } fmt.Printf("built: %d windows\npanes: %d\n", len(windows), len(panes)) return nil } ``` [`Build`]() opens a control connection for construction, closes it, and returns a session handle that can be used for later operations. Pane commands may still be running when the build returns. Check the application itself for readiness. For an application that already owns a connection, use [`Workspace.InitialSessionRequest`]() to create the initial session, then pass it to [`BuildInto`](). That function populates the supplied session and leaves connection ownership with the caller. ## Verification Resolve dependencies and run the program from the project directory: ```console $ go mod tidy ``` ```console $ go run . ``` Expected output: ```text built: 2 windows panes: 3 ``` A failed build can leave part of the workspace in tmux. Cleanup is registered before [`Build`]() and uses its own five-second deadline, so an expired build context does not skip server shutdown. If stopping tmux fails, the program keeps the socket directory and reports the cleanup error alongside any build error. For a workspace that stays open, let your application retain its explicitly selected server and choose when to stop it. [Builder source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/builder.go); [configuration source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/workspace.go). --- # Java workspace builder examples Source: https://libtmux.org/en/java/latest/workspace/internals/examples/ > Internal examples for building and inspecting workspaces through the Java API. Build a two-window workspace, inspect its panes, and remove the private tmux server. Use a POSIX host with tmux on `PATH` and JDK 25. ## Create the project In a new directory, fetch the source revision used by this documentation: ```console $ mkdir java-workspace-example $ cd java-workspace-example $ git init -q libtmux-source $ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-java.git $ git -C libtmux-source fetch --depth=1 origin 842228310449e879ebcaa3f910597757c9dbffd6 $ git -C libtmux-source checkout --detach FETCH_HEAD $ mkdir -p src/main/java ``` Save the following settings file. The included build supplies the workspace module and its core dependency from the selected source. Its toolchain resolver downloads the Temurin 21 compiler for those libraries when needed. ```kotlin title="settings.gradle.kts" rootProject.name = "workspace-example" includeBuild("libtmux-source") ``` Save the following build file: ```kotlin title="build.gradle.kts" plugins { application } repositories { mavenCentral() } dependencies { implementation("io.github.libtmux:libtmux-workspace:0.0.1-alpha.12-SNAPSHOT") } java { toolchain.languageVersion.set(JavaLanguageVersion.of(25)) } application { mainClass.set("WorkspaceExample") } ``` ## Build and inspect Save this complete program as `src/main/java/WorkspaceExample.java`: ```java title="src/main/java/WorkspaceExample.java" import io.github.libtmux.Server; import io.github.libtmux.ServerEndpoint; import io.github.libtmux.Session; import io.github.libtmux.workspace.Workspace; import io.github.libtmux.workspace.WorkspaceBuilder; import java.nio.file.Path; import java.time.Duration; import java.util.UUID; public final class WorkspaceExample { public static void main(String[] args) { Workspace workspace = WorkspaceBuilder.parse(""" session_name: built windows: - window_name: editor layout: even-horizontal panes: - shell_command: echo one - shell_command: echo two - window_name: server panes: - echo three """); try (Server server = Server.builder() .endpoint(ServerEndpoint.namedSocket("workspace-" + UUID.randomUUID())) .configFile(Path.of("/dev/null")) .defaultTimeout(Duration.ofSeconds(10)) .build()) { try { server.newSession("bootstrap"); Session session = WorkspaceBuilder.build(server, workspace); System.out.println(session.name() + ": " + session.windows().size() + " windows"); System.out.println("editor: " + session.windows().getFirst().panes().size() + " panes"); } finally { server.killServer(); } } } } ``` Use the checked-out Gradle wrapper to run the application: ```console $ ./libtmux-source/gradlew --no-daemon --max-workers=2 -p . run ``` The application prints `built: 2 windows` and `editor: 2 panes`. Its unique socket prevents a collision with an existing server. The `finally` block removes that server even if construction or inspection fails. Closing the Java handle then releases its transport. The bootstrap session starts tmux before the workspace builder checks its version. It belongs to the same private server and is removed with it. Building creates the layout and sends the pane commands. It does not wait for those programs to finish. Keep the session running instead of calling [`killServer`]() when adapting this example into an application launcher. [Workspace API source](https://github.com/libtmux/libtmux-java/tree/842228310449e879ebcaa3f910597757c9dbffd6/libtmux-workspace/src/main/java/io/github/libtmux/workspace) --- # Python workspace builder example Source: https://libtmux.org/en/py/latest/workspace/internals/examples/ > An isolated example of tmuxp internal configuration expansion and session building. This example demonstrates tmuxp's internal builder pipeline. These Python interfaces have no stability guarantee. Load workspace files through the [CLI examples](https://libtmux.org/en/py/latest/workspace/examples/) for normal use. ## Build from Python data Run this inside an environment containing tmuxp and its compatible libtmux dependency. The example expands shorthand and inherited defaults before calling the classic builder, then removes its dedicated server. ```python from uuid import uuid4 import libtmux from tmuxp.workspace import loader from tmuxp.workspace.builder import WorkspaceBuilder config = { "session_name": "workspace-example", "windows": [ {"window_name": "editor", "panes": ["echo ready", "echo ready"]} ], } expanded = loader.trickle(loader.expand(config)) server = libtmux.Server(socket_name=f"workspace-{uuid4().hex}") try: builder = WorkspaceBuilder(session_config=expanded, server=server) builder.build() print(builder.session.name) print(len(builder.session.windows)) finally: server.kill() ``` The builder stores the resulting session on [`ClassicWorkspaceBuilder.session`](). Its `build` method does not return that session as the return value. The code uses a new socket for each run so cleanup cannot select a normal user server. ## Further reading The example combines the loader sequence used by the CLI with the classic builder's documented API. The upstream builder tests exercise its expanded configuration contract, and freezer tests cover reading live sessions back into configuration. Read the upstream [configuration examples](https://tmuxp.git-pull.com/configuration/examples/) for focus, layouts, directories, environment values, and command shorthand. Those examples depend on their commands and paths; inspect each file before loading it on your own server. [Builder examples and contract](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py); [Builder tests](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/tests/workspace/test_builder.py). --- # Rust workspace builder examples Source: https://libtmux.org/en/rs/latest/workspace/internals/examples/ > Build, inspect, and capture a workspace on a private tmux server with Rust. Read a workspace file, create two windows and three panes, then capture the session as YAML. The example stops its private server after success or failure. The `/bin/cat` commands keep panes open without another application or log file. ## Prepare the project Use Rust 1.97.1, Git, and tmux 3.2a or newer. These commands use a Unix shell. Create an empty project and fetch the source revision used by this example: ```console $ mkdir rust-workspace-example && cd rust-workspace-example && \ mkdir src ``` ```console $ git init libtmux-source && \ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-rs.git && \ git -C libtmux-source fetch --depth=1 origin d4e08b4eaab62ef4eeedab79b47973ae9a1de310 && \ git -C libtmux-source checkout --detach FETCH_HEAD ``` Create the project manifest. Both library crates use that source tree. The `test-support` feature provides the public [`TestServer`]() helper, which creates and owns the isolated server used by this example. [`TestServer`]() is temporary example scaffolding. In an application, use a [`Server`](https://libtmux.org/en/rs/latest/reference/server-server/) connected to the tmux server you manage. Future versions of this example will use that regular server object directly. ```toml title="Cargo.toml" [package] name = "workspace-example" version = "0.1.0" edition = "2024" [dependencies] libtmux = { path = "libtmux-source/crates/libtmux", features = ["test-support"] } tmux-workspace = { path = "libtmux-source/crates/tmux-workspace", default-features = false } tokio = { version = "=1.53.1", features = ["macros", "rt-multi-thread", "time"] } ``` Create the workspace file beside [`Cargo.toml`](): ```yaml title="workspace.yaml" session_name: workspace-example windows: - window_name: editor layout: even-horizontal panes: [/bin/cat, /bin/cat] - window_name: logs panes: [/bin/cat] ``` ## Build and freeze Create the complete program below. It reads and validates the file before starting tmux, bounds workspace operations to 15 seconds, and explicitly checks server shutdown even when an earlier operation fails. ```rust title="src/main.rs" use std::error::Error; use std::time::Duration; use libtmux::test::TestServer; use tmux_workspace::{Workspace, WorkspaceBuilder, freeze}; use tokio::time::timeout; #[tokio::main] async fn main() -> Result<(), Box> { let source = std::fs::read_to_string("workspace.yaml")?; let workspace = Workspace::from_yaml(&source)?; let guard = TestServer::new().await?; let result = timeout(Duration::from_secs(15), async { let session = WorkspaceBuilder::new(guard.server()) .build(&workspace) .await?; let windows = session.windows().await?; let panes = session.panes().await?; if windows.len() != 2 || panes.len() != 3 { return Err("expected two windows and three panes".into()); } let captured = freeze(&session).await?; if Workspace::from_yaml(&captured.to_yaml())? != captured { return Err("captured workspace did not survive its YAML round trip".into()); } println!("built: {} windows", windows.len()); println!("panes: {}", panes.len()); println!("captured workspace: YAML round trip passed"); Ok::<_, Box>(()) }) .await .map_err(|error| -> Box { error.into() }) .and_then(|result| result); let cleanup = guard.shutdown().await; match (result, cleanup) { (Ok(()), Ok(())) => Ok(()), (Err(error), Ok(())) => Err(error), (Ok(()), Err(error)) => Err(error.into()), (Err(operation), Err(cleanup)) => { Err(format!("workspace failed: {operation}; cleanup failed: {cleanup}").into()) } } } ``` [`build`]() returns after constructing the session and sending its pane commands. Those commands may still be running. Check application output or another readiness signal before depending on an application inside a pane. [`freeze`]() captures the current session structure and observed pane commands. The YAML round trip checks that this captured value can be serialized and parsed again. It cannot recover the original command arguments or guarantee that the captured workspace recreates each application. ## Verification Run the program from the project directory: ```console $ cargo run --quiet ``` Expected output: ```text built: 2 windows panes: 3 captured workspace: YAML round trip passed ``` The program removes its private server before returning. If an operation and shutdown both fail, the error includes both failures. For a persistent workspace, let your application retain an explicitly selected server and choose its own shutdown point. [Builder source](https://github.com/libtmux/libtmux-rs/blob/d4e08b4eaab62ef4eeedab79b47973ae9a1de310/crates/tmux-workspace/src/lib.rs); [capture source](https://github.com/libtmux/libtmux-rs/blob/d4e08b4eaab62ef4eeedab79b47973ae9a1de310/crates/tmux-workspace/src/freeze.rs). --- # Swift workspace builder examples Source: https://libtmux.org/en/swift/latest/workspace/internals/examples/ > Build and inspect a private workspace with a complete Swift program. Build two windows with two editor panes, inspect a fresh snapshot, then stop the private tmux server. The example uses `/bin/cat` to keep its panes open without reading shell startup files or requiring another application. ## Prepare the project Use Swift 6.2.4, Git, and tmux 3.2a or newer on Linux. Create an empty project and the executable's source directory: ```console $ mkdir swift-workspace-example && cd swift-workspace-example && \ mkdir -p Sources/WorkspaceExample ``` Fetch the library revision used by this example: ```console $ git init libtmux-source && \ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-swift.git && \ git -C libtmux-source fetch --depth=1 origin 254f8b2be7eb60cacc3ffcb3ea8e456784f582df && \ git -C libtmux-source checkout --detach FETCH_HEAD ``` Save the following package manifest at the project root: ```swift title="Package.swift" // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "WorkspaceExample", platforms: [.macOS(.v13)], dependencies: [.package(path: "libtmux-source")], targets: [ .executableTarget( name: "WorkspaceExample", dependencies: [ .product(name: "LibTmux", package: "libtmux-source"), .product(name: "TmuxWorkspace", package: "libtmux-source"), ] ), ] ) ``` ## Run the complete program Save this file in the source directory created above. Its private socket is checked during cleanup even when startup fails. Cleanup failures preserve the original error and report the retained directory. ```swift title="Sources/WorkspaceExample/WorkspaceExample.swift" import Foundation import LibTmux import TmuxWorkspace struct ExampleFailure: Error, CustomStringConvertible { let description: String } func withPrivateTmux( _ body: @Sendable (Server) async throws -> Void ) async throws { let directory = URL(fileURLWithPath: "/tmp") .appendingPathComponent("libtmux-swift-example-\(UUID().uuidString)") let server = try Server( socketPath: directory.appendingPathComponent("s").path, configurationFile: "/dev/null" ) try FileManager.default.createDirectory( at: directory, withIntermediateDirectories: false, attributes: [.posixPermissions: 0o700] ) var failures: [String] = [] do { try await body(server) } catch { failures.append("Operation: \(error)") } do { let files = try FileManager.default.contentsOfDirectory( atPath: directory.path ) if files.contains("s") { try await server.killServer() } try FileManager.default.removeItem(at: directory) } catch { failures.append("Cleanup at \(directory.path): \(error)") } if !failures.isEmpty { throw ExampleFailure(description: failures.joined(separator: "\n")) } } @main struct WorkspaceExample { static func main() async throws { try await withPrivateTmux { server in let started = try await server.run([ TmuxCommand("set-option", ["-g", "default-shell", "/bin/sh"]), TmuxCommand("set-option", ["-g", "default-command", "exec /bin/cat"]), TmuxCommand("set-environment", ["-g", "ENV", ""]), TmuxCommand("set-environment", ["-g", "BASH_ENV", ""]), TmuxCommand("new-session", ["-d", "-s", "bootstrap"]), ]) guard started.isSuccess else { throw ExampleFailure(description: started.errorText) } let workspace = Workspace( sessionName: "workspace-example", windows: [ WindowPlan( windowName: "editor", layout: "even-horizontal", panes: [PanePlan(), PanePlan()] ), WindowPlan(windowName: "logs", panes: [PanePlan()]), ] ) let session = try await WorkspaceBuilder.build(workspace, on: server) let snapshot = try await server.snapshot() let windows = snapshot.windows(of: session) guard windows.count == 2, let editor = windows.first(where: { $0.name == "editor" }), snapshot.panes(of: editor).count == 2 else { throw ExampleFailure(description: "Unexpected workspace layout") } print("built: \(windows.count) windows") print("editor: \(snapshot.panes(of: editor).count) panes") } } } ``` Build and run the executable: ```console $ swift run --jobs 2 WorkspaceExample ``` Expected output: ```text built: 2 windows editor: 2 panes ``` The bootstrap session keeps tmux alive while the builder checks for an existing session. The program sets its default command before creating the workspace. A fresh snapshot verifies the completed layout: the value returned when its first session is created does not include later window additions. Describe panes with Swift values or decode a configuration with [`Workspace.decode(json:)`](). The [guide](https://libtmux.org/en/swift/latest/workspace/internals/guides/) explains ownership, configuration input and failed-build cleanup. [Library source](https://github.com/libtmux/libtmux-swift/tree/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Sources/TmuxWorkspace). --- # TypeScript workspace builder examples Source: https://libtmux.org/en/ts/latest/workspace/internals/examples/ > Build and inspect a workspace on a private tmux server with TypeScript. Create a workspace with two windows and two editor panes, inspect the result, then stop its private tmux server. The `/bin/cat` commands keep panes open without depending on an application or log file. ## Prepare the project Use Bun 1.4.2 or newer, Git, and tmux 3.2a or newer on Unix. Create an empty consumer directory: ```console $ mkdir workspace-example && cd workspace-example ``` Fetch the source revision used by this example: ```console $ git init libtmux-source && \ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-ts.git && \ git -C libtmux-source fetch --depth 1 origin 3fe1ca654b81b8cbf4a13b777a001a3298c87a6f && \ git -C libtmux-source checkout --detach FETCH_HEAD ``` Create the project manifest. Both packages come from the same source tree: ```json title="package.json" { "private": true, "type": "module", "workspaces": [ "libtmux-source/packages/libtmux", "libtmux-source/packages/workspace" ], "dependencies": { "libtmux": "workspace:*", "@libtmux/workspace": "workspace:*" } } ``` The local workspaces keep the consumer and companion on the same core module from that checkout. Install the dependencies: ```console $ bun install --production ``` ## Build and remove a workspace Create the program below. The bootstrap session keeps the private server running while the program sets its default shell and builds the workspace. Cleanup covers a failed build as well as a successful one. ```typescript title="workspace.ts" import { mkdtemp, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Server } from "libtmux"; import { applyWorkspace } from "@libtmux/workspace"; const directory = await mkdtemp(join(tmpdir(), "libtmux-workspace-")); const server = new Server({ socketPath: join(directory, "tmux.sock"), configFile: "/dev/null", environment: { ...process.env, ENV: "/dev/null", BASH_ENV: "/dev/null" }, timeoutMs: 5_000, }); const failures: unknown[] = []; try { await server.newSession({ name: "bootstrap", shellCommand: "/bin/cat" }); await server.setGlobalOption("session", "default-shell", "/bin/sh"); const session = await applyWorkspace(server, { session_name: "workspace-example", windows: [ { window_name: "editor", panes: ["/bin/cat", "/bin/cat"] }, { window_name: "logs", panes: ["/bin/cat"] }, ], }); const windows = session.windows.toArray(); const editor = windows.find((window) => window.name === "editor"); if (windows.length !== 2 || editor?.panes.length !== 2) { throw new Error("Expected two windows and two editor panes"); } console.log(`built: ${windows.length} windows`); console.log(`editor: ${editor.panes.length} panes`); } catch (error) { failures.push(error); } finally { for (const cleanup of [ async () => { if ((await readdir(directory)).includes("tmux.sock")) await server.kill(); await rm(directory, { recursive: true }); }, ]) { try { await cleanup(); } catch (error) { failures.push(error); } } } if (failures.length > 0) throw new AggregateError(failures, "Workspace example failed"); ``` [`newSession`]() can fail after starting tmux. Cleanup checks the owned socket even if that call did not return. If stopping tmux fails, the program keeps the socket directory and reports the error. ## Verification Run the program: ```console $ bun run workspace.ts ``` Expected output: ```text built: 2 windows editor: 2 panes ``` [`applyWorkspace`]() returns the built session snapshot. Its windows and panes reflect the completed build; request another snapshot after later changes. The program removes every session on the private server before exiting. For a workspace that stays open, let the application retain its explicitly selected server and choose when to stop it. A failed build can leave partial work; the example's server cleanup removes it. [Example source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/examples/workspace/workspace.ts); [Workspace builder source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/workspace/src/builder.ts). --- # C# workspace builder API Source: https://libtmux.org/en/csharp/latest/workspace/reference/ > Internal reference for the C# workspace builder and configuration APIs. The [`LibTmux.Workspace`]() namespace provides configuration objects and a builder that uses a caller-supplied LibTmux [`Server`](). ## Configuration [`WorkspaceFile`](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacefile/) parses YAML and holds the session description. [`WorkspaceWindow`]() and [`WorkspacePane`]() hold nested configuration. [`WorkspaceFormatException`]() identifies unsupported or invalid configuration. ## Builder options [`WorkspaceBuilder`](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacebuilder/) accepts the server to use. [`PlanAsync`]() validates the declaration and observes that endpoint; its returned [`WorkspacePlan`](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceplan/) lists the actions to review before [`ApplyAsync`]() executes them. Enumerating those actions performs no I/O. Application rechecks the observed daemon and session. [`WorkspacePlanOptions`](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceplanoptions/) controls existing-session conflicts, readiness, host scripts, and cleanup. The defaults refuse an existing session and send pane input immediately. [`BuildAsync`]() combines planning and application with those defaults. Choose [`WorkspaceReadiness.Cooperative`](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacereadiness/) when pane startup can signal its assigned channel. Configure a positive `ReadinessTimeout`; a timeout prevents command delivery to that pane. [Topics](https://libtmux.org/en/csharp/latest/workspace/topics/) explains the startup contract and its limits. ## Results and failures [`WorkspaceResult`](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceresult/) contains the session, created windows, rejected final layouts, and action journals. Reusing an existing session creates no windows. A rejected final layout does not discard its window. [`WorkspaceBuildException`](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacebuildexception/) keeps a `PartialResult` when state could be materialized before failure. It can be null when no such result could be read. `Journal` records action outcomes; `CompensationJournal` records attempted cleanup. Inspect live tmux state before retrying; a missing result does not prove that no command reached tmux. Cancellation during application raises [`WorkspaceOperationCanceledException`](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceoperationcanceledexception/) with the caller's token, partial state, and journals. Cancellation does not imply rollback. `CompensateOnFailure` requests bounded cleanup only of resources proven to belong to that application. [Result contract](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Workspace/WorkspaceResult.cs); [Failure contract](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Workspace/WorkspaceBuildException.cs). ## API declarations - [LibTmux.Workspace.WorkspaceAction](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceaction/) - [LibTmux.Workspace.WorkspaceActionKind](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceactionkind/) - [LibTmux.Workspace.WorkspaceActionOutcome](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceactionoutcome/) - [LibTmux.Workspace.WorkspaceActionState](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceactionstate/) - [LibTmux.Workspace.WorkspaceBuilder](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacebuilder/) - [LibTmux.Workspace.WorkspaceBuildException](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacebuildexception/) - [LibTmux.Workspace.WorkspaceCommand](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacecommand/) - [LibTmux.Workspace.WorkspaceExistingSession](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceexistingsession/) - [LibTmux.Workspace.WorkspaceFile](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacefile/) - [LibTmux.Workspace.WorkspaceFormatException](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceformatexception/) - [LibTmux.Workspace.WorkspaceHostCommand](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacehostcommand/) - [LibTmux.Workspace.WorkspaceHostResult](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacehostresult/) - [LibTmux.Workspace.WorkspaceOperationCanceledException](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceoperationcanceledexception/) - [LibTmux.Workspace.WorkspacePane](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacepane/) - [LibTmux.Workspace.WorkspacePlan](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceplan/) - [LibTmux.Workspace.WorkspacePlanOptions](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceplanoptions/) - [LibTmux.Workspace.WorkspaceReadiness](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacereadiness/) - [LibTmux.Workspace.WorkspaceResult](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceresult/) - [LibTmux.Workspace.WorkspaceServerStartup](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspaceserverstartup/) - [LibTmux.Workspace.WorkspaceWindow](https://libtmux.org/en/csharp/latest/workspace/reference/libtmux-workspace-workspacewindow/) --- # C++ workspace builder API Source: https://libtmux.org/en/cxx/latest/workspace/reference/ > Internal reference for the C++ workspace builder and configuration APIs. The workspace API described here belongs to the repository consumer. Its headers are available through the `workspace_builder` target and are not installed core library headers. ## Typed description [`libtmux_consumers/workspace.hpp`]() defines the [`libtmux::workspace`]() namespace: - [`Workspace`]() holds the session name, directories, options, environment, and windows. - [`Window`]() holds layout, options, index, focus, and panes. - [`Pane`]() holds its shell, directory, environment, focus, and commands. - [`Command`]() controls text, Enter, delays, and history suppression. [`build(const Server&, const Workspace&)`]() returns `libtmux::expected`. [`BuildError`]() contains a window index and reason. It does not contain a rollback result or guarantee that the server is unchanged. ## YAML reader [`libtmux_consumers/tmuxp.hpp`]() declares [`parse_tmuxp(std::string_view)`](), returning `libtmux::expected`. [`ParseError.where`]() identifies the configuration path and `reason` explains the refusal. The compiled implementation in [`src/tmuxp.cpp`]() is the part that depends on yaml-cpp. Applications constructing [`Workspace`]() values directly do not need to parse YAML. ## Core operations The returned session is a core libtmux value. Use the [C++ core reference](https://libtmux.org/en/cxx/latest/reference/) for subsequent inspection and mutation. Consumer source contracts remain the authority for the workspace types. [Workspace header](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/include/libtmux_consumers/workspace.hpp); [YAML header](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/include/libtmux_consumers/tmuxp.hpp). ## API declarations - [libtmux::workspace::append](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-append/) - [libtmux::workspace::BeforeBuild](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-beforebuild/) - [libtmux::workspace::build](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-build/) - [libtmux::workspace::BuildError](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-builderror/) - [libtmux::workspace::BuildEvent](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-buildevent/) - [libtmux::workspace::BuildObserver](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-buildobserver/) - [libtmux::workspace::BuildPhase](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-buildphase/) - [libtmux::workspace::BuildStop](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-buildstop/) - [libtmux::workspace::Command](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-command/) - [libtmux::workspace::Pane](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-pane/) - [libtmux::workspace::parse_tmuxp](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-parse_tmuxp/) - [libtmux::workspace::ParseError](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-parseerror/) - [libtmux::workspace::validate_layouts](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-validate_layouts/) - [libtmux::workspace::Window](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-window/) - [libtmux::workspace::Workspace](https://libtmux.org/en/cxx/latest/workspace/reference/libtmux-workspace-workspace/) --- # Go workspace builder API Source: https://libtmux.org/en/go/latest/workspace/reference/ > Internal reference for the Go workspace builder and configuration APIs. The [`workspace`]() module takes core [`tmux.Server`]() and session handles. Parsing is independent of a running server; building takes a context for deadlines and cancellation. ## Parse configuration [`Parse`](https://libtmux.org/en/go/latest/workspace/reference/workspace-parse/) reads YAML into a [`Workspace`](https://libtmux.org/en/go/latest/workspace/reference/workspace-workspace/). Its errors match [`ErrInvalidWorkspace`](). Inspect the individual diagnostics to locate unknown keys or invalid values. [`Window`](https://libtmux.org/en/go/latest/workspace/reference/workspace-window/), [`Pane`](https://libtmux.org/en/go/latest/workspace/reference/workspace-pane/), and [`Command`](https://libtmux.org/en/go/latest/workspace/reference/workspace-command/) let applications construct the same data in Go. [`Bool`]() preserves tmuxp's supported boolean spellings. ## Build a session [`Build`](https://libtmux.org/en/go/latest/workspace/reference/workspace-build/) creates the initial session and owns a temporary control connection for the duration of construction. It returns a session and an error; a non-nil error can accompany a partial session. [`BuildInto`](https://libtmux.org/en/go/latest/workspace/reference/workspace-buildinto/) populates a supplied session and preserves the caller's connection ownership. [`Workspace.InitialSessionRequest`]() produces the initial request for that workflow. ## Inspect before and after [`Workspace.MissingDirectories`]() reports working directories absent on the current machine. It does not make them validation errors. After construction, inspect live state through the core API rather than reading relations from the creation handle. [Build contracts](https://github.com/libtmux/libtmux-go/blob/5f808882015a975a65acc7f9da5b3ff0d5cbdc91/workspace/builder.go); [Configuration contracts](https://github.com/libtmux/libtmux-go/blob/5f808882015a975a65acc7f9da5b3ff0d5cbdc91/workspace/workspace.go). ## API declarations - [workspace.Bool](https://libtmux.org/en/go/latest/workspace/reference/workspace-bool/) - [workspace.Build](https://libtmux.org/en/go/latest/workspace/reference/workspace-build/) - [workspace.BuildInto](https://libtmux.org/en/go/latest/workspace/reference/workspace-buildinto/) - [workspace.Command](https://libtmux.org/en/go/latest/workspace/reference/workspace-command/) - [workspace.ErrInvalidWorkspace](https://libtmux.org/en/go/latest/workspace/reference/workspace-errinvalidworkspace/) - [workspace.Pane](https://libtmux.org/en/go/latest/workspace/reference/workspace-pane/) - [workspace.Parse](https://libtmux.org/en/go/latest/workspace/reference/workspace-parse/) - [workspace.Window](https://libtmux.org/en/go/latest/workspace/reference/workspace-window/) - [workspace.Workspace](https://libtmux.org/en/go/latest/workspace/reference/workspace-workspace/) --- # Java workspace builder API Source: https://libtmux.org/en/java/latest/workspace/reference/ > Internal reference for the Java workspace builder and configuration APIs. The [`io.github.libtmux.workspace`](https://github.com/libtmux/libtmux-java/tree/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-workspace/src/main/java/io/github/libtmux/workspace) package exposes the builder facade and configuration records. Applications can parse YAML or construct the records before building through a core [`Server`](). ## Builder facade [`WorkspaceBuilder`](https://libtmux.org/en/java/latest/workspace/reference/io-github-libtmux-workspace-workspacebuilder-workspacebuilder/) provides three static entry points: - [`read(Path)`]() reads a YAML file and wraps I/O errors in [`UncheckedIOException`](). - [`parse(String)`]() reads YAML text and rejects invalid descriptions. - [`build(Server, Workspace)`]() creates the session and returns a refreshed handle. Parsing and reading do not contact tmux. Build-time checks include the target server's support for the requested layout. ## Configuration records [`Workspace`](https://libtmux.org/en/java/latest/workspace/reference/io-github-libtmux-workspace-workspace-workspace/) holds the session name and ordered windows. [`WindowSpec`](https://libtmux.org/en/java/latest/workspace/reference/io-github-libtmux-workspace-windowspec-windowspec/) holds the name, optional layout, and panes. [`PaneSpec`](https://libtmux.org/en/java/latest/workspace/reference/io-github-libtmux-workspace-panespec-panespec/) holds the ordered shell commands. These records copy their lists so later changes to an input list do not alter a description already constructed. ## Errors and lifetime Invalid configuration raises [`IllegalArgumentException`](). Build failures keep the original exception and attach cleanup failures as suppressed exceptions. The caller retains ownership of the supplied server and the successful session. Use the core session API for later inspection or removal. [Public builder contract](https://github.com/libtmux/libtmux-java/blob/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-workspace/src/main/java/io/github/libtmux/workspace/WorkspaceBuilder.java) ## API declarations - [io.github.libtmux.workspace.PaneSpec](https://libtmux.org/en/java/latest/workspace/reference/io-github-libtmux-workspace-panespec-panespec/) - [io.github.libtmux.workspace.WindowSpec](https://libtmux.org/en/java/latest/workspace/reference/io-github-libtmux-workspace-windowspec-windowspec/) - [io.github.libtmux.workspace.Workspace](https://libtmux.org/en/java/latest/workspace/reference/io-github-libtmux-workspace-workspace-workspace/) - [io.github.libtmux.workspace.WorkspaceBuilder](https://libtmux.org/en/java/latest/workspace/reference/io-github-libtmux-workspace-workspacebuilder-workspacebuilder/) --- # Python workspace internal API Source: https://libtmux.org/en/py/latest/workspace/reference/ > tmuxp APIs for expanding configuration, building sessions, and exporting layouts. tmuxp's workspace APIs are internal implementation details with no stability guarantee. They use libtmux's [`Server`](), [`Session`](), [`Window`](), and [`Pane`]() objects for tmux control. Use the [CLI guide](https://libtmux.org/en/py/latest/guides/) to load workspace files. ## Load and validate [`tmuxp.workspace.loader.expand`]() normalizes shorthand, variables, and paths. [`loader.trickle`]() applies inherited configuration after expansion. Both operate on workspace dictionaries. [`validation.validate_schema`]() checks required structure; it is not a complete machine-readable schema of every runtime behavior. Consult the upstream [loader API](https://tmuxp.git-pull.com/internals/api/workspace/loader/) and [validation API](https://tmuxp.git-pull.com/internals/api/workspace/validation/) for parameter and error details. ## Build and extend [`tmuxp.workspace.builder.WorkspaceBuilder`]() is the compatibility alias for [`ClassicWorkspaceBuilder`](). Construct it with expanded `session_config` and a libtmux server, call `build`, then read [`ClassicWorkspaceBuilder.session`](). [`WorkspaceBuilderProtocol`]() defines the interface used by the CLI, including construction callbacks, building into an optional existing session, and session discovery. The registry resolves named entry points or import paths. Use the upstream [builder API](https://tmuxp.git-pull.com/internals/api/workspace/builder/) and [custom builder guide](https://tmuxp.git-pull.com/topics/custom-workspace-builders/) when implementing an extension. ## Export and CLI [`tmuxp.workspace.freezer.freeze(session)`]() reads a live session into a configuration dictionary. [`freezer.inline`]() compacts that expanded structure for a file. The [freezer API](https://tmuxp.git-pull.com/internals/api/workspace/freezer/) documents both operations. The [CLI reference](https://tmuxp.git-pull.com/cli/) covers loading, freezing, listing, searching, editing, importing, and converting workspaces. These are application commands, separate from the language-level workspace builder. [Public builder exports](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/__init__.py) ## API declarations - [tmuxp.exc.ActiveSessionMissingWorkspaceException](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-activesessionmissingworkspaceexception/) - [tmuxp.workspace.builder.available_builders](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-available_builders/) - [tmuxp.exc.BeforeLoadScriptError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-beforeloadscripterror/) - [tmuxp.exc.BeforeLoadScriptNotExists](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-beforeloadscriptnotexists/) - [tmuxp.workspace.builder.ClassicWorkspaceBuilder](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-classicworkspacebuilder/) - [tmuxp.cli.cli](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-cli/) - [tmuxp.cli.CLI_DESCRIPTION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-cli_description/) - [tmuxp.cli.debug_info.CLIDebugInfoNamespace](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-debug_info-clidebuginfonamespace/) - [tmuxp.cli.freeze.CLIFreezeNamespace](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-freeze-clifreezenamespace/) - [tmuxp.cli.load.CLILoadNamespace](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-load-cliloadnamespace/) - [tmuxp.cli.ls.CLILsNamespace](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-ls-clilsnamespace/) - [tmuxp.cli.CLINamespace](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-clinamespace/) - [tmuxp.cli.search.CLISearchNamespace](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-clisearchnamespace/) - [tmuxp.cli.shell.CLIShellNamespace](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-shell-clishellnamespace/) - [tmuxp.workspace.builder.classic.COLUMNS_FALLBACK](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-classic-columns_fallback/) - [tmuxp.cli.convert.command_convert](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-convert-command_convert/) - [tmuxp.cli.debug_info.command_debug_info](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-debug_info-command_debug_info/) - [tmuxp.cli.edit.command_edit](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-edit-command_edit/) - [tmuxp.cli.freeze.command_freeze](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-freeze-command_freeze/) - [tmuxp.cli.import_config.command_import](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-import_config-command_import/) - [tmuxp.cli.import_config.command_import_teamocil](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-import_config-command_import_teamocil/) - [tmuxp.cli.import_config.command_import_tmuxinator](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-import_config-command_import_tmuxinator/) - [tmuxp.cli.load.command_load](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-load-command_load/) - [tmuxp.cli.ls.command_ls](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-ls-command_ls/) - [tmuxp.cli.search.command_search](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-command_search/) - [tmuxp.cli.shell.command_shell](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-shell-command_shell/) - [tmuxp.cli.search.compile_search_patterns](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-compile_search_patterns/) - [tmuxp.plugin.Config](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-config/) - [tmuxp.cli.convert.CONVERT_DESCRIPTION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-convert-convert_description/) - [tmuxp.cli.convert.ConvertUnknownFileType](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-convert-convertunknownfiletype/) - [tmuxp.cli.convert.create_convert_subparser](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-convert-create_convert_subparser/) - [tmuxp.cli.debug_info.create_debug_info_subparser](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-debug_info-create_debug_info_subparser/) - [tmuxp.cli.edit.create_edit_subparser](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-edit-create_edit_subparser/) - [tmuxp.cli.freeze.create_freeze_subparser](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-freeze-create_freeze_subparser/) - [tmuxp.cli.import_config.create_import_subparser](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-import_config-create_import_subparser/) - [tmuxp.cli.load.create_load_subparser](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-load-create_load_subparser/) - [tmuxp.cli.ls.create_ls_subparser](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-ls-create_ls_subparser/) - [tmuxp.cli.create_parser](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-create_parser/) - [tmuxp.cli.search.create_search_subparser](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-create_search_subparser/) - [tmuxp.cli.shell.create_shell_subparser](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-shell-create_shell_subparser/) - [tmuxp.cli.debug_info.DEBUG_INFO_DESCRIPTION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-debug_info-debug_info_description/) - [tmuxp.log.debug_log_template](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-log-debug_log_template/) - [tmuxp.log.DebugLogFormatter](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-log-debuglogformatter/) - [tmuxp.plugin.DEFAULT_CONFIG](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-default_config/) - [tmuxp.cli.search.DEFAULT_FIELDS](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-default_fields/) - [tmuxp.shell.detect_best_shell](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-detect_best_shell/) - [tmuxp.cli.edit.EDIT_DESCRIPTION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-edit-edit_description/) - [tmuxp.exc.EmptyWorkspaceException](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-emptyworkspaceexception/) - [tmuxp.cli.search.evaluate_match](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-evaluate_match/) - [tmuxp.workspace.loader.expand](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-loader-expand/) - [tmuxp.workspace.loader.expand_cmd](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-loader-expand_cmd/) - [tmuxp.workspace.loader.expandshell](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-loader-expandshell/) - [tmuxp.cli.search.extract_workspace_fields](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-extract_workspace_fields/) - [tmuxp.cli.search.FIELD_ALIASES](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-field_aliases/) - [tmuxp.workspace.finders.find_local_workspace_files](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-finders-find_local_workspace_files/) - [tmuxp.cli.search.find_search_matches](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-find_search_matches/) - [tmuxp.workspace.finders.find_workspace_file](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-finders-find_workspace_file/) - [tmuxp.workspace.freezer.freeze](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-freezer-freeze/) - [tmuxp.cli.freeze.FREEZE_DESCRIPTION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-freeze-freeze_description/) - [tmuxp.shell.get_bpython](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-get_bpython/) - [tmuxp.shell.get_code](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-get_code/) - [tmuxp.util.get_current_pane](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-util-get_current_pane/) - [tmuxp.workspace.builder.get_default_columns](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-get_default_columns/) - [tmuxp.workspace.builder.get_default_rows](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-get_default_rows/) - [tmuxp.shell.get_ipython](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-get_ipython/) - [tmuxp.shell.get_ipython_arguments](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-get_ipython_arguments/) - [tmuxp.shell.get_launch_args](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-get_launch_args/) - [tmuxp.util.get_pane](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-util-get_pane/) - [tmuxp.shell.get_ptipython](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-get_ptipython/) - [tmuxp.shell.get_ptpython](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-get_ptpython/) - [tmuxp.util.get_session](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-util-get_session/) - [tmuxp.cli.import_config.get_teamocil_dir](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-import_config-get_teamocil_dir/) - [tmuxp.cli.import_config.get_tmuxinator_dir](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-import_config-get_tmuxinator_dir/) - [tmuxp.util.get_window](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-util-get_window/) - [tmuxp.workspace.finders.get_workspace_dir](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-finders-get_workspace_dir/) - [tmuxp.workspace.finders.get_workspace_dir_candidates](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-finders-get_workspace_dir_candidates/) - [tmuxp.shell.has_bpython](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-has_bpython/) - [tmuxp.shell.has_ipython](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-has_ipython/) - [tmuxp.shell.has_ptipython](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-has_ptipython/) - [tmuxp.shell.has_ptpython](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-has_ptpython/) - [tmuxp.cli.search.highlight_matches](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-highlight_matches/) - [tmuxp.cli.import_config.import_config](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-import_config-import_config/) - [tmuxp.cli.import_config.IMPORT_DESCRIPTION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-import_config-import_description/) - [tmuxp.workspace.importers.import_teamocil](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-importers-import_teamocil/) - [tmuxp.workspace.importers.import_tmuxinator](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-importers-import_tmuxinator/) - [tmuxp.cli.import_config.ImportConfigFn](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-import_config-importconfigfn/) - [tmuxp.workspace.finders.in_cwd](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-finders-in_cwd/) - [tmuxp.workspace.finders.in_dir](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-finders-in_dir/) - [tmuxp.workspace.freezer.inline](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-freezer-inline/) - [tmuxp.cli.search.InvalidFieldError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-invalidfielderror/) - [tmuxp.workspace.validation.InvalidPluginsValidationError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-validation-invalidpluginsvalidationerror/) - [tmuxp.exc.InvalidWorkspaceBuilder](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-invalidworkspacebuilder/) - [tmuxp.exc.InvalidWorkspaceBuilderOption](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-invalidworkspacebuilderoption/) - [tmuxp.workspace.finders.is_pure_name](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-finders-is_pure_name/) - [tmuxp.workspace.finders.is_workspace_file](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-finders-is_workspace_file/) - [tmuxp.shell.launch](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-shell-launch/) - [tmuxp.log.LEVEL_COLORS](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-log-level_colors/) - [tmuxp.plugin.LIBTMUX_MAX_VERSION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-libtmux_max_version/) - [tmuxp.plugin.LIBTMUX_MIN_VERSION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-libtmux_min_version/) - [tmuxp.cli.load.LOAD_DESCRIPTION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-load-load_description/) - [tmuxp.cli.load.load_plugins](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-load-load_plugins/) - [tmuxp.cli.load.load_workspace](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-load-load_workspace/) - [tmuxp.workspace.finders.LOCAL_WORKSPACE_FILES](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-finders-local_workspace_files/) - [tmuxp.log.LogFormatter](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-log-logformatter/) - [tmuxp.cli.ls.LS_DESCRIPTION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-ls-ls_description/) - [tmuxp.cli.search.normalize_fields](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-normalize_fields/) - [tmuxp.cli.ns](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-ns/) - [tmuxp.util.oh_my_zsh_auto_title](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-util-oh_my_zsh_auto_title/) - [tmuxp.exc.PaneNotFound](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-panenotfound/) - [tmuxp.workspace.options.PaneReadiness](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-options-panereadiness/) - [tmuxp.cli.search.parse_query_terms](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-parse_query_terms/) - [tmuxp.workspace.builder.prepended_sys_path](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-prepended_sys_path/) - [tmuxp.cli.utils.prompt](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-utils-prompt/) - [tmuxp.cli.utils.prompt_bool](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-utils-prompt_bool/) - [tmuxp.cli.utils.prompt_choices](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-utils-prompt_choices/) - [tmuxp.cli.utils.prompt_yes_no](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-utils-prompt_yes_no/) - [tmuxp.util.PY2](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-util-py2/) - [tmuxp.workspace.builder.resolve_builder_class](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-resolve_builder_class/) - [tmuxp.workspace.builder.resolve_builder_paths](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-resolve_builder_paths/) - [tmuxp.workspace.options.resolve_session_shell](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-options-resolve_session_shell/) - [tmuxp.workspace.builder.classic.ROWS_FALLBACK](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-classic-rows_fallback/) - [tmuxp.util.run_before_script](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-util-run_before_script/) - [tmuxp.workspace.validation.SchemaValidationError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-validation-schemavalidationerror/) - [tmuxp.cli.search.SEARCH_DESCRIPTION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-search_description/) - [tmuxp.cli.search.SearchPattern](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-searchpattern/) - [tmuxp.cli.search.SearchToken](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-searchtoken/) - [tmuxp.exc.SessionMissingWorkspaceException](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-sessionmissingworkspaceexception/) - [tmuxp.workspace.validation.SessionNameMissingValidationError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-validation-sessionnamemissingvalidationerror/) - [tmuxp.exc.SessionNotFound](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-sessionnotfound/) - [tmuxp.log.set_style](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-log-set_style/) - [tmuxp.log.setup_log_file](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-log-setup_log_file/) - [tmuxp.cli.setup_logger](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-setup_logger/) - [tmuxp.plugin.setup_plugin_config](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-setup_plugin_config/) - [tmuxp.cli.shell.SHELL_DESCRIPTION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-shell-shell_description/) - [tmuxp.workspace.options.shell_is_zsh](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-options-shell_is_zsh/) - [tmuxp.cli.startup](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-startup/) - [tmuxp.types.StrPath](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-types-strpath/) - [tmuxp.plugin.TMUX_MAX_VERSION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-tmux_max_version/) - [tmuxp.plugin.TMUX_MIN_VERSION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-tmux_min_version/) - [tmuxp.log.tmuxp_echo](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-log-tmuxp_echo/) - [tmuxp.plugin.TMUXP_MAX_VERSION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-tmuxp_max_version/) - [tmuxp.plugin.TMUXP_MIN_VERSION](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-tmuxp_min_version/) - [tmuxp.cli.debug_info.tmuxp_path](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-debug_info-tmuxp_path/) - [tmuxp.exc.TmuxpException](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-tmuxpexception/) - [tmuxp.log.TmuxpLoggerAdapter](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-log-tmuxploggeradapter/) - [tmuxp.plugin.TmuxpPlugin](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-tmuxpplugin/) - [tmuxp.exc.TmuxpPluginException](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-tmuxppluginexception/) - [tmuxp.workspace.loader.trickle](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-loader-trickle/) - [tmuxp.cli.search.VALID_FIELDS](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-valid_fields/) - [tmuxp.workspace.constants.VALID_WORKSPACE_DIR_FILE_EXTENSIONS](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-constants-valid_workspace_dir_file_extensions/) - [tmuxp.plugin.validate_plugin_config](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-plugin-validate_plugin_config/) - [tmuxp.workspace.validation.validate_schema](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-validation-validate_schema/) - [tmuxp.workspace.validation.WindowListMissingValidationError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-validation-windowlistmissingvalidationerror/) - [tmuxp.workspace.validation.WindowNameMissingValidationError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-validation-windownamemissingvalidationerror/) - [tmuxp.exc.WindowNotFound](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-windownotfound/) - [tmuxp.workspace.builder.WORKSPACE_BUILDERS_GROUP](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-workspace_builders_group/) - [tmuxp.workspace.builder.WorkspaceBuilder](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-workspacebuilder/) - [tmuxp.exc.WorkspaceBuilderError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-workspacebuildererror/) - [tmuxp.exc.WorkspaceBuilderImportError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-workspacebuilderimporterror/) - [tmuxp.exc.WorkspaceBuilderNotFound](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-workspacebuildernotfound/) - [tmuxp.workspace.options.WorkspaceBuilderOptions](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-options-workspacebuilderoptions/) - [tmuxp.exc.WorkspaceBuilderPathError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-workspacebuilderpatherror/) - [tmuxp.workspace.builder.WorkspaceBuilderProtocol](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-workspace-builder-workspacebuilderprotocol/) - [tmuxp.exc.WorkspaceError](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-exc-workspaceerror/) - [tmuxp.cli.search.WorkspaceFields](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-workspacefields/) - [tmuxp.cli.ls.WorkspaceInfo](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-ls-workspaceinfo/) - [tmuxp.cli.search.WorkspaceSearchResult](https://libtmux.org/en/py/latest/workspace/reference/tmuxp-cli-search-workspacesearchresult/) --- # Rust workspace builder API Source: https://libtmux.org/en/rs/latest/workspace/reference/ > Internal reference for the Rust workspace builder and configuration APIs. The `tmux_workspace` crate exports its configuration types, builder, and [`freeze`]() function. The core libtmux server and session remain the handles used for actual tmux operations. ## Configuration [`Workspace`](https://libtmux.org/en/rs/latest/workspace/reference/config-workspace/) holds the session description. [`Workspace::from_yaml`]() parses it, and [`to_yaml`]() emits its YAML representation. [`WindowConfig`]() and [`PaneConfig`]() describe the nested objects; [`ConfigError`]() identifies invalid configuration. ## Builder [`WorkspaceBuilder`](https://libtmux.org/en/rs/latest/workspace/reference/src-workspacebuilder/) borrows a [`Server`](). `new` selects that server, [`plan`]() returns the inert construction plan, and [`build`]() asynchronously creates the requested session. Keep the server alive for the builder's lifetime. [`BuildError`]() distinguishes configuration errors, underlying libtmux errors, refused operations, a missing initial window, and an existing session name. Successful completion returns a [`Session`](); failure does not imply rollback. ## Export [`freeze(&Session)`]() asynchronously produces a [`Workspace`]() describing the live session. Serialize that result with [`to_yaml`](). The exported structure is suitable for review and editing; it cannot restore process memory or recover an original shell command from a running program. [Public exports and builder](https://github.com/libtmux/libtmux-rs/blob/9331cdf556ea7a1f2589e9c3e6cece6ccdc7765c/crates/tmux-workspace/src/lib.rs); [Freeze API](https://github.com/libtmux/libtmux-rs/blob/9331cdf556ea7a1f2589e9c3e6cece6ccdc7765c/crates/tmux-workspace/src/freeze.rs). ## API declarations - [src.BuildError](https://libtmux.org/en/rs/latest/workspace/reference/src-builderror/) - [config.ConfigError](https://libtmux.org/en/rs/latest/workspace/reference/config-configerror/) - [freeze.freeze](https://libtmux.org/en/rs/latest/workspace/reference/freeze-freeze/) - [config.PaneConfig](https://libtmux.org/en/rs/latest/workspace/reference/config-paneconfig/) - [config.ShellCommand](https://libtmux.org/en/rs/latest/workspace/reference/config-shellcommand/) - [config.WindowConfig](https://libtmux.org/en/rs/latest/workspace/reference/config-windowconfig/) - [config.Workspace](https://libtmux.org/en/rs/latest/workspace/reference/config-workspace/) - [src.WorkspaceBuilder](https://libtmux.org/en/rs/latest/workspace/reference/src-workspacebuilder/) --- # Swift workspace builder API Source: https://libtmux.org/en/swift/latest/workspace/reference/ > Internal reference for the Swift workspace builder and configuration APIs. Import `TmuxWorkspace` for the configuration and builder, and [`LibTmux`](https://libtmux.org/en/swift/latest/reference/) for the server and returned session value. ## Configuration values [`Workspace`](https://libtmux.org/en/swift/latest/workspace/reference/workspace/) contains the session name, optional working directory, and ordered windows. [`WindowPlan`]() contains its name, directory, layout, and panes. [`PanePlan`]() contains its directory and commands. The values conform to [`Sendable`](), [`Hashable`](), and [`Codable`](). [`Workspace.decode(json:)`]() reads JSON data. [`Workspace.decode(yaml:)`]() reads a string only when `YAMLWorkspaces` is enabled. Encoding these values writes the existing description; it does not query tmux for a live export. ## Builder [`WorkspaceBuilder`](https://libtmux.org/en/swift/latest/workspace/reference/workspacebuilder/) exposes the async [`build(_:on:)`]() operation. It creates a new session on the supplied server and returns a [`Session`](). Keep using the server for live observation; session properties do not refresh themselves. ## Typed errors [`WorkspaceBuilderError`](https://libtmux.org/en/swift/latest/workspace/reference/workspacebuildererror/) distinguishes an empty window list, an existing session name, a vanished session, underlying tmux errors, and failure of rollback. [`rollbackFailed(original:cleanup:)`]() preserves both causes. The caller can report the initiating problem and separately inspect whether cleanup left objects behind. The supplied server remains owned by the caller. [Value and decoding contracts](https://github.com/libtmux/libtmux-swift/blob/f02a4668570e1cc5198c941413750e021f42c214/Sources/TmuxWorkspace/Workspace.swift); [Builder contract](https://github.com/libtmux/libtmux-swift/blob/f02a4668570e1cc5198c941413750e021f42c214/Sources/TmuxWorkspace/WorkspaceBuilder.swift). ## API declarations - [PanePlan](https://libtmux.org/en/swift/latest/workspace/reference/paneplan/) - [TmuxShellCommand](https://libtmux.org/en/swift/latest/workspace/reference/tmuxshellcommand/) - [WindowPlan](https://libtmux.org/en/swift/latest/workspace/reference/windowplan/) - [Workspace](https://libtmux.org/en/swift/latest/workspace/reference/workspace/) - [WorkspaceBuilder](https://libtmux.org/en/swift/latest/workspace/reference/workspacebuilder/) - [WorkspaceBuilderError](https://libtmux.org/en/swift/latest/workspace/reference/workspacebuildererror/) --- # TypeScript workspace builder API Source: https://libtmux.org/en/ts/latest/workspace/reference/ > Internal reference for the TypeScript workspace builder and configuration APIs. Import planning and application from `@libtmux/workspace`, and parsers from `@libtmux/workspace/config`. Application operates on a core libtmux [`Server`]() supplied by the caller; creating that server does not choose a workspace or apply one automatically. ## Parse and validate [`parseWorkspace`](https://libtmux.org/en/ts/latest/workspace/reference/config-parseworkspace/) validates data already read by your application. [`parseWorkspaceYaml`](https://libtmux.org/en/ts/latest/workspace/reference/config-parseworkspaceyaml/) adds Bun's YAML parsing. Both produce the workspace configuration consumed by the builder. ## Plan and apply [`planWorkspace`](https://libtmux.org/en/ts/latest/workspace/reference/builder-planworkspace/) returns a description of membership changes. [`WorkspacePlan`](https://libtmux.org/en/ts/latest/workspace/reference/planning-workspaceplan/) records creations, removals, renames, and retained surplus. [`applyWorkspace`](https://libtmux.org/en/ts/latest/workspace/reference/builder-applyworkspace/) performs the work and resolves to the resulting [`Session`](). Its options control pruning and whether commands run in existing panes. Planning accepts pruning policy; command policy belongs to application. ## Handle failure [`WorkspaceApplyError`](https://libtmux.org/en/ts/latest/workspace/reference/builder-workspaceapplyerror/) preserves the cause and completed milestones. Reinspect tmux before retrying; the error is not a transaction log of every effect or a receipt for shell commands. The language API builds workspaces directly. Availability through an MCP server is a separate protocol capability; consult this port's [MCP section](https://libtmux.org/en/ts/latest/mcp/) for its advertised tools. [Public exports](https://github.com/libtmux/libtmux-ts/blob/f85b8de551353f746d50eaf36bf0112f4fe5a528/packages/workspace/package.json) ## API declarations - [builder.applyWorkspace](https://libtmux.org/en/ts/latest/workspace/reference/builder-applyworkspace/) - [operation_options.ApplyWorkspaceOptions](https://libtmux.org/en/ts/latest/workspace/reference/operation_options-applyworkspaceoptions/) - [ownership.claimSession](https://libtmux.org/en/ts/latest/workspace/reference/ownership-claimsession/) - [operation_options.CommandPolicy](https://libtmux.org/en/ts/latest/workspace/reference/operation_options-commandpolicy/) - [config.initialPaneStartDirectory](https://libtmux.org/en/ts/latest/workspace/reference/config-initialpanestartdirectory/) - [ownership.mayPrune](https://libtmux.org/en/ts/latest/workspace/reference/ownership-mayprune/) - [config.optionValue](https://libtmux.org/en/ts/latest/workspace/reference/config-optionvalue/) - [ownership.ownedByWorkspace](https://libtmux.org/en/ts/latest/workspace/reference/ownership-ownedbyworkspace/) - [config.paneCommands](https://libtmux.org/en/ts/latest/workspace/reference/config-panecommands/) - [config.paneStartDirectory](https://libtmux.org/en/ts/latest/workspace/reference/config-panestartdirectory/) - [config.paneWantsFocus](https://libtmux.org/en/ts/latest/workspace/reference/config-panewantsfocus/) - [config.parseWorkspace](https://libtmux.org/en/ts/latest/workspace/reference/config-parseworkspace/) - [config.parseWorkspaceYaml](https://libtmux.org/en/ts/latest/workspace/reference/config-parseworkspaceyaml/) - [builder.planWorkspace](https://libtmux.org/en/ts/latest/workspace/reference/builder-planworkspace/) - [operation_options.PlanWorkspaceOptions](https://libtmux.org/en/ts/latest/workspace/reference/operation_options-planworkspaceoptions/) - [ownership.PrunePolicy](https://libtmux.org/en/ts/latest/workspace/reference/ownership-prunepolicy/) - [config.windowStartDirectory](https://libtmux.org/en/ts/latest/workspace/reference/config-windowstartdirectory/) - [config.Workspace](https://libtmux.org/en/ts/latest/workspace/reference/config-workspace/) - [builder.WorkspaceApplyError](https://libtmux.org/en/ts/latest/workspace/reference/builder-workspaceapplyerror/) - [builder.WorkspaceApplyMilestone](https://libtmux.org/en/ts/latest/workspace/reference/builder-workspaceapplymilestone/) - [builder.WorkspaceApplyStage](https://libtmux.org/en/ts/latest/workspace/reference/builder-workspaceapplystage/) - [config.WorkspaceInput](https://libtmux.org/en/ts/latest/workspace/reference/config-workspaceinput/) - [config.WorkspaceOptionValue](https://libtmux.org/en/ts/latest/workspace/reference/config-workspaceoptionvalue/) - [config.WorkspacePane](https://libtmux.org/en/ts/latest/workspace/reference/config-workspacepane/) - [planning.WorkspacePaneCreation](https://libtmux.org/en/ts/latest/workspace/reference/planning-workspacepanecreation/) - [planning.WorkspacePaneRemoval](https://libtmux.org/en/ts/latest/workspace/reference/planning-workspacepaneremoval/) - [planning.WorkspacePlan](https://libtmux.org/en/ts/latest/workspace/reference/planning-workspaceplan/) - [planning.WorkspaceRetention](https://libtmux.org/en/ts/latest/workspace/reference/planning-workspaceretention/) - [config.WorkspaceWindow](https://libtmux.org/en/ts/latest/workspace/reference/config-workspacewindow/) - [planning.WorkspaceWindowCreation](https://libtmux.org/en/ts/latest/workspace/reference/planning-workspacewindowcreation/) - [config.WorkspaceWindowInput](https://libtmux.org/en/ts/latest/workspace/reference/config-workspacewindowinput/) - [planning.WorkspaceWindowPlacement](https://libtmux.org/en/ts/latest/workspace/reference/planning-workspacewindowplacement/) - [planning.WorkspaceWindowRemoval](https://libtmux.org/en/ts/latest/workspace/reference/planning-workspacewindowremoval/) - [planning.WorkspaceWindowRename](https://libtmux.org/en/ts/latest/workspace/reference/planning-workspacewindowrename/) --- # Workspace reference generation Source: https://libtmux.org/en/csharp/latest/workspace/internals/documentation/ > Generate command references from the parser and verify task examples against the CLI. The executable's parser owns its command names, arguments and options. Keep reference generation tied to those definitions. ## Command metadata System.CommandLine owns the command definitions. `--generate reference` exports metadata; `--generate man` writes the manual. See [shell completion](https://libtmux.org/en/csharp/latest/workspace/cli/completion/) for end-user setup. A generated parser reference describes syntax; task examples also need to exercise the underlying services and their cleanup. ## Site integration Record the CLI's own source revision independently from the core library reference. Keep commands, configuration and examples specific to that source. Use the same content selection for HTML, search, Markdown and machine exports. Verify guides against a private tmux server, with cleanup limited to the objects the test owns. Check failure cases as well as successful construction. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Workspace reference generation Source: https://libtmux.org/en/cxx/latest/workspace/internals/documentation/ > Generate command references from the parser and verify task examples against the CLI. The executable's parser owns its command names, arguments and options. Keep reference generation tied to those definitions. ## Command metadata CLI11 owns the command definitions. The CLI derives shell completion from that graph. The site task guides describe executable operations separately from the workspace library API. See [shell completion](https://libtmux.org/en/cxx/latest/workspace/cli/completion/) for end-user setup. A generated parser reference describes syntax; task examples also need to exercise the underlying services and their cleanup. ## Site integration Record the CLI's own source revision independently from the core library reference. Keep commands, configuration and examples specific to that source. Use the same content selection for HTML, search, Markdown and machine exports. Verify guides against a private tmux server, with cleanup limited to the objects the test owns. Check failure cases as well as successful construction. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Workspace reference generation Source: https://libtmux.org/en/go/latest/workspace/internals/documentation/ > Generate command references from the parser and verify task examples against the CLI. The executable's parser owns its command names, arguments and options. Keep reference generation tied to those definitions. ## Command metadata Cobra owns the command tree. `--command-tree` exports JSON metadata; `--generate-docs` accepts `markdown`, `man` or `yaml`. See [shell completion](https://libtmux.org/en/go/latest/workspace/cli/completion/) for end-user setup. A generated parser reference describes syntax; task examples also need to exercise the underlying services and their cleanup. ## Site integration Record the CLI's own source revision independently from the core library reference. Keep commands, configuration and examples specific to that source. Use the same content selection for HTML, search, Markdown and machine exports. Verify guides against a private tmux server, with cleanup limited to the objects the test owns. Check failure cases as well as successful construction. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Workspace reference generation Source: https://libtmux.org/en/java/latest/workspace/internals/documentation/ > Generate command references from the parser and verify task examples against the CLI. The executable's parser owns its command names, arguments and options. Keep reference generation tied to those definitions. ## Command metadata picocli owns the command definitions. `--generate schema` exports metadata and `--generate bash` writes completion. See [shell completion](https://libtmux.org/en/java/latest/workspace/cli/completion/) for end-user setup. A generated parser reference describes syntax; task examples also need to exercise the underlying services and their cleanup. ## Site integration Record the CLI's own source revision independently from the core library reference. Keep commands, configuration and examples specific to that source. Use the same content selection for HTML, search, Markdown and machine exports. Verify guides against a private tmux server, with cleanup limited to the objects the test owns. Check failure cases as well as successful construction. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Workspace reference generation Source: https://libtmux.org/en/py/latest/workspace/internals/documentation/ > Generate command references from the parser and verify task examples against the CLI. tmuxp uses argparse definitions from [`tmuxp.cli.create_parser`]() for its command reference. The optional `shtab` integration reads that parser for completion. ## Keep syntax and behavior aligned Preserve required and mutually exclusive groups when exporting parser metadata. An optional-looking positional in help can still belong to a required group. Run examples against the corresponding tmuxp revision, including prompts, machine formats, child failures and cleanup. The CLI reference and [workspace builder API](https://libtmux.org/en/py/latest/workspace/internals/) serve different tasks. Keep their example imports, prerequisites and behavior explicit. [Parser source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Workspace reference generation Source: https://libtmux.org/en/rs/latest/workspace/internals/documentation/ > Generate command references from the parser and verify task examples against the CLI. The executable's parser owns its command names, arguments and options. Keep reference generation tied to those definitions. ## Command metadata clap owns the command definitions. `--generate schema` exports command metadata, `--generate man` writes the manual, and completion generation uses the same graph. See [shell completion](https://libtmux.org/en/rs/latest/workspace/cli/completion/) for end-user setup. A generated parser reference describes syntax; task examples also need to exercise the underlying services and their cleanup. ## Site integration Record the CLI's own source revision independently from the core library reference. Keep commands, configuration and examples specific to that source. Use the same content selection for HTML, search, Markdown and machine exports. Verify guides against a private tmux server, with cleanup limited to the objects the test owns. Check failure cases as well as successful construction. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Workspace reference generation Source: https://libtmux.org/en/swift/latest/workspace/internals/documentation/ > Generate command references from the parser and verify task examples against the CLI. The executable's parser owns its command names, arguments and options. Keep reference generation tied to those definitions. ## Command metadata ArgumentParser owns the command definitions and `--generate-completion-script` generates shell completion. The site task guides describe executable operations separately from the workspace library API. See [shell completion](https://libtmux.org/en/swift/latest/workspace/cli/completion/) for end-user setup. A generated parser reference describes syntax; task examples also need to exercise the underlying services and their cleanup. ## Site integration Record the CLI's own source revision independently from the core library reference. Keep commands, configuration and examples specific to that source. Use the same content selection for HTML, search, Markdown and machine exports. Verify guides against a private tmux server, with cleanup limited to the objects the test owns. Check failure cases as well as successful construction. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Workspace reference generation Source: https://libtmux.org/en/ts/latest/workspace/internals/documentation/ > Generate command references from the parser and verify task examples against the CLI. The executable's parser owns its command names, arguments and options. Keep reference generation tied to those definitions. ## Command metadata Commander owns the command definitions. The package generates Markdown, a JSON command catalog and completion scripts from those definitions. `docs:check` checks their freshness. See [shell completion](https://libtmux.org/en/ts/latest/workspace/cli/completion/) for end-user setup. A generated parser reference describes syntax; task examples also need to exercise the underlying services and their cleanup. ## Site integration Record the CLI's own source revision independently from the core library reference. Keep commands, configuration and examples specific to that source. Use the same content selection for HTML, search, Markdown and machine exports. Verify guides against a private tmux server, with cleanup limited to the objects the test owns. Check failure cases as well as successful construction. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # tmux MCP for Java Source: https://libtmux.org/en/java/latest/mcp/ > Run or embed the Java MCP server with typed tmux tools and a static capability resource. [`io.github.libtmux:libtmux-mcp`](https://github.com/libtmux/libtmux-java/blob/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-mcp/README.md) provides a Java MCP server and a `libtmux-mcp` application launcher. It discovers tmux objects, captures terminal output, runs framed shell commands, and applies typed topology operations. Use JDK 21 or newer and tmux. The launcher selects its endpoint and toolsets at startup. It serves MCP over stdin and stdout. ## Start here - [Install](https://libtmux.org/en/java/latest/mcp/#install) points an MCP client at this server. - [Tools](https://libtmux.org/en/java/latest/mcp/tools/) lists the MCP operations, arguments, and results. - [Guides](https://libtmux.org/en/java/latest/mcp/guides/) build the launcher and connect a client. - [Topics](https://libtmux.org/en/java/latest/mcp/topics/) explain toolsets, input preflight, and wait semantics. - [Examples](https://libtmux.org/en/java/latest/mcp/examples/) call a tool, then explore server internals. - [Language API](https://libtmux.org/en/java/latest/mcp/reference/) documents embedding and implementation types. The only MCP resource is the static `tmux://capabilities` report. The server does not register workflow prompts or dynamic resource subscriptions. The [Workspace Manager](https://libtmux.org/en/java/latest/workspace/) is a separate Java module. Application code can parse and build declarative workspaces; MCP clients compose the exposed topology tools. [Module documentation](https://github.com/libtmux/libtmux-java/blob/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-mcp/README.md). --- # Java MCP topics Source: https://libtmux.org/en/java/latest/mcp/topics/ > Understand Java toolsets, socket provenance, bounded synchronous waits, and stable targets. The Java MCP server freezes its tool selection before serving requests. The same selection controls tool listing and invocation. ## Toolsets and endpoint provenance `LIBTMUX_TOOLSETS` selects any combination of `inspect`, `manage`, `execute`, and `teardown`. `LIBTMUX_TOOLS` adds names; `LIBTMUX_EXCLUDE_TOOLS` removes them last. An empty set selects none. Unknown names and empty list elements fail startup. Without a socket selector, the launcher uses `libtmux-mcp`. If it creates that daemon with the shipped minimal configuration, all four sets are enabled by default. Existing or explicitly selected daemons omit teardown from the default. The static `tmux://capabilities` resource reports the effective surface and its provenance. Toolsets configure the interface; shell input and server configuration still act with the tmux user's authority. ## Stable targets and input checks Use IDs returned by listings. A bare numeric index is refused where a stable object ID is required. Pane input checks caller context, human attention, pane modes, and synchronized-input membership. Framed commands require one live shell and reject a synchronized cohort. A check is an observation, so tmux state can still change before dispatch. ## Waiting and cancellation `run_shell_command` returns output and exit status from a framed subshell. Directory changes and exports do not persist in the parent shell. `wait_for_text` observes output produced elsewhere. `capture_since` returns a cursor and flags discontinuity when retained history no longer follows it. Waits are capped at 30 seconds by default and two minutes absolutely. Oversized requests are clamped. A client's own request timeout is separate. The SDK dispatches synchronous handlers on a worker scheduler. A client timeout or cancellation abandons the answer but does not stop an already running synchronous handler or undo effects. Inspect state before retrying. [Behavior and waiting contract](https://github.com/libtmux/libtmux-java/blob/4f057d367a25dee818d70876fa283fc503a3a7eb/docs/guide/mcp.md). --- # Connect a Java MCP client Source: https://libtmux.org/en/java/latest/mcp/guides/ > Build the Java MCP launcher and connect it to a private tmux server. Build the Java distribution and let your MCP client launch the script below. It creates its own tmux session, exposes only `list_sessions`, and stops that private server when the MCP process exits. ## Build the launcher Use JDK 25, Git, and tmux 3.2a or newer on a Unix host. Create an empty directory: ```console $ mkdir java-mcp-client && cd java-mcp-client ``` Fetch the source revision used by this guide and build its distribution: ```console $ git init libtmux-source && \ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-java.git && \ git -C libtmux-source fetch --depth=1 origin 842228310449e879ebcaa3f910597757c9dbffd6 && \ git -C libtmux-source checkout --detach FETCH_HEAD && \ ./libtmux-source/gradlew --no-daemon --max-workers=2 \ -p libtmux-source :libtmux-mcp:installDist ``` The selected build downloads its Temurin 21 compiler when needed. The resulting application contains the launcher and required JARs; keep its directory intact. ## Save the private-server launcher Save the following file alongside the source checkout. It clears inherited endpoint, caller and tool-selection settings before choosing its own. The trap reports cleanup failures and retains a socket that could not be stopped. ```sh title="run-mcp.sh" #!/bin/sh set -eu unset TMUX TMUX_PANE LIBTMUX_SOCKET LIBTMUX_SOCKET_PATH unset LIBTMUX_SAFETY LIBTMUX_WATCH LIBTMUX_EXCLUDE_TOOLS project=$(CDPATH= cd -P "$(dirname "$0")" && pwd) directory=$(mktemp -d /tmp/libtmux-java-mcp.XXXXXXXX) cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$directory/s" ]; then if ! tmux -S "$directory/s" kill-server; then printf 'Cannot stop private server; inspect %s\n' "$directory" >&2 exit 1 fi fi if ! rm -f "$directory/s" || ! rmdir "$directory"; then printf 'Cannot remove private directory: %s\n' "$directory" >&2 exit 1 fi exit "$status" } trap cleanup 0 trap 'exit 129' HUP trap 'exit 130' INT trap 'exit 143' TERM tmux -S "$directory/s" -f /dev/null \ set-option -g default-shell /bin/sh \; \ set-environment -g ENV '' \; \ set-environment -g BASH_ENV '' \; \ new-session -d -s mcp-example 'exec /bin/cat' LIBTMUX_TMUX_CONFIG=/dev/null LIBTMUX_TOOLSETS= LIBTMUX_TOOLS=list_sessions \ "$project/libtmux-source/libtmux-mcp/build/install/libtmux-mcp/bin/libtmux-mcp" \ --socket "$directory/s" --tmux tmux ``` Run it directly to check startup: ```console $ sh run-mcp.sh ``` It waits for MCP messages on stdin. Send EOF to close the process and trigger cleanup. Startup diagnostics go to stderr; stdout carries the MCP protocol. ## Connect a client Configure the client's command as `sh` and pass the launcher's absolute path as its only argument. The client needs Java and tmux on its `PATH`, or a valid `JAVA_HOME` for Java. The launcher finds the distribution relative to its own file, so the client's working directory does not matter. ## Verify and change selection Read `tmux://capabilities`, list the offered tools, then call [`list_sessions`](https://libtmux.org/en/java/latest/mcp/tools/list_sessions/). This launcher offers only that tool, and its result contains the private `mcp-example` session. An empty `LIBTMUX_TOOLSETS` plus the one name in `LIBTMUX_TOOLS` selects this surface. Select `inspect,manage,execute` for a broader workflow. Reconnect after changing startup configuration. Invalid tool names fail startup with a visible diagnostic. To connect the distribution directly to a server your application already owns, pass `--socket` with its path or `--socket-name` with its name. `--tmux` selects the tmux executable. Environment alternatives are `LIBTMUX_SOCKET_PATH`, `LIBTMUX_SOCKET`, and `LIBTMUX_TMUX_CONFIG`. The [complete Java client example](https://libtmux.org/en/java/latest/mcp/examples/) includes public imports, project files, bounded requests, and owned-server cleanup. The [launcher contract](https://github.com/libtmux/libtmux-java/blob/842228310449e879ebcaa3f910597757c9dbffd6/libtmux-mcp/README.md) describes the direct command's flags and environment. --- # Java MCP examples Source: https://libtmux.org/en/java/latest/mcp/examples/ > Connect a Java MCP client and inspect a private tmux session. Create a private tmux session, launch the Java MCP server, and call [`list_sessions`](https://libtmux.org/en/java/latest/mcp/tools/list_sessions/) through the Java SDK client. The program checks the result and closes both the MCP process and tmux server. For a client configured to launch the server itself, use the [connection guide](https://libtmux.org/en/java/latest/mcp/guides/). ## Create the project Use JDK 25, Git, tmux 3.2a or newer, and a Unix host with `env -u`. Create an empty project and fetch the source revision used by this example: ```console $ mkdir java-mcp-example && cd java-mcp-example && \ git init libtmux-source && \ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-java.git && \ git -C libtmux-source fetch --depth=1 origin 842228310449e879ebcaa3f910597757c9dbffd6 && \ git -C libtmux-source checkout --detach FETCH_HEAD && \ mkdir -p src/main/java ``` Save the settings file. The included build supplies the MCP and core libraries from the same selected source. Its toolchain resolver downloads the Temurin 21 compiler for those libraries when needed. ```kotlin title="settings.gradle.kts" rootProject.name = "mcp-example" includeBuild("libtmux-source") ``` Save the build file. Its SDK and JSON dependencies match the selected library: ```kotlin title="build.gradle.kts" plugins { application } repositories { mavenCentral() } dependencies { implementation("io.github.libtmux:libtmux-mcp:0.0.1-alpha.12-SNAPSHOT") implementation("io.modelcontextprotocol.sdk:mcp-json-jackson2:2.0.1") implementation("com.fasterxml.jackson.core:jackson-databind:2.21.5") runtimeOnly("org.slf4j:slf4j-nop:2.0.17") } java { toolchain.languageVersion.set(JavaLanguageVersion.of(25)) } application { mainClass.set("McpExample") } ``` ## List sessions Save the complete program below. The socket name is unique to this run. Cleanup is registered before creating the session, so it also covers a failure after tmux has started. Java retains cleanup failures as suppressed exceptions when an operation has already failed. ```java title="src/main/java/McpExample.java" import com.fasterxml.jackson.databind.ObjectMapper; import io.github.libtmux.Server; import io.github.libtmux.ServerEndpoint; import io.modelcontextprotocol.client.McpClient; import io.modelcontextprotocol.client.transport.ServerParameters; import io.modelcontextprotocol.client.transport.StdioClientTransport; import io.modelcontextprotocol.json.jackson2.JacksonMcpJsonMapper; import io.modelcontextprotocol.spec.McpSchema; import java.nio.file.Path; import java.time.Duration; import java.util.List; import java.util.Map; import java.util.UUID; public final class McpExample { public static void main(String[] args) throws Exception { String socket = "mcp-example-" + UUID.randomUUID(); try (Server server = Server.builder() .endpoint(ServerEndpoint.namedSocket(socket)) .configFile(Path.of("/dev/null")) .defaultTimeout(Duration.ofSeconds(5)) .build(); AutoCloseable stopTmux = server::killServer) { server.newSession(session -> session.named("mcp-example") .running("/bin/cat", "-u")); var launcher = ServerParameters.builder("env") .args("-u", "TMUX", "-u", "TMUX_PANE", "-u", "LIBTMUX_EXCLUDE_TOOLS", "-u", "LIBTMUX_SAFETY", "-u", "LIBTMUX_WATCH", Path.of(System.getProperty("java.home"), "bin", "java").toString(), "-classpath", System.getProperty("java.class.path"), "io.github.libtmux.mcp.Main", "--socket-name", socket) .env(Map.of("LIBTMUX_TOOLSETS", "", "LIBTMUX_TOOLS", "list_sessions", "LIBTMUX_TMUX_CONFIG", "/dev/null")) .build(); var mapper = new ObjectMapper(); var transport = new StdioClientTransport(launcher, new JacksonMcpJsonMapper(mapper)); transport.setStdErrorHandler(System.err::println); try (var client = McpClient.sync(transport) .initializationTimeout(Duration.ofSeconds(10)) .requestTimeout(Duration.ofSeconds(5)) .build()) { client.initialize(); var offered = client.listTools().tools().stream() .map(McpSchema.Tool::name).toList(); if (!offered.equals(List.of("list_sessions"))) { throw new IllegalStateException("Unexpected tools: " + offered); } var result = client.callTool( McpSchema.CallToolRequest.builder("list_sessions").build()); if (Boolean.TRUE.equals(result.isError())) { throw new IllegalStateException("Tool failed: " + result.content()); } var sessions = mapper.valueToTree(result.structuredContent()).path("sessions"); if (sessions.size() != 1 || !sessions.get(0).path("name").asText().equals("mcp-example")) { throw new IllegalStateException("Expected the example's private session"); } System.out.println("tools: list_sessions"); System.out.println("sessions: mcp-example"); } } } } ``` Build the application distribution: ```console $ ./libtmux-source/gradlew --no-daemon --max-workers=2 -p . installDist ``` Run the installed application: ```console $ ./build/install/mcp-example/bin/mcp-example ``` The application prints: ```text tools: list_sessions sessions: mcp-example ``` Server startup diagnostics go to stderr; stdout contains the example's result. The client uses bounded initialization and request timeouts. It removes inherited pane identity, tool exclusions, and retired settings from the child process, then selects only `list_sessions` on the explicit private socket. Check `isError` before reading structured output. The [tool reference](https://libtmux.org/en/java/latest/mcp/tools/list_sessions/) describes the successful response; use its session IDs for later requests. ## Supply your own transport An application embedding the server can pass its existing [`Server`]() and MCP transport to [`TmuxMcpServer.serving`](). Ownership of that transport transfers on entry. The returned MCP server closes it, including during failed startup; close the returned server when serving ends. The application still chooses when to stop its tmux server. ## Inspect command completion On a disposable session with the `execute` toolset enabled, use an MCP client to discover a pane and call `run_shell_command`. Read the typed exit status and output. Use `capture_since` for subsequent screen changes; a prompt redraw can arrive after command completion. [Server entry points](https://github.com/libtmux/libtmux-java/blob/842228310449e879ebcaa3f910597757c9dbffd6/libtmux-mcp/src/main/java/io/github/libtmux/mcp/TmuxMcpServer.java); [upstream MCP tests](https://github.com/libtmux/libtmux-java/tree/842228310449e879ebcaa3f910597757c9dbffd6/libtmux-mcp/src/test). --- # Java MCP API Source: https://libtmux.org/en/java/latest/mcp/reference/ > Find the public TmuxMcpServer entry points and the separate schema-validated tool catalog. For MCP client requests, use the [tool reference](https://libtmux.org/en/java/latest/mcp/tools/). This page covers language APIs for embedding or extending the server. [`TmuxMcpServer`]() is the public Java entry point. The MCP catalog includes operations implemented by package-private classes; Java visibility does not determine whether a tool exists on the wire. ## Java entry points [`TmuxMcpServer.overStdio(server)`]() serves through standard input and output. [`TmuxMcpServer.serving(server, transport)`]() accepts a custom [`McpServerTransportProvider`](https://github.com/modelcontextprotocol/java-sdk/blob/v2.0.1/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpServerTransportProvider.java). Both return an SDK [`McpSyncServer`](https://github.com/modelcontextprotocol/java-sdk/blob/v2.0.1/mcp-core/src/main/java/io/modelcontextprotocol/server/McpSyncServer.java). The returned server owns its transport. Ownership transfers on entry, including startup failure. The embedding application owns the broader tmux server lifetime and closes the MCP server when serving ends. [Public source contract](https://github.com/libtmux/libtmux-java/blob/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-mcp/src/main/java/io/github/libtmux/mcp/TmuxMcpServer.java). ## MCP tools and resource The [tool reference](https://libtmux.org/en/java/latest/mcp/tools/) covers registered operation names and input/output schemas. Results contain typed `structuredContent` and JSON text. Expected tmux failures become tool errors so the caller can inspect the failure and choose a recovery. The `tmux://capabilities` resource is static for the process lifetime. It reports tool selection, connection provenance, and capability declarations. The server does not register prompts or dynamic hierarchy subscriptions. Use the [Workspace builder API](https://libtmux.org/en/java/latest/workspace/reference/) for declarative configuration. It is a separate Java library and has no corresponding workspace-file MCP route. ## API declarations - [io.github.libtmux.mcp.Main](https://libtmux.org/en/java/latest/mcp/reference/io-github-libtmux-mcp-main-main/) - [io.github.libtmux.mcp.TmuxMcpServer](https://libtmux.org/en/java/latest/mcp/reference/io-github-libtmux-mcp-tmuxmcpserver-tmuxmcpserver/) [Protocol catalog](https://libtmux.org/en/java/latest/mcp/tools.json) --- # Java workspace manager Source: https://libtmux.org/en/java/latest/workspace/ > Describe a tmux session in a file, then load, inspect and capture it. **Workspace Manager for Java is in development.** Build `tmux-workspace` from the source revision in the installation guide. Its CLI and workspace library have separate installation and configuration contracts. `tmux-workspace` creates tmux sessions from YAML or JSON. A file describes windows, panes, commands, directories and environment. Load it from a terminal or request machine output for automation. ## Load a workspace from the terminal 1. [Install the command and load a workspace](https://libtmux.org/en/java/latest/workspace/guides/installation/). 2. [Configure windows and panes](https://libtmux.org/en/java/latest/workspace/configuration/). 3. [Capture and reload a session](https://libtmux.org/en/java/latest/workspace/guides/export-session/). The [CLI manual](https://libtmux.org/en/java/latest/workspace/cli/) covers discovery, search, editing, loading, capture, conversion and import. [Examples](https://libtmux.org/en/java/latest/workspace/examples/gallery/) provide complete configurations with their prerequisites. ## Automate and inspect Use `load -d` when the caller should return without attaching. `--json` returns a result, and `--ndjson` supports a stream of records. Read [automation](https://libtmux.org/en/java/latest/workspace/guides/automation/) for retry and cleanup decisions and [errors](https://libtmux.org/en/java/latest/workspace/reference/exit-codes/) for failure handling. Loaded workspaces are ordinary tmux sessions. Select the same socket when inspecting them from tmux or the [MCP server](https://libtmux.org/en/java/latest/mcp/). ## Build from application code The [workspace library](https://libtmux.org/en/java/latest/workspace/internals/) has its own API and configuration contract. Use it when a program needs direct control over construction. The CLI task guides here describe the `tmux-workspace` executable and link to its documented source revision. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). - [CLI Manual](https://libtmux.org/en/java/latest/workspace/cli/): Commands, options and machine output. - [Configuration](https://libtmux.org/en/java/latest/workspace/configuration/): Workspace fields, normalization and execution. - [Install and load](https://libtmux.org/en/java/latest/workspace/guides/installation/): Load a workspace on a private socket, then capture it. - [Example gallery](https://libtmux.org/en/java/latest/workspace/examples/gallery/): Workspace files to start from, with their prerequisites. - [Runtime support](https://libtmux.org/en/java/latest/workspace/reference/compatibility/): Runtime requirements and supported behavior. - [Internals](https://libtmux.org/en/java/latest/workspace/internals/): The workspace library, for building sessions from code. --- # tmux MCP for Lua is not published Source: https://libtmux.org/en/lua/latest/mcp/ > The Lua repository contains an MCP scaffold, not a usable or published server. Lua has no published libtmux MCP server. The repository's MCP directory is a scaffold: it does not provide an installable server, executable, protocol catalog, or supported tool API. This page records availability so cross-language navigation does not turn a source placeholder into a product claim. There is no launch command, client configuration, tool reference, prompt catalog, or embedding reference to use. Use the Lua core library for direct tmux access through its luv or Neovim runtime. Choose another language's MCP server only as a separate process with that server's own package, policy, and compatibility requirements. --- # tmux workspace manager for Lua is not published Source: https://libtmux.org/en/lua/latest/workspace/ > The Lua repository contains a workspace scaffold, not a loader or supported builder API. Lua has no published libtmux workspace manager. The repository's workspace directory is a scaffold: it does not provide an installable package, workspace loader command, supported file format, or product API. This page records availability without advertising placeholder code. There is no Lua equivalent of `libtmux-workspace validate`, [`plan`](), or `load`, and no workspace reference tree is generated. Use the core Lua API to create sessions, windows, and panes explicitly. A workspace tool from another language remains a separate application with its own configuration contract; it is not a Lua feature. --- # Third-party notices Source: https://libtmux.org/en/third-party-notices/ > Thanks to tmux's creator and contributors, with licences and attribution for the software behind libtmux.org. ## tmux First and foremost, thank you to **[Nicholas Marriott (nicm)](https://github.com/nicm)**, the creator of tmux, and to the many [tmux contributors](https://github.com/tmux/tmux/graphs/contributors). We are grateful for the work that makes tmux possible. libtmux is a separate project. Our libraries and supporting tools control a real tmux server; tmux itself provides the terminal multiplexer. This is the libtmux website. Visit the [official tmux website](https://github.com/tmux/tmux/wiki) for the upstream project and its documentation. See tmux's [COPYING file](https://github.com/tmux/tmux/blob/master/COPYING) and the copyright and permission notices in its source files for its licensing. ### tmux artwork The tmux logomark is by Jason Long. The site uses the unmodified [upstream SVG](https://github.com/tmux/tmux/blob/8f25579c5aef8d93924a20681f394e2a582fd3ad/logo/tmux-logomark.svg) under its [copyright and permission notice](https://libtmux.org/en/brand/tmux/LICENSE.txt). ## Programming-language artwork The homepage language selector uses local copies of the following artwork to identify the selected language. Each source record includes the download URL, retrieval time, file hash, copyright information and usage terms. These marks identify their respective languages and do not imply endorsement of libtmux. The SVG files are copied unchanged except for Scala, whose empty surrounding canvas is cropped. Its paths, gradients and colors are preserved, and the original SVG is retained beside the cropped copy. Rust's supplied SVG includes its own dark-theme colors. | Language | Credit and terms | Local source record | |---|---|---| | Python | Python Software Foundation. The [PSF logo terms](https://www.python.org/psf/trademarks/) permit the unaltered mark to identify Python. | [Python provenance](https://libtmux.org/en/brand/languages/py/provenance.json) | | Ruby | Copyright © 2006, Yukihiro Matsumoto. The [Ruby logo](https://www.ruby-lang.org/en/about/logo/) is licensed under [CC BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/). | [Ruby provenance](https://libtmux.org/en/brand/languages/ruby/provenance.json) | | Lua | Copyright © 1998 Lua.org; graphic design by Alexandre Nakonechnyj. The Devicon copy carries its [MIT notice](https://libtmux.org/en/brand/languages/lua/LICENSE.txt); [Lua's logo terms](https://www.lua.org/images/) also apply. Visit [Lua.org](https://www.lua.org/). | [Lua provenance](https://libtmux.org/en/brand/languages/lua/provenance.json) | | TypeScript | Microsoft. The [official branding terms](https://www.typescriptlang.org/branding/) govern the mark; the website repository licenses exclude logo and trademark rights. | [TypeScript provenance](https://libtmux.org/en/brand/languages/ts/provenance.json) | | Rust | The Rust Foundation. [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) and the [Rust trademark policy](https://rustfoundation.org/policy/rust-trademark-policy/) apply. | [Rust provenance](https://libtmux.org/en/brand/languages/rs/provenance.json) | | Go | The [Go gopher](https://go.dev/blog/gopher) is by Renee French, licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). | [Go provenance](https://libtmux.org/en/brand/languages/go/provenance.json) | | C++ | Created by Jeremy Kratz and licensed by the Standard C++ Foundation under its [logo-use terms](https://isocpp.org/home/terms-of-use). | [C++ provenance](https://libtmux.org/en/brand/languages/cxx/provenance.json) | | Swift | Apple Inc., under the [Swift Logo Guidelines](https://developer.apple.com/swift/downloads/swift-logo.zip). Swift and the Swift logo are trademarks of Apple Inc. | [Swift provenance](https://libtmux.org/en/brand/languages/swift/provenance.json) | | Java | Devicon collection copyright (c) 2015 konpa, with its [MIT notice](https://libtmux.org/en/brand/languages/java/LICENSE.txt). This does not establish unrestricted rights to the underlying Java logo; [Oracle's logo terms](https://www.oracle.com/legal/logos/) apply. | [Java provenance](https://libtmux.org/en/brand/languages/java/provenance.json) | | Kotlin | Kotlin Foundation brand guidelines preserve JetBrains copyrights. The [icon-use terms](https://kotlinfoundation.org/guidelines/) permit identifying Kotlin alongside other programming-language icons. | [Kotlin provenance](https://libtmux.org/en/brand/languages/kotlin/provenance.json) | | Scala | Copyright EPFL. [Historical permission](https://groups.google.com/g/scala-user/c/bCC-R0FQn1w) covers noncommercial Scala promotion; the [general artwork-license question](https://github.com/scala/scala-lang/issues/1040) remains unresolved. | [Scala provenance](https://libtmux.org/en/brand/languages/scala/provenance.json) | | C# | Copyright the .NET authors. [Brand-use permission](https://github.com/dotnet/brand/issues/10#issuecomment-669465301) allows the unmodified logo to represent .NET. The repository's CC0 statement covers illustrations; no blanket CC0 claim is made for the logo. | [.NET provenance](https://libtmux.org/en/brand/languages/csharp/provenance.json) | | F# | The F# Software Foundation. Its [logo terms](https://foundation.fsharp.org/logo) require unchanged shape, colors and proportions, without implying Foundation representation. | [F# provenance](https://libtmux.org/en/brand/languages/fsharp/provenance.json) | ## Terminal artwork The tmux CLI selector displays the Windows Terminal artwork by Microsoft Corporation, licensed under [CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0/). The SVG is unmodified. See the [source and provenance](https://libtmux.org/en/brand/tools/terminal/provenance.json) and [copyright and license](https://libtmux.org/en/brand/tools/terminal/LICENSE.txt). ## Documentation toolchain libtmux and this site are built with open-source software. The following tools have their own licences and attribution requirements. | Tool | Licence | Role | |---|---|---| | [Astro](https://astro.build/) | MIT | The site shell | | [Tailwind CSS](https://tailwindcss.com/) | MIT | Styling | | [Pagefind](https://pagefind.app/) | MIT | Site-wide search | | [Expressive Code](https://expressive-code.com/) | MIT | Code blocks | | [Sphinx](https://www.sphinx-doc.org/) | BSD-2-Clause | Python and C++ reference | | [Furo](https://github.com/pradyunsg/furo) | MIT | Sphinx theme | | [Breathe](https://github.com/breathe-doc/breathe) | BSD-3-Clause | Doxygen XML into Sphinx | | [Doxygen](https://www.doxygen.nl/) | GPL-2.0-only | Parses C++ headers to XML | | [API Extractor](https://api-extractor.com/) | MIT | TypeScript API model | | [IBM Plex](https://github.com/IBM/plex) | OFL-1.1 | Typeface | ### A note on Doxygen Doxygen is licensed GPL-2.0-only. It runs as a build step that reads libtmux's own headers and emits XML; that XML is rendered by Breathe and Sphinx, and no Doxygen-generated HTML is published. Running a GPL program over your own input does not place its licence on the output, and libtmux does not distribute Doxygen or any modified version of it. ## Reference hosting The [PyPI blocks logo](https://pypi.org/trademarks/) is a trademark of the Python Software Foundation and identifies links to the Python Package Index. Other package-host icons use [Simple Icons](https://simpleicons.org/) (CC0-1.0). Three ports deep-link to the canonical host their ecosystem already uses, rather than duplicating it here: - Rust: [docs.rs](https://docs.rs/libtmux) - Go: [pkg.go.dev](https://pkg.go.dev/github.com/libtmux/libtmux-go/tmux) - Java and Kotlin: [javadoc.io](https://javadoc.io/doc/io.github.libtmux/libtmux) Those sites are operated independently of this project and carry their own terms. ## libtmux itself Each port is MIT licensed. See the `LICENSE` file in that port's repository for the authoritative text. --- # tmux MCP for Python Source: https://libtmux.org/en/py/latest/mcp/ > Expose tmux tools, resources, and prompts through Python's libtmux-mcp server. `libtmux-mcp` lets an MCP client inspect tmux, create sessions and panes, run commands, and wait for their results. The distribution and executable are `libtmux-mcp`; Python imports use [`libtmux_mcp`](). The server runs over standard input and output. It requires Python 3.10 or newer and tmux 3.2a or newer. Its default toolsets are [`inspect`](), `manage`, and `execute`; deletion tools require an explicit selection. ## Start here - [Install](https://libtmux.org/en/py/latest/mcp/#install) points an MCP client at this server. - [Tools](https://libtmux.org/en/py/latest/mcp/tools/) lists the MCP operations, arguments, and results. - [Guides](https://libtmux.org/en/py/latest/mcp/guides/) connect a client and select a tmux socket. - [Topics](https://libtmux.org/en/py/latest/mcp/topics/) explain toolsets, trust, waiting, and caller context. - [Examples](https://libtmux.org/en/py/latest/mcp/examples/) call a tool, then explore server internals. - [Language API](https://libtmux.org/en/py/latest/mcp/reference/) documents embedding and implementation types. For declarative session configuration, use the [Workspace Manager](https://libtmux.org/en/py/latest/workspace/), provided by the separate `tmuxp` project. The MCP server does not provide a tmuxp file loader. The [upstream Python documentation](https://libtmux-mcp.git-pull.com/) covers client integrations and the complete tool reference. These pages follow the [Python implementation](https://github.com/tmux-python/libtmux-mcp/tree/v0.1.0a22). --- # Python MCP topics Source: https://libtmux.org/en/py/latest/mcp/topics/ > Understand Python toolsets, socket overrides, terminal output, and command completion. Python's MCP toolsets select advertised and callable tools. They do not confine the programs running inside tmux. ## Select independent toolsets [`inspect`]() requests state or output. `manage` changes tmux structure, presentation, or coordination without supplying executable input. `execute` starts processes, sends input, or changes executable configuration. `teardown` removes objects or retained history. The default is `inspect,manage,execute`. `LIBTMUX_TOOLS` adds exact names, and `LIBTMUX_EXCLUDE_TOOLS` removes them last. Unknown names fail startup. An empty `LIBTMUX_TOOLSETS` selects no sets. These settings filter tools only. Hierarchy resources and native prompts remain available even with no tools. Resource reads contact tmux; native prompts return text without contacting it. ## Know the endpoint and caller `LIBTMUX_SOCKET` selects a default socket name. Targeted tools can accept [`socket_name`]() to override it for one call. This differs from servers that pin every call to one endpoint. Dedicated teardown tools refuse the pane containing the MCP process and its enclosing window, session, or server. The check compares socket identity as well as [`TMUX_PANE`](). It cannot turn open-ended shell input into a constrained operation. ## Choose the completion signal Use [`run_command`]() for a command the agent authors. Read [`exit_status`](), [`timed_out`](), and [`output`](); a timeout does not prove the shell stopped. Use [`wait_for_text`]() for output produced elsewhere and [`capture_since`]() for repeated observation with an opaque cursor. The default wait ceiling is 30 seconds, configurable within 1 to 120 seconds. Oversized requests are clamped. Command-history suppression defaults on for MCP calls to [`run_command`](), while direct Python calls default it off; this is best-effort shell behavior. ## Treat terminal output as data A private socket separates tmux objects. It does not restrict filesystem, network, or same-user process access. Server aliases and hooks can add effects even to a nominal inspection. Pane output can contain credentials or instructions from another program; it remains untrusted data. See the [upstream trust model](https://libtmux-mcp.git-pull.com/topics/trust/) and [configuration source](https://github.com/tmux-python/libtmux-mcp/blob/v0.1.0a22/docs/configuration.md). --- # Connect a Python MCP client Source: https://libtmux.org/en/py/latest/mcp/guides/ > Launch libtmux-mcp on a chosen socket and verify the tools your client receives. Configure the client to launch `libtmux-mcp` with a named tmux socket. Install [uv](https://docs.astral.sh/uv/) first, and make tmux 3.2a or newer available in the environment the client passes to the server. ## Launch the server This command resolves the package in its own uv environment and starts its stdio transport. It waits for an MCP client to send requests. ```console $ LIBTMUX_SOCKET=docs-agent LIBTMUX_TOOLSETS=inspect \ uvx libtmux-mcp@latest ``` For a client that accepts an `mcpServers` object, use: ```json { "mcpServers": { "tmux-python": { "command": "uvx", "args": ["libtmux-mcp@latest"], "env": { "LIBTMUX_SOCKET": "docs-agent", "LIBTMUX_TOOLSETS": "inspect" } } } } ``` Client configuration formats differ; the [upstream client guide](https://libtmux-mcp.git-pull.com/clients/) gives their individual formats. Restart the MCP process after changing startup environment variables. ## Verify the connection Ask the client to list the tools, then call [`list_sessions`](). Ask it to identify a pane before capturing content. An empty session listing can be correct for the selected socket. To allow commands and topology creation, change the toolset selection to `inspect,manage,execute`. Check the new listing after reconnecting. Removing `teardown` does not stop a shell command from deleting work. ## Diagnose a mismatch Compare the client's executable path and environment with your shell. `LIBTMUX_TMUX_BIN` selects the tmux executable. `LIBTMUX_SOCKET_PATH` selects an explicit socket path. A targeted tool's [`socket_name`]() argument can override the default endpoint. Keep this application in its own Python environment when also using [tmuxp](https://libtmux.org/en/py/latest/workspace/); the projects have independent libtmux dependency requirements. [Configuration contract](https://github.com/tmux-python/libtmux-mcp/blob/v0.1.0a22/docs/configuration.md). --- # Python MCP examples Source: https://libtmux.org/en/py/latest/mcp/examples/ > List sessions through the Python MCP server and inspect implementation examples. Connect the server using the [setup guide](https://libtmux.org/en/py/latest/mcp/guides/), then call [`list_sessions`](https://libtmux.org/en/py/latest/mcp/tools/list_sessions/) from your MCP client. ## List sessions This is the `params` object for an MCP `tools/call` request. Send it through the connected client: ```json { "name": "list_sessions", "arguments": {} } ``` Use the returned session IDs when choosing a window or pane. The [tool reference](https://libtmux.org/en/py/latest/mcp/tools/list_sessions/) describes this port's result and optional arguments. ## Internals The following examples are for applications that embed or extend the server. Installing and connecting an MCP client does not require this code. Use a FastMCP client to inspect the same registered server that the `libtmux-mcp` executable serves. This checks the advertised contract without creating tmux sessions. ### Inspect the catalog in Python Run this in an environment containing `libtmux-mcp`. It uses the production factory and closes the in-process client when the context ends. ```python import asyncio from fastmcp import Client from libtmux_mcp.server import build_mcp_server async def main() -> None: async with Client(build_mcp_server()) as client: tools = await client.list_tools() for tool in tools: print(tool.name, tool.input_schema) asyncio.run(main()) ``` The [production factory](https://github.com/tmux-python/libtmux-mcp/blob/v0.1.0a22/src/libtmux_mcp/server.py) registers tools and applies visibility once. The [server tests](https://github.com/tmux-python/libtmux-mcp/blob/v0.1.0a22/tests/test_server.py) exercise this client/factory pattern. Set selection variables before importing the server in a fresh process. ### Run and observe through a client On a disposable session, ask the client to create a pane, run `printf 'ready\n'` with [`run_command`](), and report its typed exit status. For subsequent output, seed [`capture_since`]() and reuse the returned cursor. Use [`wait_for_text`]() when waiting for output from a process you did not launch. These are workflows for the client to carry out, not literal tool argument objects. Use the [tool reference](https://libtmux.org/en/py/latest/mcp/tools/) for each operation's schema. The [upstream quickstart](https://libtmux-mcp.git-pull.com/quickstart/) describes command completion and lower-level channel composition. --- # Python MCP API Source: https://libtmux.org/en/py/latest/mcp/reference/ > Find Python server entry points, typed models, and the separate MCP wire contract. For MCP client requests, use the [tool reference](https://libtmux.org/en/py/latest/mcp/tools/). This page covers language APIs for embedding or extending the server. The Python API and MCP protocol expose different interfaces. Python callers import functions and models; MCP clients send registered tool names and schema-validated arguments. ## MCP operations Browse the [tool reference](https://libtmux.org/en/py/latest/mcp/tools/) for the protocol catalog. `tools/list` on a running server is the effective selection after startup filtering. Registration defaults can differ from direct Python function defaults, including command-history suppression. The server also registers hierarchy resources and workflow prompts. These remain available independently of the toolset selection. ## Python entry points [`libtmux_mcp.server.build_mcp_server()`]() returns the registered production FastMCP server. [`run_server()`]() serves it over stdio. The factory uses the module's server instance; repeated calls do not create independent configuration contexts. The package separates tool functions, typed models, middleware, resource handlers, and prompt recipes. Model classes describe request/result data; their existence does not make them separate MCP tools. - [Server API](https://libtmux-mcp.git-pull.com/reference/api/server/) - [Tools API](https://libtmux-mcp.git-pull.com/reference/api/tools/) - [Models API](https://libtmux-mcp.git-pull.com/reference/api/models/) - [Registration source](https://github.com/tmux-python/libtmux-mcp/blob/v0.1.0a22/src/libtmux_mcp/server.py) Use [Examples](https://libtmux.org/en/py/latest/mcp/examples/) to inspect the protocol with an in-process client. Use the [Workspace builder API](https://libtmux.org/en/py/latest/workspace/reference/) for tmuxp configuration and builders. ## API declarations - [libtmux_mcp.middleware.AuditMiddleware](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-middleware-auditmiddleware/) - [libtmux_mcp.models.BufferContent](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-buffercontent/) - [libtmux_mcp.models.BufferRef](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-bufferref/) - [libtmux_mcp.prompts.recipes.build_dev_workspace](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-prompts-recipes-build_dev_workspace/) - [libtmux_mcp.server.build_mcp_server](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-server-build_mcp_server/) - [libtmux_mcp.tools.batch_tools.call_read_tools_batch](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-batch_tools-call_read_tools_batch/) - [libtmux_mcp.tools.pane_tools.io.CAPTURE_DEFAULT_MAX_LINES](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-io-capture_default_max_lines/) - [libtmux_mcp.tools.pane_tools.capture_pane](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-capture_pane/) - [libtmux_mcp.tools.pane_tools.capture_since](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-capture_since/) - [libtmux_mcp.tools.pane_tools.capture_since.CAPTURE_SINCE_DEFAULT_MAX_BYTES](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-capture_since-capture_since_default_max_bytes/) - [libtmux_mcp.tools.pane_tools.capture_since.CAPTURE_SINCE_DEFAULT_MAX_LINES](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-capture_since-capture_since_default_max_lines/) - [libtmux_mcp.models.CaptureSinceResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-capturesinceresult/) - [libtmux_mcp.tools.pane_tools.clear_pane](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-clear_pane/) - [libtmux_mcp.tools.server_tools.create_session](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-server_tools-create_session/) - [libtmux_mcp.tools.session_tools.create_window](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-session_tools-create_window/) - [libtmux_mcp.middleware.DEFAULT_RESPONSE_LIMIT_BYTES](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-middleware-default_response_limit_bytes/) - [libtmux_mcp.server.DEFAULT_TOOLSETS](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-server-default_toolsets/) - [libtmux_mcp.tools.buffer_tools.delete_buffer](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-buffer_tools-delete_buffer/) - [libtmux_mcp.prompts.recipes.diagnose_failing_pane](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-prompts-recipes-diagnose_failing_pane/) - [libtmux_mcp.tools.pane_tools.display_message](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-display_message/) - [libtmux_mcp.tools.pane_tools.enter_copy_mode](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-enter_copy_mode/) - [libtmux_mcp.prompts.ENV_PROMPTS_AS_TOOLS](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-prompts-env_prompts_as_tools/) - [libtmux_mcp.models.EnvironmentResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-environmentresult/) - [libtmux_mcp.models.EnvironmentSetResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-environmentsetresult/) - [libtmux_mcp.tools.pane_tools.exit_copy_mode](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-exit_copy_mode/) - [libtmux_mcp.tools.pane_tools.find_pane_by_position](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-find_pane_by_position/) - [libtmux_mcp.tools.pane_tools.get_pane_info](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-get_pane_info/) - [libtmux_mcp.tools.server_tools.get_server_info](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-server_tools-get_server_info/) - [libtmux_mcp.tools.session_tools.get_session_info](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-session_tools-get_session_info/) - [libtmux_mcp.tools.window_tools.get_window_info](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-window_tools-get_window_info/) - [libtmux_mcp.tools.pane_tools.state.HISTORY_LIMIT_FORMAT](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-state-history_limit_format/) - [libtmux_mcp.models.HookEntry](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-hookentry/) - [libtmux_mcp.models.HookListResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-hooklistresult/) - [libtmux_mcp.middleware.install_fastmcp_validation_log_filter](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-middleware-install_fastmcp_validation_log_filter/) - [libtmux_mcp.prompts.recipes.interrupt_gracefully](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-prompts-recipes-interrupt_gracefully/) - [libtmux_mcp.tools.pane_tools.kill_pane](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-kill_pane/) - [libtmux_mcp.tools.server_tools.kill_server](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-server_tools-kill_server/) - [libtmux_mcp.tools.session_tools.kill_session](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-session_tools-kill_session/) - [libtmux_mcp.tools.window_tools.kill_window](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-window_tools-kill_window/) - [libtmux_mcp.tools.window_tools.list_panes](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-window_tools-list_panes/) - [libtmux_mcp.tools.server_tools.list_servers](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-server_tools-list_servers/) - [libtmux_mcp.tools.server_tools.list_sessions](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-server_tools-list_sessions/) - [libtmux_mcp.tools.session_tools.list_windows](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-session_tools-list_windows/) - [libtmux_mcp.tools.buffer_tools.load_buffer](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-buffer_tools-load_buffer/) - [libtmux_mcp.main](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-main/) - [libtmux_mcp.tools.batch_tools.MAX_BATCH_OPERATIONS](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-batch_tools-max_batch_operations/) - [libtmux_mcp.server.mcp](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-server-mcp/) - [libtmux_mcp.tools.window_tools.move_window](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-window_tools-move_window/) - [libtmux_mcp.models.OptionResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-optionresult/) - [libtmux_mcp.models.OptionSetResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-optionsetresult/) - [libtmux_mcp.tools.pane_tools.state.PANE_STATE_FORMAT](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-state-pane_state_format/) - [libtmux_mcp.models.PaneContentMatch](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-panecontentmatch/) - [libtmux_mcp.tools.pane_tools.lifecycle.PaneCorner](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-lifecycle-panecorner/) - [libtmux_mcp.models.PaneInfo](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-paneinfo/) - [libtmux_mcp.models.PaneSnapshot](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-panesnapshot/) - [libtmux_mcp.tools.buffer_tools.paste_buffer](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-buffer_tools-paste_buffer/) - [libtmux_mcp.tools.pane_tools.paste_text](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-paste_text/) - [libtmux_mcp.tools.pane_tools.pipe_pane](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-pipe_pane/) - [libtmux_mcp.resources.hierarchy.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-resources-hierarchy-register/) - [libtmux_mcp.tools.batch_tools.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-batch_tools-register/) - [libtmux_mcp.tools.buffer_tools.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-buffer_tools-register/) - [libtmux_mcp.tools.env_tools.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-env_tools-register/) - [libtmux_mcp.tools.hook_tools.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-hook_tools-register/) - [libtmux_mcp.tools.option_tools.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-option_tools-register/) - [libtmux_mcp.tools.pane_tools.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-register/) - [libtmux_mcp.tools.server_tools.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-server_tools-register/) - [libtmux_mcp.tools.session_tools.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-session_tools-register/) - [libtmux_mcp.tools.wait_for_tools.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-wait_for_tools-register/) - [libtmux_mcp.tools.window_tools.register](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-window_tools-register/) - [libtmux_mcp.resources.hierarchy.register_completions](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-resources-hierarchy-register_completions/) - [libtmux_mcp.prompts.register_prompts](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-prompts-register_prompts/) - [libtmux_mcp.resources.register_resources](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-resources-register_resources/) - [libtmux_mcp.tools.register_tools](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-register_tools/) - [libtmux_mcp.tools.session_tools.rename_session](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-session_tools-rename_session/) - [libtmux_mcp.tools.window_tools.rename_window](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-window_tools-rename_window/) - [libtmux_mcp.tools.pane_tools.resize_pane](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-resize_pane/) - [libtmux_mcp.tools.window_tools.resize_window](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-window_tools-resize_window/) - [libtmux_mcp.tools.pane_tools.respawn_pane](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-respawn_pane/) - [libtmux_mcp.prompts.recipes.run_and_wait](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-prompts-recipes-run_and_wait/) - [libtmux_mcp.tools.pane_tools.run_command](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-run_command/) - [libtmux_mcp.server.run_server](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-server-run_server/) - [libtmux_mcp.models.RunCommandResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-runcommandresult/) - [libtmux_mcp.tools.pane_tools.search.SEARCH_DEFAULT_LIMIT](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-search-search_default_limit/) - [libtmux_mcp.tools.pane_tools.search.SEARCH_DEFAULT_MAX_LINES_PER_PANE](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-search-search_default_max_lines_per_pane/) - [libtmux_mcp.tools.pane_tools.search.SEARCH_MATCH_MAX_SECONDS](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-search-search_match_max_seconds/) - [libtmux_mcp.tools.pane_tools.search.SEARCH_MAX_PATTERN_LENGTH](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-search-search_max_pattern_length/) - [libtmux_mcp.tools.pane_tools.search_panes](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-search_panes/) - [libtmux_mcp.models.SearchPanesResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-searchpanesresult/) - [libtmux_mcp.tools.window_tools.select_layout](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-window_tools-select_layout/) - [libtmux_mcp.tools.pane_tools.select_pane](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-select_pane/) - [libtmux_mcp.tools.session_tools.select_window](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-session_tools-select_window/) - [libtmux_mcp.tools.pane_tools.send_keys](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-send_keys/) - [libtmux_mcp.tools.pane_tools.send_keys_batch](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-send_keys_batch/) - [libtmux_mcp.models.SendKeysBatchResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-sendkeysbatchresult/) - [libtmux_mcp.models.SendKeysOperation](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-sendkeysoperation/) - [libtmux_mcp.models.SendKeysOperationResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-sendkeysoperationresult/) - [libtmux_mcp.models.ServerInfo](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-serverinfo/) - [libtmux_mcp.models.SessionInfo](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-sessioninfo/) - [libtmux_mcp.tools.env_tools.set_environment](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-env_tools-set_environment/) - [libtmux_mcp.tools.option_tools.set_option](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-option_tools-set_option/) - [libtmux_mcp.tools.pane_tools.set_pane_title](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-set_pane_title/) - [libtmux_mcp.tools.buffer_tools.show_buffer](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-buffer_tools-show_buffer/) - [libtmux_mcp.tools.buffer_tools.SHOW_BUFFER_DEFAULT_MAX_LINES](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-buffer_tools-show_buffer_default_max_lines/) - [libtmux_mcp.tools.env_tools.show_environment](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-env_tools-show_environment/) - [libtmux_mcp.tools.hook_tools.show_hook](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-hook_tools-show_hook/) - [libtmux_mcp.tools.hook_tools.show_hooks](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-hook_tools-show_hooks/) - [libtmux_mcp.tools.option_tools.show_option](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-option_tools-show_option/) - [libtmux_mcp.tools.wait_for_tools.signal_channel](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-wait_for_tools-signal_channel/) - [libtmux_mcp.tools.pane_tools.snapshot_pane](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-snapshot_pane/) - [libtmux_mcp.tools.server_tools.SOCKET_NAME_EXEMPT](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-server_tools-socket_name_exempt/) - [libtmux_mcp.tools.window_tools.split_window](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-window_tools-split_window/) - [libtmux_mcp.tools.pane_tools.swap_pane](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-swap_pane/) - [libtmux_mcp.middleware.TailPreservingResponseLimitingMiddleware](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-middleware-tailpreservingresponselimitingmiddleware/) - [libtmux_mcp.models.ToolCallBatchResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-toolcallbatchresult/) - [libtmux_mcp.models.ToolCallOperation](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-toolcalloperation/) - [libtmux_mcp.models.ToolCallOperationResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-toolcalloperationresult/) - [libtmux_mcp.middleware.ToolErrorResultMiddleware](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-middleware-toolerrorresultmiddleware/) - [libtmux_mcp.middleware.ToolsetMiddleware](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-middleware-toolsetmiddleware/) - [libtmux_mcp.tools.wait_for_tools.wait_for_channel](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-wait_for_tools-wait_for_channel/) - [libtmux_mcp.tools.pane_tools.wait_for_text](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-tools-pane_tools-wait_for_text/) - [libtmux_mcp.models.WaitForTextResult](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-waitfortextresult/) - [libtmux_mcp.models.WindowInfo](https://libtmux.org/en/py/latest/mcp/reference/libtmux_mcp-models-windowinfo/) [Protocol catalog](https://libtmux.org/en/py/latest/mcp/tools.json) --- # Python workspace manager Source: https://libtmux.org/en/py/latest/workspace/ > Describe a tmux session in a file, then load, inspect and capture it. [tmuxp](https://tmuxp.git-pull.com/) loads tmux sessions from YAML or JSON using libtmux. A file describes windows, panes and commands. `tmuxp load` builds the session and can attach to it or leave it detached. ## Start here 1. [Install tmuxp and load a workspace](https://libtmux.org/en/py/latest/workspace/guides/installation/). 2. [Configure windows and panes](https://libtmux.org/en/py/latest/workspace/configuration/). 3. [Capture and reload a session](https://libtmux.org/en/py/latest/workspace/guides/export-session/). The [CLI manual](https://libtmux.org/en/py/latest/workspace/cli/) covers discovery, search, editing, conversion and import. Use [examples](https://libtmux.org/en/py/latest/workspace/examples/gallery/) for complete files and their prerequisites. Install tmuxp separately from the core libtmux package. Its dependency resolver selects a compatible libtmux release. [Workspace internals](https://libtmux.org/en/py/latest/workspace/internals/) describe the builder and Python extension APIs. [Quickstart source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/docs/quickstart.md). - [CLI Manual](https://libtmux.org/en/py/latest/workspace/cli/): Commands, options and machine output. - [Configuration](https://libtmux.org/en/py/latest/workspace/configuration/): Workspace fields, normalization and execution. - [Install and load](https://libtmux.org/en/py/latest/workspace/guides/installation/): Load a workspace on a private socket, then capture it. - [Example gallery](https://libtmux.org/en/py/latest/workspace/examples/gallery/): Workspace files to start from, with their prerequisites. - [Runtime support](https://libtmux.org/en/py/latest/workspace/reference/compatibility/): Runtime requirements and supported behavior. - [Internals](https://libtmux.org/en/py/latest/workspace/internals/): The workspace library, for building sessions from code. --- # Python workspace topics Source: https://libtmux.org/en/py/latest/workspace/topics/ > Understand workspace configuration, existing sessions, and tmuxp freeze. Use `tmuxp load` to turn a YAML or JSON configuration into a tmux session. The configuration controls its windows, panes, directories, and commands. ## Configuration and commands A workspace names a session and contains windows with panes. Pane shorthand can name a command directly, while mappings describe command lists, working directories, focus, and other configuration. The loader expands environment variables and resolves relative paths using the workspace location. `shell_command_before` supplies setup commands inherited by the relevant panes. Commands, scripts, plugins, and custom builders execute code in your runtime. Use workspace files whose commands and extension imports you intend to run. Successful construction does not mean a launched application has completed startup; its own readiness check is a separate task. ## Existing sessions `tmuxp load` handles attachment and switching as part of its CLI workflow. It can attach to an existing named session, and its append mode adds windows to the current session. Those choices differ from replacing a session or converging a description automatically. Read the load command's prompts and options before automating an existing-session workflow. ## Export a session `tmuxp freeze` writes the structure of a running session as YAML or JSON. It recovers current layouts and working directories, and uses observable current programs when forming commands. It cannot recover the original command line, process memory, or a complete application checkpoint. Review its output before relying on it as a launcher. See the upstream [workspace configuration](https://tmuxp.git-pull.com/configuration/) for supported fields. Contributor details about the loader and custom builders belong in [Internals](https://libtmux.org/en/py/latest/workspace/internals/topics/). [Expansion implementation](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [Freeze implementation](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/freezer.py). --- # Load a Python workspace Source: https://libtmux.org/en/py/latest/workspace/guides/ > Install tmuxp, load YAML on a dedicated socket, and inspect the session. Install tmuxp as a Python tool, with Python 3.10 or newer and tmux 3.2 or newer available on the host: ```console $ uv tool install tmuxp ``` The tool environment owns tmuxp's dependencies. Keep a separately installed MCP application in its own environment if its libtmux requirement differs. ## Describe the workspace Save this upstream example as `workspace.yaml`: ```yaml session_name: 2-pane-vertical windows: - window_name: my test window panes: - echo hello - echo hello ``` Load it detached on a dedicated socket, without changing your attached session: ```console $ tmuxp load \ -L workspace-guide \ -d \ workspace.yaml ``` The `-L` value selects the tmux server and `-d` prevents attachment. Reserve that socket name for this example. Omit `-d` when you want tmuxp to attach or offer its normal client-switching flow. Inspect the created session: ```console $ tmux -L workspace-guide list-sessions ``` When finished, remove only the example session: ```console $ tmux -L workspace-guide kill-session -t '=2-pane-vertical' ``` ## Saved workspaces and export `tmuxp load` accepts file paths and names resolved through its configuration search. Use an explicit path while learning the format so the loaded file is unambiguous. Use `tmuxp freeze` for a session you want to capture as a starting configuration. It offers YAML or JSON output. Inspect the generated command lists and paths before using the export later. The upstream [load reference](https://tmuxp.git-pull.com/cli/load/) covers append, session-name, socket, and attachment options. The [freeze reference](https://tmuxp.git-pull.com/cli/freeze/) covers output choices. [Workspace source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/2-pane-vertical.yaml); [CLI option definitions](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/load.py). --- # Python workspace examples Source: https://libtmux.org/en/py/latest/workspace/examples/ > Load tmux workspaces from YAML or JSON with the tmuxp CLI. Save a workspace file and pass it to [tmuxp](https://tmuxp.git-pull.com/). These examples require tmuxp and tmux; the [guide](https://libtmux.org/en/py/latest/workspace/guides/) covers installation. No Python program is needed. ## Load YAML Save this upstream two-pane example as `workspace.yaml`: ```yaml session_name: 2-pane-vertical windows: - window_name: my test window panes: - echo hello - echo hello ``` Load the workspace and attach to it: ```console $ tmuxp load workspace.yaml ``` Inside tmux, the loader offers to switch clients or append windows. Detach with your tmux prefix followed by `d` to leave the session running. ## Load JSON without attaching The same configuration fields also work in JSON. Save this separate workspace as `workspace.json`: ```json { "session_name": "json-workspace", "windows": [ { "window_name": "editor", "panes": ["echo ready", "echo ready"] } ] } ``` Load it detached on a dedicated socket: ```console $ tmuxp load \ -L workspace-json-example \ -d \ workspace.json ``` Inspect its panes: ```console $ tmux -L workspace-json-example list-panes -t '=json-workspace:editor' ``` Remove the example session when finished: ```console $ tmux -L workspace-json-example kill-session -t '=json-workspace' ``` ## More configurations The upstream [configuration examples](https://tmuxp.git-pull.com/configuration/examples/) cover layouts, focus, directories, environment values, and command shorthand. The [load reference](https://tmuxp.git-pull.com/cli/load/) documents file selection, attachment, and existing sessions. For contributors studying how a file becomes a session, see the [internal builder example](https://libtmux.org/en/py/latest/workspace/internals/examples/). [Two-pane YAML source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/examples/2-pane-vertical.yaml) --- # Exit codes and errors Source: https://libtmux.org/en/csharp/latest/workspace/reference/exit-codes/ > Use process status and structured error codes to handle workspace failures. Check the process status before treating a result as complete. A failed load can report retained effects; a later failure does not undo an earlier input. | Exit status | Meaning | | --- | --- | | `0` | Command completed; an explicitly declined prompt can also finish without changes | | `1` | Workspace validation or operation failure | | `2` | Invalid arguments or execution context | | `130` | Interrupted operation | Child commands such as `edit` can propagate another nonzero child status. Status `70` reports an internal error. ## Machine errors With `--json` or `--ndjson`, diagnostics identify a `code` and readable `message`. Use the code for program decisions and keep the message for users. | Code | Condition | | --- | --- | | `workspace_not_found` | Requested workspace was not found | | `invalid_workspace` | Document shape or value is invalid | | `unsupported_key` | An execution field is unsupported | | `session_not_found` | The selected session does not exist | | `session_mismatch` | Existing session does not match the requested document | | `tmux_unavailable` | tmux cannot be found or used | | `tmux_failed` | A tmux operation failed | | `script_failed` | A bootstrap process failed | | `destination_exists` | A file would be replaced without authorization | | `usage` | Arguments or execution context are invalid | | `interrupted` | A signal stopped the operation | Additional codes describe implementation failures such as a closed output stream, unavailable runtime or log-file failure. Keep unknown codes visible instead of assuming they mean success. See [troubleshooting](https://libtmux.org/en/csharp/latest/workspace/guides/troubleshooting/) for collecting a useful report. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Exit codes and errors Source: https://libtmux.org/en/cxx/latest/workspace/reference/exit-codes/ > Use process status and structured error codes to handle workspace failures. Check the process status before treating a result as complete. A failed load can report retained effects; a later failure does not undo an earlier input. | Exit status | Meaning | | --- | --- | | `0` | Command completed; an explicitly declined prompt can also finish without changes | | `1` | Workspace validation or operation failure | | `2` | Invalid arguments or execution context | | `130` | Interrupted operation | Child commands such as `edit` can propagate another nonzero child status. Termination by SIGTERM can return `143`. ## Machine errors With `--json` or `--ndjson`, diagnostics identify a `code` and readable `message`. Use the code for program decisions and keep the message for users. | Code | Condition | | --- | --- | | `workspace_not_found` | Requested workspace was not found | | `invalid_workspace` | Document shape or value is invalid | | [`unsupported_key`]() | An execution field is unsupported | | `session_not_found` | The selected session does not exist | | `session_mismatch` | Existing session does not match the requested document | | `tmux_unavailable` | tmux cannot be found or used | | `tmux_failed` | A tmux operation failed | | `script_failed` | A bootstrap process failed | | `destination_exists` | A file would be replaced without authorization | | `usage` | Arguments or execution context are invalid | | `interrupted` | A signal stopped the operation | Additional codes describe implementation failures such as a closed output stream, unavailable runtime or log-file failure. Keep unknown codes visible instead of assuming they mean success. See [troubleshooting](https://libtmux.org/en/cxx/latest/workspace/guides/troubleshooting/) for collecting a useful report. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Exit codes and errors Source: https://libtmux.org/en/go/latest/workspace/reference/exit-codes/ > Use process status and structured error codes to handle workspace failures. Check the process status before treating a result as complete. A failed load can report retained effects; a later failure does not undo an earlier input. | Exit status | Meaning | | --- | --- | | `0` | Command completed; an explicitly declined prompt can also finish without changes | | `1` | Workspace validation or operation failure | | `2` | Invalid arguments or execution context | | `130` | Interrupted operation | Child commands such as `edit` can propagate another nonzero child status. ## Machine errors With `--json` or `--ndjson`, diagnostics identify a `code` and readable `message`. Use the code for program decisions and keep the message for users. | Code | Condition | | --- | --- | | `workspace_not_found` | Requested workspace was not found | | `invalid_workspace` | Document shape or value is invalid | | `unsupported_key` | An execution field is unsupported | | `session_not_found` | The selected session does not exist | | `session_mismatch` | Existing session does not match the requested document | | `tmux_unavailable` | tmux cannot be found or used | | `tmux_failed` | A tmux operation failed | | `script_failed` | A bootstrap process failed | | `destination_exists` | A file would be replaced without authorization | | `usage` | Arguments or execution context are invalid | | `interrupted` | A signal stopped the operation | Additional codes describe implementation failures such as a closed output stream, unavailable runtime or log-file failure. Keep unknown codes visible instead of assuming they mean success. See [troubleshooting](https://libtmux.org/en/go/latest/workspace/guides/troubleshooting/) for collecting a useful report. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Exit codes and errors Source: https://libtmux.org/en/java/latest/workspace/reference/exit-codes/ > Use process status and structured error codes to handle workspace failures. Check the process status before treating a result as complete. A failed load can report retained effects; a later failure does not undo an earlier input. | Exit status | Meaning | | --- | --- | | `0` | Command completed; an explicitly declined prompt can also finish without changes | | `1` | Workspace validation or operation failure | | `2` | Invalid arguments or execution context | | `130` | Interrupted operation | Child commands such as `edit` can propagate another nonzero child status. ## Machine errors With `--json` or `--ndjson`, diagnostics identify a `code` and readable `message`. Use the code for program decisions and keep the message for users. | Code | Condition | | --- | --- | | `workspace_not_found` | Requested workspace was not found | | `invalid_workspace` | Document shape or value is invalid | | `unsupported_key` | An execution field is unsupported | | `session_not_found` | The selected session does not exist | | `session_mismatch` | Existing session does not match the requested document | | `tmux_unavailable` | tmux cannot be found or used | | `tmux_failed` | A tmux operation failed | | `script_failed` | A bootstrap process failed | | `destination_exists` | A file would be replaced without authorization | | `usage` | Arguments or execution context are invalid | | `interrupted` | A signal stopped the operation | Additional codes describe implementation failures such as a closed output stream, unavailable runtime or log-file failure. Keep unknown codes visible instead of assuming they mean success. See [troubleshooting](https://libtmux.org/en/java/latest/workspace/guides/troubleshooting/) for collecting a useful report. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Exit codes and errors Source: https://libtmux.org/en/py/latest/workspace/reference/exit-codes/ > Use process status and structured error codes to handle workspace failures. tmuxp generally uses `0` for success, `1` for operation failures and `2` for argument errors. Some commands have exceptions at this documented revision. ## Exceptions to check - `edit` does not propagate the editor child's status. - Machine [`search`]() can return normally with no output for an invalid pattern; a missing query can show human help. - A missing import source exits with status `2`. - A missing or unsupported tmux executable can print a diagnostic and return status `0` before argument parsing. - [`freeze`]() can catch a missing-session error, print it and return normally. Read both the command's output and [reference page](https://libtmux.org/en/py/latest/workspace/cli/) before using its status as the only success check. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Exit codes and errors Source: https://libtmux.org/en/rs/latest/workspace/reference/exit-codes/ > Use process status and structured error codes to handle workspace failures. Check the process status before treating a result as complete. A failed load can report retained effects; a later failure does not undo an earlier input. | Exit status | Meaning | | --- | --- | | `0` | Command completed; an explicitly declined prompt can also finish without changes | | `1` | Workspace validation or operation failure | | `2` | Invalid arguments or execution context | | `130` | Interrupted operation | Child commands such as `edit` can propagate another nonzero child status. ## Machine errors With `--json` or `--ndjson`, diagnostics identify a `code` and readable `message`. Use the code for program decisions and keep the message for users. | Code | Condition | | --- | --- | | `workspace_not_found` | Requested workspace was not found | | `invalid_workspace` | Document shape or value is invalid | | `unsupported_key` | An execution field is unsupported | | `session_not_found` | The selected session does not exist | | `session_mismatch` | Existing session does not match the requested document | | `tmux_unavailable` | tmux cannot be found or used | | `tmux_failed` | A tmux operation failed | | `script_failed` | A bootstrap process failed | | `destination_exists` | A file would be replaced without authorization | | `usage` | Arguments or execution context are invalid | | `interrupted` | A signal stopped the operation | Additional codes describe implementation failures such as a closed output stream, unavailable runtime or log-file failure. Keep unknown codes visible instead of assuming they mean success. See [troubleshooting](https://libtmux.org/en/rs/latest/workspace/guides/troubleshooting/) for collecting a useful report. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Exit codes and errors Source: https://libtmux.org/en/swift/latest/workspace/reference/exit-codes/ > Use process status and structured error codes to handle workspace failures. Check the process status before treating a result as complete. A failed load can report retained effects; a later failure does not undo an earlier input. | Exit status | Meaning | | --- | --- | | `0` | Command completed; an explicitly declined prompt can also finish without changes | | `1` | Workspace validation or operation failure | | `2` | Invalid arguments or execution context | | `130` | Interrupted operation | Child commands such as `edit` can propagate another nonzero child status. ## Machine errors With `--json` or `--ndjson`, diagnostics identify a `code` and readable `message`. Use the code for program decisions and keep the message for users. | Code | Condition | | --- | --- | | `workspace_not_found` | Requested workspace was not found | | `invalid_workspace` | Document shape or value is invalid | | `unsupported_key` | An execution field is unsupported | | `session_not_found` | The selected session does not exist | | `session_mismatch` | Existing session does not match the requested document | | `tmux_unavailable` | tmux cannot be found or used | | `tmux_failed` | A tmux operation failed | | `script_failed` | A bootstrap process failed | | `destination_exists` | A file would be replaced without authorization | | `usage` | Arguments or execution context are invalid | | `interrupted` | A signal stopped the operation | Additional codes describe implementation failures such as a closed output stream, unavailable runtime or log-file failure. Keep unknown codes visible instead of assuming they mean success. See [troubleshooting](https://libtmux.org/en/swift/latest/workspace/guides/troubleshooting/) for collecting a useful report. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Exit codes and errors Source: https://libtmux.org/en/ts/latest/workspace/reference/exit-codes/ > Use process status and structured error codes to handle workspace failures. Check the process status before treating a result as complete. A failed load can report retained effects; a later failure does not undo an earlier input. | Exit status | Meaning | | --- | --- | | `0` | Command completed; an explicitly declined prompt can also finish without changes | | `1` | Workspace validation or operation failure | | `2` | Invalid arguments or execution context | | `130` | Interrupted operation | Child commands such as `edit` can propagate another nonzero child status. ## Machine errors With `--json` or `--ndjson`, diagnostics identify a `code` and readable `message`. Use the code for program decisions and keep the message for users. | Code | Condition | | --- | --- | | `workspace_not_found` | Requested workspace was not found | | `invalid_workspace` | Document shape or value is invalid | | `unsupported_key` | An execution field is unsupported | | `session_not_found` | The selected session does not exist | | `session_mismatch` | Existing session does not match the requested document | | `tmux_unavailable` | tmux cannot be found or used | | `tmux_failed` | A tmux operation failed | | `script_failed` | A bootstrap process failed | | `destination_exists` | A file would be replaced without authorization | | `usage` | Arguments or execution context are invalid | | `interrupted` | A signal stopped the operation | Additional codes describe implementation failures such as a closed output stream, unavailable runtime or log-file failure. Keep unknown codes visible instead of assuming they mean success. See [troubleshooting](https://libtmux.org/en/ts/latest/workspace/guides/troubleshooting/) for collecting a useful report. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Output formats Source: https://libtmux.org/en/csharp/latest/workspace/reference/output/ > Read JSON results, NDJSON events and diagnostics from the workspace command. Every command accepts `--json` and `--ndjson`. JSON writes one document to stdout. NDJSON writes one JSON record per line and takes precedence if both flags are present. Machine output contains no terminal styling. ## Choose a stream ```console $ tmux-workspace ls --json ``` The shape depends on the operation: listing and search describe workspace records; conversion and import can return the translated document; loading describes completed work and failures. Saving a document returns information about that save. The file's YAML/JSON encoding is controlled separately by `--workspace-format`. Use [automation](https://libtmux.org/en/csharp/latest/workspace/guides/automation/) for a detached load and streamed progress. Read stdout as results and stderr as diagnostics. Check the exit status even when stdout contains valid data. ## Partial work and interrupted streams Load results can contain completed inputs, created IDs and retained effects. Treat a failed operation as partial until its result tells you what remains. A creation event alone does not establish that the workspace finished. An output failure or interruption can leave a final record unwritten or incomplete. A consumer must handle EOF and parse errors. Preserve the exit status and inspect the private server before retrying mutations. ## Child output and logging Machine calls encode captured child text so it cannot be confused with result records. The optional [inspection shell](https://libtmux.org/en/csharp/latest/workspace/cli/shell/) reports its child status along with captured output. A nonzero editor status is propagated. NDJSON can carry child-output records while a command is running. Read the terminal result and child status after those records. `load --log-file PATH` appends diagnostics to a separate file. `--log-level` selects advisory detail. A later log-file failure reports a diagnostic and preserves the operation's result; the log can end with an incomplete record. ## Human output `--color auto|always|never` selects styling; nonempty `NO_COLOR` disables color. Human progress uses the terminal. `--no-progress` disables drawing without hiding errors. Redirected or machine output avoids the progress display. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Output formats Source: https://libtmux.org/en/cxx/latest/workspace/reference/output/ > Read JSON results, NDJSON events and diagnostics from the workspace command. Every command accepts `--json` and `--ndjson`. JSON writes one document to stdout. NDJSON writes one JSON record per line and takes precedence if both flags are present. Machine output contains no terminal styling. ## Choose a stream ```console $ tmux-workspace ls --json ``` The shape depends on the operation: listing and search describe workspace records; conversion and import can return the translated document; loading describes completed work and failures. Saving a document returns information about that save. The file's YAML/JSON encoding is controlled separately by `--workspace-format`. Use [automation](https://libtmux.org/en/cxx/latest/workspace/guides/automation/) for a detached load and streamed progress. Read stdout as results and stderr as diagnostics. Check the exit status even when stdout contains valid data. ## Partial work and interrupted streams Load results can contain completed inputs, created IDs and retained effects. Treat a failed operation as partial until its result tells you what remains. A creation event alone does not establish that the workspace finished. An output failure or interruption can leave a final record unwritten or incomplete. A consumer must handle EOF and parse errors. Preserve the exit status and inspect the private server before retrying mutations. ## Child output and logging Machine calls encode captured child text so it cannot be confused with result records. The optional [inspection shell](https://libtmux.org/en/cxx/latest/workspace/cli/shell/) reports its child status along with captured output. A nonzero editor status is propagated. NDJSON can carry child-output records while a command is running. Read the terminal result and child status after those records. `load --log-file PATH` appends diagnostics to a separate file. `--log-level` selects advisory detail. A later log-file failure reports a diagnostic and preserves the operation's result; the log can end with an incomplete record. ## Human output `--color auto|always|never` selects styling; nonempty `NO_COLOR` disables color. Human progress uses the terminal. `--no-progress` disables drawing without hiding errors. Redirected or machine output avoids the progress display. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Output formats Source: https://libtmux.org/en/go/latest/workspace/reference/output/ > Read JSON results, NDJSON events and diagnostics from the workspace command. Every command accepts `--json` and `--ndjson`. JSON writes one document to stdout. NDJSON writes one JSON record per line and takes precedence if both flags are present. Machine output contains no terminal styling. ## Choose a stream ```console $ tmux-workspace ls --json ``` The shape depends on the operation: listing and search describe workspace records; conversion and import can return the translated document; loading describes completed work and failures. Saving a document returns information about that save. The file's YAML/JSON encoding is controlled separately by `--workspace-format`. Use [automation](https://libtmux.org/en/go/latest/workspace/guides/automation/) for a detached load and streamed progress. Read stdout as results and stderr as diagnostics. Check the exit status even when stdout contains valid data. ## Partial work and interrupted streams Load results can contain completed inputs, created IDs and retained effects. Treat a failed operation as partial until its result tells you what remains. A creation event alone does not establish that the workspace finished. An output failure or interruption can leave a final record unwritten or incomplete. A consumer must handle EOF and parse errors. Preserve the exit status and inspect the private server before retrying mutations. ## Child output and logging Machine calls encode captured child text so it cannot be confused with result records. The optional [inspection shell](https://libtmux.org/en/go/latest/workspace/cli/shell/) reports its child status along with captured output. A nonzero editor status is propagated. NDJSON can carry child-output records while a command is running. Read the terminal result and child status after those records. `load --log-file PATH` appends diagnostics to a separate file. `--log-level` selects advisory detail. A later log-file failure reports a diagnostic and preserves the operation's result; the log can end with an incomplete record. ## Human output `--color auto|always|never` selects styling; nonempty `NO_COLOR` disables color. Human progress uses the terminal. `--no-progress` disables drawing without hiding errors. Redirected or machine output avoids the progress display. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Output formats Source: https://libtmux.org/en/java/latest/workspace/reference/output/ > Read JSON results, NDJSON events and diagnostics from the workspace command. Every command accepts `--json` and `--ndjson`. JSON writes one document to stdout. NDJSON writes one JSON record per line and takes precedence if both flags are present. Machine output contains no terminal styling. ## Choose a stream ```console $ tmux-workspace ls --json ``` The shape depends on the operation: listing and search describe workspace records; conversion and import can return the translated document; loading describes completed work and failures. Saving a document returns information about that save. The file's YAML/JSON encoding is controlled separately by `--workspace-format`. Use [automation](https://libtmux.org/en/java/latest/workspace/guides/automation/) for a detached load and streamed progress. Read stdout as results and stderr as diagnostics. Check the exit status even when stdout contains valid data. ## Partial work and interrupted streams Load results can contain completed inputs, created IDs and retained effects. Treat a failed operation as partial until its result tells you what remains. A creation event alone does not establish that the workspace finished. An output failure or interruption can leave a final record unwritten or incomplete. A consumer must handle EOF and parse errors. Preserve the exit status and inspect the private server before retrying mutations. ## Child output and logging Machine calls encode captured child text so it cannot be confused with result records. The optional [inspection shell](https://libtmux.org/en/java/latest/workspace/cli/shell/) reports its child status along with captured output. A nonzero editor status is propagated. NDJSON can carry child-output records while a command is running. Read the terminal result and child status after those records. `load --log-file PATH` appends diagnostics to a separate file. `--log-level` selects advisory detail. A later log-file failure reports a diagnostic and preserves the operation's result; the log can end with an incomplete record. ## Human output `--color auto|always|never` selects styling; nonempty `NO_COLOR` disables color. Human progress uses the terminal. `--no-progress` disables drawing without hiding errors. Redirected or machine output avoids the progress display. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Output formats Source: https://libtmux.org/en/py/latest/workspace/reference/output/ > Read JSON results, NDJSON events and diagnostics from the workspace command. Choose the output supported by each tmuxp command: | Command | Machine output | | --- | --- | | `ls` | `--json` returns an object containing `workspaces`; `--ndjson` returns records | | [`search`]() | `--json` and `--ndjson`; read the command's empty-result caveats | | `debug-info` | `--json` | | [`freeze`](), `convert`, imports | YAML or JSON workspace document output, separate from a result protocol | ```console $ tmuxp ls --json ``` Do not assume every command accepts a global JSON mode. Read the [command reference](https://libtmux.org/en/py/latest/workspace/cli/) for flags, prompts and destinations, and [exit codes](https://libtmux.org/en/py/latest/workspace/reference/exit-codes/) before interpreting an empty stream as success. `--color auto|always|never`, `NO_COLOR` and `FORCE_COLOR` control human styling. Use explicit output formats when a script reads the result. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Output formats Source: https://libtmux.org/en/rs/latest/workspace/reference/output/ > Read JSON results, NDJSON events and diagnostics from the workspace command. Every command accepts `--json` and `--ndjson`. JSON writes one document to stdout. NDJSON writes one JSON record per line and takes precedence if both flags are present. Machine output contains no terminal styling. ## Choose a stream ```console $ tmux-workspace ls --json ``` The shape depends on the operation: listing and search describe workspace records; conversion and import can return the translated document; loading describes completed work and failures. Saving a document returns information about that save. The file's YAML/JSON encoding is controlled separately by `--workspace-format`. Use [automation](https://libtmux.org/en/rs/latest/workspace/guides/automation/) for a detached load and streamed progress. Read stdout as results and stderr as diagnostics. Check the exit status even when stdout contains valid data. ## Partial work and interrupted streams Load results can contain completed inputs, created IDs and retained effects. Treat a failed operation as partial until its result tells you what remains. A creation event alone does not establish that the workspace finished. An output failure or interruption can leave a final record unwritten or incomplete. A consumer must handle EOF and parse errors. Preserve the exit status and inspect the private server before retrying mutations. ## Child output and logging Machine calls encode captured child text so it cannot be confused with result records. The optional [inspection shell](https://libtmux.org/en/rs/latest/workspace/cli/shell/) reports its child status along with captured output. A nonzero editor status is propagated. NDJSON can carry child-output records while a command is running. Read the terminal result and child status after those records. `load --log-file PATH` appends diagnostics to a separate file. `--log-level` selects advisory detail. A later log-file failure reports a diagnostic and preserves the operation's result; the log can end with an incomplete record. ## Human output `--color auto|always|never` selects styling; nonempty `NO_COLOR` disables color. Human progress uses the terminal. `--no-progress` disables drawing without hiding errors. Redirected or machine output avoids the progress display. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Output formats Source: https://libtmux.org/en/swift/latest/workspace/reference/output/ > Read JSON results, NDJSON events and diagnostics from the workspace command. Every command accepts `--json` and `--ndjson`. JSON writes one document to stdout. NDJSON writes one JSON record per line and takes precedence if both flags are present. Machine output contains no terminal styling. ## Choose a stream ```console $ tmux-workspace ls --json ``` The shape depends on the operation: listing and search describe workspace records; conversion and import can return the translated document; loading describes completed work and failures. Saving a document returns information about that save. The file's YAML/JSON encoding is controlled separately by `--workspace-format`. Use [automation](https://libtmux.org/en/swift/latest/workspace/guides/automation/) for a detached load and streamed progress. Read stdout as results and stderr as diagnostics. Check the exit status even when stdout contains valid data. ## Partial work and interrupted streams Load results can contain completed inputs, created IDs and retained effects. Treat a failed operation as partial until its result tells you what remains. A creation event alone does not establish that the workspace finished. An output failure or interruption can leave a final record unwritten or incomplete. A consumer must handle EOF and parse errors. Preserve the exit status and inspect the private server before retrying mutations. ## Child output and logging Machine calls encode captured child text so it cannot be confused with result records. The optional [inspection shell](https://libtmux.org/en/swift/latest/workspace/cli/shell/) reports its child status along with captured output. A nonzero editor status is propagated. Bootstrap and inspection output streams as warning records on stderr, with up to one MiB per stream. The final result carries captured text. `--log-level` can filter advisory records; fatal errors and results remain visible. `load --log-file PATH` appends diagnostics to a separate file. `--log-level` selects advisory detail. A later log-file failure reports a diagnostic and preserves the operation's result; the log can end with an incomplete record. ## Human output `--color auto|always|never` selects styling; nonempty `NO_COLOR` disables color. Human progress uses the terminal. `--no-progress` disables drawing without hiding errors. Redirected or machine output avoids the progress display. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Output formats Source: https://libtmux.org/en/ts/latest/workspace/reference/output/ > Read JSON results, NDJSON events and diagnostics from the workspace command. Every command accepts `--json` and `--ndjson`. JSON writes one document to stdout. NDJSON writes one JSON record per line and takes precedence if both flags are present. Machine output contains no terminal styling. ## Choose a stream ```console $ tmux-workspace ls --json ``` The shape depends on the operation: listing and search describe workspace records; conversion and import can return the translated document; loading describes completed work and failures. Saving a document returns information about that save. The file's YAML/JSON encoding is controlled separately by `--workspace-format`. Use [automation](https://libtmux.org/en/ts/latest/workspace/guides/automation/) for a detached load and streamed progress. Read stdout as results and stderr as diagnostics. Check the exit status even when stdout contains valid data. ## Partial work and interrupted streams Load results can contain completed inputs, created IDs and retained effects. Treat a failed operation as partial until its result tells you what remains. A creation event alone does not establish that the workspace finished. An output failure or interruption can leave a final record unwritten or incomplete. A consumer must handle EOF and parse errors. Preserve the exit status and inspect the private server before retrying mutations. ## Child output and logging Machine calls encode captured child text so it cannot be confused with result records. The optional [inspection shell](https://libtmux.org/en/ts/latest/workspace/cli/shell/) reports its child status along with captured output. A nonzero editor status is propagated. Captured child results retain up to 64 KiB of source bytes per stream and mark truncation. NDJSON forwards child output as it arrives. `load --log-file PATH` appends diagnostics to a separate file. `--log-level` selects advisory detail. A later log-file failure reports a diagnostic and preserves the operation's result; the log can end with an incomplete record. ## Human output `--color auto|always|never` selects styling; nonempty `NO_COLOR` disables color. Human progress uses the terminal. `--no-progress` disables drawing without hiding errors. Redirected or machine output avoids the progress display. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # Runtime and configuration support Source: https://libtmux.org/en/csharp/latest/workspace/reference/compatibility/ > Runtime requirements and configuration boundaries for the C# workspace command. `tmux-workspace` is the .NET command for loading and capturing tmux workspaces. The [installation guide](https://libtmux.org/en/csharp/latest/workspace/guides/installation/) builds the documented source revision and runs a session on a private socket. The walkthroughs require tmux 3.2a or newer. ## Runtime and execution The CLI has .NET 8 and .NET 10 builds. Keep the selected runtime available, or install the packaged .NET tool. Native services handle loading, capture, discovery, search, conversion, import and editing. Plugins, custom builders and `shell` use an optional interpreter with tmuxp 1.74.0. Set `TMUX_WORKSPACE_PYTHON` to select it. Use detached loading for extension workspaces when terminal handoff is unavailable. [`LibTmux.Workspace`]() is a separate library API. Its parser and builder contract does not define every configuration feature accepted by the CLI. ## Configuration and failure handling Read [configuration](https://libtmux.org/en/csharp/latest/workspace/configuration/) for the CLI's fields. Unsupported execution fields fail visibly; generic [conversion](https://libtmux.org/en/csharp/latest/workspace/cli/convert/) preserves document values without proving that they can be executed. Use [machine output](https://libtmux.org/en/csharp/latest/workspace/reference/output/) for automation and check both the process status and any retained effects. Capture reads live tmux state; it cannot recover original command arguments, scripts, comments or application state. [Examples](https://libtmux.org/en/csharp/latest/workspace/examples/gallery/) provide complete starter documents. Their pane commands can need additional applications and directories when adapted. Use [library internals](https://libtmux.org/en/csharp/latest/workspace/internals/) for the programmatic builder. [CLI source](https://github.com/libtmux/libtmux-dotnet/blob/f77fe776ba67a04abb20ddbbc26cf4a000d63b74/src/LibTmux.Workspace.Cli/README.md). --- # Runtime and configuration support Source: https://libtmux.org/en/cxx/latest/workspace/reference/compatibility/ > Runtime requirements and configuration boundaries for the C++ workspace command. `tmux-workspace` is the C++ command for loading and capturing tmux workspaces. The [installation guide](https://libtmux.org/en/cxx/latest/workspace/guides/installation/) builds the documented source revision and runs a session on a private socket. The walkthroughs require tmux 3.2a or newer. ## Runtime and execution Build with the repository's `cxx-dev` CMake preset and its selected compiler. Native services handle loading, capture, discovery, search, conversion, import and editing. Search uses C++ ECMAScript regular expressions. Plugins and custom workspace builders are unsupported. `shell` is a separate optional feature that runs tmuxp 1.74.0; select its interpreter with `TMUX_WORKSPACE_PYTHON`, or select the executable with `TMUX_WORKSPACE_TMUXP`. Use detached loading when no unambiguous controlling terminal or tmux client is available. Append retains its borrowed session and reports changes that remain after a failure. The workspace library has its own configuration and construction APIs; use their reference for C++ application code. ## Configuration and failure handling Read [configuration](https://libtmux.org/en/cxx/latest/workspace/configuration/) for the CLI's fields. Unsupported execution fields fail visibly; generic [conversion](https://libtmux.org/en/cxx/latest/workspace/cli/convert/) preserves document values without proving that they can be executed. Use [machine output](https://libtmux.org/en/cxx/latest/workspace/reference/output/) for automation and check both the process status and any retained effects. Capture reads live tmux state; it cannot recover original command arguments, scripts, comments or application state. [Examples](https://libtmux.org/en/cxx/latest/workspace/examples/gallery/) provide complete starter documents. Their pane commands can need additional applications and directories when adapted. Use [library internals](https://libtmux.org/en/cxx/latest/workspace/internals/) for the programmatic builder. [CLI source](https://github.com/libtmux/libtmux-cxx/blob/9c8c6a264114277df84c9f6819855093adae5c6e/apps/workspace/README.md). --- # Runtime and configuration support Source: https://libtmux.org/en/go/latest/workspace/reference/compatibility/ > Runtime requirements and configuration boundaries for the Go workspace command. `tmux-workspace` is the Go command for loading and capturing tmux workspaces. The [installation guide](https://libtmux.org/en/go/latest/workspace/guides/installation/) builds the documented source revision and runs a session on a private socket. The walkthroughs require tmux 3.2a or newer. ## Runtime and execution Build with Go 1.26 or newer from the repository root so its workspace modules are selected together. Ordinary loading, capture, discovery, conversion, import and search use native Go services. Search uses Go regular expressions. `--regex-engine python` explicitly selects the optional Python regex backend. Plugins, custom builders and `shell` need tmuxp 1.74.0 in the interpreter selected by `TMUX_WORKSPACE_PYTHON`. Extension append refuses a document containing `before_script`; native scripted append remains supported. Inspect retained effects before retrying extension failures. The Go workspace library has a separate parser and builder contract. In particular, its accepted fields and variable expansion differ from the CLI. ## Configuration and failure handling Read [configuration](https://libtmux.org/en/go/latest/workspace/configuration/) for the CLI's fields. Unsupported execution fields fail visibly; generic [conversion](https://libtmux.org/en/go/latest/workspace/cli/convert/) preserves document values without proving that they can be executed. Use [machine output](https://libtmux.org/en/go/latest/workspace/reference/output/) for automation and check both the process status and any retained effects. Capture reads live tmux state; it cannot recover original command arguments, scripts, comments or application state. [Examples](https://libtmux.org/en/go/latest/workspace/examples/gallery/) provide complete starter documents. Their pane commands can need additional applications and directories when adapted. Use [library internals](https://libtmux.org/en/go/latest/workspace/internals/) for the programmatic builder. [CLI source](https://github.com/libtmux/libtmux-go/blob/bb06e26e116e941813ca40bf45e7e3a47d38f52a/workspace/CLI.md). --- # Runtime and configuration support Source: https://libtmux.org/en/java/latest/workspace/reference/compatibility/ > Runtime requirements and configuration boundaries for the Java workspace command. `tmux-workspace` is the Java command for loading and capturing tmux workspaces. The [installation guide](https://libtmux.org/en/java/latest/workspace/guides/installation/) builds the documented source revision and runs a session on a private socket. The walkthroughs require tmux 3.2a or newer. ## Runtime and execution Use JDK 25 or newer. Keep the generated application distribution together; its launcher depends on the adjacent libraries. Native services handle loading, capture, discovery, search, conversion, import and editing. Plugins, custom builders and `shell` need the optional tmuxp 1.74.0 environment selected by `TMUX_WORKSPACE_PYTHON`. Extension append refuses a document containing `before_script` to preserve its borrowed session on failure. The CLI validates execution fields before changing tmux. Use the separate workspace library reference when constructing sessions from Java code. ## Configuration and failure handling Read [configuration](https://libtmux.org/en/java/latest/workspace/configuration/) for the CLI's fields. Unsupported execution fields fail visibly; generic [conversion](https://libtmux.org/en/java/latest/workspace/cli/convert/) preserves document values without proving that they can be executed. Use [machine output](https://libtmux.org/en/java/latest/workspace/reference/output/) for automation and check both the process status and any retained effects. Capture reads live tmux state; it cannot recover original command arguments, scripts, comments or application state. [Examples](https://libtmux.org/en/java/latest/workspace/examples/gallery/) provide complete starter documents. Their pane commands can need additional applications and directories when adapted. Use [library internals](https://libtmux.org/en/java/latest/workspace/internals/) for the programmatic builder. [CLI source](https://github.com/libtmux/libtmux-java/blob/3e5b20d22af3890ae5f7f52842e4b05d170a983f/libtmux-workspace-cli/README.md). --- # Runtime and configuration support Source: https://libtmux.org/en/py/latest/workspace/reference/compatibility/ > Runtime, configuration and extension requirements for tmuxp. These pages document tmuxp 1.74.0 at the source revision linked below. Install tmuxp in its own Python environment and let its dependency resolver select a compatible libtmux release. The walkthroughs use Python 3.10 or newer and tmux 3.2a or newer. ## Configuration and extensions Read [configuration](https://libtmux.org/en/py/latest/workspace/configuration/) for normalization, inheritance, directories, commands and hooks. Parsing YAML alone does not establish that a field changes builder behavior. Plugins and custom builders execute Python code from their installed packages or configured import paths. The [inspection shell](https://libtmux.org/en/py/latest/workspace/cli/shell/) runs in the same Python environment. Optional interactive backends need their corresponding packages installed. ## Output and errors Machine formats are command-specific. Read [output](https://libtmux.org/en/py/latest/workspace/reference/output/) and [exit codes](https://libtmux.org/en/py/latest/workspace/reference/exit-codes/) for empty output and status exceptions before using tmuxp in automation. Capture reads current tmux state; it cannot recover original scripts, application state or comments. Review captured commands and directories before reloading. Gallery examples may require their named applications or plugins. Use [builder internals](https://libtmux.org/en/py/latest/workspace/internals/) for programmatic construction and extension development. [Command source](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/cli/__init__.py). --- # Runtime and configuration support Source: https://libtmux.org/en/rs/latest/workspace/reference/compatibility/ > Runtime requirements and configuration boundaries for the Rust workspace command. `tmux-workspace` is the Rust command for loading and capturing tmux workspaces. The [installation guide](https://libtmux.org/en/rs/latest/workspace/guides/installation/) builds the documented source revision and runs a session on a private socket. The walkthroughs require tmux 3.2a or newer. ## Runtime and execution Build with the toolchain selected by the repository's [`rust-toolchain.toml`](). The executable provides native loading, capture, discovery, search, conversion, import and editing. `--generate` exports its command metadata, manual and completion scripts. Plugins, custom builders and [`shell`]() use an optional tmuxp 1.74 runtime selected by `TMUX_WORKSPACE_PYTHON`. Scripted and extension loads require supported child-process observation; targets without it refuse those operations before changing tmux. The workspace crate also exposes a library. Its unsupported-field handling and modeled builder features differ from the CLI; use the library reference for application code. ## Configuration and failure handling Read [configuration](https://libtmux.org/en/rs/latest/workspace/configuration/) for the CLI's fields. Unsupported execution fields fail visibly; generic [conversion](https://libtmux.org/en/rs/latest/workspace/cli/convert/) preserves document values without proving that they can be executed. Use [machine output](https://libtmux.org/en/rs/latest/workspace/reference/output/) for automation and check both the process status and any retained effects. Capture reads live tmux state; it cannot recover original command arguments, scripts, comments or application state. [Examples](https://libtmux.org/en/rs/latest/workspace/examples/gallery/) provide complete starter documents. Their pane commands can need additional applications and directories when adapted. Use [library internals](https://libtmux.org/en/rs/latest/workspace/internals/) for the programmatic builder. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). --- # Runtime and configuration support Source: https://libtmux.org/en/swift/latest/workspace/reference/compatibility/ > Runtime requirements and configuration boundaries for the Swift workspace command. `tmux-workspace` is the Swift command for loading and capturing tmux workspaces. The [installation guide](https://libtmux.org/en/swift/latest/workspace/guides/installation/) builds the documented source revision and runs a session on a private socket. The walkthroughs require tmux 3.2a or newer. ## Runtime and execution Use Swift 6.2. YAML decoding requires the `YAMLWorkspaces` build trait; JSON documents work without it. Keep the matching runtime libraries available when running a source-built Linux executable. Native services handle loading, capture, discovery, search, conversion, import and editing. Search uses ICU regular expressions. Select an explicit endpoint with `-S` or `-L` when loading outside tmux. Set delays on panes. Command mappings support Enter overrides but reject per-command timing fields. Plugins and custom workspace builders are unsupported. The optional [`tmux-workspace shell`](https://libtmux.org/en/swift/latest/workspace/cli/shell/) command requires tmuxp 1.74.0 in the interpreter selected by `TMUX_WORKSPACE_PYTHON`. The `TmuxWorkspace` library has a separate model and construction API. Consult its reference when building sessions from Swift code. ## Configuration and failure handling Read [configuration](https://libtmux.org/en/swift/latest/workspace/configuration/) for the CLI's fields. Unsupported execution fields fail visibly; generic [conversion](https://libtmux.org/en/swift/latest/workspace/cli/convert/) preserves document values without proving that they can be executed. Use [machine output](https://libtmux.org/en/swift/latest/workspace/reference/output/) for automation and check both the process status and any retained effects. Capture reads live tmux state; it cannot recover original command arguments, scripts, comments or application state. [Examples](https://libtmux.org/en/swift/latest/workspace/examples/gallery/) provide complete starter documents. Their pane commands can need additional applications and directories when adapted. Use [library internals](https://libtmux.org/en/swift/latest/workspace/internals/) for the programmatic builder. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). --- # Runtime and configuration support Source: https://libtmux.org/en/ts/latest/workspace/reference/compatibility/ > Runtime requirements and configuration boundaries for the TypeScript workspace command. `tmux-workspace` is the TypeScript command for loading and capturing tmux workspaces. The [installation guide](https://libtmux.org/en/ts/latest/workspace/guides/installation/) builds the documented source revision and runs a session on a private socket. The walkthroughs require tmux 3.2a or newer. ## Runtime and execution The CLI runs on Node.js 22 or newer and can be built with Bun. Use the installation guide for the documented revision. Ordinary load, capture, discovery, search, conversion and import use native services. Search uses JavaScript regular expressions. Explicit plugins, custom workspace builders and `shell` use an optional interpreter with tmuxp 1.74.0. Select it with `TMUX_WORKSPACE_PYTHON`. Empty extension selections keep native execution. The CLI and `@libtmux/workspace` are separate implementations. The library's convergence API and strict schema have a different contract from CLI loading. ## Configuration and failure handling Read [configuration](https://libtmux.org/en/ts/latest/workspace/configuration/) for the CLI's fields. Unsupported execution fields fail visibly; generic [conversion](https://libtmux.org/en/ts/latest/workspace/cli/convert/) preserves document values without proving that they can be executed. Use [machine output](https://libtmux.org/en/ts/latest/workspace/reference/output/) for automation and check both the process status and any retained effects. Capture reads live tmux state; it cannot recover original command arguments, scripts, comments or application state. [Examples](https://libtmux.org/en/ts/latest/workspace/examples/gallery/) provide complete starter documents. Their pane commands can need additional applications and directories when adapted. Use [library internals](https://libtmux.org/en/ts/latest/workspace/internals/) for the programmatic builder. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). --- # tmux MCP for Ruby Source: https://libtmux.org/en/ruby/latest/mcp/ > Run the libtmux-mcp server with an explicit tmux endpoint and tool policy. `libtmux-mcp` exposes one existing tmux server over MCP standard input and output. Requiring `libtmux/mcp` starts no server; the installed `libtmux-mcp` executable owns the protocol transport and borrows the selected tmux daemon. The default catalog contains `tmux_capabilities` and `tmux_snapshot`. Observation and mutation tools are opt-in, so a client cannot acquire them by calling an undisclosed name. ## Start here - [Install](https://libtmux.org/en/ruby/latest/mcp/#install) configures an MCP client to launch the Ruby server. - [Tools](https://libtmux.org/en/ruby/latest/mcp/tools/) records the actual wire schemas and per-tool policy. - [Guides](https://libtmux.org/en/ruby/latest/mcp/guides/) connect a client to a private tmux server. - [Topics](https://libtmux.org/en/ruby/latest/mcp/topics/) explain captures, cursors, references, and tool policy. - [Examples](https://libtmux.org/en/ruby/latest/mcp/examples/) run a client launcher or embed the MCP application. - [Language API](https://libtmux.org/en/ruby/latest/mcp/reference/) documents the Ruby embedding surface. The server requires Ruby 3.3 or newer. Strong process tracking for waits and authored runs requires tmux 3.3 or newer plus native process identity support. The [MCP server guide](https://libtmux.org/en/ruby/latest/mcp/source-guide/) is staged from the same revision as the generated reference. --- # Ruby MCP API reference Source: https://libtmux.org/en/ruby/latest/mcp/reference/ > Public libtmux-mcp embedding types and methods. Require `libtmux/mcp` to embed the server. Imports start no tmux process, scheduler, or protocol transport. [`Application`]() borrows an application-owned [`LibTmux::Async::Server`](); its SDK server and stdio transport remain on that application's reactor thread. The declarations below come from the public Ruby inventory, enriched with RBS signatures, YARD documentation, behavior contracts, and source coordinates at the selected revision. ## API declarations - [LibTmux::MCP](https://libtmux.org/en/ruby/latest/mcp/reference/libtmux-mcp/) [Protocol catalog](https://libtmux.org/en/ruby/latest/mcp/tools.json) --- # tmux workspace manager for Ruby Source: https://libtmux.org/en/ruby/latest/workspace/ > Validate, plan, and load bounded YAML or JSON workspaces with libtmux-workspace. `libtmux-workspace` parses bounded YAML or JSON into an immutable creation plan. `validate` and offline [`plan`]() do not contact tmux. [`load`]() and `plan --live` borrow an existing server selected with `--socket`. The manager creates a new session. It does not reconcile, replace, or delete a preexisting workspace. Applying a plan authorizes declared shell commands; their delivery does not prove that the pane programs completed. ## Start here - [Guides](https://libtmux.org/en/ruby/latest/workspace/guides/) covers `validate`, [`plan`](), and [`load`](). - [Topics](https://libtmux.org/en/ruby/latest/workspace/topics/) explains the supported format and creation-only model. - [Examples](https://libtmux.org/en/ruby/latest/workspace/examples/) provides a bounded YAML configuration. - [CLI Manual](https://libtmux.org/en/ruby/latest/workspace/cli/) documents commands, flags, output and exit statuses. - [Language API](https://libtmux.org/en/ruby/latest/workspace/reference/) documents the workspace gem. The [source-owned workspace guide](https://libtmux.org/en/ruby/latest/workspace/source-guide/) is staged from the same revision as the generated reference. --- # Ruby workspace guides Source: https://libtmux.org/en/ruby/latest/workspace/guides/ > Validate, inspect, and explicitly apply a Ruby workspace plan. ## Validate without tmux Validation reads and bounds the configuration without starting or contacting a tmux server. ```console $ libtmux-workspace validate workspace.yaml ``` ## Inspect an offline plan An offline plan lists the ordered creation operations. JSON output includes configured commands and paths, so treat it as application data rather than a redacted diagnostic. ```console $ libtmux-workspace plan \ --json \ workspace.yaml ``` ## Load on an explicit socket Start an application-owned server, then pass its socket path to [`load`](). ```console $ libtmux-workspace load \ --socket "$TMUX_SOCKET" \ --json \ workspace.yaml ``` `plan --live` requires the same selector. `--compensate` enables guarded cleanup of positively identified created state after failure; it cannot undo shell effects. Attach and client switching are explicit post-apply choices, not defaults. [Source-owned CLI guide](https://libtmux.org/en/ruby/latest/workspace/source-guide/#command-line-interface) --- # Ruby workspace topics Source: https://libtmux.org/en/ruby/latest/workspace/topics/ > Workspace format, planning boundaries, application effects, and failure ledgers. ## Configuration boundary The supported format describes one session with windows, panes, options, directories, environment values, and shell commands. YAML tags, aliases, duplicate keys, ERB, plugins, and callbacks are rejected. Environment substitution is opt-in and consults only the explicitly supplied mapping. ## Creation-only plans Plans create new state and reject a captured session-name conflict. They do not reconcile an existing workspace. Every apply takes a fresh snapshot and rechecks its binding and the target name before the first creation command. ## Effects and failure Shell commands are dispatched as literal text followed by Enter. Success means tmux accepted the dispatch, not that the shell command finished. An apply failure retains completed steps, positively identified created references, observed or dispatch-only effects, uncertainty, and cleanup diagnostics. Optional compensation kills only a positively returned new session after an atomic guard proves ownership of every current window and pane. Unknown or borrowed entities cause cleanup refusal. [Source-owned workspace guide](https://libtmux.org/en/ruby/latest/workspace/source-guide/) --- # Ruby workspace examples Source: https://libtmux.org/en/ruby/latest/workspace/examples/ > A bounded creation-only workspace for libtmux-workspace. Save this as `workspace.yaml`: ```yaml session_name: work environment: PROJECT_MODE: development windows: - window_name: editor window_index: 1 layout: tiled panes: - shell_command: printf 'editor ready\n' - {} ``` Run `libtmux-workspace validate workspace.yaml`, inspect `libtmux-workspace plan --json workspace.yaml`, then pass an owned socket to [`load`](). Relative directories resolve against the configuration file. The [source-owned workspace guide](https://libtmux.org/en/ruby/latest/workspace/source-guide/) links the installed-package example that checks inert planning, apply, and guarded compensation. --- # Ruby workspace API reference Source: https://libtmux.org/en/ruby/latest/workspace/reference/ > Public libtmux-workspace parsing, planning, application, and CLI types. Require `libtmux/workspace` for library use. Parsing and planning do not start tmux or execute commands. `Plan#apply` requires an explicitly opened core server and leaves that binding open. The declarations below come from the public Ruby inventory, enriched with RBS signatures, YARD documentation, behavior contracts, and source coordinates at the selected revision. ## API declarations - [LibTmux::Workspace](https://libtmux.org/en/ruby/latest/workspace/reference/libtmux-workspace/) --- # Runtime ownership Source: https://libtmux.org/en/lua/latest/guides/runtime/ > Runtime ownership: libtmux documentation. The runtime schedules asynchronous requests and owns their cleanup. Use its [connection and snapshot API](https://libtmux.org/en/lua/latest/guides/snapshots/) for explicit capture. [Literal command execution](https://libtmux.org/en/lua/latest/guides/commands/) shares that connection. Named domain operations and observation are still being integrated. Select [`libtmux.runtime.luv`]() for a standalone Lua process. Its [`run(body, limits)`]() function drives a quiescent top-level loop and returns `value, err` after owned work retires. It rejects coroutine entry, Neovim, active borrowed handles and nested calls from a Lua-driven luv loop. A C host that drives libuv without a Lua [`uv.run`]() frame is outside this standalone contract. Importing the adapter does not import luv or start a loop. Select [`libtmux.runtime.nvim`]() in Neovim. Its [`start(body, on_done, limits)`]() function returns the runtime and root Request immediately. It borrows the host loop and schedules callbacks outside fast events. `on_done(value, err)` runs after owned cleanup; unrelated host handles remain open. ## Tasks and results The body receives its runtime. [`runtime:spawn(body)`]() creates a child task and returns its Request eagerly. Tasks return `value, err`; a non-nil error or exception fails the enclosing task scope. Public library operations isolate operational failures in their returned Request; an unhandled failure in a caller's spawned task still fails the root. Returning normally joins child tasks, requests and deferred callbacks. A task may yield only through runtime operations; arbitrary Lua CPU work is not preemptible. [`request:await()`]() returns `value, err` from a managed coroutine in the same runtime. Main-thread, foreign-coroutine and cross-runtime waits raise `invalid_await_context`. Multiple tasks can wait on one Request. [`request:on_complete(fn)`]() registers a deferred `fn(value, err)` callback. Registration after settlement remains deferred while the runtime is live. Registration after root retirement or closure raises `closed`; exceeding callback or retained-byte limits raises `queue_full` synchronously. Callback failures fail their scope or appear in [`runtime:errors()`]() when the scope has already failed or retired. [`request:result()`]() reads a settled result without waiting; an unsettled request returns `nil, err` with code `pending`. [`is_settled()`]() describes caller completion. [`is_retired()`]() describes transport cleanup. Cancellation can settle before retirement, so these states differ. ## Cancellation and limits The task that creates an operation owns its cancellation. Canceling another task that waits on that operation detaches its wait; it does not cancel the producer. [`request:cancel(reason)`]() cancels the requested operation explicitly. [`runtime:close(reason)`]() rejects new work, cancels owned work and returns the root Request; repeated close calls are safe. Transport errors preserve `effect`: `not_sent`, [`unknown`](), or `completed`. Canceling a tmux client cannot prove that accepted daemon work stopped. Cleanup failures remain visible even when a result has already settled. | Limit | Default | | --- | ---: | | [`max_active`]() | 16 | | `max_pending` | 128 | | [`max_logical`]() | 128 | | `max_bytes` | 16 MiB | | [`max_tasks`]() | 128 | | [`max_callbacks`]() | 256 | | [`max_resources`]() | 128 | | [`dispatch_budget`]() | 64 | Pass overrides as the adapter's `limits` table. Runtime counters are exposed by [`runtime:stats()`](). Byte accounting includes queued callback and waiter delivery until transport retirement and delivery finish. Completed values retained by the caller belong to the caller's memory budget. Timers use monotonic milliseconds and reject delays above 2,147,483,647 ms. Logical Requests represent one-shot waits owned by the runtime, such as an observation's next event. They use the separate [`max_logical`]() limit through retirement and do not occupy active or pending process slots. A normal root return joins these waits. Cancel them, close their producer, or supply a deadline when no further event is expected. Canceling a borrowed waiter still detaches that waiter without canceling the producer. Persistent native resources use private leases outside process slots. A lease can own one bounded byte reservation for its buffers; those bytes count toward `max_bytes` and [`stats().resource_bytes`](). Internal producers can release discarded bytes or transfer their reservation atomically to a same-runtime, unsettled Request before delivering its value. The total runtime charge stays unchanged during transfer and lasts through queued delivery. Closing the lease stops new retention and transfer; release remains available during cleanup. Cleanup must discard and release its buffers before reporting completion. Unreleased bytes report `cleanup_failed`, remain charged, and increment `resources_failed` even after the native close attempt ends. Leases and raw Request constructors remain private implementation APIs. Standalone host failures trigger bounded cleanup. If cleanup cannot finish, `cleanup_failed` reports remaining counters; it does not report successful retirement. The runtime never closes borrowed host loops or kills a tmux server as part of request cancellation. See [development checks](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/.github/CONTRIBUTING.md) for real luv and Neovim host probes and [compatibility targets](https://libtmux.org/en/lua/latest/guides/compatibility/) for pending lanes. LuaLS 3.19.1 completes runtime, Request, Server and snapshot chains in both adapter bodies, including related pane/window fields. It preserves the standalone [`run`]() return type. That version does not infer the body result's members inside Neovim's separate `on_done` callback; annotate the callback's result parameter explicitly when editor completion is needed there. --- # tmux MCP for Rust Source: https://libtmux.org/en/rs/latest/mcp/ > Run tmux-mcp or embed its typed tool surface in a Rust application. `tmux-mcp` serves tmux over MCP stdio. It provides topology discovery, terminal capture, command execution, bounded waits, and a static capability resource. Building requires Rust 1.88 or newer. Running requires tmux 3.2a or newer. Toolsets select inspection, management, execution, and teardown. Read `tmux://capabilities` for the effective startup selection. ## Start here - [Install](https://libtmux.org/en/rs/latest/mcp/#install) points an MCP client at this server. - [Tools](https://libtmux.org/en/rs/latest/mcp/tools/) lists the MCP operations, arguments, and results. - [Guides](https://libtmux.org/en/rs/latest/mcp/guides/) connect a client and choose its tmux socket. - [Topics](https://libtmux.org/en/rs/latest/mcp/topics/) explain toolsets, command waits, and capability discovery. - [Examples](https://libtmux.org/en/rs/latest/mcp/examples/) run a Rust MCP client with a private tmux server. - [Language API](https://libtmux.org/en/rs/latest/mcp/reference/) documents embedding and implementation types. The Rust [Workspace Manager](https://libtmux.org/en/rs/latest/workspace/) is a separate crate. The current MCP catalog does not include a workspace-file operation. [Crate documentation and prerequisites](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/README.md). --- # Rust MCP API Source: https://libtmux.org/en/rs/latest/mcp/reference/ > Find TmuxTools, tool selections, schema-bearing registrations, and MCP resources. For MCP client requests, use the [tool reference](https://libtmux.org/en/rs/latest/mcp/tools/). This page covers language APIs for embedding or extending the server. The `tmux_mcp` crate exports the tool surface for applications that need a custom policy or transport. Its executable supplies the stdio launcher. ## Rust types [`TmuxTools::builder(server)`]() constructs a tool surface over a libtmux [`Server`](). Pass a [`Selection`]() through [`.selection()`](), then build it. [`offered()`]() reports the definitions available under that selection. The resulting type integrates with rmcp's server machinery; the [embedding example](https://libtmux.org/en/rs/latest/mcp/examples/) uses [`ServiceExt`](https://docs.rs/rmcp/3.1.2/rmcp/service/trait.ServiceExt.html) and a stdio transport. The [crate API](https://docs.rs/tmux-mcp) documents the Rust exports. ## Protocol contract The [tool reference](https://libtmux.org/en/rs/latest/mcp/tools/) describes MCP names and schemas. Registered tools provide structured results and output schemas. Errors distinguish stale objects, retryable failures, and partial effects. The static `tmux://capabilities` resource reports the startup-frozen surface. Inspect tools read live tmux state. The current surface has no workflow prompts or dynamic resource templates. [Workspace builder API](https://libtmux.org/en/rs/latest/workspace/reference/) describes the separate workspace parser, builder, and live-session export. [Crate source and examples](https://github.com/libtmux/libtmux-rs/tree/f0e37052c232636b61d095817046e6bfc8f2ca40/crates/tmux-mcp). ## API declarations - [mcp.views.Branch](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-branch/) - [mcp.views.BranchPane](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-branchpane/) - [mcp.views.BranchWindow](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-branchwindow/) - [mcp.policy.Builder](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-builder/) - [mcp.caller.CallerIdentity](https://libtmux.org/en/rs/latest/mcp/reference/mcp-caller-calleridentity/) - [mcp.resources.capabilities](https://libtmux.org/en/rs/latest/mcp/reference/mcp-resources-capabilities/) - [mcp.resources.CAPABILITIES_URI](https://libtmux.org/en/rs/latest/mcp/reference/mcp-resources-capabilities_uri/) - [mcp.manifest.CapabilityReport](https://libtmux.org/en/rs/latest/mcp/reference/mcp-manifest-capabilityreport/) - [mcp.views.Capture](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-capture/) - [mcp.model.CapturePaneArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-capturepaneargs/) - [mcp.model.CaptureSinceArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-capturesinceargs/) - [mcp.model.ChannelArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-channelargs/) - [mcp.views.ChannelSignal](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-channelsignal/) - [mcp.views.ChannelWait](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-channelwait/) - [mcp.model.CreateSessionArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-createsessionargs/) - [mcp.tail.Cursor](https://libtmux.org/en/rs/latest/mcp/reference/mcp-tail-cursor/) - [mcp.views.Environment](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-environment/) - [mcp.policy.ENVIRONMENT_VALUES_ENV](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-environment_values_env/) - [mcp.policy.environment_values_from_env](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-environment_values_from_env/) - [mcp.views.EnvironmentEntry](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-environmententry/) - [mcp.views.EnvironmentState](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-environmentstate/) - [mcp.policy.EXCLUDE_TOOLS_ENV](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-exclude_tools_env/) - [mcp.cli.HELP](https://libtmux.org/en/rs/latest/mcp/reference/mcp-cli-help/) - [mcp.views.Hook](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-hook/) - [mcp.views.Hooks](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-hooks/) - [mcp.views.Killed](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-killed/) - [mcp.views.Layout](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-layout/) - [mcp.resources.listed](https://libtmux.org/en/rs/latest/mcp/reference/mcp-resources-listed/) - [mcp.views.Marks](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-marks/) - [mcp.views.Matches](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-matches/) - [mcp.views.MatchView](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-matchview/) - [mcp.model.OptionArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-optionargs/) - [mcp.cli.Options](https://libtmux.org/en/rs/latest/mcp/reference/mcp-cli-options/) - [mcp.views.OptionValue](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-optionvalue/) - [mcp.model.PaneArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-paneargs/) - [mcp.views.PaneChanged](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-panechanged/) - [mcp.views.Panes](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-panes/) - [mcp.views.PaneView](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-paneview/) - [mcp.policy.parse_environment_values](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-parse_environment_values/) - [mcp.views.Pasted](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-pasted/) - [mcp.model.PasteTextArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-pastetextargs/) - [mcp.caller.Relation](https://libtmux.org/en/rs/latest/mcp/reference/mcp-caller-relation/) - [mcp.policy.Reporter](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-reporter/) - [mcp.model.ResizePaneArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-resizepaneargs/) - [mcp.policy.RETIRED_RUST_SAFETY_ENV](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-retired_rust_safety_env/) - [mcp.policy.RETIRED_SAFETY_ENV](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-retired_safety_env/) - [mcp.model.RunCommandArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-runcommandargs/) - [mcp.exec.RunOutcome](https://libtmux.org/en/rs/latest/mcp/reference/mcp-exec-runoutcome/) - [mcp.exec.RunView](https://libtmux.org/en/rs/latest/mcp/reference/mcp-exec-runview/) - [mcp.model.SearchPanesArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-searchpanesargs/) - [mcp.policy.Selection](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-selection/) - [mcp.model.SelectLayoutArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-selectlayoutargs/) - [mcp.model.SelectPaneArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-selectpaneargs/) - [mcp.model.SelectWindowArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-selectwindowargs/) - [mcp.model.SendKeysArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-sendkeysargs/) - [mcp.views.Sent](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-sent/) - [mcp.model.SessionArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-sessionargs/) - [mcp.views.Sessions](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-sessions/) - [mcp.views.SessionView](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-sessionview/) - [mcp.model.ShowEnvironmentArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-showenvironmentargs/) - [mcp.model.ShowHooksArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-showhooksargs/) - [mcp.views.Since](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-since/) - [mcp.views.Size](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-size/) - [mcp.views.Snapshot](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-snapshot/) - [mcp.model.SnapshotArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-snapshotargs/) - [mcp.policy.SocketProvenance](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-socketprovenance/) - [mcp.cli.Stop](https://libtmux.org/en/rs/latest/mcp/reference/mcp-cli-stop/) - [mcp.policy.SurfaceError](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-surfaceerror/) - [mcp.resources.templates](https://libtmux.org/en/rs/latest/mcp/reference/mcp-resources-templates/) - [mcp.src.TmuxTools](https://libtmux.org/en/rs/latest/mcp/reference/mcp-src-tmuxtools/) - [mcp.tools.error.ToolError](https://libtmux.org/en/rs/latest/mcp/reference/mcp-tools-error-toolerror/) - [mcp.policy.TOOLS_ENV](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-tools_env/) - [mcp.policy.Toolset](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-toolset/) - [mcp.policy.TOOLSETS_ENV](https://libtmux.org/en/rs/latest/mcp/reference/mcp-policy-toolsets_env/) - [mcp.views.Tree](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-tree/) - [mcp.tools.contract.VariablesArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-tools-contract-variablesargs/) - [mcp.tools.contract.VariablesValue](https://libtmux.org/en/rs/latest/mcp/reference/mcp-tools-contract-variablesvalue/) - [mcp.model.WaitForTextArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-waitfortextargs/) - [mcp.exec.WaitOutcome](https://libtmux.org/en/rs/latest/mcp/reference/mcp-exec-waitoutcome/) - [mcp.exec.WaitView](https://libtmux.org/en/rs/latest/mcp/reference/mcp-exec-waitview/) - [mcp.model.WindowArgs](https://libtmux.org/en/rs/latest/mcp/reference/mcp-model-windowargs/) - [mcp.views.Windows](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-windows/) - [mcp.views.WindowView](https://libtmux.org/en/rs/latest/mcp/reference/mcp-views-windowview/) [Protocol catalog](https://libtmux.org/en/rs/latest/mcp/tools.json) --- # Rust workspace manager Source: https://libtmux.org/en/rs/latest/workspace/ > Describe a tmux session in a file, then load, inspect and capture it. **Workspace Manager for Rust is in development.** Build `tmux-workspace` from the source revision in the installation guide. Its CLI and workspace library have separate installation and configuration contracts. `tmux-workspace` creates tmux sessions from YAML or JSON. A file describes windows, panes, commands, directories and environment. Load it from a terminal or request machine output for automation. ## Load a workspace from the terminal 1. [Install the command and load a workspace](https://libtmux.org/en/rs/latest/workspace/guides/installation/). 2. [Configure windows and panes](https://libtmux.org/en/rs/latest/workspace/configuration/). 3. [Capture and reload a session](https://libtmux.org/en/rs/latest/workspace/guides/export-session/). The [CLI manual](https://libtmux.org/en/rs/latest/workspace/cli/) covers discovery, search, editing, loading, capture, conversion and import. [Examples](https://libtmux.org/en/rs/latest/workspace/examples/gallery/) provide complete configurations with their prerequisites. ## Automate and inspect Use `load -d` when the caller should return without attaching. `--json` returns a result, and `--ndjson` supports a stream of records. Read [automation](https://libtmux.org/en/rs/latest/workspace/guides/automation/) for retry and cleanup decisions and [errors](https://libtmux.org/en/rs/latest/workspace/reference/exit-codes/) for failure handling. Loaded workspaces are ordinary tmux sessions. Select the same socket when inspecting them from tmux or the [MCP server](https://libtmux.org/en/rs/latest/mcp/). ## Build from application code The [workspace library](https://libtmux.org/en/rs/latest/workspace/internals/) has its own API and configuration contract. Use it when a program needs direct control over construction. The CLI task guides here describe the `tmux-workspace` executable and link to its documented source revision. [CLI source](https://github.com/libtmux/libtmux-rs/blob/e9be0b6f6d22cd2eb79b0ec08964f82e717e5fe4/crates/tmux-workspace/docs/cli.md). - [CLI Manual](https://libtmux.org/en/rs/latest/workspace/cli/): Commands, options and machine output. - [Configuration](https://libtmux.org/en/rs/latest/workspace/configuration/): Workspace fields, normalization and execution. - [Install and load](https://libtmux.org/en/rs/latest/workspace/guides/installation/): Load a workspace on a private socket, then capture it. - [Example gallery](https://libtmux.org/en/rs/latest/workspace/examples/gallery/): Workspace files to start from, with their prerequisites. - [Runtime support](https://libtmux.org/en/rs/latest/workspace/reference/compatibility/): Runtime requirements and supported behavior. - [Internals](https://libtmux.org/en/rs/latest/workspace/internals/): The workspace library, for building sessions from code. --- # tmux MCP for Swift Source: https://libtmux.org/en/swift/latest/mcp/ > Run the Swift MCP executable or embed its typed tool service with explicit authority. `libtmux-mcp` is the Swift stdio executable. [`LibTmuxMCP`](https://github.com/libtmux/libtmux-swift/blob/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Package.swift) is the SwiftPM library product for embedding the same tools. They expose tmux discovery, captures, waits, input, configuration, and process control. The package requires Swift 6.2 or newer and supports Linux and macOS. The documented Darwin dependency build uses Xcode's Swift 6.3 toolchain. tmux is required at runtime. ## Start here - [Install](https://libtmux.org/en/swift/latest/mcp/#install) points an MCP client at this server. - [Tools](https://libtmux.org/en/swift/latest/mcp/tools/) lists the MCP operations, arguments, and results. - [Guides](https://libtmux.org/en/swift/latest/mcp/guides/) build the executable and configure its environment. - [Topics](https://libtmux.org/en/swift/latest/mcp/topics/) explain toolsets, command waits, and capability discovery. - [Examples](https://libtmux.org/en/swift/latest/mcp/examples/) call a tool, then explore server internals. - [Language API](https://libtmux.org/en/swift/latest/mcp/reference/) documents embedding and implementation types. The executable defaults to inspection, management, and execution; a verified dedicated daemon can also receive teardown tools. The embedding initializer defaults to inspection alone. Read `tmux://capabilities` for the startup selection. [Workspace Manager](https://libtmux.org/en/swift/latest/workspace/) is a separate library product. The current MCP catalog does not include a workspace-file operation. [Library contract](https://github.com/libtmux/libtmux-swift/blob/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Sources/LibTmuxMCP/README.md) and [platform requirements](https://github.com/libtmux/libtmux-swift/blob/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/README.md#requirements). --- # Swift MCP topics Source: https://libtmux.org/en/swift/latest/mcp/topics/ > Select toolsets, inspect the pinned endpoint, and observe bounded commands. The server selects one tmux endpoint and freezes its offered tools at startup. Read `tmux://capabilities` to inspect that endpoint's provenance and the effective tool selection. ## Select tools `LIBTMUX_TOOLSETS` selects any combination of [`inspect`](), [`manage`](), [`execute`](), and [`teardown`](). `LIBTMUX_TOOLS` adds exact names; `LIBTMUX_EXCLUDE_TOOLS` removes names last. Unknown names and malformed lists fail startup. Use [`inspect`]() for discovery and terminal reads. Add [`manage`]() for topology changes and [`execute`]() for input and process creation. Select [`teardown`]() explicitly when removal is needed on an existing or explicitly selected server. A default dedicated daemon can receive teardown tools when the launcher verifies its own minimal-configuration provenance. Tool selection shapes the callable interface. Execute tools act with the tmux user's authority; selecting a socket does not confine shell effects. ## Observe a command Use [`run_shell_command`](https://libtmux.org/en/swift/latest/mcp/tools/run_shell_command/) for a bounded command and its exit status. A deadline ends the wait; the pane command may still be running. Inspect it before submitting another command. Use [`capture_since`](https://libtmux.org/en/swift/latest/mcp/tools/capture_since/) to collect subsequent output and [`wait_for_text`](https://libtmux.org/en/swift/latest/mcp/tools/wait_for_text/) for an expected terminal condition. Their schemas and result limits are in the [tool reference](https://libtmux.org/en/swift/latest/mcp/tools/). The current catalog has no detached job-handle API. ## Resources and prompts The server exposes the static `tmux://capabilities` resource. Read live hierarchy and terminal state through tools. The current surface has no workflow prompts or dynamic resource templates. [Configuration and lifecycle contract](https://github.com/libtmux/libtmux-swift/blob/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Sources/libtmux-mcp/README.md). --- # Connect a Swift MCP client Source: https://libtmux.org/en/swift/latest/mcp/guides/ > Build the Swift MCP executable and connect it to a private tmux server. Build the Swift executable, then let your MCP client launch the script below. The script owns a private tmux server and exposes only `list_sessions`. It stops tmux when the MCP process exits; it does not require an existing tmux session. ## Build the executable Use Swift 6.2.4, Git, and tmux 3.2a or newer on Linux. Create an empty directory for the launcher and source checkout: ```console $ mkdir swift-mcp-client && cd swift-mcp-client ``` Fetch the library revision and build its stdio server: ```console $ git init libtmux-source && \ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-swift.git && \ git -C libtmux-source fetch --depth=1 origin 254f8b2be7eb60cacc3ffcb3ea8e456784f582df && \ git -C libtmux-source checkout --detach FETCH_HEAD && \ swift build --package-path libtmux-source --product libtmux-mcp --jobs 2 ``` Keep the build directory: the executable uses its adjacent resource bundle. ## Save the launcher Save the following file alongside the source checkout. The trap preserves a failed-stop socket for inspection and reports cleanup errors on stderr. ```sh title="run-mcp.sh" #!/bin/sh set -eu unset TMUX TMUX_PANE LIBTMUX_SOCKET project=$(CDPATH= cd -P "$(dirname "$0")" && pwd) directory=$(mktemp -d /tmp/libtmux-swift-mcp.XXXXXXXX) cleanup() { status=$? trap - 0 HUP INT TERM if [ -S "$directory/s" ]; then if ! tmux -S "$directory/s" kill-server; then printf 'Cannot stop private server; inspect %s\n' "$directory" >&2 exit 1 fi fi if ! rm -f "$directory/s" || ! rmdir "$directory"; then printf 'Cannot remove private directory: %s\n' "$directory" >&2 exit 1 fi exit "$status" } trap cleanup 0 trap 'exit 129' HUP trap 'exit 130' INT trap 'exit 143' TERM tmux -S "$directory/s" -f /dev/null \ set-option -g default-shell /bin/sh \; \ set-environment -g ENV '' \; \ set-environment -g BASH_ENV '' \; \ new-session -d -s mcp-example 'exec /bin/cat' LIBTMUX_SOCKET_PATH="$directory/s" \ LIBTMUX_TMUX_BIN=tmux LIBTMUX_TMUX_CONFIG=/dev/null \ LIBTMUX_TOOLSETS= LIBTMUX_TOOLS=list_sessions LIBTMUX_EXCLUDE_TOOLS= \ "$project/libtmux-source/.build/debug/libtmux-mcp" ``` Run it directly to check startup: ```console $ sh run-mcp.sh ``` It waits for MCP messages on stdin. Send EOF to close the process and trigger cleanup. The executable accepts no flags; its endpoint and tool selection come from environment variables. ## Connect a client Configure the client to run `sh` with the launcher's absolute path as its only argument. The client must have tmux on its `PATH`. The launcher finds the build relative to its own file, so the client's working directory does not matter. Ask the client to list its tools, then call [`list_sessions`](https://libtmux.org/en/swift/latest/mcp/tools/list_sessions/). The offered surface contains only that tool, and its result contains the launcher's `mcp-example` session. An empty `LIBTMUX_TOOLSETS` plus the named `LIBTMUX_TOOLS` selection excludes other operations. Reconnect after changing the selection. Invalid selections fail startup and write diagnostics to stderr. For a server the application already owns, select its absolute socket with `LIBTMUX_SOCKET_PATH` or its socket name with `LIBTMUX_SOCKET`; these settings are mutually exclusive. `LIBTMUX_TMUX_BIN` selects a specific tmux executable. The [complete embedded example](https://libtmux.org/en/swift/latest/mcp/examples/) calls the Swift tool surface inside a consumer program. The [executable contract](https://github.com/libtmux/libtmux-swift/blob/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Sources/libtmux-mcp/README.md) describes its environment and protocol behavior. --- # Swift MCP examples Source: https://libtmux.org/en/swift/latest/mcp/examples/ > Call an embedded Swift MCP tool against a private tmux server. Embed the Swift MCP tool surface, expose only `list_sessions`, and check its structured result against a private tmux session. The program calls the same tool implementation used by the stdio server. For an external MCP client, use the [connection guide](https://libtmux.org/en/swift/latest/mcp/guides/). ## Prepare the project Use Swift 6.2.4, Git, and tmux 3.2a or newer on Linux. Create an empty project and the executable's source directory: ```console $ mkdir swift-mcp-example && cd swift-mcp-example && \ mkdir -p Sources/MCPExample ``` Fetch the library revision used by this example: ```console $ git init libtmux-source && \ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-swift.git && \ git -C libtmux-source fetch --depth=1 origin 254f8b2be7eb60cacc3ffcb3ea8e456784f582df && \ git -C libtmux-source checkout --detach FETCH_HEAD ``` Save the following package manifest at the project root: ```swift title="Package.swift" // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "MCPExample", platforms: [.macOS(.v13)], dependencies: [.package(path: "libtmux-source")], targets: [ .executableTarget( name: "MCPExample", dependencies: [ .product(name: "LibTmux", package: "libtmux-source"), .product(name: "LibTmuxMCP", package: "libtmux-source"), ] ), ] ) ``` ## Run the complete program Save this file in the source directory created above. Its private socket is checked during cleanup even when startup fails. Cleanup failures preserve the original error and report the retained directory. ```swift title="Sources/MCPExample/MCPExample.swift" import Foundation import LibTmux import LibTmuxMCP struct ExampleFailure: Error, CustomStringConvertible { let description: String } func withPrivateTmux( _ body: @Sendable (Server) async throws -> Void ) async throws { let directory = URL(fileURLWithPath: "/tmp") .appendingPathComponent("libtmux-swift-example-\(UUID().uuidString)") let server = try Server( socketPath: directory.appendingPathComponent("s").path, configurationFile: "/dev/null" ) try FileManager.default.createDirectory( at: directory, withIntermediateDirectories: false, attributes: [.posixPermissions: 0o700] ) var failures: [String] = [] do { try await body(server) } catch { failures.append("Operation: \(error)") } do { let files = try FileManager.default.contentsOfDirectory( atPath: directory.path ) if files.contains("s") { try await server.killServer() } try FileManager.default.removeItem(at: directory) } catch { failures.append("Cleanup at \(directory.path): \(error)") } if !failures.isEmpty { throw ExampleFailure(description: failures.joined(separator: "\n")) } } @main struct MCPExample { static func main() async throws { try await withPrivateTmux { server in let started = try await server.run([ TmuxCommand("set-option", ["-g", "default-shell", "/bin/sh"]), TmuxCommand("set-environment", ["-g", "ENV", ""]), TmuxCommand("set-environment", ["-g", "BASH_ENV", ""]), TmuxCommand("new-session", [ "-d", "-s", "mcp-example", "exec /bin/cat", ]), ]) guard started.isSuccess else { throw ExampleFailure(description: started.errorText) } let tools = TmuxTools( server: server, authority: ToolAuthority( toolsets: [], includedTools: ["list_sessions"] ), caller: nil ) let names = tools.visibleDefinitions.map(\.name) guard names == ["list_sessions"] else { throw ExampleFailure(description: "Unexpected tool selection") } let result = try await tools.call(ToolCall(name: "list_sessions")) guard let sessions = result.structured["sessions"]?.arrayValue, sessions.count == 1, sessions[0]["name"]?.stringValue == "mcp-example" else { throw ExampleFailure(description: "Unexpected session result") } print("tools: \(names.joined(separator: ", "))") print("sessions: mcp-example") } } } ``` Build and run the executable: ```console $ swift run --jobs 2 MCPExample ``` Expected output: ```text tools: list_sessions sessions: mcp-example ``` [`ToolAuthority`]() starts with no toolsets and includes only `list_sessions`. `caller: nil` avoids importing an ambient tmux pane identity. The explicitly configured server selects the private socket. A thrown [`ToolError`]() reports a failed invocation. The successful result carries structured session data; retain the returned session IDs for later operations. The [tool reference](https://libtmux.org/en/swift/latest/mcp/tools/list_sessions/) describes the result schema. [Library source](https://github.com/libtmux/libtmux-swift/tree/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Sources/LibTmuxMCP). --- # Swift MCP API Source: https://libtmux.org/en/swift/latest/mcp/reference/ > Find Swift embedding types, typed tool authority, and the separate protocol catalog. For MCP client requests, use the [tool reference](https://libtmux.org/en/swift/latest/mcp/tools/). This page covers language APIs for embedding or extending the server. [`LibTmuxMCP`](https://github.com/libtmux/libtmux-swift/blob/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Package.swift) is a SwiftPM library product. `libtmux-mcp` wraps it in a stdio executable. Public Swift types and MCP wire operations have separate names and responsibilities. ## Swift embedding API [`TmuxTools(server:)`]() constructs a readonly tool surface. [`ToolAuthority`]() selects [`Toolset`]() groups and named tool inclusions or exclusions. [`visibleDefinitions`]() reports the selection; [`call(ToolCall)`]() invokes an operation and returns structured data or throws [`ToolError`](). [`MCPRequestHandler`]() and [`MCPService`]() provide protocol composition. [`ServerConfiguration`]() parses the executable's environment and builds its libtmux endpoint. [Embedding contract](https://github.com/libtmux/libtmux-swift/blob/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Sources/LibTmuxMCP/README.md) and [configuration source](https://github.com/libtmux/libtmux-swift/blob/254f8b2be7eb60cacc3ffcb3ea8e456784f582df/Sources/LibTmuxMCP/Configuration.swift). ## MCP contract The [tool reference](https://libtmux.org/en/swift/latest/mcp/tools/) describes the wire catalog and schemas. Follow-up calls use opaque references returned by hierarchy discovery. The static `tmux://capabilities` resource reports the startup-frozen surface. Live state comes from inspect tools. The current surface has no workflow prompts or dynamic resource templates. The [Workspace builder API](https://libtmux.org/en/swift/latest/workspace/reference/) owns workspace decoding and construction; those operations are separate from the MCP catalog. ## API declarations - [CallerIdentity](https://libtmux.org/en/swift/latest/mcp/reference/calleridentity/) - [InputSink](https://libtmux.org/en/swift/latest/mcp/reference/inputsink/) - [JSONValue](https://libtmux.org/en/swift/latest/mcp/reference/jsonvalue/) - [MCPRequestHandler](https://libtmux.org/en/swift/latest/mcp/reference/mcprequesthandler/) - [MCPService](https://libtmux.org/en/swift/latest/mcp/reference/mcpservice/) - [OutputClass](https://libtmux.org/en/swift/latest/mcp/reference/outputclass/) - [ProcessReach](https://libtmux.org/en/swift/latest/mcp/reference/processreach/) - [ProgressReporter](https://libtmux.org/en/swift/latest/mcp/reference/progressreporter/) - [ServerConfiguration](https://libtmux.org/en/swift/latest/mcp/reference/serverconfiguration/) - [ServerProvenance](https://libtmux.org/en/swift/latest/mcp/reference/serverprovenance/) - [TmuxEffect](https://libtmux.org/en/swift/latest/mcp/reference/tmuxeffect/) - [TmuxFormatControl](https://libtmux.org/en/swift/latest/mcp/reference/tmuxformatcontrol/) - [TmuxTools](https://libtmux.org/en/swift/latest/mcp/reference/tmuxtools/) - [ToolAnnotations](https://libtmux.org/en/swift/latest/mcp/reference/toolannotations/) - [ToolArgument](https://libtmux.org/en/swift/latest/mcp/reference/toolargument/) - [ToolAuthority](https://libtmux.org/en/swift/latest/mcp/reference/toolauthority/) - [ToolCall](https://libtmux.org/en/swift/latest/mcp/reference/toolcall/) - [ToolDefinition](https://libtmux.org/en/swift/latest/mcp/reference/tooldefinition/) - [ToolError](https://libtmux.org/en/swift/latest/mcp/reference/toolerror/) - [ToolOperation](https://libtmux.org/en/swift/latest/mcp/reference/tooloperation/) - [ToolOutcome](https://libtmux.org/en/swift/latest/mcp/reference/tooloutcome/) - [Toolset](https://libtmux.org/en/swift/latest/mcp/reference/toolset/) [Protocol catalog](https://libtmux.org/en/swift/latest/mcp/tools.json) --- # Swift workspace manager Source: https://libtmux.org/en/swift/latest/workspace/ > Describe a tmux session in a file, then load, inspect and capture it. **Workspace Manager for Swift is in development.** Build `tmux-workspace` from the source revision in the installation guide. Its CLI and workspace library have separate installation and configuration contracts. `tmux-workspace` creates tmux sessions from YAML or JSON. A file describes windows, panes, commands, directories and environment. Load it from a terminal or request machine output for automation. ## Load a workspace from the terminal 1. [Install the command and load a workspace](https://libtmux.org/en/swift/latest/workspace/guides/installation/). 2. [Configure windows and panes](https://libtmux.org/en/swift/latest/workspace/configuration/). 3. [Capture and reload a session](https://libtmux.org/en/swift/latest/workspace/guides/export-session/). The [CLI manual](https://libtmux.org/en/swift/latest/workspace/cli/) covers discovery, search, editing, loading, capture, conversion and import. [Examples](https://libtmux.org/en/swift/latest/workspace/examples/gallery/) provide complete configurations with their prerequisites. ## Automate and inspect Use `load -d` when the caller should return without attaching. `--json` returns a result, and `--ndjson` supports a stream of records. Read [automation](https://libtmux.org/en/swift/latest/workspace/guides/automation/) for retry and cleanup decisions and [errors](https://libtmux.org/en/swift/latest/workspace/reference/exit-codes/) for failure handling. Loaded workspaces are ordinary tmux sessions. Select the same socket when inspecting them from tmux or the [MCP server](https://libtmux.org/en/swift/latest/mcp/). ## Build from application code The [workspace library](https://libtmux.org/en/swift/latest/workspace/internals/) has its own API and configuration contract. Use it when a program needs direct control over construction. The CLI task guides here describe the `tmux-workspace` executable and link to its documented source revision. [CLI source](https://github.com/libtmux/libtmux-swift/blob/53c67947879f4976ddf2c43f3c8df7c7671c5b19/Sources/TmuxWorkspaceCLI/README.md). - [CLI Manual](https://libtmux.org/en/swift/latest/workspace/cli/): Commands, options and machine output. - [Configuration](https://libtmux.org/en/swift/latest/workspace/configuration/): Workspace fields, normalization and execution. - [Install and load](https://libtmux.org/en/swift/latest/workspace/guides/installation/): Load a workspace on a private socket, then capture it. - [Example gallery](https://libtmux.org/en/swift/latest/workspace/examples/gallery/): Workspace files to start from, with their prerequisites. - [Runtime support](https://libtmux.org/en/swift/latest/workspace/reference/compatibility/): Runtime requirements and supported behavior. - [Internals](https://libtmux.org/en/swift/latest/workspace/internals/): The workspace library, for building sessions from code. --- # C# MCP topics Source: https://libtmux.org/en/csharp/latest/mcp/topics/ > Choose callable tools, interpret bounded results, and understand pane observation and cancellation. The server selects one tmux endpoint and freezes its offered tools at startup. Read `tmux://capabilities` to inspect that endpoint's provenance and the effective tool selection. ## Select tools [Tool selection](https://libtmux.org/en/csharp/latest/mcp/topics/tool-selection/) explains the four groups, exact-name inclusions, exclusions, and the difference between an unset and an empty selection. A socket limits the tmux objects the process addresses; it does not restrict the operating-system authority of commands running in panes. ## Observe a command [Waits and captured output](https://libtmux.org/en/csharp/latest/mcp/topics/waits-and-output/) distinguishes command completion from terminal text changes. It covers `run_shell_command`, `wait_for_text`, incremental captures, response budgets, and cancellation. An expired wait can leave a command running. ## Resources and prompts The [capability resource](https://libtmux.org/en/csharp/latest/mcp/topics/tool-selection/#inspect-the-connection) reports startup configuration. Read live hierarchy and terminal state through tools. The server offers no workflow prompts or dynamic resource templates. - [Tool selection](https://libtmux.org/en/csharp/latest/mcp/topics/tool-selection/): Combine toolsets, exact names, and exclusions; inspect the frozen capability report. - [Waits and captured output](https://libtmux.org/en/csharp/latest/mcp/topics/waits-and-output/): Read command results, follow a pane, and handle deadlines, truncation, and lost events. --- # Go MCP topics Source: https://libtmux.org/en/go/latest/mcp/topics/ > Choose tools, inspect the pinned endpoint, and interpret command completion and output. The server selects one tmux endpoint and freezes its offered tools at startup. These choices determine what the connected client can call. ## Select tools Use `inspect` for hierarchy and terminal reads, `manage` for topology changes, and `execute` for input and command execution. Select `teardown` when removal is needed. [Tool selection](https://libtmux.org/en/go/latest/mcp/topics/tool-selection/) explains defaults, individual names, exclusions, and the distinction between missing and failing tools. ## Observe a command [`run_shell_command`](https://libtmux.org/en/go/latest/mcp/tools/run_shell_command/) waits for a bounded command and reports completion separately from its exit status and captured output. A timeout does not establish that the command stopped. Read [Waits and output](https://libtmux.org/en/go/latest/mcp/topics/waits-and-output/) before deciding whether to submit more input to that pane. ## Resources and prompts `tmux://capabilities` reports the startup endpoint and effective tools. Its payload is static; use tools to read live hierarchy and terminal state. The server offers no workflow prompts, dynamic resource templates, or detached job handles. The [module contract](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/README.md) describes the resource and capability metadata. - [Tool selection](https://libtmux.org/en/go/latest/mcp/topics/tool-selection/): Combine toolsets, exact tool names, and exclusions at startup. - [Waits and output](https://libtmux.org/en/go/latest/mcp/topics/waits-and-output/): Distinguish tool errors, exit status, timeouts, and incomplete output. --- # Topics Source: https://libtmux.org/en/lua/latest/topics/ > Topics for libtmux. Understand object ownership, state, and operation behavior. - [Options and hooks](https://libtmux.org/en/lua/latest/topics/options-and-hooks/): Read about options and hooks. - [Persistent environment](https://libtmux.org/en/lua/latest/topics/environment/): Read about persistent environment. - [tmux field catalog](https://libtmux.org/en/lua/latest/topics/format-token-fields/): Read about tmux field catalog. --- # Topics Source: https://libtmux.org/en/ruby/latest/topics/ > Topics for libtmux. Understand object ownership, state, and operation behavior. - [Ownership and errors](https://libtmux.org/en/ruby/latest/topics/errors-and-exceptions/): Understand server ownership, immutable references, and operation failures. --- # Topics Source: https://libtmux.org/en/tmux/topics/ > Object traversal, cleanup, pane I/O, configuration, and failure handling. Use these pages for object traversal, cleanup, pane I/O, configuration, and failure handling. [Concepts](https://libtmux.org/en/tmux/concepts/) introduces the shared object model. The concept guides also cover [control mode vs one-shot](https://libtmux.org/en/tmux/concepts/transports/), [filtering and queries](https://libtmux.org/en/tmux/concepts/queries/), and [workspaces](https://libtmux.org/en/tmux/concepts/workspaces/). Choose a topic for more detailed behavior. Use your port's API reference for signatures and defaults. Each topic explains the behavior behind those calls. - [Architecture](https://libtmux.org/en/tmux/topics/architecture/): Locate operations and field definitions in the library source. - [Traversal](https://libtmux.org/en/tmux/topics/traversal/): Navigate related objects, test membership, and compare identity. - [Ownership and cleanup](https://libtmux.org/en/tmux/topics/context-managers/): Manage cleanup on block exit and identify objects that need a kill. - [Pane interaction](https://libtmux.org/en/tmux/topics/pane-interaction/): Choose input modes, capture ranges, and completion waits. - [Options and hooks](https://libtmux.org/en/tmux/topics/options-and-hooks/): Configure tmux and register event commands at a supported scope. - [Format-token fields](https://libtmux.org/en/tmux/topics/format-tokens/): Read typed state and handle absent fields. - [Waiting and retrying](https://libtmux.org/en/tmux/topics/waiting-and-retry/): Wait on a condition or a named tmux signal. - [Environment](https://libtmux.org/en/tmux/topics/environment/): Locate objects from process variables and configure new panes. - [Socket and servers](https://libtmux.org/en/tmux/topics/socket-and-servers/): Select a server, check liveness, and detect a replacement daemon. - [Errors and exceptions](https://libtmux.org/en/tmux/topics/errors-and-exceptions/): Handle command failures and decide whether a mutation can be retried. --- # Architecture Source: https://libtmux.org/en/tmux/topics/architecture/ > Locate operations, distinguish snapshots from live commands, and find their implementation. A server handle selects a tmux server. Object IDs select sessions, windows, and panes within it. For the object hierarchy and stable IDs, start with [Server, session, window, pane](https://libtmux.org/en/tmux/concepts/server-session-window-pane/). ## Calling operations Session, window, and pane handles carry their ID and server context. Call an operation on the object you want to change. The examples below send input and kill that pane. ```python pane.send_keys("echo hi") pane.kill() ``` ```typescript await pane.sendKeys("echo hi"); await pane.kill(); ``` ```go cmd := "printf 'hello\\n'" if err := pane.SendKeys(ctx, tmux.SendKeysRequest{Command: &cmd, Literal: true}); err != nil { return err } if err := pane.Kill(ctx); err != nil { return err } ``` ```rust pane.send_line("echo hi").await?; pane.kill().await?; // consumes the handle: see Context managers ``` ```java pane.sendLine("echo hi"); pane.kill(); ``` ```csharp await pane.SendTextAsync("echo hi"); await pane.KillAsync(); ``` ```cpp pane->send_text("echo hi"); pane->kill(); ``` Swift's [`Session`](), [`Window`](), and [`Pane`]() are [`Sendable`]() value types holding IDs and state fields. [Format-token fields](https://libtmux.org/en/tmux/topics/format-tokens/) lists their fields. Perform operations through [`Server`](), passing the target value: ```swift try await server.sendKeys(["echo hi", "Enter"], to: pane) try await server.kill(pane) ``` Keep the [`Server`]() that produced the snapshot. Pass its captured values back to that server for operations. ## Reading tmux fields Object IDs become tmux targets (`-t`). Format variables (`#{...}`) provide the state returned by tmux. ### Python [`libtmux.constants`]() defines the format fields and their scope and tmux-version requirements. [`Obj`]() in [`libtmux.neo`]() exposes the captured values as dataclass fields. A field excluded by those requirements is [`None`](). ### TypeScript [`packages/libtmux/src/_generated/format_fields.ts`]() records each token's scope and first tmux version. [`packages/libtmux/src/_generated/field_aliases.ts`]() provides camelCase aliases for fields on [`Pane`](), [`Session`](), and [`Window`](). ### Go [`tmux/format_generated.go`]() defines format fields, and [`tmux/option_generated.go`]() defines options. The format generator lives in [`tmux/internal/generate/formats/`](). Accessors return a value and a boolean when a field can be unavailable; check the boolean before using the value. ### Rust [`crates/libtmux/src/formats.rs`]() defines the format catalog. Each entry records the tmux name, required context, first supported release, decoder, and handling of empty values. [`crates/libtmux/src/snapshot.rs`]() uses that catalog to decode captured fields. Handle accessors such as [`Pane.current_command`]() return `Option` when a value can be absent. Typed field queries return [`Availability`](), which also distinguishes an unsupported field from an absent value. See [Format-token fields](https://libtmux.org/en/tmux/topics/format-tokens/) for field availability. ### Java Typed field classes such as [`Pane_`]() and [`Session_`]() support the query layer. Accessors use `Optional` for fields that may be unavailable on the running tmux version. [Filtering and queries](https://libtmux.org/en/java/latest/concepts/queries/) explains how to select and query those fields. ### C# Typed properties read a dictionary captured from tmux. A property throws [`IncompleteSnapshotException`]() when the capture did not request its field. This differs from a captured field whose value is absent. ### Swift Snapshots capture a fixed set of non-optional fields, including indices, dimensions, active state, command, path, and edge flags. [Format-token fields](https://libtmux.org/en/tmux/topics/format-tokens/) covers other tokens. ### C++ Handles capture a fixed set of non-optional fields. Use [`pane->expand("#{...}")`]() for tokens outside those fields. [Format-token fields](https://libtmux.org/en/tmux/topics/format-tokens/) covers their interpretation. ## Source layout ### Python [`Server`](), [`Session`](), [`Window`](), [`Pane`](), and [`Client`]() each have their own module: [`src/libtmux/server.py`](), [`src/libtmux/session.py`](), [`src/libtmux/window.py`](), [`src/libtmux/pane.py`](), and [`src/libtmux/client.py`](). [`src/libtmux/common.py`]() holds shared behavior. [`src/libtmux/neo.py`]() defines the dataclass query layer, [`src/libtmux/options.py`]() and [`src/libtmux/hooks.py`]() provide mixins, and [`src/libtmux/exc.py`]() defines the exception hierarchy. ### TypeScript The public classes live in [`packages/libtmux/src/server.ts`](), [`packages/libtmux/src/session.ts`](), [`packages/libtmux/src/window.ts`](), [`packages/libtmux/src/pane.ts`](), and [`packages/libtmux/src/client.ts`](). Their operations are split by concern under [`packages/libtmux/src/_internal/operations/`](), including [`packages/libtmux/src/_internal/operations/pane_io.ts`](), [`packages/libtmux/src/_internal/operations/hooks.ts`](), [`packages/libtmux/src/_internal/operations/options.ts`](), and [`packages/libtmux/src/_internal/operations/topology.ts`](). [`packages/libtmux/src/_generated/`]() contains the generated field catalogs. Workspaces and the MCP server have separate packages in the same repository. ### Go The [`tmux`]() package groups its implementation by concern. [`tmux/model.go`]() defines the core structs. [`tmux/lifecycle_kill.go`](), [`tmux/pane_capture.go`](), [`tmux/pane_geometry.go`](), and [`tmux/hierarchy.go`]() implement lifecycle, capture, geometry, and traversal. [`tmux/plan_server.go`]() combines commands into fewer invocations. [`tmuxq/`]() provides predicate queries over an already-read snapshot; see [Filtering and queries](https://libtmux.org/en/go/latest/concepts/queries/). Workspace support lives in [`workspace/`](). ### Rust [`Server`](), [`Session`](), [`Window`](), and [`Pane`]() are defined in [`crates/libtmux/src/server.rs`](), [`crates/libtmux/src/session.rs`](), [`crates/libtmux/src/window.rs`](), and [`crates/libtmux/src/pane.rs`](). Their additional operations live in [`crates/libtmux/src/server/`](), [`crates/libtmux/src/session/`](), [`crates/libtmux/src/window/`](), and [`crates/libtmux/src/pane/`](). The [options and hooks](https://libtmux.org/en/tmux/topics/options-and-hooks/) methods are grouped in [`crates/libtmux/src/server/settings.rs`](), [`crates/libtmux/src/session/settings.rs`](), [`crates/libtmux/src/window/settings.rs`](), and [`crates/libtmux/src/pane/settings.rs`](). [`crates/libtmux/src/hooks.rs`]() defines [`IndexedHooks`]() and [`SparseValues`](); [`crates/libtmux/src/options.rs`]() defines option schemas and values. Workspaces and the MCP server are separate crates under [`crates/tmux-workspace/`]() and [`crates/tmux-mcp/`](). ### Java [`libtmux/src/main/java/io/github/libtmux/`]() holds the [`Server`](), [`Session`](), [`Window`](), and [`Pane`]() classes. Their `options()` and `hooks()` accessors return [`Options`]() and [`Hooks`]() views scoped to the object. [`Session_`](), [`Window_`](), and [`Pane_`]() are typed-field classes for the query layer. ### C# [`src/LibTmux/`]() splits each entity into partial-class files by concern. For example, [`src/LibTmux/Pane.cs`](), [`src/LibTmux/Pane.Capture.cs`](), [`src/LibTmux/Pane.Input.cs`](), [`src/LibTmux/Pane.Relations.cs`](), [`src/LibTmux/Pane.Scopes.cs`](), and [`src/LibTmux/Pane.Topology.cs`]() contribute to one [`Pane`]() type. `Options` and `Hooks` views are reached through the object's properties. ### C++ [`include/libtmux/entities.hpp`]() declares [`Session`](), [`Window`](), and [`Pane`](). Their method bodies live in [`src/`](). [`include/libtmux/server.hpp`](), [`include/libtmux/options.hpp`](), and [`include/libtmux/capabilities.hpp`]() define server operations, options, and capability checks. The [`include/libtmux/testing/`]() component is separate from the library; [Context managers](https://libtmux.org/en/tmux/topics/context-managers/) explains its test-server ownership. ### Swift [`Sources/LibTmux/Server.swift`]() defines [`Server`](). [`Sources/LibTmux/Session.swift`](), [`Sources/LibTmux/Window.swift`](), and [`Sources/LibTmux/Pane.swift`]() define the snapshot value types. [`Sources/LibTmux/Snapshot.swift`]() implements the [relationship queries](https://libtmux.org/en/tmux/topics/traversal/). Extensions on [`Server`]() group related operations: [`Sources/LibTmux/Options.swift`]() implements options and hooks, [`Sources/LibTmux/PaneInteraction.swift`]() handles input and capture, and [`Sources/LibTmux/Mutations.swift`]() handles changes such as killing a pane. ## Naming conventions Method names follow language conventions: Python, Rust, and C++ use `snake_case`; TypeScript, Java, and Swift use `camelCase`; Go and C# use `PascalCase`. Option and hook names remain tmux's dash-separated strings, such as `automatic-rename`, regardless of the method's spelling. --- # Options and hooks Source: https://libtmux.org/en/lua/latest/topics/options-and-hooks/ > Options and hooks: libtmux documentation. Options and hooks return Requests through the process lane. Session, Window and Pane handles select their own storage scope. Server methods default to server options; use `scope = "global_session"` or `"global_window"` for global defaults. Server hook methods require one of those explicit global scopes. There is no global pane scope. A scope that conflicts with the handle or built-in definition fails before I/O. The [release catalog](https://libtmux.org/en/lua/latest/guides/options/) records exact names, types and scopes for supported tmux releases. Names do not accept tmux's abbreviations. Unknown releases fail with `unsupported_version`. User options support names such as `@project_name`, with ASCII letters, digits, underscores, dots and hyphens after `@`; broader native names return `unsupported_name`. ## Read a setting `get_option(name, options)` returns a record with `present`, `inherited`, `type`, requested `scope` and `target`. Scalar [`value`]() preserves booleans, integers and bytes. Choice values use their canonical names. Keys, colours, styles and command options return native canonical text. Reads never execute that text. `list_options(options)` returns records sorted by name. Reads include inherited values by default. Set `inherit = false` to inspect only the selected table. `present = false` distinguishes absence from an empty string, `false` or an explicit empty array. Local and inherited reads are separate observations; concurrent changes can occur between them. Arrays return ordered `entries`, each with a native zero-based `index` and `value`. Indices may have gaps. An `index` read option selects a slot after reading the complete array, preserving the distinction between an absent slot and an empty string. An absent slot has `present = false` and no entries. ## Change a setting `set_option(name, value, options)` accepts booleans for flags, integers within the release-specific range, exact choice names and NUL-free strings for string, key, colour and style options. Native key, colour and style grammar is still checked by tmux. Command values use the program record described below. Input structure, types, bounds and scopes are checked before I/O. Use `index` to write one array slot. To replace a sparse array, supply `{ entries = { { index = 0, value = "first" }, ... } }`. The library copies and validates the whole input, clears the local array, then writes slots in index order in one stop-on-error command group. Empty entries create an explicit empty local array. A first local indexed write also creates a local array; it does not copy inherited slots. Replacement is not atomic. Native value validation or hooks may fail after an earlier write; the returned error preserves the process result without claiming which slots completed. tmux can run hooks between group commands. `append = true` concatenates a scalar string or an indexed string-array value. Whole-array append is unsupported: native separator splitting cannot preserve arbitrary string elements. Indexed colour or command append is rejected because tmux replaces those values instead of appending. `unset_option(name, options)` removes a local override, restoring inheritance. For global defaults it restores tmux's default. An optional `index` removes one array slot. The API never uses tmux's wider `-U` operation, which can also remove pane overrides. ## Store and run hook programs `set_hook(name, program, options)` stores a tmux command program. Supply exactly one of `commands`, a dense sequence of argv sequences, or `source`, explicit tmux program text. `commands` encodes each argument as literal tmux-parser data in one command group. Commands retain their own native format and shell semantics. `source` is not pre-parsed; tmux aliases and grammar are resolved by tmux. Neither form is evaluated as Lua. Use `index` for a built-in hook slot. Without an index, setting a built-in hook replaces its array with one program. `append = true` adds a program at the first free native slot. Indexed append is rejected because native command-array append replaces that slot. Invalid native source can clear an existing array before tmux reports failure; storing a hook is not transactional. `get_hook` and `list_hooks` return the same presence and inheritance metadata as options. Built-in hooks have sparse `entries` containing `index` and canonical program `source`. Canonical text may expand aliases or reorder flags; it does not reconstruct the original argv. Custom `@` hooks return a single `source`. They can be retrieved by name but are omitted from `list_hooks`, since tmux cannot distinguish them from ordinary user options. `unset_hook` removes the selected hook or slot. Session, Window and Pane handles offer `run_hook(name, options)`. Execution uses that live context's native hook lookup. Only process limits are accepted; storage scopes, indices, append and replacement source do not select a hook for execution. Custom hook execution requires tmux 3.3 or newer. A successful process result means tmux completed its command; malformed custom source may still be ignored by tmux without an error. ## Bounds and failures Settings use at most one MiB of encoded input and aggregate native output. Listings accept at most 4096 rows. Array replacement accepts at most 512 entries and remains subject to the aggregate argv and byte limits. Programs accept at most 1024 commands, 4096 arguments and one MiB after encoding. `process` accepts deadline, timeout, output and cleanup limits. Caller-provided process environment, cwd and stdin are rejected. Output preserves bytes even when the caller uses a C locale. No operation changes the caller's environment. Canceling a client does not undo accepted tmux mutations. Errors distinguish `not_sent`, [`unknown`]() and `completed` effects. A stale handle detected after a completed command retains that completed effect; it does not imply rollback. --- # Ownership and errors Source: https://libtmux.org/en/ruby/latest/topics/errors-and-exceptions/ > Understand server ownership, immutable references, and operation failures. An entity reference contains a binding identity, kind and tmux-assigned ID. Window links also retain session and index context. A snapshot can describe one window at several indexes without creating several window identities. Names are query values, not substitutes for stable command targets. A borrowed binding retains its private socket route. Replacing the public socket does not authorize following a new server. Closing the binding retires owned clients and pipes and preserves the borrowed daemon. A server started with `Server.start` owns its daemon and temporary directory as well. Handles, Async tasks and subscriptions cannot be transferred to another process or scheduler as if their ownership were unchanged. | Failure or empty value | Meaning | | --- | --- | | Empty [`Selection`]() / [`one_or_nil`]() returns `nil` | A valid complete local selection has no matching record | | [`NoMatchError`]() / [`MultipleMatchesError`]() | [`one`]() cannot establish exactly one match | | [`InvalidFilterError`]() / [`FieldDecodeError`]() | Criteria or wire values do not satisfy the declared schema | | [`IncompleteSnapshotError`]() | Required coverage is unavailable; do not infer absence | | [`TargetNotFoundError`]() | The guarded target no longer matches its identity/context | | [`Cancelled`]() / [`DeadlineExceeded`]() | The requested wait ended; delivery evidence determines possible effects | | [`SubscriptionOverflow`]() / gap event | A bounded stream cannot establish uninterrupted delivery | | [`Workspace::ApplyError`]() | Inspect its immutable result ledger before deciding whether to compensate | Operation errors report a phase and delivery evidence: `not_sent`, `possibly_sent`, or `observed`. An observed nonzero exit still needs its command result. Cleanup diagnostics accompany failures; cleanup failure is not a successful close. A cancelled mutating request can already have effects. A timed-out WAIT lock request can still acquire its queued remote lock after a later unlock; retiring the client does not roll back tmux's command queue. Client cancellation sends TERM, then KILL if exit is still unobserved, and uses the remaining cleanup deadline to reap the owned child. There is no scheduled grace period for a TERM handler. This policy applies to owned command clients; cancelling their requests does not terminate borrowed panes or daemons. Create [`LibTmux::Cancellation.new`]() for blocking requests and pass it as `cancel:`. Calling [`cancel`]() from another thread wakes current users of that token and makes `cancelled?` true permanently; later requests with the same token refuse before dispatch. A token can cancel several requests. It owns a pipe, starts no thread, and must remain open until every request using it has returned. Join those callers before calling `close`; closing a token does not join them. Both methods are idempotent and their return values are unspecified. [`reader`]() belongs to the token: do not consume its bytes or close it separately. After a fork, a child may close its inherited descriptors but cannot query or cancel the parent's token. The [plain-Ruby example](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/cancel.rb) proves wakeup, delivery evidence and client reaping without sleeps. Async tasks can instead use `Task#cancel` as shown in the [Async example](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/examples/async_cancel.rb). Workspace compensation is explicit. It removes only a positively created session whose current windows and panes all belong to the creation ledger, checked in the same tmux command turn. A borrowed window or pane moved into that session prevents destructive compensation. Arbitrary shell effects cannot be rolled back, and an unacknowledged creation is never guessed by name. Parsing errors and ordinary inspection redact payloads. Explicit results, captures, plans and canonical exports contain the requested data, including commands or normalized paths; callers control their storage and display. See [execution modes](https://libtmux.org/en/ruby/latest/concepts/transports/) and [workspace details](https://libtmux.org/en/ruby/latest/workspace/source-guide/). --- # Ruby MCP topics Source: https://libtmux.org/en/ruby/latest/mcp/topics/ > Understand tool policy, retained observations, resources, and authored runs. The Ruby MCP server exposes selected operations on one tmux endpoint. Its tool policy controls what clients can request; captured metadata and references determine what those requests describe. ## Tool policy `tmux_capabilities` and `tmux_snapshot` are enabled by default. Capture, wait, create, send, close, and run tools remain absent until the process receives a matching `--enable-tool` option. Direct application calls enforce the same policy as protocol discovery. ## Captures and resources Snapshots and screen captures retain immutable observations. A cursor pages that retained state; it does not silently substitute a newer live listing. Resource templates expose metadata pages and pane screens using encoded endpoint and generation identities. The server advertises neither resource subscriptions nor resource-list change notifications, and it has no prompt catalog. ## Authored runs `tmux_run` needs both `--enable-tool tmux_run` and an exact `--enroll-pane %ID=FILE` entry. The operator must source the generated file in that pane's interactive zsh 5.9. Enrollment does not type into the terminal, and a later pane respawn cannot redirect an authorized request to the replacement process. The tool reports stdout and stderr independently. Nonzero exits and signals are completion results; overflow is an error, not truncated success. [Source-owned policy and enrollment guide](https://libtmux.org/en/ruby/latest/mcp/source-guide/) - [Snapshots and references](https://libtmux.org/en/ruby/latest/mcp/topics/snapshots-and-references/): Filter metadata, continue a retained result, and handle expired cursors and stale references. --- # Rust MCP topics Source: https://libtmux.org/en/rs/latest/mcp/topics/ > Select toolsets, inspect the pinned endpoint, and observe bounded commands. The server selects one tmux endpoint and freezes its offered tools at startup. Read `tmux://capabilities` to inspect that endpoint's provenance and the effective tool selection. ## Select tools [Tool selection](https://libtmux.org/en/rs/latest/mcp/topics/tool-selection/) gives complete client configurations and explains how direct calls and batch children use the effective selection. `LIBTMUX_TOOLSETS` selects any combination of `inspect`, `manage`, `execute`, and `teardown`. `LIBTMUX_TOOLS` adds exact names; `LIBTMUX_EXCLUDE_TOOLS` removes names last. Unknown names and malformed lists fail startup. Use `inspect` for discovery and terminal reads. Add `manage` for topology changes and `execute` for input and process creation. Select `teardown` explicitly when removal is needed on an existing or explicitly selected server. A default dedicated daemon can receive teardown tools when the launcher verifies its own minimal-configuration provenance. Tool selection shapes the callable interface. Execute tools act with the tmux user's authority; selecting a socket does not confine shell effects. ## Observe a command Use [`run_shell_command`](https://libtmux.org/en/rs/latest/mcp/tools/run_shell_command/) for a bounded command and its exit status. A deadline ends the wait; the pane command may still be running. Inspect it before submitting another command. Use [`capture_since`](https://libtmux.org/en/rs/latest/mcp/tools/capture_since/) to collect subsequent output and [`wait_for_text`](https://libtmux.org/en/rs/latest/mcp/tools/wait_for_text/) for an expected terminal condition. Their schemas and result limits are in the [tool reference](https://libtmux.org/en/rs/latest/mcp/tools/). The current catalog has no detached job-handle API. ## Resources and prompts The server exposes the static `tmux://capabilities` resource. Read live hierarchy and terminal state through tools. The current surface has no workflow prompts or dynamic resource templates. [Configuration and lifecycle contract](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/README.md). - [Tool selection](https://libtmux.org/en/rs/latest/mcp/topics/tool-selection/): Select groups and exact names, apply exclusions, and inspect aggregate-call authority. --- # Persistent environment Source: https://libtmux.org/en/lua/latest/topics/environment/ > Persistent environment: libtmux documentation. Server methods address tmux's global environment store. Session methods address that session's local store. Each method returns a Request; reads never evaluate shell text. Window and Pane handles reject these operations with `invalid_scope`. ```lua local adapter = require("libtmux.runtime.luv") local result, err = adapter.run(function(runtime) local server = assert(runtime:connect({ binary = "/usr/bin/tmux", socket_path = "/tmp/example-tmux.sock", config_path = "/dev/null", }):await()) local snapshot = assert(server:snapshot():await()) local session = assert(server:handle(snapshot, snapshot.sessions[1])) assert(server:set_environment("APP_MODE", "global"):await()) assert(session:set_environment("APP_MODE", "local"):await()) local local_value = assert(session:get_environment("APP_MODE"):await()) assert(session:unset_environment("APP_MODE"):await()) local inherited = assert(session:get_environment("APP_MODE", { inherit = true }):await()) return { local_value = local_value, inherited = inherited } end) assert(result, tostring(err)) ``` Names must match `[A-Za-z_][A-Za-z0-9_]*` and fit within 256 bytes. Native tmux accepts some other names; this API returns `unsupported_name` for them. Values are NUL-free byte strings up to one MiB. Empty strings, embedded newlines, quotes, dollar signs and invalid UTF-8 remain bytes without interpolation. ## Reads and storage source `get_environment(name, options)` returns one record. `list_environment(options)` returns records sorted by portable name. Records have these fields: | Field | Meaning | | --- | --- | | `name` | Portable name | | [`state`]() | `value`, `removed`, or `absent`; lists omit absent names | | `value` | Exact bytes for `value`, including an empty string | | `hidden` | Native visibility flag; omitted when absent | | `scope` | Storage source: `global` or `session` | | `inherited` | Whether a session read used global fallback | | `target` | Session reference when the source is a session | Reads default to local storage, with `inherit = false`. A session read with `inherit = true` uses global storage only when the name is absent locally. Local hidden entries and removal markers suppress fallback. If both stores lack a named entry, the returned absent record describes the requested session. Named reads detect hidden entries automatically. Lists include hidden entries by default; `include_hidden = false` omits them. An inherited list still reads local hidden entries to prevent a hidden override from exposing a global value. Treat returned hidden values as sensitive application data. The optional `scope` must match the receiver: `global` for Server, `session` for Session. `inherit = true` requires a session read. [`include_hidden`]() applies only to lists. Unsupported option combinations fail before I/O. ## Mutations and inheritance `set_environment(name, value, { hidden = true })` stores a hidden value. Omitting `hidden` stores an ordinary value and clears an existing hidden flag. `unset_environment(name)` deletes the stored entry, allowing global fallback for a session. `remove_environment(name)` installs a removal marker that blocks fallback and preserves the entry's existing native hidden flag. Each mutation returns `true` after native completion. These stores influence newly spawned processes. They do not change the environment of processes already running. A merged read is not an exact future process environment: tmux also supplies variables and may obtain PATH from the creating client. ## Consistency and bounds Reads use literal `show-environment -s` arguments and a bounded decoder, never a shell evaluator. The decoder recognizes the thirteen catalog releases from 3.2a through 3.7c. It reverses the 3.4–3.5a printer escapes and the additional 3.4 variable-like dollar escape. Unsupported releases fail explicitly. A listing of a nonportable removal name can resemble several portable removal rows. Before returning a list, the library verifies each parsed removal through named reads in the same scope and visibility, in groups of at most 128 commands. Missing, duplicate, extra or changed verification rows produce `inconsistent`. The verification uses aggregate group completion and makes no per-member effect claims. Nonportable assignments fail decoding. This verification does not make multiple reads a transaction: concurrent native changes can still occur between observations. There is no automatic retry. An operation reads at most one MiB of aggregate stdout and stderr and 4096 source entries, including both visibility views and global fallback. Verification output counts toward the byte limit. Runtime capacity accounts for copied input, raw output and decoded records through callback delivery. Capacity and protocol errors return no partial list. `process` accepts `timeout`, `deadline`, `max_output_bytes`, `drain_timeout` and `kill_timeout`; its output limit cannot exceed one MiB. A timeout applies to each native client; an absolute deadline also bounds later clients. Process stdin, environment and working-directory overrides are unavailable here. Closed handles and stale generations reject dispatch or publication. Once a client is sent, cancellation cannot undo accepted daemon work. Native errors retain their receipt; decoding or consistency failures after successful reads have `effect = "completed"`. --- # Traversal Source: https://libtmux.org/en/tmux/topics/traversal/ > Moving up and down the server/session/window/pane tree, and the two questions that come up once you have more than one object. Use relationships to move between sessions, windows, and panes. [Server, session, window, pane](https://libtmux.org/en/tmux/concepts/server-session-window-pane/) explains the hierarchy and snapshot model. This page covers relationship calls, collection membership, and object identity. ## Down the hierarchy List children through the parent object or a captured snapshot. Whether a read issues another tmux command depends on the API, independently of whether the call is async; see [Server, session, window, pane](https://libtmux.org/en/tmux/concepts/server-session-window-pane/). ### Python Read [`Server.sessions`](), then [`Session.windows`]() and [`Window.panes`]() to traverse from the server down to its panes. ### TypeScript Await [`Server.sessions`](), then read [`Session.windows`]() and [`Window.panes`]() from the loaded graph. ### Go Call [`Server.Sessions`]() with a context to read the sessions. [`Session.Windows`]() and [`Window.Panes`]() traverse their captured relationships. ### Rust Use [`Server.sessions`](), [`Session.windows`](), and [`Window.panes`]() to read each level of the hierarchy. ### Java Use [`Server.sessions`](), [`Session.windows`](), and [`Window.panes`]() to read each level of the hierarchy. ### C# Use [`Server.GetSessionsAsync`](), [`Session.GetWindowsAsync`](), and [`Window.GetPanesAsync`]() to read each level of the hierarchy. ### C++ Use [`Server::sessions`](), [`Session::windows`](), and [`Window::panes`]() to read each level of the hierarchy. ### Swift Read sessions through [`Server.sessions()`](). Once you have a [`Snapshot`](), use its relationship queries, including [`Snapshot.windows(of:)`](), to find the windows and panes for those captured objects. [`session.windows`]() and [`window.panes`]() read the graph loaded by [`await server.sessions()`]() without additional tmux commands. [`server.attached_sessions()`]() lists only sessions with an attached client. ## All panes in a session Use a session-wide pane collection when the task spans several windows, such as finding a command or capturing output from every pane. A window linked to multiple sessions still refers to the same tmux panes. Check whether the API reads live state or traverses a captured graph before reusing its result. ### Python [`libtmux.Session.panes`]() runs a session-scoped `list-panes -s` read. Use it to list panes across the session's windows without manually listing each window. ### TypeScript [`session.Session.panes`]() returns a [`Selection`]() from the session's captured graph. Reading it does not issue another tmux command; refresh the snapshot when you need newer state. ### Rust [`session.Session.panes`]() performs a live listing and returns a [`Result`]() from the async call. Handle a command failure before using the returned panes. ### Go [`tmux.Session.Panes`]() reads captured relations without another tmux command. The relation must have been included in the read that produced the session; an uncaptured relation does not establish that the session has no panes. ### C# [`LibTmux.Session.Panes`]() reads the session's captured relations. It does not issue a tmux command; an incomplete capture may lack the required relation. ### C++ [`libtmux::Session::panes`]() runs a session-scoped `list-panes` command. Inspect the returned result before traversing the panes. ### Swift [`Snapshot.panes(of:)`]() accepts a session or a window. The session overload traverses the captured graph and deduplicates pane IDs without a tmux read. ### Java Java has no direct session-wide pane member. Traverse [`Session.windows()`]() and then [`Window.panes()`]() in the captured relations. Deduplicate pane IDs when combining results from sessions that may share linked windows. ## Up the hierarchy Parent lookups may read captured data or query tmux again. Check the method's read and failure semantics; [Server, session, window, pane](https://libtmux.org/en/tmux/concepts/server-session-window-pane/) introduces that distinction: ### Python Read [`Pane.window`]() for a pane’s window and [`Window.session`]() for a window’s session. ### TypeScript [`Pane.window`]() and [`Window.session`]() are getters that follow the relationships in the loaded graph. ### Go [`Pane.Window`]() returns `(Window, bool)` and [`Window.Session`]() returns `(Session, bool)`. Check the boolean before using the parent. ### Rust [`Pane.window`]() and [`Window.session`]() asynchronously return `Result, Error>` and `Result, Error>`. Handle both a command failure and an absent parent. ### Java Call [`Pane.window`]() and [`Window.session`]() to find an object’s parent. ### C# Read the [`Pane.Window`]() and [`Window.Session`]() properties. ### C++ Call [`Pane::window`]() and [`Window::session`]() to find an object’s parent. ### Swift Use [`Pane.windowID`]() to look up the window in a [`Snapshot`](). Find a window’s sessions through the snapshot’s relationships; a window does not store a single session field. Check the boolean from a relationship lookup. It reports whether the relation was captured, not whether the object still exists in tmux. Use a live read when current existence matters. Handle both a command failure and an absent parent in the optional result. [`.Window`](), [`.Session`](), [`.ActiveWindow`](), and `.ActivePane` read captured state synchronously. They throw [`IncompleteSnapshotException`]() when the capture lacks the required context. ## One walk, down and back up List a session's windows, then look up a parent and compare its identity with the starting object: ```python session = server.sessions[0] window = session.windows[0] pane = window.panes[0] pane.window.window_id == window.window_id window.session.session_id == session.session_id ``` ```typescript const session = (await server.sessions())[0]; const window = session.windows[0]; const pane = window.panes[0]; pane.window.id === window.id; window.session.id === session.id; ``` ```go sessions, err := server.Sessions(ctx) if err != nil { return err } for _, session := range sessions { windows, captured := session.Windows() if !captured { return fmt.Errorf("session %s has no captured window relations", session.ID()) } for _, window := range windows { back, captured := window.Session() if !captured { return fmt.Errorf("window %s has no captured session", window.ID()) } fmt.Println(window.ID(), "belongs to session:", back.ID() == session.ID()) } } ``` ```rust let sessions = server.sessions().await?; let session = &sessions[0]; let windows = session.windows().await?; let window = &windows[0]; let back = window.session().await?; // Result, Error> back.is_some_and(|s| s.id() == session.id()) ``` ```java Session session = server.sessions().get(0); Window window = session.windows().get(0); Session back = window.session(); back.equals(session); ``` ```csharp Session session = (await server.GetSessionsAsync())[0]; Window window = (await session.GetWindowsAsync())[0]; Session back = window.Session; // property, read from the captured snapshot back.Equals(session); ``` ```cpp auto sessions = server.sessions(); // expected, CommandFailure> const auto& session = sessions->at(0); auto windows = session.windows(); // expected, CommandFailure> const auto& window = windows->at(0); auto back = window.session(); // expected *back == session; // operator== is defined directly on Session/Window/Pane ``` ```swift let sessions = try await server.sessions() let session = sessions[0] let snapshot = try await server.snapshot() let window = snapshot.windows(of: session)[0] let pane = snapshot.panes(of: window)[0] // An array, not one Session: link-window can put a window in more than one. snapshot.sessions(of: window).contains(session) ``` ## The active child The active window and pane identify where untargeted input goes. Use their accessors or inspect the active flags in a captured snapshot: ### Python Read [`Session.active_window`]() and [`Window.active_pane`]() for the selected objects. ### TypeScript Read the [`Session.activeWindow`]() and [`Window.activePane`]() getters. ### Go [`Session.ActiveWindow`]() returns `(Window, bool)` and [`Window.ActivePane`]() returns `(Pane, bool)`. Check the boolean before use. ### Rust [`Session.active_window`]() and [`Window.active_pane`]() asynchronously return `Result, Error>` and `Result, Error>`. Handle errors and the absence of an active object. ### Java [`Session.activeWindow`]() returns `Optional`, and [`Window.activePane`]() returns `Optional`. ### C# Read the [`Session.ActiveWindow`]() and [`Window.ActivePane`]() properties. ### C++ Call [`Session::active_window`]() and [`Window::active_pane`](). ### Swift Filter the snapshot’s windows or panes by their `isActive` flag. For example, inspect the windows returned by [`Snapshot.windows(of:)`]() for the selected session. Filter snapshot children by `isActive`. [Format-token fields](https://libtmux.org/en/tmux/topics/format-tokens/) describes the underlying `window_active` and `pane_active` fields. ## Is it in that collection? Checking membership generally goes through whatever your language uses for collection membership, since most of these calls already return an ordinary array, slice, or list: [`QueryList`]() supports [`in`](): use `window in session.windows` or `pane in window.panes`. Use standard collection membership operations with the object identity comparison described below. `Selection` is iterable. Iterate and compare IDs, or spread it into an array for standard array operations. Iterate over the slice and compare each object's stable ID, such as [`Pane.ID()`](). Confirm the objects belong to the same server before comparing IDs. Iterate over the vector and compare each object's `id()`. Confirm the objects belong to the same server before comparing IDs. Use the collection's `contains(where:)` to compare IDs. Confirm the objects belong to the same server before comparing IDs. ## Is this the same object? Compare IDs to determine whether two handles refer to the same tmux object on the same server. Check what handle equality includes before using it as an identity test: ### Python Compare [`Window.window_id`]() or [`Pane.pane_id`]() when checking whether two handles name the same object on the same server. ### TypeScript Compare the handles’ `id` properties when checking identity on the same server. ### Go Compare [`Pane.ID`]() values. [`PaneID`]() is a string type and supports `==`; include the server context when comparing objects from different servers. ### Rust Compare [`Pane.id`]() values when checking identity on the same server. ### Java [`Pane.equals`]() compares the server identity and pane ID. ### C# [`Pane.Equals`]() compares a generation counter and the pane ID. ### C++ [`Session`](), [`Window`](), and [`Pane`]() define `operator==` for equality checks. ### Swift Compare the `id` values when checking identity on the same server. The equality behavior described below also includes captured state. **Swift's equality compares captured state.** Compiler-synthesized equality for [`Session`](), [`Window`](), and [`Pane`]() compares every stored property, including dimensions and current command. Two reads can compare unequal even when they describe the same tmux object. Compare `.id` when checking identity on the same server. --- # Ownership and cleanup Source: https://libtmux.org/en/tmux/topics/context-managers/ > Scope-based cleanup for tmux objects, and when your program must kill them explicitly. 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](https://libtmux.org/en/tmux/concepts/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: | Port | Server | Session | Window | Pane | |------|:------:|:-------:|:------:|:----:| | Python | yes | yes | yes | yes | | C# | yes | yes | yes | - | | Java | closes conn. | - | - | - | | Rust | test-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: ```python 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: ```csharp 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. ```java 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. ```rust 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: ```cpp 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: ```typescript 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: ```go 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](https://libtmux.org/en/tmux/guides/testing-with-libtmux/). --- # tmux field catalog Source: https://libtmux.org/en/lua/latest/topics/format-token-fields/ > tmux field catalog: libtmux documentation. This curated catalog describes the scalar fields needed by the core entity model. It does not enumerate every tmux format. Edit [the source catalog](https://github.com/libtmux/libtmux-lua/blob/0395620d362ef75c74cd488f9577afda68922586/data/tmux-fields.json) and regenerate this reference together with Lua metadata and LuaLS field annotations: ```console $ python scripts/generate_fields.py ``` Check generated files without changing them: ```console $ python scripts/generate_fields.py --check ``` Generation uses Python and the pinned StyLua formatter; it needs no network or tmux process. The optional `--verify-source` argument accepts a local tmux Git checkout and verifies every pinned format mapping and source anchor. ## Availability and values `Since` means the first release supported by this catalog for that field, not necessarily the release that introduced it. The floor is tmux 3.2a. Source inspection establishes format availability; it does not establish complete runtime or platform compatibility. Later release strings retain known fields; development and prerelease strings require explicit capability evidence and are rejected by the schema helper. Record names are Lua aliases for literal tmux format names. IDs retain their `$`, `@`, and `%` prefixes. [`number`]() fields represent integers; consumers must reject values outside the exact integer range of their Lua runtime rather than silently round them. All generated LuaLS fields are optional because a projection may leave a field unloaded. Nullable fields may be absent within an otherwise valid native context. Loaded absence uses [`query.NULL`](); an omitted key means not loaded. Known fields unavailable at the requested version remain in the query schema with `supported = false`. Empty text remains text for nonnullable string fields. The scalar catalog does not build relationships or perform I/O. Window index, active state, and flags belong to [`window_link`](). Windows and panes have no scalar session ID because a window can be linked into several sessions. `client_session` provides a session name, not a session ID. Client names and buffer names need contextual revalidation before later mutations. ## Source provenance - floor: [3.2a](https://github.com/tmux/tmux/blob/3b929f332aafa7f1080eacc31feb11ffbb1d1841/format.c). - added: [3.3](https://github.com/tmux/tmux/blob/87fe00e8b44901240fc22d7120c1b31e4331f6f5/format.c). - stable: [3.7c](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c). - upstream: [inspected upstream revision](https://github.com/tmux/tmux/blob/e880cf63e0a9fe095d7c5d313761520fb1a8653c/format.c). ## Server | Record field | tmux format | Type | Nullable | Since | Native scope | | --- | --- | --- | --- | --- | --- | | `pid` | [`pid`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L541) | number | no | 3.2a | server | | `socket_path` | [`socket_path`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2690) | string | no | 3.2a | server | | `version` | [`version`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2697) | string | no | 3.2a | server | | [`start_time`]() | [`start_time`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L3107) | number | no | 3.2a | server | - `pid`: Daemon process ID. - `socket_path`: Socket path reported by the daemon. - `version`: Daemon version string. - [`start_time`](): Daemon start time in Unix seconds. ## Session | Record field | tmux format | Type | Nullable | Since | Native scope | | --- | --- | --- | --- | --- | --- | | `id` | [`session_id`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2630) | string | no | 3.2a | session | | `name` | [`session_name`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2663) | string | no | 3.2a | session | | `created` | [`session_created`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L3089) | number | no | 3.2a | session | | `activity` | [`session_activity`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L3080) | number | no | 3.2a | session | | `attached` | [`session_attached`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2553) | number | no | 3.2a | session | | `window_count` | [`session_windows`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2681) | number | no | 3.2a | session | | `group` | [`session_group`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2571) | string | yes | 3.2a | session | | `grouped` | [`session_grouped`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2618) | boolean | no | 3.2a | session | | `path` | [`session_path`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2672) | string | no | 3.2a | session | - `id`: Session ID, including its dollar-sign prefix. - `name`: Session name. - `created`: Creation time in Unix seconds. - `activity`: Last activity time in Unix seconds. - `attached`: Attached client count, not a boolean. - `window_count`: Number of window links in this session. - `group`: Session group name; absent for an ungrouped session. - `grouped`: Whether this session belongs to a group. - `path`: Session working directory. ## Window | Record field | tmux format | Type | Nullable | Since | Native scope | | --- | --- | --- | --- | --- | --- | | `id` | [`window_id`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2844) | string | no | 3.2a | window | | `name` | [`window_name`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2936) | string | no | 3.2a | window | | `width` | [`window_width`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L3015) | number | no | 3.2a | window | | `height` | [`window_height`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2835) | number | no | 3.2a | window | | `pane_count` | [`window_panes`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2973) | number | no | 3.2a | window | | `layout` | [`window_layout`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L839) | string | yes | 3.2a | window | | `visible_layout` | [`window_visible_layout`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L853) | string | yes | 3.2a | window | | `zoomed` | [`window_zoomed_flag`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L3024) | boolean | no | 3.2a | window | - `id`: Window ID, including its at-sign prefix. - `name`: Window name. - `width`: Width in character cells. - `height`: Height in character cells. - `pane_count`: Number of panes owned by this window. - `layout`: Layout including panes hidden by zoom; absent without a layout tree. - `visible_layout`: Visible layout; absent without a layout tree. - `zoomed`: Whether this window is zoomed. ## Window link | Record field | tmux format | Type | Nullable | Since | Native scope | | --- | --- | --- | --- | --- | --- | | `session_id` | [`session_id`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2630) | string | no | 3.2a | session | | `window_id` | [`window_id`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2844) | string | no | 3.2a | window | | `index` | [`window_index`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2853) | number | no | 3.2a | winlink | | `active` | [`window_active`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2737) | boolean | no | 3.2a | winlink | | `flags` | [`window_flags`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2817) | string | no | 3.2a | winlink | - `session_id`: Session owning this contextual link. - `window_id`: Underlying window shared by links. - `index`: tmux index within the session, not Lua array position. - `active`: Whether this link is the session current window. - `flags`: Printable flags for this session/window link. ## Pane | Record field | tmux format | Type | Nullable | Since | Native scope | | --- | --- | --- | --- | --- | --- | | `id` | [`pane_id`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2152) | string | no | 3.2a | pane | | `window_id` | [`window_id`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2844) | string | no | 3.2a | window | | `index` | [`pane_index`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2161) | number | no | 3.2a | pane | | `active` | [`pane_active`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2028) | boolean | no | 3.2a | pane | | `title` | [`pane_title`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2384) | string | no | 3.2a | pane | | `width` | [`pane_width`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2411) | number | no | 3.2a | pane | | `height` | [`pane_height`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2143) | number | no | 3.2a | pane | | `left` | [`pane_left`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2225) | number | no | 3.2a | pane | | `top` | [`pane_top`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2393) | number | no | 3.2a | pane | | `pid` | [`pane_pid`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2285) | number | no | 3.2a | pane | | `tty` | [`pane_tty`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2402) | string | no | 3.2a | pane | | `current_path` | [`pane_current_path`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L915) | string | yes | 3.2a | pane | | `current_command` | [`pane_current_command`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L891) | string | yes | 3.2a | pane | | `start_command` | [`pane_start_command`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L865) | string | no | 3.2a | pane | | `dead` | [`pane_dead`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2075) | boolean | no | 3.2a | pane | | `dead_status` | [`pane_dead_status`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2106) | number | yes | 3.2a | pane | | `dead_signal` | [`pane_dead_signal`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2089) | string | yes | 3.3 | pane | | `dead_time` | [`pane_dead_time`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2120) | number | yes | 3.3 | pane | | `mode` | [`pane_mode`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2258) | string | yes | 3.2a | pane | | `mode_count` | [`pane_in_mode`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1138) | number | no | 3.2a | pane | | `synchronized` | [`pane_synchronized`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L2372) | boolean | no | 3.2a | pane | - `id`: Pane ID, including its percent-sign prefix. - `window_id`: ID of the window that owns this pane. - `index`: tmux pane index within its window. - `active`: Whether this pane is active in its window. - `title`: Pane title; an empty title remains an empty string. - `width`: Width in character cells. - `height`: Height in character cells. - `left`: Left cell offset in the window. - `top`: Top cell offset in the window. - `pid`: PID recorded for the pane process. - `tty`: Pseudo-terminal name; empty is preserved. - `current_path`: Process working directory when the OS can determine it. - `current_command`: Displayed command name; absent without pane shell context. - `start_command`: Stringified startup argv; this is not a shell-safe command. - `dead`: Whether tmux has a ready dead-process status. - `dead_status`: Exit status only when the process exited normally. - `dead_signal`: Signal name only when the process terminated by signal. - `dead_time`: Dead-pane display time in Unix seconds, when available. - `mode`: Top mode name; absent outside pane modes. - `mode_count`: Number of active modes, not a boolean. - `synchronized`: Effective synchronize-panes option. ## Client | Record field | tmux format | Type | Nullable | Since | Native scope | | --- | --- | --- | --- | --- | --- | | `name` | [`client_name`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1539) | string | no | 3.2a | client | | `tty` | [`client_tty`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1623) | string | no | 3.2a | client | | `pid` | [`client_pid`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1548) | number | no | 3.2a | client | | `session_name` | [`client_session`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1584) | string | yes | 3.2a | client | | `width` | [`client_width`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1677) | number | yes | 3.2a | client | | `height` | [`client_height`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1510) | number | yes | 3.2a | client | | `control_mode` | [`client_control_mode`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1480) | boolean | no | 3.2a | client | | `readonly` | [`client_readonly`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1572) | boolean | no | 3.2a | client | | `created` | [`client_created`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L3071) | number | no | 3.2a | client | | `activity` | [`client_activity`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L3062) | number | no | 3.2a | client | - `name`: Observed client name; not a persistent identifier. - `tty`: Observed terminal name; empty is preserved. - `pid`: Client process ID. - `session_name`: Attached session name, not a session ID. - `width`: Terminal width; nullable without a started TTY. - `height`: Terminal height; nullable without a started TTY. - `control_mode`: Whether this is a control-mode client. - `readonly`: Whether this client is read-only. - `created`: Creation time in Unix seconds. - `activity`: Last activity time in Unix seconds. ## Buffer | Record field | tmux format | Type | Nullable | Since | Native scope | | --- | --- | --- | --- | --- | --- | | `name` | [`buffer_name`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1416) | string | no | 3.2a | buffer | | `size` | [`buffer_size`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1449) | number | no | 3.2a | buffer | | `sample` | [`buffer_sample`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L1425) | string | no | 3.2a | buffer | | `created` | [`buffer_created`](https://github.com/tmux/tmux/blob/e476c1230b958df0cb12977517d24b3dc931375b/format.c#L3048) | number | no | 3.2a | buffer | - `name`: Buffer name; revalidate before later mutations. - `size`: Buffer size in bytes. - `sample`: tmux printable preview; not complete buffer bytes. - `created`: Creation time in Unix seconds. --- # Pane interaction Source: https://libtmux.org/en/tmux/topics/pane-interaction/ > Input defaults, screen capture, and waiting for a command to finish. Send input to a pane and capture its screen to interact with a running program. [Attach and send keys](https://libtmux.org/en/tmux/examples/attach-and-send-keys/) provides examples. [Sending keys](https://libtmux.org/en/tmux/guides/sending-keys/) and [Capturing output](https://libtmux.org/en/tmux/guides/capturing-output/) are task guides; this page covers input defaults, capture ranges, and completion handling. ## Typing into a pane Two questions come up every time you send something to a pane: should tmux press Enter afterward, and should tmux interpret what you sent as key names (`Enter`, `C-c`) rather than literal characters? Choose both explicitly when a command depends on them. ### Python **Type without Enter:** [`pane.send_keys(text, enter=False)`]() **Type + Enter (default):** [`pane.send_keys(text)`]() **How "literal" is chosen:** `literal=True` flag on the same method ### TypeScript **Type without Enter:** `pane.sendKeys(text, { enter: false })` **Type + Enter (default):** [`pane.sendKeys(text)`]() **How "literal" is chosen:** `{ literal: true }` option ### Go **Type without Enter:** `pane.SendKeys(ctx, SendKeysRequest{Command: &text, SkipEnter: true})` **Type + Enter (default):** `pane.SendKeys(ctx, SendKeysRequest{Command: &text})` **How "literal" is chosen:** `Literal: true` field ### Rust **Type without Enter:** [`pane.send_keys(keys)`](): **always literal**, key names typed as text **Type + Enter (default):** [`pane.send_line(text)`]() **How "literal" is chosen:** [`send_keys`]() sends literal text; [`send_key_names`]() interprets tmux key names. ### Java **Type without Enter:** [`pane.send(keys)`]() **Type + Enter (default):** [`pane.sendLine(command)`]() **How "literal" is chosen:** Separate text and key-sending methods. ### C# **Type without Enter:** [`SendKeysAsync(new SendKeysRequest(text, enter: false))`]() **Type + Enter (default):** [`SendTextAsync(text)`]() (defaults `enter: true`) **How "literal" is chosen:** [`SendKeysRequest.Literal`]() field; [`SendTextAsync`]() hardcodes it ### C++ **Type without Enter:** [`pane->send_text(text)`]() **Type + Enter:** [`pane->send_text(text)`]() then [`pane->send_key("Enter")`]() separately: no combined convenience exists **How "literal" is chosen:** `send_text` is always literal; `send_key` is always a key name ### Swift **Type without Enter:** [`server.sendKeys([text], to: pane)`]() **Type + Enter (default):** `server.run(text, in: pane)` (sugar for [`sendKeys([text, "Enter"], to: pane)`]()) **How "literal" is chosen:** `literally: true` option on [`sendKeys`]() ### Examples [`send_keys`]() sends literal text. Use [`send_key_names`]() for tmux key names. Passing `"Enter"` to [`send_keys`]() types those characters. [`send_line`]() appends a carriage return and delivers it with the text in one tmux command. `sendLine` appends a carriage return and delivers it with the text in one tmux command. Text and Enter can be separate tmux commands. If the second operation fails, the text may already be in the pane. Check the current state before retrying; repeating the whole request can duplicate input. Send a command line and press Enter: ```python pane.send_keys("echo hi", enter=False) # type without pressing Enter pane.send_keys("echo hi") # default: presses Enter afterward ``` ```typescript await pane.sendKeys("echo hi", { enter: false }); await pane.sendKeys("echo hi"); ``` ```go text := "printf 'hello\\n'" if err := pane.SendKeys(ctx, tmux.SendKeysRequest{ Command: &text, Literal: true, }); err != nil { return fmt.Errorf("send command: %w", err) } ``` ```rust pane.send_keys("echo hi").await?; // Always literal text. pane.send_line("echo hi").await?; // text and Enter in one send-keys -l call ``` ```java pane.send("echo hi"); // no Enter pane.sendLine("echo hi"); // text and \r in one send-keys -l call ``` ```csharp await pane.SendKeysAsync(new SendKeysRequest("echo hi", enter: false)); await pane.SendTextAsync("echo hi"); // defaults enter: true ``` ```cpp pane->send_text("echo hi"); pane->send_key("Enter"); // separate command: no combined convenience exists ``` ```swift try await server.sendKeys(["echo hi"], to: pane) // no Enter try await server.run("echo hi", in: pane) // sugar for sendKeys([text, "Enter"]) ``` ## Reading a pane back Capture reads the pane's visible screen by default. Request scrollback when you need earlier output. A capture is a snapshot of terminal contents, including any input echoed by the application. [`pane.Capture`]() returns `([]string, error)`. Pass a [`context.Context`]() with a deadline and check the error before using the result. Set the start boundary to [`tmux.CaptureBoundary`]() to include scrollback. `End: tmux.CaptureBoundary` includes the bottom of the visible pane. ```python pane.capture_pane() ``` ```typescript await pane.capture(); ``` ```go lines, err := pane.Capture(ctx, tmux.CapturePaneRequest{}) if err != nil { return fmt.Errorf("capture pane: %w", err) } for _, line := range lines { fmt.Println(line) } ``` ```rust pane.capture().await?; ``` ```java pane.capture(); ``` ```csharp await pane.CaptureAsync(); ``` ```cpp pane->capture(); ``` ```swift try await server.capture(pane) ``` ## Waiting for something to finish A send call completes when input reaches tmux. It does not wait for the shell command to finish. Wait for expected output or a completion signal. Poll capture output for a marker or use the [`wait_for`]() signal channel when you control the command. The test-support module provides `libtmux.test.retry_until(condition, ...)` for arbitrary conditions. [`server.waitForOutput(...)`]() waits for a pattern in pane output and returns an [`OutputWait`](). Give the wait a timeout. Use [`server.WaitFor`]() with a [`WaitForRequest`]() when the command can signal tmux's `wait-for` channel. For streaming output, open [`pane.OpenObservation(ctx)`]() before sending input so the observation includes the command's first bytes. Both paths take a context; cancellation bounds how long the caller waits. For a new command whose exit status matters, use [`session.Run`]() and inspect its result. Capturing screen text alone cannot establish the command's exit status. Use [`TmuxWaitChannel`]() when the command can signal a named tmux `wait-for` channel. Use a cancellation token to bound the wait. [Capture pane output](https://libtmux.org/en/tmux/examples/capture-pane-output/) shows capture and waiting examples. [Waiting and retrying](https://libtmux.org/en/tmux/topics/waiting-and-retry/) explains completion conditions and timeouts.
tmux manual and source The tmux manual defines [key-name and literal input](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1#L4457) and [screen and history capture](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1#L2798). A send operation delivers input; it does not establish the program's exit status.
--- # Options and hooks Source: https://libtmux.org/en/tmux/topics/options-and-hooks/ > Read and update tmux options, and register commands for tmux events. Use options to change tmux behavior, such as `automatic-rename` or the status-line format. Use hooks to run commands on events such as `session-renamed` or `after-split-window`. Choose the scope supported by the option or hook. ## Reading and writing options Read, set, or unset an option at its supported scope. Distinguish a local override from the effective value inherited from a parent scope. ### Python **Read all (this scope):** [`pane.show_options()`]() **Read effective/inherited:** [`pane.show_option(name, global_=True)`]() reaches the global fallback explicitly; no separate "resolved" call **Set:** [`pane.set_option(name, value)`]() **Unset:** [`pane.unset_option(name)`]() ### TypeScript **Read all (this scope):** [`pane.showOptions()`]() **Read effective/inherited:** [`pane.showResolvedOptions()`]() **Set:** [`pane.setOption(name, value)`]() **Unset:** [`pane.unsetOption(name)`]() ### Go [`pane.Options(ctx)`]() returns a fresh typed snapshot, including inherited values. Its accessors return an [`OptionValue`](); use [`OptionValue.Get`]() to distinguish a present value from an absent one. Check the read error before inspecting the snapshot. Use the handle that owns the option's scope. For example, `automatic-rename` belongs to a window: use [`Window.SetOption`]() or [`Window.UnsetOption`](), then read [`Window.Options`]() again for an updated snapshot. For a single raw value, [`Pane.RawOption`]() returns the string, its presence, and an error. Do not treat an error as an absent option. ### Rust **Read all (this scope):** [`pane.options()`]() (typed [`BTreeMap`]()), [`pane.option_names()`]() **Read effective/inherited:** [`pane.typed_option(name)`]() decodes one value by its declared kind **Set:** [`pane.set_option(name, value)`](), [`pane.append_option(name, value)`]() **Unset:** [`pane.unset_option(name)`]() ### Java **Read all (this scope):** [`pane.options().all()`]() **Read effective/inherited:** [`pane.options().get(name)`]() reads `show-options -A -v`: inherited, not just local **Set:** [`pane.options().set(name, value)`]() **Unset:** [`pane.options().unset(name)`]() ### C# **Read all (this scope):** [`pane.Options.GetAllAsync()`]() **Read effective/inherited:** [`pane.Options.GetAsync(new GetOptionRequest(name, includeInherited: true))`](): an explicit opt-in flag, mapped straight to tmux's own `-A` **Set:** [`pane.Options.SetAsync(new SetOptionRequest(name, value))`]() **Unset:** [`pane.Options.UnsetAsync(...)`]() ### C++ **Read all (this scope):** [`pane->options()`]() **Read effective/inherited:** Not listed. **Set:** [`pane->set_option(name, value)`]() **Unset:** [`pane->unset_option(name)`]() ### Swift **Read all (this scope):** [`server.options(.pane(pane))`]() **Read effective/inherited:** [`server.option(name, scope: .pane(pane))`]() reads presence from the listing, then the value with `-v` **Set:** [`server.setOption(name, to: value, scope: .pane(pane))`]() **Unset:** [`server.unsetOption(name, scope: .pane(pane))`]() ### Examples After a successful write completes, read the option to obtain its updated value. The following examples set, read, and unset an option: ```python pane.set_option("automatic-rename", "off") pane.show_options() pane.unset_option("automatic-rename") ``` ```typescript await pane.setOption("automatic-rename", "off"); await pane.showOptions(); await pane.unsetOption("automatic-rename"); ``` ```go if err := window.SetOption(ctx, "automatic-rename", "off", tmux.SetOptionOptions{}); err != nil { return fmt.Errorf("set automatic rename: %w", err) } options, err := window.Options(ctx) if err != nil { return fmt.Errorf("read window options: %w", err) } value, present := options.AutomaticRename().Get() fmt.Println("automatic rename:", value, "present:", present) if err := window.UnsetOption(ctx, "automatic-rename", tmux.UnsetOptionOptions{}); err != nil { return fmt.Errorf("unset automatic rename: %w", err) } ``` ```rust pane.set_option("automatic-rename", "off").await?; pane.options().await?; pane.unset_option("automatic-rename").await?; ``` ```java pane.options().set("automatic-rename", "off"); pane.options().all(); pane.options().unset("automatic-rename"); ``` ```csharp await pane.Options.SetAsync(new SetOptionRequest("automatic-rename", "off")); await pane.Options.GetAllAsync(); await pane.Options.UnsetAsync("automatic-rename"); ``` ```cpp pane->set_option("automatic-rename", "off"); pane->options(); pane->unset_option("automatic-rename"); ``` ```swift try await server.setOption("automatic-rename", to: "off", scope: .pane(pane)) try await server.options(.pane(pane)) try await server.unsetOption("automatic-rename", scope: .pane(pane)) ``` ## Hooks ### Python **Set:** [`pane.set_hook(name, command)`]() **Unset:** [`pane.unset_hook(name)`]() **List:** [`pane.show_hook(name)`](), [`pane.show_hooks()`]() (all) **Run now, without the event:** Not listed. ### TypeScript **Set:** [`pane.setHook(name, command, { append })`]() **Unset:** [`pane.unsetHook(name)`]() **List:** [`pane.showHooks()`]() (all; no singular `showHook`) **Run now, without the event:** Not listed. ### Go Use [`session.SetHook`]() to register a command and [`session.Hooks`]() to read the session's typed hook values. [`session.UnsetHook`]() removes a registration. [`Session.SetHooks`]() writes indexed entries when an event needs more than one command. Use [`server.GlobalSessionScope()`]() for hooks shared by sessions. Keep hook registration at a scope supported by the tmux event. ### Rust **Set:** [`pane.set_hook(name, command)`]() **Unset:** [`pane.unset_hook(name)`]() **List:** [`pane.hook(name)`](): one name only; **no listing at pane/window scope**, by design (see below) **Run now, without the event:** Not listed. ### Java **Set:** [`pane.hooks().set(event, command)`](), `.append(event, command)` **Unset:** [`pane.hooks().unset(event)`]() **List:** [`pane.hooks().all()`]() **Run now, without the event:** [`pane.hooks().run(event)`](): tmux's `set-hook -R` ### C# **Set:** [`pane.Hooks.SetAsync(new SetHookRequest(event, command))`]() **Unset:** [`pane.Hooks.UnsetAsync(...)`]() **List:** [`pane.Hooks.GetAllAsync()`]() **Run now, without the event:** [`pane.Hooks.RunAsync(...)`]() ### C++ **Set:** [`session.set_hook(name, command)`](): no [`Window`]()/[`Pane`]() overload exists at all **Unset:** Not listed. **List:** [`session.hooks()`](), [`server.global_hooks()`]() **Run now, without the event:** Not listed. ### Swift **Set:** [`server.setHook(name, to: command, at: index, in: scope)`]() **Unset:** [`server.unsetHook(name, in: scope)`]() **List:** [`server.hooks(scope)`]() **Run now, without the event:** [`server.runHook(name, in: scope)`]() ### Examples tmux stores hook commands in indexed arrays, such as `after-new-window[0]`. Include the array index in the hook name. Include the array index in the hook name or pass `{ append: true }` to append. [`Session.SetHooks`]() accepts indexed hook entries. Pass a context and check errors from both mutations and reads; a successful write does not refresh earlier snapshots. The `at:` parameter selects the array index. Use `.append()` to add a command without choosing the next array index. Set and list a session hook. The next section explains window and pane scope limitations: ```python session.set_hook("session-renamed", "display-message 'renamed'") session.show_hooks() ``` ```typescript await session.setHook("session-renamed", "display-message 'renamed'"); await session.showHooks(); ``` ```go if err := session.SetHook(ctx, "session-renamed", "display-message 'renamed'"); err != nil { return fmt.Errorf("set session hook: %w", err) } value, present, err := session.RawHook(ctx, "session-renamed") if err != nil { return fmt.Errorf("read session hooks: %w", err) } fmt.Println("session-renamed:", value, "present:", present) ``` ```rust session.set_hook("session-renamed", "display-message 'renamed'").await?; session.hooks().await?; ``` ```java session.hooks().set("session-renamed", "display-message 'renamed'"); session.hooks().all(); ``` ```csharp await session.Hooks.SetAsync(new SetHookRequest("session-renamed", "display-message 'renamed'")); await session.Hooks.GetAllAsync(); ``` ```cpp session.set_hook("session-renamed", "display-message 'renamed'"); session.hooks(); // No session unset helper is listed above. ``` ```swift try await server.setHook("session-renamed", to: "display-message 'renamed'", in: .session(session.id.rawValue)) try await server.hooks(.session(session.id.rawValue)) ``` ## Supported hook scopes tmux stores hooks globally or per session. Accepted `set-hook -w` or `-p` flags do not imply a separate window or pane hook table, and `show-hooks` does not provide a corresponding listing. Check the event's supported scope if a hook is accepted but never fires. Check `hooks().all()` when diagnosing a hook that does not fire. tmux can accept a hook at an unsupported scope without an effective registration. [`Pane::set_hook`]() and [`Window::set_hook`]() return [`Error::OptionScopeMismatch`]() for an unsupported scope. [`HookScope`]() restricts registration to `.global` and `.session`. Use [`Session::set_hook`]() or [`Server::global_hooks()`](). Window and pane handles do not provide hook methods. Options have window and pane tables of their own. The hook-scope limitation does not apply to ordinary options. ## tmux version compatibility The compatibility notes list these tmux requirements: | Feature | Minimum tmux | |---------|-------------| | All options/hooks features | 3.2+ | | Window/pane hook *scope flags* (`-w`, `-p`) accepted | 3.2+; see the supported-scope caveat above | | `client-active`, `window-resized` hooks | 3.3+ | | `pane-title-changed` hook | 3.5+ | Check the library's supported tmux versions before using a version-specific option or hook. Use the command references for [show-options](https://libtmux.org/en/tmux/latest/manual/show-options/), [set-option](https://libtmux.org/en/tmux/latest/manual/set-option/), [show-hooks](https://libtmux.org/en/tmux/latest/manual/show-hooks/), and [set-hook](https://libtmux.org/en/tmux/latest/manual/set-hook/) to check the flags and scope rules for your tmux version.
tmux manual and source The tmux manual defines [option scopes and inherited reads](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1#L4725). Unsetting a local value restores inheritance. Hook programs run in tmux when their event occurs; see the [hook implementation](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/cmd-set-option.c).
--- # Format-token fields Source: https://libtmux.org/en/tmux/topics/format-tokens/ > The typed fields every object exposes, mirroring tmux's own format tokens, and why a field is sometimes absent. Object fields expose values from tmux's [FORMATS](https://man.openbsd.org/tmux.1#FORMATS), such as `pane_id`, `window_zoomed_flag`, and [`session_name`](). The available fields depend on the accessor, object scope, tmux version, and data requested by the read. A token needs the right **scope** and **tmux version**. For example, a pane token needs a pane context, and a token added after your tmux release may be absent. Check the accessor's result before using a field that can be missing, as described below. ## Handling an absent field ### Python An excluded field has the value [`None`](). ### TypeScript An excluded field has the value [`undefined`](). ### Go Accessors return a value and a boolean when a field can be unavailable. For example, [`Pane.DeadSignal`]() returns `(string, bool)`; check the boolean before using the string. ### Rust Some handle accessors return `Option` for unavailable values. Check the reference for the selected accessor and its return type. ### Java Accessors use `Optional` for fields that may be unavailable. For example, [`Pane.floating`]() returns an empty `Optional` when that field is not populated. ### C# A nullable value represents an absent value. A field that was not captured can instead raise [`IncompleteSnapshotException`](). ### C++ Handles expose fixed, non-optional fields. See below for accessing tokens outside that fixed set. ### Swift Snapshots expose fixed, non-optional fields. See below for accessing tokens outside that fixed set. These examples read optional fields, including `pane_dead_signal` on tmux 3.3 or newer: ```python pane.pane_dead_signal # None below tmux 3.3, or on a pane that isn't dead ``` ```typescript pane.deadSignal; // undefined under the same conditions ``` ```go signal, ok := pane.DeadSignal() // ok is false when the token isn't populated ``` ```java pane.floating(); // Optional: a different field, same idiom: empty // rather than a sentinel when the token isn't populated ``` [`crates/libtmux/src/formats.rs`]() marks this token as optional. Consult the reference for the accessor name. Missing values differ from incomplete captures. [`Pane.Title`]() is nullable because tmux may report no title. [`Pane.Height`](), `.Width`, and `.Index` throw [`IncompleteSnapshotException`]() when the read that produced the handle did not request those fields. A handle resolved by ID alone may therefore lack enough data to answer: ```csharp string? title = pane.Title; // nullable: the ordinary absence case int height = pane.Height; // throws IncompleteSnapshotException instead, // if this Pane wasn't captured with a full listing ``` ## Field availability Field accessors retain the scope and version requirements of tmux tokens. ### TypeScript [`packages/libtmux/src/_generated/format_fields.ts`]() records each token's scope and first tmux version. For example, `pane_zoomed_flag` has pane scope and requires tmux 3.7. [`packages/libtmux/src/_generated/field_aliases.ts`]() supplies the camelCase alias `pane.zoomedFlag`. ### Rust [`crates/libtmux/src/formats.rs`]() records each token's tmux name, required context, first supported release, decoder, and handling of empty values. `pane_dead_signal` requires pane context and tmux 3.3. Its text value preserves arbitrary non-NUL bytes. ### Go [`tmux/internal/generate/formats/`]() generates [`tmux/format_generated.go`](). Some accessors also parse the returned text: [`Pane.DeadTime`]() returns `(time.Time, bool)`, so the caller does not need to parse the timestamp. Version gates describe tmux behavior: `pane_dead_signal` and `pane_dead_time` arrived in tmux 3.3, and a cluster of pane-geometry and floating-pane tokens (`pane_floating_flag`, `pane_pb_progress`, `pane_x`, `pane_y`, `pane_z`, `pane_zoomed_flag`, `bracket_paste_flag`, `synchronized_output_flag`, among others) arrived together in 3.7. ## Fixed fields and additional tokens `Session`, `Window`, and `Pane` expose a fixed set of captured fields: ### Swift Captured pane fields include `index`, `width`, `height`, `isActive`, [`currentCommand`](), [`currentPath`](), and the four edge flags. ### C++ The `kFields` arrays declare which fields to capture. Pane fields include `id`, `command`, `active`, `index`, `title`, `pid`, `tty`, `path`, `width`, `height`, `dead`, `in_mode`, edge flags, and `piping`. Accessors return [`std::string_view`](), [`bool`](), or `long long`. ```swift pane.isActive // Bool, not Bool?: always populated, never gated pane.currentCommand // String, likewise ``` ```cpp pane->active(); // bool, not std::optional pane->command(); // std::string_view, likewise ``` Expand a token outside the fixed fields with [`pane->expand("#{pane_dead_signal}")`](). Use [`FormatSubscription`]() on a control connection to observe other tokens. It delivers [`SubscriptionChange`]() when tmux re-evaluates the token. [Architecture](https://libtmux.org/en/tmux/topics/architecture/) describes the fixed-field model. ## Fields promoted from the active child Python exposes fields promoted from an active child. For example, [`session.pane_id`]() identifies the active pane of the session's active window: ```python >>> session = server.new_session() >>> session.pane_id == session.active_window.active_pane.pane_id True ``` tmux's format engine includes active-child fields when listing a parent. A `list-sessions -F` row can include `window_id` and `pane_id` for the active window and pane. Check the port reference for typed access to those fields, or use the explicit relationships described in [Traversal](https://libtmux.org/en/tmux/topics/traversal/). A pane context can include parent window and session fields. A session cannot identify one attached client when several clients may be attached, so client tokens such as `client_name` require a client context. --- # Waiting and retrying Source: https://libtmux.org/en/tmux/topics/waiting-and-retry/ > Polling a condition instead of guessing a sleep, and tmux's own wait-for signal channel as the alternative to polling. After sending input or starting a process, wait for the state your next step requires. [Pane interaction](https://libtmux.org/en/tmux/topics/pane-interaction/#waiting-for-something-to-finish) covers waiting for screen text. This page covers arbitrary conditions and tmux's named `wait-for` signal channels. ## Polling a condition Polling checks a condition repeatedly until it succeeds or a deadline expires. Set a deadline and choose an interval that limits unnecessary tmux commands. ### Python **Helper:** `libtmux.test.retry_until(fn, seconds=, interval=)` **Where it lives:** [`src/libtmux/test/`]() in the main package; raises [`WaitTimeout`](). ### TypeScript **Helper:** [`connectedServer.waitFor(matches, options)`]() **Where it lives:** The public control-connection API. Tests a predicate over [`ServerSnapshot`](); see [Control mode vs one-shot](https://libtmux.org/en/ts/latest/concepts/transports/). ### Go **Helper:** [`tmuxtest.WaitFor(ctx, interval, condition)`]() **Where it lives:** [`tmuxtest`](), a separate test-support package from [`tmux`]() ### Rust **Helper:** [`libtmux::test::retry_until(within, condition)`]() **Where it lives:** [`crates/libtmux/src/test.rs`](), enabled with the `test-support` Cargo feature. ### Java **Helper:** Not listed. **Where it lives:** not found in the shipped library; a package-private `Await.until(...)` exists only inside the `integration-tests` module, which downstream code cannot depend on ### C# **Helper:** [`LibTmux.Testing.TmuxWait.UntilAsync(probe, timeout, interval)`]() **Where it lives:** the separate [`LibTmux.Testing`]() package ### C++ **Helper:** Not listed. **Where it lives:** no generic condition-poll helper found in the public library; a [`wait_until`]() exists only in the private `testing` component, for waiting on a spawned child process, not on tmux state ### Swift **Helper:** Not listed. **Where it lives:** a [`waitUntil`]() helper exists only inside the test target's own support code, not shipped ### Examples [`waitFor`]() subscribes before reading a server snapshot so it does not miss a change between those steps. [`tmuxtest.WaitFor`]() probes immediately, then at the requested positive interval. It returns a probe error or context error unchanged. Each probe must read fresh state and honor its context. [`Session.Windows()`]() only reads a stored snapshot; use [`Session.SearchWindows`]() to query tmux on every probe. ```python def is_window_up(pane, name): return any(w.window_name == name for w in pane.window.session.windows) libtmux.test.retry_until(lambda: is_window_up(pane, "build"), seconds=5.0) ``` ```typescript await using live = await server.connect(); await live.waitFor((snapshot) => snapshot.windows.exists({ name: "build" })); ``` ```go waitCtx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() err := tmuxtest.WaitFor(waitCtx, 50*time.Millisecond, func(ctx context.Context) (bool, error) { windows, err := session.SearchWindows(ctx, nil) if err != nil { return false, err } for _, w := range windows { if name, ok := w.Name(); ok && name == "build" { return true, nil } } return false, nil }) if err != nil { return fmt.Errorf("wait for build window: %w", err) } ``` ```rust libtmux::test::retry_until(std::time::Duration::from_secs(5), async || { session.windows().await.map(|ws| ws.iter().any(|w| w.name() == "build")).unwrap_or(false) }) .await?; ``` ```csharp await LibTmux.Testing.TmuxWait.UntilAsync( async ct => (await session.GetWindowsAsync(ct)).Any(w => w.Name == "build"), TimeSpan.FromSeconds(5), TimeSpan.FromMilliseconds(50)); ``` Use a loop with a deadline and interval when a specific wait API does not fit. [Pane interaction](https://libtmux.org/en/tmux/topics/pane-interaction/#waiting-for-something-to-finish) covers output waits. ## tmux's own wait-for channel Use `tmux wait-for -S ` to signal and `tmux wait-for ` to block until signalled. This avoids repeated screen captures when the command can announce its own completion: ### Python Signal a channel with [`Server.wait_for`]() and `set_flag=True`. Call the same method without that flag to wait for the signal. ### TypeScript The public API does not expose the channel handshake used internally by the test server during startup. ### Go Call [`Server.WaitFor`]() with a [`WaitForRequest`](). Set its mode to [`WaitForModeSignal`]() to signal the channel; the zero-value mode waits. ### Rust [`Server.signal_channel`]() signals a channel. [`Server.wait_for_channel`]() waits with a timeout and returns a [`ChannelWait`]() indicating whether it was signalled or timed out. ### Java Obtain a channel through [`Server.channel`](). Its [`signal()`]() method wakes a waiter; `await(timeout)` returns a [`WakeReason`]() so the caller can distinguish a signal from a timeout. ### C# [`Server.OpenWaitChannel`]() returns a [`TmuxWaitChannel`](). Keep it in an `await using` scope and call [`WaitAsync`]() with a budget. Select the signal mode to signal the channel. ### C++ [`Server.signal`]() signals a channel. [`Server.wait_for`]() waits for the channel with a timeout. ### Swift [`Server.signal`]() signals a channel, and [`Server.wait(for:)`]() waits for it. Both calls are async and throwing. ```python server.new_session(session_name="work") server.wait_for("built", set_flag=True) # signal server.wait_for("built") # block until signalled ``` ```go if err := server.WaitFor(ctx, tmux.WaitForRequest{ Channel: "built", Mode: tmux.WaitForModeSignal, }); err != nil { return err } if err := server.WaitFor(ctx, tmux.WaitForRequest{Channel: "built"}); err != nil { return err } ``` ```rust server.signal_channel("built").await?; let outcome = server.wait_for_channel("built", std::time::Duration::from_secs(5)).await?; ``` ```java Channel built = server.channel("built"); built.signal(); WakeReason reason = built.await(Duration.ofSeconds(5)); ``` ```csharp await using TmuxWaitChannel channel = server.OpenWaitChannel("built"); bool signalled = await channel.WaitAsync(TimeSpan.FromSeconds(5)); ``` ```cpp server.signal("built"); server.wait_for("built", std::chrono::seconds{5}); ``` ```swift try await server.signal("built") try await server.wait(for: "built") ``` tmux remembers a signal sent before a waiter starts. The next wait on that channel returns immediately, so completion is not lost when the command finishes first. A raw `wait-for` client can exit zero when the server dies, as well as when the channel is signalled. Verify server liveness when a lost server must be treated as a failed task. Check [`WakeReason`]() to distinguish server loss from a signal. [`drain()`]() can clear a remembered signal before reusing a channel. [`wait(for:)`]() checks the server PID before and after waiting to distinguish server loss from a signal. Use a channel name specific to the task. A remembered signal can otherwise satisfy an unrelated later wait. The [wait-for reference](https://libtmux.org/en/tmux/latest/manual/wait-for/) describes completion signals and locks for each supported tmux version.
tmux manual and source The tmux manual describes [completion channels](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1#L8715). The [channel implementation](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/cmd-wait-for.c#L388) retains an early signal until a waiter consumes it. Use a fresh channel name for each operation.
--- # Environment Source: https://libtmux.org/en/tmux/topics/environment/ > Locate tmux objects from process variables and manage the environment inherited by new panes. tmux exposes two environment APIs. Process variables such as [`TMUX`]() and [`TMUX_PANE`]() let code inside a pane identify its server and pane. The server also stores variables through `set-environment` and `show-environment` for new processes to inherit. Like the tables in [Options and hooks](https://libtmux.org/en/tmux/topics/options-and-hooks/), this persistent store has explicit scopes. ## Locating yourself from inside a pane Inside a pane, [`TMUX`]() contains `,,`, and [`TMUX_PANE`]() contains the pane ID, such as `%1`. Use these variables to locate the current tmux objects. Select the object your operation needs: ### Python **Server:** [`Server.from_env()`]() **Session:** [`Session.from_env()`]() **Window:** [`Window.from_env()`]() **Pane:** [`Pane.from_env()`]() ### TypeScript **Server:** Not listed. **Session:** [`Session.fromEnv()`]() **Window:** Not listed. **Pane:** Not listed. ### Go **Server:** [`NewServerFromEnv(env)`]() **Session:** [`SessionFromEnv(ctx, env)`]() **Window:** [`WindowFromEnv(ctx, env)`]() **Pane:** [`PaneFromEnv(ctx, env)`]() ### Rust **Server:** [`Server::from_env()`]() **Session:** [`Session::from_env(&server)`]() **Window:** [`Window::from_env(&server)`]() **Pane:** [`Pane::from_env(&server)`]() ### Java **Server:** Not listed. **Session:** Not listed. **Window:** Not listed. **Pane:** See the Java context example below. ### C# **Server:** [`Server.FromEnvironment(env)`]() **Session:** [`Session.FromEnvironmentAsync()`]() **Window:** [`Window.FromEnvironmentAsync()`]() **Pane:** [`Pane.FromEnvironmentAsync()`]() ### C++ **Server:** [`Server::from_env()`]() **Session:** Not listed. **Window:** Not listed. **Pane:** Not listed. ### Swift **Server:** [`TmuxContext.current()`]() **Session:** [`TmuxContext.current()`]() (same call: see below) **Window:** Not listed. **Pane:** Not listed. ### Examples [`Session`](), [`Window`](), and [`Pane::from_env`]() require an existing `&Server`. Use [`Session.fromEnv()`]() to resolve the session of the current process. ```python Pane.from_env().pane_id Window.from_env().window_id Session.from_env().session_id Server.from_env().sessions ``` ```typescript const session = await Session.fromEnv(); ``` ```go pane, err := tmux.PaneFromEnv(ctx, nil) if err != nil { return err } fmt.Println("current pane:", pane.ID()) ``` ```rust let server = libtmux::Server::from_env()?; let session = libtmux::Session::from_env(&server).await?; // Option let window = libtmux::Window::from_env(&server).await?; let pane = libtmux::Pane::from_env(&server).await?; ``` ```csharp Server server = Server.FromEnvironment(null); Session session = await Session.FromEnvironmentAsync(); Window window = await Window.FromEnvironmentAsync(); Pane pane = await Pane.FromEnvironmentAsync(); ``` Environment lookup requires valid tmux targeting variables. If your process can run outside tmux, handle that case before using the result. [`NotInsideTmux`]() reports a missing or invalid tmux environment. Check the returned [`error`](). A [`FromEnvError`]() identifies a missing or malformed variable. Passing `nil` reads the process environment; pass an explicit map to resolve a captured environment. Handle [`TmuxObjectNotFoundException`]() when the environment cannot identify an object. ### Resolve the server socket [`Server::from_env()`]() selects the socket. Use the resulting server to resolve sessions or panes. ### Resolve context identifiers [`TmuxEnvironment`]() parses `TMUX` and `TMUX_PANE` into identifiers: socket path, server PID, [`SessionId`](), and `Optional`. It returns context data rather than a live pane handle: ```java TmuxEnvironment here = TmuxEnvironment.current().orElseThrow(); try (Server server = Server.open(here.config())) { Session mine = server.sessions().stream() .filter(session -> session.id().equals(here.session())) .findFirst() .orElseThrow(); } ``` ### Swift context fields Swift's [`TmuxContext.current()`]() parses the socket path, server PID, and session ID from `TMUX`. It does not read `TMUX_PANE`, so it cannot identify the current pane: ```swift let context = TmuxContext.current()! // socket path, server pid, session id let server = try context.server() ``` Read `TMUX_PANE` separately if you need the pane ID; [`TmuxContext`]() does not provide it. ## tmux's own environment variable store Like [Options and hooks](https://libtmux.org/en/tmux/topics/options-and-hooks/), tmux's persistent environment store has global and per-session scopes. It is read with `show-environment` and updated with `set-environment`. Newly spawned processes inherit it; existing processes retain their own environments. ### Python **Set:** [`server.set_environment(name, value)`](), [`session.set_environment(...)`]() **Read all:** [`server.show_environment()`](), [`session.show_environment()`]() **Unset:** [`server.unset_environment(name)`](). See below for `.remove_environment()`. ### TypeScript **Set:** [`server.setEnvironment(name, value)`](), [`session.setEnvironment(...)`]() **Read all:** [`server.showEnvironment()`](), [`session.showEnvironment()`]() **Unset:** [`server.unsetEnvironment(name)`](), [`session.unsetEnvironment(name)`]() ### Go **Set:** [`server.SetEnvironment(ctx, name, value, opts)`]() (global, `-g`) **Read all:** [`server.ShowEnvironment(ctx)`]() **Unset:** [`server.UnsetEnvironment(ctx, name)`]() ### Rust **Set:** [`server.set_environment(...)`](), [`session.set_environment(...)`]() **Read all:** [`server.environment_all()`](), [`session.environment_all()`]() **Unset:** [`server.unset_environment(name)`](), [`session.unset_environment(name)`]() ### Java **Set:** Not documented here; see the process-environment note below. **Read all:** Not documented here; see the process-environment note below. **Unset:** Not documented here; see the process-environment note below. ### C# **Set:** [`server.Environment.SetAsync(name, value)`](), [`session.Environment.SetAsync(...)`]() **Read all:** [`server.Environment.GetAllAsync()`]() **Unset:** [`server.Environment.UnsetAsync(name)`](), [`.RemoveAsync(name)`]() ### C++ **Set:** Not documented here; see the process-environment note below. **Read all:** Not documented here; see the process-environment note below. **Unset:** Not documented here; see the process-environment note below. ### Swift **Set:** [`server.setEnvironment(name, to: value, in: scope)`]() **Read all:** [`server.environment(scope)`]() **Unset:** [`server.unsetEnvironment(name, in: scope)`](), [`.removeEnvironment(name, in:)`]() ### Examples ```python server.set_environment("EDITOR", "vim") # global session.set_environment("EDITOR", "hx") # this session only session.show_environment() ``` ```typescript await server.setEnvironment("EDITOR", "vim"); await session.setEnvironment("EDITOR", "hx"); await session.showEnvironment(); ``` ```go if err := session.SetEnvironment(ctx, "EDITOR", "hx", tmux.SetEnvironmentOptions{}); err != nil { return err } values, err := session.ShowEnvironment(ctx) if err != nil { return err } fmt.Println(values) ``` ```rust server.set_environment("EDITOR", "vim").await?; session.set_environment("EDITOR", "hx").await?; session.environment_all().await?; ``` ```csharp await server.Environment.SetAsync("EDITOR", "vim"); await session.Environment.SetAsync("EDITOR", "hx"); await session.Environment.GetAllAsync(); ``` ```swift try await server.setEnvironment("EDITOR", to: "vim", in: .global) try await server.setEnvironment("EDITOR", to: "hx", in: .session(session.id.rawValue)) try await server.environment(.session(session.id.rawValue)) ``` `set-environment` writes a value. Its `-u` flag removes the entry, while `-r` marks the variable for exclusion from new processes, including values tmux inherited at startup. The listing retains an excluded variable as `-NAME`. Use `unset_environment` for `-u`, or `remove_environment` for `-r`. Use [`unsetEnvironment`]() for `-u`, or [`removeEnvironment`]() for `-r`. Use `.UnsetAsync` for `-u`, or [`.RemoveAsync`]() for `-r`. ### Process environment [`SessionSpec.Builder.environment(Map)`](), [`WindowSpec.Builder.environment(Map)`](), and [`SplitSpec.Builder.environment(Map)`]() pass initial variables to `new-session -e`, `new-window -e`, and `split-window -e`. These creation options do not change the stored environment of an existing session. ### Process environment Creation-time environment values affect the new process. They do not update an existing process's environment. To change tmux's persistent table, use `set-environment` on the same socket as the server handle. --- # Choose the tools a client can call Source: https://libtmux.org/en/go/latest/mcp/topics/tool-selection/ > Combine startup toolsets, exact names, and exclusions, then inspect the effective MCP surface. Tool selection is evaluated at startup. Only advertised tools can be called directly. A selected batch tool can also invoke its permitted nested operations, as described below. Changing the environment requires a new server process and connection. ## Toolsets `LIBTMUX_TOOLSETS` accepts a comma-separated selection: | Toolset | Use it for | | --- | --- | | `inspect` | Read sessions, windows, panes, configuration, and terminal output. | | `manage` | Create and arrange sessions, windows, and panes. | | `execute` | Send terminal input and run commands. | | `teardown` | Remove sessions, windows, and panes. | With no explicit selection, an existing or explicitly selected endpoint uses `inspect,manage,execute`. The default dedicated daemon gains `teardown` only when the launcher verifies that its own minimal-config startup created it. An explicit `inspect` selection remains inspection-only regardless of that ownership result. A present but empty `LIBTMUX_TOOLSETS` selects no toolsets. An unset variable uses defaults. There is no `none` sentinel. Leading, trailing, and interior empty list items are errors, as are unknown names. Validate configuration before reconnecting a client that depends on it. ## Exact tools and exclusions `LIBTMUX_TOOLS` adds exact names after expanding toolsets. `LIBTMUX_EXCLUDE_TOOLS` removes names last, even if another selection included them. For a connected command-only client, the [complete command example](https://libtmux.org/en/go/latest/mcp/examples/run-command/) uses an empty toolset plus `LIBTMUX_TOOLS=run_shell_command`. To allow session metadata without the rest of `inspect`, set these values in the client's environment: ```json { "LIBTMUX_TOOLSETS": "", "LIBTMUX_TOOLS": "list_sessions" } ``` [`call_read_tools_batch`](https://libtmux.org/en/go/latest/mcp/tools/call_read_tools_batch/) has its own set of permitted nested operations. Selecting that batch by name includes those operations even when they are absent from top-level discovery. For example, an empty toolset plus `LIBTMUX_TOOLS=call_read_tools_batch` exposes the batch and its nested reads without exposing those reads as separate tools. `LIBTMUX_EXCLUDE_TOOLS` also removes operations from the batch's advertised schema and dispatch. Exclude an operation explicitly when it must be unavailable through both paths. Inspect the batch schema before constructing a request. ## Inspect the active selection Read `tmux://capabilities` and compare it with the client's tool discovery. The resource records the effective names, selection, connection provenance, and capability rows also attached to each tool's metadata. It is a startup snapshot. Use [`list_sessions`](https://libtmux.org/en/go/latest/mcp/tools/list_sessions/) and [`list_panes`](https://libtmux.org/en/go/latest/mcp/tools/list_panes/) for current topology. The [selection resolver](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/tool_surface.go) and [capability catalog](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/manifest_catalog.go) define names, schemas, and expansion. The [tool reference](https://libtmux.org/en/go/latest/mcp/tools/) describes individual arguments and results. ## Terminal input Inspection can reveal terminal content and configuration. Input and execution run with the tmux user's authority; choosing a socket does not confine a shell command's effects to tmux. Choose the smallest useful selection for the task. The input handlers also check the target's current mode and synchronized-pane membership. A tool may require client interaction before input is sent, or refuse a dead or unsuitable target. If the client cannot complete the requested interaction, treat the tool error as a failed operation; do not infer success from the tool being present in discovery. See the [input handlers](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/capability_handlers.go) and [input checks](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/input_tools.go) for the selected release's behavior. --- # Snapshots, cursors, and references Source: https://libtmux.org/en/ruby/latest/mcp/topics/snapshots-and-references/ > Query Ruby MCP metadata, page a retained result, and use references within the server binding that created them. Use [`tmux_snapshot`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_snapshot/) to inspect sessions, windows, panes, window links, or attached clients. The tool captures metadata and evaluates the Ruby criteria against that capture. Reading a later page keeps the original result; starting another query acquires new metadata. The [client guide](https://libtmux.org/en/ruby/latest/mcp/guides/connect-client/) provides the complete setup used below. Its launcher creates a private daemon with one session named `mcp-example`. These JSON blocks are tool arguments to send through that connected MCP client. ## Discover the binding and limits Call [`tmux_capabilities`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_capabilities/) with an empty argument object. Read [`structuredContent.ok`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_capabilities/) before using `"data"`. The successful data identifies the selected endpoint, its server generation, the enabled tools, the criteria schema, and the current limits. `endpoint` is the public alias chosen by the launcher; the socket was selected separately when the MCP process started. Requests cannot choose a different socket. Use the returned generation and references as opaque identities. The tmux daemon PID, its start time, and an entity's numeric ID are useful context; they do not replace the generation when constructing a target. ## Read a session listing Call `tmux_snapshot` with: ```json {"entity": "session", "limit": 50} ``` The example returns one item whose `fields.name` is `mcp-example`. Its result has `truncated: false` and no `next_cursor`; pagination applies when a selection contains more records than its page limit. Each item has a `kind`, a `fields` object, and a `ref`. The fields describe the captured state; the reference identifies an entity for a later operation. Client records have `ref: null`, because clients are not supported mutation targets. Window-link references additionally identify the session and index of that particular link. The result also includes a `capture_id`, `server_identity`, `"coverage"`, and an `interval`. Acquisition reads several tmux listings. It reports the start, finish, and number of reads; it does not claim that all fields were observed at one instant. A complete acquisition can still be old by the time the client uses it. Unsupported or incomplete acquisition produces an error rather than silently presenting a partial listing as complete. ## Filter captured metadata Include the versioned Ruby criteria object to select the example session: ```json { "entity": "session", "criteria": { "profile": "libtmux-ruby.where", "version": 1, "entity": "session", "where": {"name": "mcp-example"} } } ``` This also returns one item. A valid criterion that matches nothing returns an empty `items` array, not a missing-session exception. Filtering happens locally after acquisition; selecting one session does not turn the operation into a tmux query that reads only that session. Use the schema returned by discovery for field names and operators. The wire format uses names such as `currentCommand` and `startsWith`, which differ from Ruby method spelling. The criteria entity must match the outer `entity`. The decoder also bounds bytes, nesting and nodes, rejects duplicate keys, and rejects floating-point tokens for integer fields. A generic JSON Schema validator alone does not establish that the Ruby decoder will accept a value. ## Continue the same result The default page limit is 50 records; the accepted range is 1 through 200. When a page has `truncated: true`, its `next_cursor` identifies the next position in that retained result. Send a new `tmux_snapshot` call with only the `cursor` property set to that returned string. Do not also send `entity`, `criteria`, or `limit`: a continuation cannot change its query or page size. Each page retains the same capture identity, acquisition interval, and selection, even if tmux changes meanwhile. `truncated` describes whether more records remain in this result. It does not mean that the tool silently discarded the rest. Follow the cursor until no next page remains. Captures are retained for 30 seconds by default, within a shared budget of 16 captures and 8 MiB. Screen tracking also uses that retention budget. New captures can evict older ones before their lifetime expires. A well-formed cursor with an unknown or expired capture, or a position outside its result, produces `stale_cursor`. A malformed cursor produces `invalid_input`. Neither starts a new listing on the client's behalf. Start a new query and keep its pages separate from any earlier capture when a current result is needed. The request deadline is five seconds by default and a structured response is limited to 1 MiB. A smaller page can reduce response size, but it does not reduce the work or retained bytes required to acquire and filter the complete metadata capture. Treat a capacity refusal as a failed request. ## Keep references within their binding Pass an item's returned `ref` to an enabled operation that accepts that entity kind. Preserve the whole object, including `generation`. Do not reconstruct a reference from the visible name, attach a generation from another connection, or assume a reused tmux ID still describes the same entity. A reference is not a lease on a live pane process. The entity may disappear after the snapshot; a pane can remain while its program is replaced. Process observation uses additional retained identity checks where the platform and tmux version support them. A metadata snapshot alone does not establish that a process is still running or that a command has completed. Reconnecting the client guide's launcher creates a new daemon and binding. Rediscover capabilities and acquire fresh references. Even when an application keeps its daemon running between MCP connections, a reference from one binding must not be transplanted into another. ## Read metadata through resources Clients that support MCP resource templates can discover `tmux_metadata` and `tmux_metadata_page`. The first acquires a metadata snapshot with the default page limit; the second reads a retained page. Resource access uses the same tool policy and response bounds. Fill the advertised URI template from discovery and the current result, percent-encoding each component. The endpoint, generation, entity, and cursor must agree with the retained query. A URI is not a way to bypass the binding or select another daemon. Resource reads return JSON content containing the same application result envelope; protocol errors carry the failed operation's details. The server advertises neither subscriptions nor resource-list change notifications, so a client must explicitly request a fresh observation. ## Handle errors before reading data Successful tool responses have `structuredContent.ok: true` and `"data"`. Application failures set `isError: true` and return `ok: false` with an `error` object containing a code, message, and delivery evidence. Check this envelope even when the JSON-RPC request itself completed. | Error | Reader action | | --- | --- | | `invalid_input` | Correct the argument shape, types, page limit, cursor format, or continuation fields. | | `invalid_filter` | Check the criteria profile, version, fields, and matching entity. | | `stale_cursor` | Start a fresh query instead of joining pages from different captures. | | `stale_target` | Rediscover and inspect the entity before deciding whether to retry. | | `capacity` | Reduce the requested work where possible and inspect the published limits. | | `deadline`, `transport_error`, `incomplete_snapshot` | Treat the requested observation as unavailable; do not report an empty successful result. | The pinned [snapshot implementation](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/application.rb), [tool schemas](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/catalog.rb), and [resource implementation](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/resources.rb) define the behavior described here. --- # Socket and servers Source: https://libtmux.org/en/tmux/topics/socket-and-servers/ > Select a server socket, check liveness, and detect a replacement daemon. A tmux server is selected by its Unix-domain socket. Use different sockets for independent servers, such as a development session and an isolated test server. Choose the default socket, a named socket (`-L`), or an explicit path (`-S`). ## Naming a server ### Python [`Server()`]() selects the default socket. Pass `socket_name="work"` to select a named socket, or `socket_path="/tmp/tmux-1000/work"` for an explicit path. ### TypeScript `new Server()` selects the default socket. Set `socketName` to select a named socket, or `socketPath` to use an explicit path. ### Go [`tmux.NewServer(tmux.ServerOptions{})`]() selects the default socket. Set [`ServerOptions.SocketName`]() for a named socket or [`ServerOptions.SocketPath`]() for an explicit path. ### Rust [`Server::new()`]() selects the default socket. Use [`Server::builder().socket_name("work").build()?`]() for a named socket or [`Server::builder().socket_path(path).build()?`]() for an explicit path. ### Java [`ServerEndpoint.defaultSocket()`]() selects the default socket. [`ServerEndpoint.namedSocket("work")`]() selects a named socket, and [`ServerEndpoint.socketPath(path)`]() selects an explicit path. ### C# `new ServerConnectionOptions()` selects the default socket. Supply `socketName` for a named socket or `socketPath` for an explicit path. ### C++ [`Server::at_default()`]() selects the default socket. Use [`Server::at_socket_name("work")`]() for a named socket or [`Server::at_socket_path(path)`]() for an explicit path. ### Swift Select a named socket with [`Server(socketName: "work")`]() or an explicit path with [`Server(socketPath: path)`](). The initializer requires a socket selection; see the default-socket example below. ```python default_server = libtmux.Server() named = libtmux.Server(socket_name="work") ``` ```typescript const named = new Server({ socketName: "work" }); ``` ```go named, err := tmux.NewServer(tmux.ServerOptions{SocketName: "work"}) if err != nil { return err } ``` ```rust let named = libtmux::Server::builder().socket_name("work").build()?; ``` ```java ServerConfig config = ServerConfig.builder() .endpoint(ServerEndpoint.namedSocket("work")) .build(); Server named = Server.open(config); ``` ```csharp using LibTmux; Server named = await Server.ConnectAsync(new ServerConnectionOptions(socketName: "work")); ``` ```cpp auto named = libtmux::Server::at_socket_name("work"); ``` ```swift let named = try Server(socketName: "work") ``` Choose either a socket name or a socket path. tmux uses `TMUX_TMPDIR` to resolve the directory for default and named sockets. Supplying both selectors raises [`TypeError`](). [`ServerOptions.SocketPath`]() takes precedence over [`ServerOptions.SocketName`]() when both are set. Swift requires an explicit `socketPath` or [`socketName`]() argument. To reach tmux's default socket, use [`Server(socketName: "default")`](). [`Server(socket_name_factory=...)`]() accepts a callable that generates socket names. Use a unique name for each isolated test server. [`ServerConnectionOptions(socketNameFactory: ...)`]() accepts a callable that generates socket names. Use a unique name for each isolated test server. ## Is the server actually there? A server handle does not prove that the target server is running. Use a liveness check when your program needs to distinguish a live server from an unavailable socket: ### Python [`Server.is_alive`]() returns a boolean indicating whether the server responds. ### TypeScript [`Server.isAlive`]() returns a promise of a boolean. [`Server.raiseIfDead`]() throws when the server is unavailable and retains the reason reported by tmux. ### Go [`Server.IsAlive`]() returns `(bool, error)`. The error reports a check that could not be completed; a false result alone means the server is not alive. ### Rust [`Server.is_alive`]() returns a boolean. Use [`Server.check_alive`]() when you also need to distinguish a failed check from a server that is not alive. ### Java [`Server.isAlive`]() returns a boolean. ### C# [`Server.IsAliveAsync`]() returns `Task`. ### C++ [`Server.is_alive`]() takes a timeout and returns a boolean. ### Swift [`Server.isRunning`]() is an async throwing check that returns [`Bool`](). ```python if server.is_alive(): server.sessions ``` ```typescript if (await server.isAlive()) { await server.snapshot(); } ``` ```go alive, err := server.IsAlive(ctx) if err != nil { return err } fmt.Println("server running:", alive) ``` ```rust if server.is_alive().await { server.sessions().await?; } ``` ```java if (server.isAlive()) { server.sessions(); } ``` ```csharp if (await server.IsAliveAsync()) { await server.GetSessionsAsync(); } ``` ```cpp if (server.is_alive(std::chrono::seconds{2})) { server.sessions(); } ``` ```swift if try await server.isRunning() { try await server.sessions() } ``` [`isAlive()`]() returns a boolean. Use [`raiseIfDead()`]() when you need failure details. [`is_alive()`]() returns a boolean. Use [`check_alive()`]() when you need failure details. ## Killing a server, and telling two apart Killing a server ends all its sessions. Use this only for a server your program owns; for narrower cleanup, kill the session or pane you created. Call [`server.kill_server()`](). [`Server.__eq__`]() compares [`socket_name`]() and `socket_path` when deciding whether two handles select the same endpoint. Call [`await server.kill()`](). [`TmuxServerRestartedError`]() reports an operation whose handle encountered a replacement daemon on the same socket. Call [`server.Kill(ctx)`]() and check its error. [`server.Equal(other)`]() compares the captured socket bindings, resolving relative paths and environment-based socket names. Equal endpoints do not prove equal daemon lifetimes. [`ErrDaemonReplaced`]() reports a replacement daemon on the selected socket. Call [`server.kill().await?`]() and handle a cleanup failure before returning. Call [`server.killServer()`]() to stop tmux. [`Server.close()`]() releases the local connection and leaves tmux running; see [Ownership and cleanup](https://libtmux.org/en/tmux/topics/context-managers/). Call [`await server.KillAsync()`]() and handle a cleanup failure before returning. Call [`server.kill()`]() and inspect its result for a failure. Call [`try await server.killServer()`]() and handle a cleanup failure before returning. A restarted server can reuse a socket path while having different state. Do not treat a matching path as proof that a cached object still exists. --- # Tool selection Source: https://libtmux.org/en/csharp/latest/mcp/topics/tool-selection/ > Choose the C# MCP server's callable operations and interpret its startup capability report. The server registers its callable tools once at startup. Select groups with `LIBTMUX_TOOLSETS`, add individual tools with `LIBTMUX_TOOLS`, and remove tools with `LIBTMUX_EXCLUDE_TOOLS`. Reconnect the client after changing a selection. ## Choose groups The groups are unordered. Selecting one does not imply the others. | Toolset | Use it for | | --- | --- | | `inspect` | Session, window, and pane discovery; terminal reads and text waits. | | `manage` | Topology, layout, naming, options, hooks, and environment changes. | | `execute` | Sending input and running commands. | | `teardown` | Removing sessions, windows, panes, or the server. | For an inspection client, set `LIBTMUX_TOOLSETS` to `inspect`. The [complete client example](https://libtmux.org/en/csharp/latest/mcp/examples/inspect-sessions/) verifies both an included tool and an absent execution tool through discovery. When the variable is absent, defaults depend on the chosen endpoint. A newly created dedicated daemon with the launcher's minimal configuration can receive all four groups. Existing and explicitly configured endpoints omit teardown unless you request it. Read `tmux://capabilities` to see which default applied. An entirely empty `LIBTMUX_TOOLSETS` value selects no groups. This is useful when adding only particular tools. A nonempty list cannot contain empty segments: `inspect,`, `,inspect`, and `inspect,,manage` are startup errors. Names are case-sensitive; surrounding whitespace on a valid token is trimmed. ## Add and exclude exact names This environment configuration offers only the two named hierarchy tools: ```json { "LIBTMUX_TOOLSETS": "", "LIBTMUX_TOOLS": "list_sessions,list_windows" } ``` This selection enables inspection while removing environment reads: ```json { "LIBTMUX_TOOLSETS": "inspect", "LIBTMUX_EXCLUDE_TOOLS": "show_environment" } ``` Inclusions add tools after groups are selected. Exclusions apply last, even when a tool was explicitly included. Unknown toolset or tool names stop startup. Unlike `LIBTMUX_TOOLSETS`, an explicitly empty `LIBTMUX_TOOLS` or `LIBTMUX_EXCLUDE_TOOLS` value is invalid; omit an unused variable. Tool selection changes both discovery and dispatch. A tool removed from the effective selection cannot be called by guessing its name. The [tool reference](https://libtmux.org/en/csharp/latest/mcp/tools/) lists the full catalog, which can be broader than the set offered by a particular connection. ## Read several facts [`call_read_tools_batch`](https://libtmux.org/en/csharp/latest/mcp/tools/call_read_tools_batch/) executes a bounded list of typed inspection operations serially. Each operation names a tool and supplies that tool's normal arguments. `onError` chooses whether the batch stops at the first failure or continues. Select the batch tool and the operations you intend to call, through a toolset or by exact name. Those operations also appear as individual tools. This configuration offers the batch and `list_sessions`: ```json { "LIBTMUX_TOOLSETS": "", "LIBTMUX_TOOLS": "call_read_tools_batch,list_sessions" } ``` The server omits the batch when no nested operation is selected. Exclusions remove operations from its schema and dispatch as well. Inspect the batch's `nestedAuthority` capability field for the allowed operations. The pinned [selection implementation](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L251-L281) applies the same selection to individual tools and nested operations. Check the status and nested MCP result for each completed row. A successful outer request does not imply that every nested operation succeeded. A batch can also omit nested payloads to fit its aggregate result bound; its result reports that omission. Operations are separate reads, so a hierarchy can change between them. ## Inspect the connection Read `tmux://capabilities` after connecting. It includes the frozen socket selection, ownership provenance, effective toolsets and tools, and pane observation policy. Each tool has a capability record describing its process reach, tmux effects, output classes, and nested operations. The same per-tool record appears in discovery under `_meta["com.git-pull.libtmux-mcp/capability"]`. Use current hierarchy tools for live session and pane state; the resource describes startup configuration. There are no dynamic resource templates or workflow prompts. ## Execution authority Tool filters shape the interface. They do not provide an operating-system sandbox. Commands execute with the tmux user's filesystem, process, network, and credential access. Selecting a socket confines which tmux objects a call can address, not what a process inside those objects can do. Inspection tools can expose secrets in terminal text or environment values. Captured terminal content can include instructions written by another process; receiving it through a tool does not make those instructions trusted. MCP annotations describe tools for clients and consent interfaces. They do not enforce a separate authorization policy. See the pinned [selection parser](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilitySelection.cs), [capability resource](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Resources/CapabilityResource.cs), and [protocol behavior](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/docs/mcp/README.md) for the behavior documented here. --- # Tool selection Source: https://libtmux.org/en/rs/latest/mcp/topics/tool-selection/ > Choose toolsets, add individual tools, and apply exclusions to direct and batched calls. `tmux-mcp` freezes its offered tools at startup. Changing a client's environment requires restarting the connection. Inspect the result with `tools/list` and `tmux://capabilities`; a tool omitted from the direct interface cannot be called directly by guessing its name. Complete the [client setup](https://libtmux.org/en/rs/latest/mcp/guides/connect-client/) first. These examples change that client's environment and retain its chosen socket. ## Toolsets `LIBTMUX_TOOLSETS` selects an unordered set of groups. Commas separate names; surrounding whitespace is ignored. These are categories, not levels that imply the categories before them. | Toolset | Operations | Examples | | --- | --- | --- | | `inspect` | Read tmux metadata and terminal output | [`list_sessions`](), [`snapshot_pane`](), [`capture_since`]() | | `manage` | Change tmux objects without supplying executable input | [`rename_session`](), [`resize_pane`](), [`select_layout`]() | | `execute` | Start configured processes or supply pane input | [`create_session`](), [`send_keys`](), `run_shell_command` | | `teardown` | Delete tmux state | [`kill_session`](), `clear_pane_scrollback`, [`set_history_limit`]() | Creating a session belongs to `execute`: it starts the configured pane process. Lowering a history limit can discard existing scrollback on tmux 3.7 and later, so that operation belongs to `teardown`. For inspection and command execution, set: ```json { "LIBTMUX_TOOLSETS": "inspect,execute" } ``` This JSON is the client entry's `env` object. It does not include the `manage` or `teardown` groups. ## Unset and empty values An **unset** `LIBTMUX_TOOLSETS` uses defaults. An explicit empty string selects no toolsets. | Startup condition | Default toolsets | | --- | --- | | The launcher creates its default dedicated daemon and verifies the minimal configuration | `inspect`, `manage`, `execute`, `teardown` | | An existing daemon, an explicit socket or configuration, or unknown provenance | `inspect`, `manage`, `execute` | To offer only one direct tool, start with an empty group selection and add its exact name: ```json { "LIBTMUX_TOOLSETS": "", "LIBTMUX_TOOLS": "list_sessions" } ``` With an empty group selection and no named additions, `tools/list` is empty. The capabilities resource remains available. ## Additions and exclusions The server expands toolsets, adds names from `LIBTMUX_TOOLS`, then removes names from `LIBTMUX_EXCLUDE_TOOLS`. Exclusions win even when the same name appears in the additions. This offers inspection plus [`send_keys`](), while removing [`capture_pane`](): ```json { "LIBTMUX_TOOLSETS": "inspect", "LIBTMUX_TOOLS": "send_keys", "LIBTMUX_EXCLUDE_TOOLS": "capture_pane" } ``` Removing one capture tool does not remove other ways to read terminal output. For example, [`snapshot_pane`]() and [`capture_since`]() remain in `inspect`. Choose the exact operations your client needs, then inspect the complete offered list. ## Batched reads [`call_read_tools_batch`](https://libtmux.org/en/rs/latest/mcp/tools/call_read_tools_batch/) carries its own nested operations. Offering only that tool can still allow reads that are absent from the direct tool list: ```json { "LIBTMUX_TOOLSETS": "", "LIBTMUX_TOOLS": "call_read_tools_batch", "LIBTMUX_EXCLUDE_TOOLS": "show_environment" } ``` The direct list contains only [`call_read_tools_batch`](). Its capability metadata and input schema describe the nested operations it accepts. The exclusion removes [`show_environment`]() from both. It cannot be restored by placing it inside a batch. This `tools/call` params object reads sessions through the batch: ```json { "name": "call_read_tools_batch", "arguments": { "operations": [ {"tool": "list_sessions", "arguments": {}} ] } } ``` Read the batch's structured result and each result row. A successful outer MCP call can contain failed child operations. An excluded nested tool produces a failed row with an `invalid_input` error; the batch reports that failure in its totals. Do not infer that every child succeeded from the outer `isError` flag. One client approval covers the whole batch. Nested tools do not receive separate approvals. Inspect the batch's `nestedAuthority` metadata when deciding whether to offer it. ## Invalid selections Unknown tool or toolset names fail startup. So do empty elements inside a nonempty list, such as `inspect,` or `inspect,,execute`. An entirely empty value is valid. The launcher validates selections before opening a tmux connection; a typo does not fall back to the defaults. The retired `LIBTMUX_SAFETY` and `TMUX_MCP_SAFETY` settings also stop startup. Remove them and choose the required toolsets explicitly. A direct call to a known but unoffered tool returns an invalid-params error. A batched call reports a refused child in its result rows. Changing either selection requires a new connection. Tool selection shapes the interface. Execute operations still act with the tmux user's authority, and MCP annotations give the client hints for its approval policy. Neither mechanism confines a pane's command to a filesystem or network sandbox. [Selection source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/policy.rs) and [tool registration](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/manifest.rs) define these rules. --- # Errors and exceptions Source: https://libtmux.org/en/tmux/topics/errors-and-exceptions/ > Handle command failures, inspect delivery status, and decide when a retry is safe. A command can fail because tmux rejects it, or because the transport stops before returning a reply. Inspect the reported error and delivery state before retrying a mutation: tmux may already have received it. For lookup failures caused by zero or multiple matches, see [Filtering and queries](https://libtmux.org/en/tmux/concepts/queries/#the-cardinality-contract-side-by-side). ## A failed command, as a value ### Python Command failures raise [`LibTmuxException`](). It can carry a `subcommand`; its string representation includes the subcommand and stderr. ### TypeScript [`TmuxCommandError`]() reports a command tmux rejected. [`TmuxTransportError`]() reports a failure to obtain a reply. Catch these error types separately when the distinction affects recovery. ### Go Operations return an error alongside their result. Inspect typed errors and sentinel values with [`errors.As`]() and [`errors.Is`](); preserve them when wrapping with `%w`. ### Rust Fallible operations return `Result`. Match the non-exhaustive [`Error`]() enum and include a fallback for variants added later. ### Java Command failures raise unchecked exceptions derived from [`LibTmuxException`](), which extends [`RuntimeException`](). ### C# Failures raise subclasses of [`LibTmuxException`](), including [`TmuxCommandException`](), [`TmuxTransportException`](), and [`TmuxObjectNotFoundException`](). ### C++ Fallible operations return `expected`. [`CommandFailure`]() records the failure kind, delivery status, exit code, and diagnostic. ### Swift Fallible operations use typed throws with [`TmuxError`](). Catch that error to inspect the failure. Use [`errors.Is`]() for sentinel errors such as [`tmux.ErrNoServer`]() and [`tmux.ErrNotFound`](). Use [`errors.As`]() to inspect a `*tmux.CommandError` and its completed command result. Wrap errors with `%w` to preserve that information. Distinguish a command rejected by tmux from a transport failure: ```typescript import { TmuxCommandError, TmuxTransportError } from "libtmux"; try { await pane.capture(); } catch (error) { if (error instanceof TmuxCommandError) { error.args; // the argument vector error.exitCode; error.stderr; // tmux's own lines } else if (error instanceof TmuxTransportError) { error.kind; // "cancelled" | "pipe" | "protocol" | "spawn" | "timeout" error.delivery; // see below: this is the question a retry depends on } } ``` ## Is it safe to retry? Retry a mutation automatically only when you know it was not dispatched, or when repeating it is safe for your operation. A timeout, cancellation, or dropped connection can occur after tmux has acted. These APIs expose delivery information: ### TypeScript [`TmuxTransportError.delivery`]() distinguishes `not_started`, [`written`](), `replied`, and `indeterminate`. Only `not_started` establishes that retrying cannot repeat an already-dispatched command. ### C# [`LibTmuxException.Dispatch`]() reports a [`TmuxDispatchState`](): [`NotDispatched`](), [`Dispatched`](), or [`Unknown`](). Treat the default, [`Unknown`](), as potentially dispatched. ### Java `TmuxTimeoutException.outcome()` exposes a [`DispatchOutcome`](): [`NOT_DISPATCHED`](), `COMPLETE`, or `UNKNOWN`. ### C++ [`DeliveryStatus`]() distinguishes [`not_started`](), [`written`](), [`replied`](), and [`indeterminate`](). ### Rust With the `control-mode` feature, [`ControlModeErrorKind.DispatchTimedOut`]() means the command was not dispatched. A plain timeout can occur after tmux received the command, so do not infer that retrying is safe. ### Python Inspect the exit status after a subprocess completes. If the call was interrupted, verify the resulting tmux state before repeating a mutation. ### Go Inspect the exit status after a subprocess completes. If the call was interrupted, verify the resulting tmux state before repeating a mutation. A failed pooled control connection is retired, but its failure does not prove that a mutation was never dispatched. ### Swift A control-session failure does not establish that tmux never received the command. Retry only when non-delivery is known or repeating the operation is safe. ```typescript import { TmuxTransportError } from "libtmux"; try { await session.newWindow({ name: "build" }); } catch (error) { if (error instanceof TmuxTransportError && error.delivery === "not_started") { // safe to retry: nothing reached tmux } } ``` ```csharp try { await session.CreateWindowAsync(new NewWindowRequest(name: "build")); } catch (LibTmuxException error) when (error.Dispatch == TmuxDispatchState.NotDispatched) { // safe to retry } ``` ```cpp auto result = session.new_window({.name = "build"}); if (!result.has_value() && result.error().delivery == libtmux::DeliveryStatus::not_started) { // safe to retry } ``` Treat unknown delivery as potentially executed. A [`not_started`]() result means the request did not reach tmux. A [`written`]() result means the transport accepted the request but no terminal reply arrived. [`NotDispatched`]() identifies a request that did not reach tmux. [`NOT_DISPATCHED`]() identifies a request that did not reach tmux. [`DispatchTimedOut`]() identifies a request that did not reach tmux. For subprocess calls that complete normally, inspect the exit status. If a call is interrupted or times out without a delivery state, check tmux's resulting state before repeating a mutation. --- # Waits and captured output Source: https://libtmux.org/en/csharp/latest/mcp/topics/waits-and-output/ > Choose command completion or text observation, handle bounded captures, and cancel the right operation. Use a command's exit status to determine whether it finished successfully. Use terminal text observation when the process was started elsewhere or a long-running service needs to report readiness. A text match does not prove that a command exited. ## Command results [`run_shell_command`](https://libtmux.org/en/csharp/latest/mcp/tools/run_shell_command/) sends a command to a selected pane and waits for a tmux completion signal. Check the MCP result's `isError` before interpreting its structured result, then read `exitStatus`, `timedOut`, and `output`. An unsuccessful shell exit and a tool failure are different results. The shell can finish with a nonzero exit status while the MCP exchange succeeds. If the wait times out or is cancelled, the command may still be running. Inspect the pane before retrying or sending more input; a second submission can start duplicate work. `started: false` means the command wrapper was not seen to begin, usually because the pane was not at an empty shell prompt. `paneExited` reports that the pane's program ended before returning a status. Neither case provides a successful shell exit. The [complete command example](https://libtmux.org/en/csharp/latest/mcp/examples/run-command/) checks these fields along with captured output. The command must target a pane that can accept the intended shell input. Input refuses modal targets rather than leaving a human's copy mode for them. `run_shell_command` also refuses a configured synchronized-input cohort larger than one pane. These checks observe current state; they are not atomic transactions with later tmux input delivery. ## Wait for text [`wait_for_text`](https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_text/) reads the pane and observes control-mode notifications for changes. Notifications wake the wait; returned text comes from a capture of tmux's rendered pane, not the raw event stream. Layout and window-close events can also trigger a fresh read. Control startup failure or stream loss ends the wait by default. Set `LIBTMUX_MCP_ALLOW_POLLING_FALLBACK=true` only when repeated pane captures are acceptable. Fallback waits 60 milliseconds between reads and remains bounded by the original deadline and cancellation token. The capability resource reports the configured policy, and an activated fallback reports `pollingFallback: true` in the wait result. `eventsDropped` reports lost session notifications while the wait held its observer. That count can include other panes in the session. The server reads the current pane again, but a fresh capture cannot reconstruct intermediate output that is no longer available. A match establishes what the capture contained, not a complete terminal transcript. Polling fallback applies to pane text waits. `run_shell_command` and [`wait_for_channel`](https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_channel/) use tmux rendezvous signals independently of that setting. ## Follow a pane Use [`capture_pane`](https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/) for a bounded text capture or [`snapshot_pane`](https://libtmux.org/en/csharp/latest/mcp/tools/snapshot_pane/) when pane metadata and content should be returned together. Use [`capture_since`](https://libtmux.org/en/csharp/latest/mcp/tools/capture_since/) to read subsequent output across several requests. The first `capture_since` call omits a cursor and establishes a position. Keep its returned opaque cursor and supply it on the next call for that same pane. Cursors are authenticated and bound to the socket, daemon generation, and pane. They cannot move between panes or servers, and restarting the MCP process expires them. Omit an expired cursor to establish a new baseline. Inspect the content's truncation and dropped-line or dropped-byte fields. A successful capture can be incomplete. Narrow the requested history or increase a relevant limit when the missing text matters to the task. ## Response limits Startup policy bounds waits and returned data: | Variable | Default | Accepted range | | --- | --- | --- | | `LIBTMUX_MCP_WAIT_MAX_SECONDS` | 30 seconds | 1–600 seconds | | `LIBTMUX_MCP_MAX_LINES` | 500 lines | 10–100,000 lines | | `LIBTMUX_MCP_MAX_BYTES` | 128,000 bytes | 4,000–4,000,000 bytes | Numeric values outside those ranges are clamped. Invalid values fall back to the default and produce a stderr diagnostic. These are ceilings or defaults; individual tool arguments and schemas can impose tighter bounds. The byte budget covers serialized results, including text, structured content, and metadata. It is not a raw terminal-text byte count. JSON escaping and duplicate representations can increase the serialized size. Content tools truncate within the budget and report the loss. A result that still cannot fit becomes a bounded error explaining how to narrow the call or adjust the ceiling. ## Cancellation A plain pending MCP request is cancelled with `notifications/cancelled` for its JSON-RPC request ID. A client-side timeout alone does not establish that the server received that notification. Check the client's cancellation behavior when prompt observer cleanup matters. When using the protocol's task support, cancel the task with `tasks/cancel` and its task ID. Cancelling the request that created a task does not cancel the task's work. Task-status polling is separate from polling pane contents. Wait cleanup releases the control observer. Cancelling the wait does not terminate a shell command already running in the pane. The server does not provide a separate detached command-job registry. These rules come from the pinned [protocol guide](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/docs/mcp/README.md) and [server policy](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/ServerPolicy.cs). --- # Waits and command output Source: https://libtmux.org/en/go/latest/mcp/topics/waits-and-output/ > Check tool errors, command completion, exit status, and captured output separately. [`run_shell_command`](https://libtmux.org/en/go/latest/mcp/tools/run_shell_command/) sends a command to a selected pane, waits for completion, and returns structured status and output. The [complete client program](https://libtmux.org/en/go/latest/mcp/examples/run-command/) demonstrates a command that deliberately exits with status 7. ## Read the result Check each layer before using the result: 1. A client call error means the protocol exchange failed or was cancelled. 2. A reply with [`IsError`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk@v1.6.1/mcp#CallToolResult) set reports a tool failure. Read its text content. 3. In a successful tool reply, `timed_out` and `exit_status` establish whether completion was observed. A nonzero exit status is a command result. 4. `output_unavailable` or `lines_missed` means the returned output is incomplete, even if the command's exit status is known. Clear flags still leave the request's `max_lines` limit in effect. The command example decodes the public snake_case fields, including `pane_id`, `resolved_pane_ids`, `exit_status`, and `timed_out`. Use the [advertised tool schema](https://libtmux.org/en/go/latest/mcp/tools/run_shell_command/) when constructing a request. Internal Go structs may have different JSON field names. ## Choose one pane Use a discovered pane ID for the request. The command example creates a private session, resolves its active pane, and verifies that the reply names that same pane exactly once. Synchronized input can reach other panes, so the command handler checks the resolved membership before execution. The [command wrapper](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/command_wrapper.go) provides completion tracking; the [public handler](https://github.com/libtmux/libtmux-go/blob/6e7420927f4cb717fe089a710328e44e8d551025/mcp/capability_handlers.go) validates the request and constructs its result. ## Deadlines The request's `timeout` bounds the wait for completion. The server's `LIBTMUX_MCP_WAIT_MAX_SECONDS` imposes a further ceiling, defaulting to 300 seconds. A requested wait above the ceiling is clamped. Inspect the tool's returned timeout metadata when choosing a follow-up action. A wait timeout or a cancelled client call does not establish that the shell command stopped. Inspect the pane before sending more input. Retrying an unconfirmed command can execute it twice. The server does not return a background job handle that can later be polled or cancelled. Keep the client deadline long enough to cover startup and the bounded tool wait. The complete examples use a 20-second context for startup and requests, three seconds at each subprocess shutdown stage, and a separate five-second context for their own tmux cleanup. ## Observe existing output Use [`capture_pane`](https://libtmux.org/en/go/latest/mcp/tools/capture_pane/) for a current capture, [`capture_since`](https://libtmux.org/en/go/latest/mcp/tools/capture_since/) for output after a cursor, and [`wait_for_text`](https://libtmux.org/en/go/latest/mcp/tools/wait_for_text/) for an expected terminal condition. Each tool's reference defines its cursor, matching, and output limits. A terminal view is not a durable process log: history limits and pane changes can prevent a complete capture. The command example requests `max_lines: 20`, retaining the newest bounded output. The public reply omits the internal truncation fields, so clear `output_unavailable` and `lines_missed` flags do not establish that every line was returned. Choose the limit for the output you need. The example treats unavailable or missed output as a failure while preserving a known exit status in its error. Applications can instead retain that partial data and show its limitations explicitly. --- # tmux MCP for TypeScript Source: https://libtmux.org/en/ts/latest/mcp/ > Run or embed @libtmux/mcp to inspect tmux, drive panes, and wait for commands. `@libtmux/mcp` exposes tmux through an MCP stdio server and an embeddable TypeScript factory. Clients can inspect topology, capture output, run framed shell commands, and create or arrange panes. The package requires Node 22 or newer, or Bun 1.3.14 or newer, plus tmux 3.2a or newer. Real tmux operation is supported on Linux; the package's macOS artifact checks do not establish runtime support. ## Start here - [Install](https://libtmux.org/en/ts/latest/mcp/#install) points an MCP client at this server. - [Tools](https://libtmux.org/en/ts/latest/mcp/tools/) lists the MCP operations, arguments, and results. - [Guides](https://libtmux.org/en/ts/latest/mcp/guides/) install and connect a client. - [Topics](https://libtmux.org/en/ts/latest/mcp/topics/) explain toolsets, socket provenance, and waiting. - [Examples](https://libtmux.org/en/ts/latest/mcp/examples/) call a tool, then explore server internals. - [Language API](https://libtmux.org/en/ts/latest/mcp/reference/) documents embedding and implementation types. The server exposes a static `tmux://capabilities` resource. It does not register workflow prompts or dynamic hierarchy resources. Use [Workspace Manager](https://libtmux.org/en/ts/latest/workspace/) to load and apply declarative configurations in application code. MCP clients create topology through individual tools; there is no workspace-file tool. [Package and runtime contract](https://github.com/libtmux/libtmux-ts/blob/f85b8de551353f746d50eaf36bf0112f4fe5a528/packages/mcp/README.md). --- # TypeScript MCP topics Source: https://libtmux.org/en/ts/latest/mcp/topics/ > Understand immutable tool selection, tmux provenance, pane protections, and output cursors. The TypeScript MCP server selects its endpoint and tool surface at startup. Later environment changes do not retarget a running process. ## Toolsets and startup provenance `inspect`, `manage`, `execute`, and `teardown` are independent sets. `LIBTMUX_TOOLSETS` selects sets, `LIBTMUX_TOOLS` adds exact names, and `LIBTMUX_EXCLUDE_TOOLS` removes names last. Exclusions also govern nested operations in `call_read_tools_batch`. An explicitly empty selection starts with no tools. Unknown names, empty comma-separated elements, and retired safety/allowlist variables fail startup before contacting tmux. Without socket or configuration variables, the executable selects `libtmux-mcp`. If it creates that daemon with the shipped minimal configuration and verifies its startup marker, all four sets are enabled by default. Existing or explicitly selected daemons default to `inspect,manage,execute`. Tool filtering controls this MCP interface. A shell command still acts with the tmux user's authority, and a socket name does not confine processes. ## Pane input and human activity Input preflight checks caller context, attached human clients, pane modes, and synchronized-input membership. A `force` argument confirms only the exact MCP caller pane; it does not override the other checks. `run_shell_command` requires one live supported POSIX shell and refuses a synchronized input cohort. It checks before setup and immediately before dispatch. These observations are not an atomic tmux transaction. ## Commands, waits, and cursors Use `run_shell_command` for authored commands. Its result separates command output from the echoed wrapper and includes the real exit status. It runs the command in a subshell, so directory and environment changes do not persist in the parent shell. Use `wait_for_text` for output produced elsewhere and `capture_since` for repeated reads. Waits report why they stopped, their effective timeout, and captured output. Cancelling a request stops its wait. Setting `LIBTMUX_MCP_LIVE=0` prevents control-mode connections. `wait_for_text` remains listed but returns a `no_stream` error; `capture_since` returns a bounded non-streaming capture. [Tool and runtime semantics](https://github.com/libtmux/libtmux-ts/blob/f85b8de551353f746d50eaf36bf0112f4fe5a528/packages/mcp/README.md). --- # Connect a TypeScript MCP client Source: https://libtmux.org/en/ts/latest/mcp/guides/ > Launch @libtmux/mcp on a named socket and select the tools the client receives. Launch `@libtmux/mcp` from a client with a dedicated socket name and an explicit toolset selection. Ensure the client can locate Node or Bun and tmux in its own environment. ## Start the stdio server With Node 22 or newer: ```console $ LIBTMUX_SOCKET=docs-agent LIBTMUX_TOOLSETS=inspect \ npx -y @libtmux/mcp@latest ``` The process waits for MCP requests on stdin. Its diagnostics go to stderr. For clients using the `mcpServers` format: ```json { "mcpServers": { "tmux-typescript": { "command": "npx", "args": ["-y", "@libtmux/mcp@latest"], "env": { "LIBTMUX_SOCKET": "docs-agent", "LIBTMUX_TOOLSETS": "inspect" } } } } ``` ## Verify and expand the surface After connecting, read `tmux://capabilities` and call `list_sessions`. The resource reports the frozen tool selection and connection provenance. To permit authored commands, choose `inspect,execute`. Add `manage` for topology changes classified in that set. Read each tool's classification instead of assuming that creating a pane has no process effects. For an exact selection, set `LIBTMUX_TOOLSETS` to the empty string and `LIBTMUX_TOOLS` to `list_sessions,capture_pane`. Restart after changing the environment. ## Choose another endpoint `LIBTMUX_SOCKET_PATH` selects an absolute socket path and is mutually exclusive with `LIBTMUX_SOCKET`. `LIBTMUX_TMUX_BIN` selects the executable. `LIBTMUX_TMUX_CONFIG` supplies a nonempty absolute configuration path when starting a daemon; connecting to an existing daemon cannot replace its startup configuration. [Launch and configuration source](https://github.com/libtmux/libtmux-ts/blob/f85b8de551353f746d50eaf36bf0112f4fe5a528/packages/mcp/README.md). --- # TypeScript MCP examples Source: https://libtmux.org/en/ts/latest/mcp/examples/ > Connect an embedded TypeScript MCP client and list a private tmux session. Connect a client using the [setup guide](https://libtmux.org/en/ts/latest/mcp/guides/), then call [`list_sessions`](https://libtmux.org/en/ts/latest/mcp/tools/list_sessions/). ## List sessions Send this params object through the connected client's MCP tools/call request: ```json { "name": "list_sessions", "arguments": {} } ``` Use the returned session IDs when choosing a window or pane. ## Internals The complete program below embeds a TypeScript MCP client and server with linked in-memory transports. It offers only `list_sessions`; a client that launches the stdio server does not need embedding code. ### Prepare the project Use Bun 1.4.2 or newer, Git, and tmux 3.2a or newer on Unix. Create an empty consumer directory: ```console $ mkdir mcp-example && cd mcp-example ``` Fetch the source revision used by this example: ```console $ git init libtmux-source && \ git -C libtmux-source remote add origin https://github.com/libtmux/libtmux-ts.git && \ git -C libtmux-source fetch --depth 1 origin 3fe1ca654b81b8cbf4a13b777a001a3298c87a6f && \ git -C libtmux-source checkout --detach FETCH_HEAD ``` Create the project manifest. The core and MCP packages come from that source tree; the SDK version matches the MCP package's dependency: ```json title="package.json" { "private": true, "type": "module", "workspaces": [ "libtmux-source/packages/libtmux", "libtmux-source/packages/mcp" ], "dependencies": { "libtmux": "workspace:*", "@libtmux/mcp": "workspace:*", "@modelcontextprotocol/sdk": "1.30.0" } } ``` The local workspaces keep the consumer and companion on the same core module from that checkout. Install the dependencies: ```console $ bun install --production ``` ### Connect an embedded client Create the program below. It starts a private tmux session, connects both sides of the transport, checks the offered tools, then calls [`list_sessions`](https://libtmux.org/en/ts/latest/mcp/tools/list_sessions/). Cleanup closes the MCP client and server before stopping tmux. Operation and cleanup failures stay visible. ```typescript title="mcp.ts" import { mkdtemp, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js"; import { createTmuxMcpServer } from "@libtmux/mcp"; import { Server } from "libtmux"; const directory = await mkdtemp(join(tmpdir(), "libtmux-mcp-example-")); const server = new Server({ socketPath: join(directory, "tmux.sock"), configFile: "/dev/null", environment: { ...process.env, ENV: "/dev/null", BASH_ENV: "/dev/null" }, timeoutMs: 5_000, }); const failures: unknown[] = []; let client: Client | undefined; let mcp: ReturnType | undefined; try { await server.newSession({ name: "mcp-example", shellCommand: "/bin/cat" }); mcp = createTmuxMcpServer(server, { callerEnvironment: {}, environment: { LIBTMUX_TOOLSETS: "", LIBTMUX_TOOLS: "list_sessions" }, }); client = new Client({ name: "example", version: "1.0.0" }); const [clientSide, serverSide] = InMemoryTransport.createLinkedPair(); await Promise.all([ mcp.connect(serverSide), client.connect(clientSide, { timeout: 5_000 }), ]); const offered = (await client.listTools(undefined, { timeout: 5_000 })) .tools.map((tool) => tool.name); if (offered.length !== 1 || offered[0] !== "list_sessions") { throw new Error(`Unexpected tools: ${offered.join(", ")}`); } const result = await client.callTool( { name: "list_sessions", arguments: {} }, undefined, { timeout: 5_000 }, ); if (result.isError) throw new Error(JSON.stringify(result.content)); const sessions = result.structuredContent?.sessions; if (!Array.isArray(sessions) || sessions.length !== 1 || sessions[0]?.name !== "mcp-example") { throw new Error("Expected the example's private session"); } console.log(`tools: ${offered.join(", ")}`); console.log(`sessions: ${sessions[0].name}`); } catch (error) { failures.push(error); } finally { for (const cleanup of [ () => client?.close(), () => mcp?.close(), async () => { if ((await readdir(directory)).includes("tmux.sock")) await server.kill(); await rm(directory, { recursive: true }); }, ]) { try { await cleanup(); } catch (error) { failures.push(error); } } } if (failures.length > 0) throw new AggregateError(failures, "MCP example failed"); ``` [`newSession`]() can fail after starting tmux. Cleanup checks the owned socket even if that call did not return. If stopping tmux fails, the program keeps the socket directory and reports the error. ### Run the example's checks Run the program: ```console $ bun run mcp.ts ``` Expected output: ```text tools: list_sessions sessions: mcp-example ``` An empty `LIBTMUX_TOOLSETS` plus one name in `LIBTMUX_TOOLS` selects only that operation. `callerEnvironment: {}` avoids importing the surrounding pane's identity into the embedded server. The explicitly configured [`Server`]() selects the private socket. Use the result's structured session IDs for later tool requests. Check `isError` before reading successful output; the [tool reference](https://libtmux.org/en/ts/latest/mcp/tools/list_sessions/) describes its schema. [Embedded server source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/server.ts); [upstream agent example](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/examples/mcp-agent/mcp-agent.ts); [upstream example tests](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/examples/mcp-agent/mcp-agent.test.ts). For declarative application code, see [Workspace builder examples](https://libtmux.org/en/ts/latest/workspace/internals/examples/). --- # TypeScript MCP API Source: https://libtmux.org/en/ts/latest/mcp/reference/ > Find the TypeScript server factory and the MCP tool, schema, and capability contracts. For MCP client requests, use the [tool reference](https://libtmux.org/en/ts/latest/mcp/tools/). This page covers language APIs for embedding or extending the server. Import the server factory to embed MCP. Use protocol tool names when communicating through an MCP client. ## Embedding API [`createTmuxMcpServer(tmux, options)`]() accepts a libtmux [`Server`]() and returns the SDK's [`McpServer`](https://ts.sdk.modelcontextprotocol.io/server). Options can supply the caller environment, tool-selection environment, resolved policy, and startup provenance. Without supplied provenance, the factory treats the server as unprobed with unknown configuration. [`serverFromEnvironment(environment)`]() builds the libtmux endpoint from startup configuration. The executable combines endpoint resolution, startup probing, policy selection, and stdio transport. An embedding application owns its transport and shutdown. [Exported server functions](https://github.com/libtmux/libtmux-ts/blob/f85b8de551353f746d50eaf36bf0112f4fe5a528/packages/mcp/src/server.ts) and [in-process example](https://libtmux.org/en/ts/latest/mcp/examples/) describe this boundary. ## MCP reference The [tool reference](https://libtmux.org/en/ts/latest/mcp/tools/) covers wire operations. Registered tools publish input schemas, output schemas, structured results, and effect annotations. The startup selection determines which tools are listed and callable. `tmux://capabilities` is a static JSON resource containing the frozen surface and its declarations. There are no workflow prompts or dynamic hierarchy-resource subscriptions. [Resource registration](https://github.com/libtmux/libtmux-ts/blob/f85b8de551353f746d50eaf36bf0112f4fe5a528/packages/mcp/src/resources.ts). Workspace parsing and application belong to [`@libtmux/workspace`](https://libtmux.org/en/ts/latest/workspace/reference/), not to a workspace MCP tool. ## API declarations - [mcp.startup.ConfigurationProvenance](https://libtmux.org/en/ts/latest/mcp/reference/mcp-startup-configurationprovenance/) - [mcp.server.createTmuxMcpServer](https://libtmux.org/en/ts/latest/mcp/reference/mcp-server-createtmuxmcpserver/) - [mcp.server.describeStartupFailure](https://libtmux.org/en/ts/latest/mcp/reference/mcp-server-describestartupfailure/) - [mcp.server.main](https://libtmux.org/en/ts/latest/mcp/reference/mcp-server-main/) - [mcp.policy.Policy](https://libtmux.org/en/ts/latest/mcp/reference/mcp-policy-policy/) - [mcp.server.serverFromEnvironment](https://libtmux.org/en/ts/latest/mcp/reference/mcp-server-serverfromenvironment/) - [mcp.startup.ServerStartup](https://libtmux.org/en/ts/latest/mcp/reference/mcp-startup-serverstartup/) - [mcp.startup.ServerState](https://libtmux.org/en/ts/latest/mcp/reference/mcp-startup-serverstate/) - [mcp.policy.Toolset](https://libtmux.org/en/ts/latest/mcp/reference/mcp-policy-toolset/) [Protocol catalog](https://libtmux.org/en/ts/latest/mcp/tools.json) --- # TypeScript workspace manager Source: https://libtmux.org/en/ts/latest/workspace/ > Describe a tmux session in a file, then load, inspect and capture it. **Workspace Manager for TypeScript is in development.** The `tmux-workspace` CLI is published to npm as a prerelease. Pin its version when automation depends on its output. `tmux-workspace` creates tmux sessions from YAML or JSON. A file describes windows, panes, commands, directories and environment. Load it from a terminal or request machine output for automation. ## Load a workspace from the terminal 1. [Install the command and load a workspace](https://libtmux.org/en/ts/latest/workspace/guides/installation/). 2. [Configure windows and panes](https://libtmux.org/en/ts/latest/workspace/configuration/). 3. [Capture and reload a session](https://libtmux.org/en/ts/latest/workspace/guides/export-session/). The [CLI manual](https://libtmux.org/en/ts/latest/workspace/cli/) covers discovery, search, editing, loading, capture, conversion and import. [Examples](https://libtmux.org/en/ts/latest/workspace/examples/gallery/) provide complete configurations with their prerequisites. ## Automate and inspect Use `load -d` when the caller should return without attaching. `--json` returns a result, and `--ndjson` supports a stream of records. Read [automation](https://libtmux.org/en/ts/latest/workspace/guides/automation/) for retry and cleanup decisions and [errors](https://libtmux.org/en/ts/latest/workspace/reference/exit-codes/) for failure handling. Loaded workspaces are ordinary tmux sessions. Select the same socket when inspecting them from tmux or the [MCP server](https://libtmux.org/en/ts/latest/mcp/). ## Build from application code The [workspace library](https://libtmux.org/en/ts/latest/workspace/internals/) has its own API and configuration contract. Use it when a program needs direct control over construction. The CLI task guides here describe the `tmux-workspace` executable and link to its documented source revision. [CLI source](https://github.com/libtmux/libtmux-ts/blob/f36d692552bb9a373b45338bb5fece854e57cc3d/packages/workspace-cli/README.md). - [CLI Manual](https://libtmux.org/en/ts/latest/workspace/cli/): Commands, options and machine output. - [Configuration](https://libtmux.org/en/ts/latest/workspace/configuration/): Workspace fields, normalization and execution. - [Install and load](https://libtmux.org/en/ts/latest/workspace/guides/installation/): Load a workspace on a private socket, then capture it. - [Example gallery](https://libtmux.org/en/ts/latest/workspace/examples/gallery/): Workspace files to start from, with their prerequisites. - [Runtime support](https://libtmux.org/en/ts/latest/workspace/reference/compatibility/): Runtime requirements and supported behavior. - [Internals](https://libtmux.org/en/ts/latest/workspace/internals/): The workspace library, for building sessions from code. --- # Python MCP tools Source: https://libtmux.org/en/py/latest/mcp/tools/ > Tools, resources, and prompts advertised by the Python MCP server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Use the wire name shown here when calling a tool. The Python server advertises 54 tools with the reference configuration below. Your client’s list follows the policy configured for its server. Read the [setup guide](https://libtmux.org/en/py/latest/mcp/guides/) before choosing tool access. The [language API reference](https://libtmux.org/en/py/latest/mcp/reference/) covers embedding and implementation types. [Download the protocol catalog as JSON](https://libtmux.org/en/py/latest/mcp/tools.json). Reference configuration * `LIBTMUX_TOOLSETS` `inspect,manage,execute,teardown` Protocol version: `2025-11-25`. ## Tools * [`call_read_tools_batch`](https://libtmux.org/en/py/latest/mcp/tools/call_read_tools_batch/) Call several \`inspect\` tools serially and return per-tool results. * [`capture_pane`](https://libtmux.org/en/py/latest/mcp/tools/capture_pane/) Capture the visible contents of a tmux pane (terminal scrollback). * [`capture_since`](https://libtmux.org/en/py/latest/mcp/tools/capture_since/) Capture new tmux terminal scrollback since the previous cursor. * [`clear_pane`](https://libtmux.org/en/py/latest/mcp/tools/clear_pane/) Clear the contents of a tmux pane. * [`create_session`](https://libtmux.org/en/py/latest/mcp/tools/create_session/) Create a new tmux session. * [`create_window`](https://libtmux.org/en/py/latest/mcp/tools/create_window/) Create a new window in a tmux session. * [`delete_buffer`](https://libtmux.org/en/py/latest/mcp/tools/delete_buffer/) Delete an MCP-owned buffer. * [`display_message`](https://libtmux.org/en/py/latest/mcp/tools/display_message/) Read tmux variables against a target and return the substituted text. * [`enter_copy_mode`](https://libtmux.org/en/py/latest/mcp/tools/enter_copy_mode/) Enter copy mode in a tmux pane, optionally scrolling up. * [`exit_copy_mode`](https://libtmux.org/en/py/latest/mcp/tools/exit_copy_mode/) Exit copy mode in a tmux pane. * [`find_pane_by_position`](https://libtmux.org/en/py/latest/mcp/tools/find_pane_by_position/) Find the pane occupying a corner of a tmux window. * [`get_pane_info`](https://libtmux.org/en/py/latest/mcp/tools/get_pane_info/) Get detailed information about a tmux pane. * [`get_server_info`](https://libtmux.org/en/py/latest/mcp/tools/get_server_info/) Get information about the tmux server. * [`get_session_info`](https://libtmux.org/en/py/latest/mcp/tools/get_session_info/) Return metadata for a single tmux session (ID, name, window count, activity). * [`get_window_info`](https://libtmux.org/en/py/latest/mcp/tools/get_window_info/) Return metadata for a single tmux window (ID, name, layout, dimensions). * [`kill_pane`](https://libtmux.org/en/py/latest/mcp/tools/kill_pane/) Kill (close) a tmux pane. Requires exact pane_id (e.g. '%5'). * [`kill_server`](https://libtmux.org/en/py/latest/mcp/tools/kill_server/) Kill the tmux server and all its sessions. * [`kill_session`](https://libtmux.org/en/py/latest/mcp/tools/kill_session/) Kill a tmux session. * [`kill_window`](https://libtmux.org/en/py/latest/mcp/tools/kill_window/) Kill (close) a tmux window. Requires exact window_id (e.g. '@3'). * [`list_panes`](https://libtmux.org/en/py/latest/mcp/tools/list_panes/) List tmux panes (terminal multiplexer splits) in a window, session, or server. * [`list_servers`](https://libtmux.org/en/py/latest/mcp/tools/list_servers/) Discover live tmux servers under the current user's \`\`$TMUX_TMPDIR\`\`. * [`list_sessions`](https://libtmux.org/en/py/latest/mcp/tools/list_sessions/) List tmux sessions (terminal workspaces) on a tmux server. * [`list_windows`](https://libtmux.org/en/py/latest/mcp/tools/list_windows/) List tmux windows (terminal tabs) in a session, or across the server. * [`load_buffer`](https://libtmux.org/en/py/latest/mcp/tools/load_buffer/) Load text into a new agent-namespaced tmux paste buffer. * [`move_window`](https://libtmux.org/en/py/latest/mcp/tools/move_window/) Move a window to a different index or session. * [`paste_buffer`](https://libtmux.org/en/py/latest/mcp/tools/paste_buffer/) Paste an MCP-owned buffer into a pane. * [`paste_text`](https://libtmux.org/en/py/latest/mcp/tools/paste_text/) Paste multi-line text into a pane using tmux paste buffers. * [`pipe_pane`](https://libtmux.org/en/py/latest/mcp/tools/pipe_pane/) Log a pane's live output to a file (or stop an active log). * [`rename_session`](https://libtmux.org/en/py/latest/mcp/tools/rename_session/) Rename a tmux session. * [`rename_window`](https://libtmux.org/en/py/latest/mcp/tools/rename_window/) Rename a tmux window. * [`resize_pane`](https://libtmux.org/en/py/latest/mcp/tools/resize_pane/) Resize a tmux pane. * [`resize_window`](https://libtmux.org/en/py/latest/mcp/tools/resize_window/) Resize a tmux window. * [`respawn_pane`](https://libtmux.org/en/py/latest/mcp/tools/respawn_pane/) Restart a pane's process in place, preserving pane_id and layout. * [`run_command`](https://libtmux.org/en/py/latest/mcp/tools/run_command/) Run a shell command in a pane, wait for completion, and capture output. * [`search_panes`](https://libtmux.org/en/py/latest/mcp/tools/search_panes/) Search visible terminal text across all tmux panes. * [`select_layout`](https://libtmux.org/en/py/latest/mcp/tools/select_layout/) Set the layout of a tmux window. * [`select_pane`](https://libtmux.org/en/py/latest/mcp/tools/select_pane/) Select (focus) a tmux pane by ID or direction. * [`select_window`](https://libtmux.org/en/py/latest/mcp/tools/select_window/) Select (focus) a tmux window by ID, index, or direction. * [`send_keys`](https://libtmux.org/en/py/latest/mcp/tools/send_keys/) Send keys (commands or text) to a tmux pane. * [`send_keys_batch`](https://libtmux.org/en/py/latest/mcp/tools/send_keys_batch/) Send an ordered batch of raw key/text operations to tmux panes. * [`set_environment`](https://libtmux.org/en/py/latest/mcp/tools/set_environment/) Set a tmux environment variable. * [`set_option`](https://libtmux.org/en/py/latest/mcp/tools/set_option/) Set a tmux option value. * [`set_pane_title`](https://libtmux.org/en/py/latest/mcp/tools/set_pane_title/) Set the title of a tmux pane. * [`show_buffer`](https://libtmux.org/en/py/latest/mcp/tools/show_buffer/) Read back the contents of an MCP-owned buffer. * [`show_environment`](https://libtmux.org/en/py/latest/mcp/tools/show_environment/) Show tmux environment variables. * [`show_hook`](https://libtmux.org/en/py/latest/mcp/tools/show_hook/) Look up a specific tmux hook by name. * [`show_hooks`](https://libtmux.org/en/py/latest/mcp/tools/show_hooks/) List configured tmux hooks at the given scope. * [`show_option`](https://libtmux.org/en/py/latest/mcp/tools/show_option/) Show a tmux option value. * [`signal_channel`](https://libtmux.org/en/py/latest/mcp/tools/signal_channel/) Signal a tmux \`\`wait-for\`\` channel, waking blocked waiters. * [`snapshot_pane`](https://libtmux.org/en/py/latest/mcp/tools/snapshot_pane/) Snapshot a tmux pane: visible terminal output, cursor, mode, scroll. * [`split_window`](https://libtmux.org/en/py/latest/mcp/tools/split_window/) Split a tmux window to create a new pane. * [`swap_pane`](https://libtmux.org/en/py/latest/mcp/tools/swap_pane/) Swap the positions of two panes. * [`wait_for_channel`](https://libtmux.org/en/py/latest/mcp/tools/wait_for_channel/) Block until a tmux \`\`wait-for\`\` channel is signalled. * [`wait_for_text`](https://libtmux.org/en/py/latest/mcp/tools/wait_for_text/) Wait for NEW output in a tmux pane, then return. ## Resources This server does not advertise resources in this configuration. ## Resource templates * `tmux://panes/{pane_id}{?socket_name}` Get details of a specific pane. Parameters ---------- pane_id : str The pane ID (e.g. '%1'). socket_name : str, optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Returns ------- str JSON object of pane details (MIME: \`\`application/json\`\`). * `tmux://panes/{pane_id}/content{?socket_name}` Capture and return the content of a pane. Parameters ---------- pane_id : str The pane ID (e.g. '%1'). socket_name : str, optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Returns ------- str Plain text captured pane content (MIME: \`\`text/plain\`\`). * `tmux://sessions/{session_name}{?socket_name}` Get details of a specific tmux session. Parameters ---------- session_name : str The session name. socket_name : str, optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Returns ------- str JSON object with session info and its windows (MIME: \`\`application/json\`\`). * `tmux://sessions/{session_name}/windows{?socket_name}` List all windows in a tmux session. Parameters ---------- session_name : str The session name. socket_name : str, optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Returns ------- str JSON array of window objects (MIME: \`\`application/json\`\`). * `tmux://sessions{?socket_name}` List all tmux sessions. Parameters ---------- socket_name : str, optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Returns ------- str JSON array of session objects (MIME: \`\`application/json\`\`). * `tmux://sessions/{session_name}/windows/{window_index}{?socket_name}` Get details of a specific window in a session. Parameters ---------- session_name : str The session name. window_index : str The window index within the session. socket_name : str, optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Returns ------- str JSON object with window info and its panes (MIME: \`\`application/json\`\`). ## Prompts * `build_dev_workspace` Construct a simple 3-pane development session. Produces editor (top), terminal (bottom-left), logs (bottom-right) layout — the most common shape for a working session. * `session_name`: required. Name for the new session. Provide a value matching the following JSON schema: {"type":"string"}. Encode non-string values as JSON. * `log_command`: optional. Command to run in the logs pane. Defaults to an OS-neutral \`\`watch -n 1 date\`\` so the recipe does not assume Linux log paths. Pass e.g. \`\`"tail -f /var/log/syslog"\`\` on Linux or \`\`"log stream --level info"\`\` on macOS. Provide a value matching the following JSON schema: {"type":"string"}. Encode non-string values as JSON. * `diagnose_failing_pane` Gather pane context and propose a root-cause hypothesis. Uses \`\`snapshot_pane\`\` (content + cursor + mode + scroll state in one call) instead of \`\`capture_pane\`\` + \`\`get_pane_info\`\` so the agent sees everything in a single protocol call. When the diagnosis needs another read after waiting or observing, the rendered recipe points agents at \`\`capture_since\`\` instead of a repeated full capture. * `pane_id`: required. The pane to diagnose. Provide a value matching the following JSON schema: {"type":"string"}. Encode non-string values as JSON. * `interrupt_gracefully` Interrupt a running command and verify the prompt returned. Sends \`\`C-c\`\` through \`\`send_keys(literal=True)\`\`, then waits on shell-prompt patterns via \`\`wait_for_text\`\`. Fails loudly if the process ignores SIGINT — the right escalation point is the caller, not an automatic \`\`C-\\\`\` follow-up (SIGQUIT can core-dump). * `pane_id`: required. Target pane. Provide a value matching the following JSON schema: {"type":"string"}. Encode non-string values as JSON. * `run_and_wait` Run a shell command in a tmux pane and wait for completion. The returned template teaches the high-level authored-command primitive: \`\`run_command\`\` sends the command, waits through a private tmux signal, captures output, and reports exit status in one typed result. Use lower-level \`\`send_keys\`\` + \`\`wait_for_channel\`\` only when the caller needs custom shell composition outside this common command-completion shape. * `command`: required. The shell command to run. Provide a value matching the following JSON schema: {"type":"string"}. Encode non-string values as JSON. * `pane_id`: required. Target pane (e.g. \`\`%1\`\`). Provide a value matching the following JSON schema: {"type":"string"}. Encode non-string values as JSON. * `timeout`: optional. Maximum seconds to wait for command completion. Default 60. Provide a value matching the following JSON schema: {"type":"number"}. Encode non-string values as JSON. Source revision: [tmux-python/libtmux-mcp@4daddc0dfca96c43bf521d818bf91564e1434760](https://github.com/tmux-python/libtmux-mcp/tree/4daddc0dfca96c43bf521d818bf91564e1434760). --- # call_read_tools_batch Source: https://libtmux.org/en/py/latest/mcp/tools/call_read_tools_batch/ > Call several `inspect` tools serially and return per-tool results. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Call several `inspect` tools serially and return per-tool results. Use when one agent turn needs several observations. Each nested call still goes through FastMCP validation and this server’s middleware. Only `inspect` tools are accepted; anything that changes tmux state is refused, whatever this server has enabled. This wrapper aggregates authority under its own name: a client rule keyed on a nested tool’s name does not fire for a call made through it. Read it as authority to invoke any `inspect` tool. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/call_read_tools_batch.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/batch_tools.py#L277) ## Arguments * `on_error` optional · string See the schema for this argument’s constraints. Default: `"stop"`. * `operations` required · array See the schema for this argument’s constraints. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "on_error": { "default": "stop", "enum": [ "stop", "continue" ], "type": "string" }, "operations": { "items": { "additionalProperties": false, "description": "One nested MCP tool call for a batch wrapper.", "properties": { "arguments": { "additionalProperties": true, "description": "Arguments for the nested tool call.", "type": "object" }, "tool": { "description": "Registered MCP tool name to call.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "description": "Structured result for a serial batch of MCP tool calls.", "properties": { "failed": { "description": "Number of nested tool calls that failed.", "type": "integer" }, "response_truncated": { "default": false, "description": "True when nested result payloads were elided to keep the batch response under the server response cap.", "type": "boolean" }, "response_truncated_bytes": { "default": 0, "description": "Approximate serialized bytes removed from nested result payloads.", "type": "integer" }, "results": { "description": "Per-operation results in attempted order.", "items": { "description": "Per-operation result from a generic MCP tool batch.", "properties": { "content": { "description": "MCP content blocks returned by the nested tool.", "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, "elapsed_seconds": { "description": "Time spent on this operation.", "type": "number" }, "error": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Error message for this operation, if it failed." }, "index": { "description": "Zero-based index in the submitted operation list.", "type": "integer" }, "meta": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "default": null, "description": "Runtime metadata returned by the nested tool, if any." }, "structured_content": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "default": null, "description": "Structured content returned by the nested tool, if any." }, "success": { "description": "True when this nested tool call succeeded.", "type": "boolean" }, "tool": { "description": "Nested tool name that was attempted.", "type": "string" } }, "required": [ "index", "tool", "success", "elapsed_seconds" ], "type": "object" }, "type": "array" }, "stopped_at": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Index where processing stopped because on_error='stop', or None when all operations were attempted." }, "succeeded": { "description": "Number of nested tool calls that succeeded.", "type": "integer" } }, "required": [ "succeeded", "failed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # capture_pane Source: https://libtmux.org/en/py/latest/mcp/tools/capture_pane/ > Capture the visible contents of a tmux pane (terminal scrollback). MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Capture the visible contents of a tmux pane (terminal scrollback). Use for tmux pane output — ‘capture the build log’, ‘what did the server print’ — not editor file contents. The tool for reading what is displayed in a terminal; use [search_panes](https://libtmux.org/en/py/latest/mcp/tools/search_panes/) to search across multiple panes at once. Output is tail-preserved: when the capture exceeds `max_lines` the oldest lines are dropped and the returned string is prefixed with a single `[... truncated K lines ...]` header line so the agent can tell truncation occurred and re-request with a narrower `start`/`end` window or a larger `max_lines` if needed. Pass `max_lines=None` to disable truncation entirely. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/capture_pane.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L101) ## Arguments * `end` optional End line number. Default: `null`. * `max_lines` optional Maximum number of lines to return. Defaults to \`\`CAPTURE_DEFAULT_MAX_LINES\`\`. Pass \`\`None\`\` to return the full capture with no truncation. Default: `500`. * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID (e.g. '$1') for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `start` optional Start line number. 0 is the first visible line. Negative values reach into scrollback history (e.g. -100 for last 100 lines). Default: `null`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "end": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "End line number." }, "max_lines": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": 500, "description": "Maximum number of lines to return. Defaults to\n``CAPTURE_DEFAULT_MAX_LINES``. Pass ``None`` to return the\nfull capture with no truncation." }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "start": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Start line number. 0 is the first visible line. Negative values\nreach into scrollback history (e.g. -100 for last 100 lines)." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # capture_since Source: https://libtmux.org/en/py/latest/mcp/tools/capture_since/ > Capture new tmux terminal scrollback since the previous cursor. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Capture new tmux terminal scrollback since the previous cursor. Use for observation-first workflows: tailing a shell, watching a long-running command, or repeatedly checking a tmux workspace pane without re-sending the same visible screen every turn. The first call with `cursor=None` returns the current visible pane and an opaque cursor. Later calls pass that cursor back and receive only rows written or rewritten after the cursor, as long as tmux still retains the required scrollback history. If tmux history was cleared or trimmed before the cursor anchor, the tool returns the current visible pane with `lines_missed=True` and a fresh cursor. Malformed cursors, cursors for a different pane, pane death, and pane respawn fail with `ExpectedToolError` so agents do not accidentally observe the wrong process. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/capture_since.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L106) ## Arguments * `cursor` optional Opaque cursor returned by a prior \`\`capture_since\`\` call. When omitted, the tool captures the current visible screen and starts a new cursor. Default: `null`. * `max_bytes` optional Maximum UTF-8 bytes to return across \`\`lines\`\`. Defaults to \`\`CAPTURE_SINCE_DEFAULT_MAX_BYTES\`\`. Pass \`\`None\`\` to disable byte truncation. Default: `128000`. * `max_lines` optional Maximum number of lines to return. Defaults to \`\`CAPTURE_SINCE_DEFAULT_MAX_LINES\`\`. Pass \`\`None\`\` to disable line truncation. Default: `500`. * `pane_id` optional Pane ID (e.g. '%1'). Optional when \`\`cursor\`\` is supplied; the cursor carries the original pane id. Default: `null`. * `session_id` optional Session ID (e.g. '$1') for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Opaque cursor returned by a prior ``capture_since`` call. When\nomitted, the tool captures the current visible screen and\nstarts a new cursor." }, "max_bytes": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": 128000, "description": "Maximum UTF-8 bytes to return across ``lines``. Defaults to\n``CAPTURE_SINCE_DEFAULT_MAX_BYTES``. Pass ``None`` to\ndisable byte truncation." }, "max_lines": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": 500, "description": "Maximum number of lines to return. Defaults to\n``CAPTURE_SINCE_DEFAULT_MAX_LINES``. Pass ``None`` to\ndisable line truncation." }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1'). Optional when ``cursor`` is supplied; the\ncursor carries the original pane id." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # clear_pane Source: https://libtmux.org/en/py/latest/mcp/tools/clear_pane/ > Clear the contents of a tmux pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Clear the contents of a tmux pane. Use before a fresh [run_command](https://libtmux.org/en/py/latest/mcp/tools/run_command/) call or raw-input observation workflow when prior scrollback would make the result harder to inspect. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/clear_pane.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L141) ## Arguments * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID (e.g. '$1') for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # create_session Source: https://libtmux.org/en/py/latest/mcp/tools/create_session/ > Create a new tmux session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Create a new tmux session. Check [list_sessions](https://libtmux.org/en/py/latest/mcp/tools/list_sessions/) first to avoid name conflicts. A new session starts with one window and one pane. Values in `environment` are stored in the tmux session environment, so future panes inherit them too. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/create_session.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/server_tools.py#L372) ## Arguments * `environment` optional Environment variables to store in the session environment. Accepts either a dict of env vars or a JSON-serialized string of the same — the latter is the cursor-composer-1 workaround described in :func:\`libtmux_mcp.\_utils.\_coerce_dict_arg\`. Each item appears in the tmux client argv as one \`\`-eKEY=VALUE\`\` element and may be visible to host process inspection during launch. tmux retains the values in tmux session state, where \`\`show-environment\`\` can reveal them. They reach the initial and future child environments unless a later spawn overrides them. MCP audit redaction does not hide these surfaces. Pass credential references, not literal credentials. Default: `null`. * `session_name` optional Name for the new session. Default: `null`. * `socket_name` optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Default: `null`. * `start_directory` optional Existing directory to start in. \`\`\~\`\` expands; a relative path resolves against the MCP server process's directory. Default: `null`. * `suppress_persistent_history` optional · boolean Whether to suppress persistent history for the spawned shell. Defaults to False for MCP and direct Python calls. This per-call option does not inherit LIBTMUX_SUPPRESS_HISTORY. Startup files may override these controls. Default: `false`. * `window_name` optional Name for the initial window. Default: `null`. * `x` optional Width of the initial window. Default: `null`. * `y` optional Height of the initial window. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "environment": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "string" }, { "type": "null" } ], "default": null, "description": "Environment variables to store in the session environment. Accepts\neither a dict of env vars or a JSON-serialized string of the same —\nthe latter is the cursor-composer-1 workaround described in\n:func:`libtmux_mcp._utils._coerce_dict_arg`. Each item appears in the\ntmux client argv as one ``-eKEY=VALUE`` element and may be visible to\nhost process inspection during launch. tmux retains the values in\ntmux session state, where ``show-environment`` can reveal them. They reach\nthe initial and future child environments unless a later spawn\noverrides them. MCP audit redaction does not hide these surfaces. Pass\ncredential references, not literal credentials." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Name for the new session." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name. Defaults to LIBTMUX_SOCKET env var." }, "start_directory": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Existing directory to start in. ``~`` expands; a relative path\nresolves against the MCP server process's directory." }, "suppress_persistent_history": { "default": false, "description": "Whether to suppress persistent history for the spawned shell. Defaults\nto False for MCP and direct Python calls. This per-call option does not\ninherit LIBTMUX_SUPPRESS_HISTORY. Startup files may override these\ncontrols.", "type": "boolean" }, "window_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Name for the initial window." }, "x": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Width of the initial window." }, "y": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Height of the initial window." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux session.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the session's active pane. Guaranteed non-None on ``create_session`` return (libtmux creates the session with one initial pane). May be None from ``list_sessions`` rows for sessions in transient teardown states where ``active_pane`` is unavailable." }, "session_attached": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Attached client count" }, "session_created": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Creation timestamp" }, "session_id": { "description": "Session ID (e.g. '$1')", "type": "string" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name" }, "window_count": { "description": "Number of windows", "type": "integer" } }, "required": [ "session_id", "window_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # create_window Source: https://libtmux.org/en/py/latest/mcp/tools/create_window/ > Create a new window in a tmux session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Create a new window in a tmux session. Creates a window with one pane. Use [split_window](https://libtmux.org/en/py/latest/mcp/tools/split_window/) to add more panes afterward. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/create_window.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/session_tools.py#L364) ## Arguments * `attach` optional · boolean Whether to make the new window active. Default: `false`. * `direction` optional Window placement direction. Default: `null`. * `environment` optional Per-process environment as a mapping or JSON object string. Values do not modify the tmux session environment. Each item becomes a tmux \`\`-e\`\` launch option. Values may be visible to host process inspection in the tmux client argv during launch and in the child environment afterward; MCP audit redaction does not hide either surface. Pass credential references, not literal credentials. Default: `null`. * `session_id` optional Session ID (e.g. '$1') to look up. Default: `null`. * `session_name` optional Session name to look up. Default: `null`. * `socket_name` optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Default: `null`. * `start_directory` optional Existing directory to start in. \`\`\~\`\` expands; a relative path resolves against the MCP server process's directory. Default: `null`. * `suppress_persistent_history` optional · boolean Whether to suppress persistent history for the spawned shell. Defaults to False for MCP and direct Python calls. This per-call option does not inherit LIBTMUX_SUPPRESS_HISTORY. Startup files may override these controls. Default: `false`. * `window_name` optional Name for the new window. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "attach": { "default": false, "description": "Whether to make the new window active.", "type": "boolean" }, "direction": { "anyOf": [ { "enum": [ "before", "after" ], "type": "string" }, { "type": "null" } ], "default": null, "description": "Window placement direction." }, "environment": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "string" }, { "type": "null" } ], "default": null, "description": "Per-process environment as a mapping or JSON object string. Values do\nnot modify the tmux session environment. Each item becomes a tmux\n``-e`` launch option. Values may be visible to host process inspection\nin the tmux client argv during launch and in the child environment\nafterward; MCP audit redaction does not hide either surface. Pass\ncredential references, not literal credentials." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') to look up." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name to look up." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name. Defaults to LIBTMUX_SOCKET env var." }, "start_directory": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Existing directory to start in. ``~`` expands; a relative path\nresolves against the MCP server process's directory." }, "suppress_persistent_history": { "default": false, "description": "Whether to suppress persistent history for the spawned shell. Defaults\nto False for MCP and direct Python calls. This per-call option does not\ninherit LIBTMUX_SUPPRESS_HISTORY. Startup files may override these\ncontrols.", "type": "boolean" }, "window_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Name for the new window." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux window.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the window's active pane." }, "pane_count": { "description": "Number of panes", "type": "integer" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session name" }, "window_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "window_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "window_id": { "description": "Window ID (e.g. '@1')", "type": "string" }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index" }, "window_layout": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Layout string" }, "window_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window name" }, "window_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" } }, "required": [ "window_id", "pane_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # delete_buffer Source: https://libtmux.org/en/py/latest/mcp/tools/delete_buffer/ > Delete an MCP-owned buffer. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete an MCP-owned buffer. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/delete_buffer.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/buffer_tools.py#L401) ## Arguments * `buffer_name` required · string Must match the full MCP-namespaced form. * `socket_name` optional tmux socket name. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "buffer_name": { "description": "Must match the full MCP-namespaced form.", "type": "string" }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." } }, "required": [ "buffer_name" ], "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # display_message Source: https://libtmux.org/en/py/latest/mcp/tools/display_message/ > Read tmux variables against a target and return the substituted text. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read tmux variables against a target and return the substituted text. Use this when no dedicated tool covers the field you want, e.g. ’#{window_zoomed_flag}’, ’#{pane_dead}’, ’#{client_activity}’. Accepts literal text and ’#{variable}’ references. Format modifiers, conditionals, and jobs are refused: tmux expands ’#{E:x}’ by running x’s *value* through the expander again, and a value can arrive from a pane rather than from the caller. For raw format syntax, run ‘tmux display-message -p’ through [run_command](https://libtmux.org/en/py/latest/mcp/tools/run_command/), where the caller supplies it on a surface labelled execution. Returned values can carry text a pane chose, such as a working directory or a running command. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/display_message.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L179) ## Arguments * `format_string` required · string Literal text and '#{variable}' references (e.g. '#{cursor_x} #{cursor_y}'). * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "format_string": { "description": "Literal text and '#{variable}' references (e.g.\n'#{cursor_x} #{cursor_y}').", "type": "string" }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "required": [ "format_string" ], "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # enter_copy_mode Source: https://libtmux.org/en/py/latest/mcp/tools/enter_copy_mode/ > Enter copy mode in a tmux pane, optionally scrolling up. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Enter copy mode in a tmux pane, optionally scrolling up. Use to navigate scrollback history. After entering copy mode, use [snapshot_pane](https://libtmux.org/en/py/latest/mcp/tools/snapshot_pane/) to read the scroll_position and content. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/enter_copy_mode.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L184) ## Arguments * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `scroll_up` optional Number of lines to scroll up immediately after entering copy mode. Default: `null`. * `session_id` optional Session ID for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "scroll_up": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Number of lines to scroll up immediately after entering copy mode." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # exit_copy_mode Source: https://libtmux.org/en/py/latest/mcp/tools/exit_copy_mode/ > Exit copy mode in a tmux pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Exit copy mode in a tmux pane. Returns the pane to normal mode. Use after scrolling through scrollback history. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/exit_copy_mode.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L189) ## Arguments * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # find_pane_by_position Source: https://libtmux.org/en/py/latest/mcp/tools/find_pane_by_position/ > Find the pane occupying a corner of a tmux window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Find the pane occupying a corner of a tmux window. Composes the four `pane_at_*` predicates so callers can target a layout-relative position (e.g. “the bottom-right pane”) in one round-trip instead of listing every pane and computing the geometry. Resolves the window the same way as the other window-scoped tools. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/find_pane_by_position.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L136) ## Arguments * `corner` required · string One of \`\`'top-left'\`\`, \`\`'top-right'\`\`, \`\`'bottom-left'\`\`, \`\`'bottom-right'\`\`. * `session_id` optional Session ID. Default: `null`. * `session_name` optional Session name. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID (e.g. '@1'). Default: `null`. * `window_index` optional Window index. Requires session_name or session_id. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "corner": { "description": "One of ``'top-left'``, ``'top-right'``, ``'bottom-left'``,\n``'bottom-right'``.", "enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ], "type": "string" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID (e.g. '@1')." }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index. Requires session_name or session_id." } }, "required": [ "corner" ], "type": "object" } ``` Output schema ```json { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # get_pane_info Source: https://libtmux.org/en/py/latest/mcp/tools/get_pane_info/ > Get detailed information about a tmux pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Get detailed information about a tmux pane. Use this for metadata (PID, path, dimensions) without reading terminal content. To read what is displayed in the pane, use [capture_pane](https://libtmux.org/en/py/latest/mcp/tools/capture_pane/) instead. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/get_pane_info.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L131) ## Arguments * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID (e.g. '$1') for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # get_server_info Source: https://libtmux.org/en/py/latest/mcp/tools/get_server_info/ > Get information about the tmux server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Get information about the tmux server. Use to verify the tmux server is running before other operations. For session-level details, use [list_sessions](https://libtmux.org/en/py/latest/mcp/tools/list_sessions/) instead. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/get_server_info.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/server_tools.py#L382) ## Arguments * `socket_name` optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name. Defaults to LIBTMUX_SOCKET env var." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux server info.", "properties": { "is_alive": { "description": "Whether the server is running", "type": "boolean" }, "session_count": { "description": "Number of sessions", "type": "integer" }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Socket name" }, "socket_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Socket path" }, "version": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux version" } }, "required": [ "is_alive", "session_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # get_session_info Source: https://libtmux.org/en/py/latest/mcp/tools/get_session_info/ > Return metadata for a single tmux session (ID, name, window count, activity). MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return metadata for a single tmux session (ID, name, window count, activity). Use this instead of [list_sessions](https://libtmux.org/en/py/latest/mcp/tools/list_sessions/) + filter when you only need one session’s info. Resolves by session_id first; falls back to session_name. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/get_session_info.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/session_tools.py#L359) ## Arguments * `session_id` optional Session ID (e.g. '$0'). Default: `null`. * `session_name` optional Session name. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$0')." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux session.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the session's active pane. Guaranteed non-None on ``create_session`` return (libtmux creates the session with one initial pane). May be None from ``list_sessions`` rows for sessions in transient teardown states where ``active_pane`` is unavailable." }, "session_attached": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Attached client count" }, "session_created": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Creation timestamp" }, "session_id": { "description": "Session ID (e.g. '$1')", "type": "string" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name" }, "window_count": { "description": "Number of windows", "type": "integer" } }, "required": [ "session_id", "window_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # get_window_info Source: https://libtmux.org/en/py/latest/mcp/tools/get_window_info/ > Return metadata for a single tmux window (ID, name, layout, dimensions). MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return metadata for a single tmux window (ID, name, layout, dimensions). Use this instead of [list_windows](https://libtmux.org/en/py/latest/mcp/tools/list_windows/) + filter when you only need one window’s info. Resolves the window by window_id first; falls back to window_index within a session if window_id is not given. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/get_window_info.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/window_tools.py#L507) ## Arguments * `session_id` optional Session ID for window_index lookup. Default: `null`. * `session_name` optional Session name for window_index lookup. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID (e.g. '@1'). Default: `null`. * `window_index` optional Window index within the session. Requires session_name or session_id to disambiguate. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID for window_index lookup." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for window_index lookup." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID (e.g. '@1')." }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index within the session. Requires session_name or\nsession_id to disambiguate." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux window.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the window's active pane." }, "pane_count": { "description": "Number of panes", "type": "integer" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session name" }, "window_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "window_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "window_id": { "description": "Window ID (e.g. '@1')", "type": "string" }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index" }, "window_layout": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Layout string" }, "window_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window name" }, "window_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" } }, "required": [ "window_id", "pane_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # kill_pane Source: https://libtmux.org/en/py/latest/mcp/tools/kill_pane/ > Kill (close) a tmux pane. Requires exact pane_id (e.g. '%5'). MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Kill (close) a tmux pane. Requires exact pane_id (e.g. ‘%5’). Use to clean up panes no longer needed. To remove an entire window and all its panes, use [kill_window](https://libtmux.org/en/py/latest/mcp/tools/kill_window/) instead. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/kill_pane.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L116) ## Arguments * `pane_id` required · string Pane ID (e.g. '%1'). Required — no fallback resolution. * `socket_name` optional tmux socket name. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "Pane ID (e.g. '%1'). Required — no fallback resolution.", "type": "string" }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # kill_server Source: https://libtmux.org/en/py/latest/mcp/tools/kill_server/ > Kill the tmux server and all its sessions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Kill the tmux server and all its sessions. Destroys ALL sessions, windows, and panes on this server. Use [kill_session](https://libtmux.org/en/py/latest/mcp/tools/kill_session/) to remove a single session instead. Self-kill protection prevents killing the server running this MCP process. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/kill_server.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/server_tools.py#L377) ## Arguments * `socket_name` optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name. Defaults to LIBTMUX_SOCKET env var." } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # kill_session Source: https://libtmux.org/en/py/latest/mcp/tools/kill_session/ > Kill a tmux session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Kill a tmux session. Destroys the session and all its windows and panes. Use [kill_window](https://libtmux.org/en/py/latest/mcp/tools/kill_window/) to remove a single window instead. Self-kill protection prevents killing the session containing this MCP process. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/kill_session.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/session_tools.py#L374) ## Arguments * `session_id` optional Session ID (e.g. '$1') to look up. Default: `null`. * `session_name` optional Session name to look up. Default: `null`. * `socket_name` optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') to look up." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name to look up." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name. Defaults to LIBTMUX_SOCKET env var." } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # kill_window Source: https://libtmux.org/en/py/latest/mcp/tools/kill_window/ > Kill (close) a tmux window. Requires exact window_id (e.g. '@3'). MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Kill (close) a tmux window. Requires exact window_id (e.g. ‘@3’). Destroys the window and all its panes. Use [kill_pane](https://libtmux.org/en/py/latest/mcp/tools/kill_pane/) to remove a single pane instead. Self-kill protection prevents killing the window containing this MCP process. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/kill_window.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/window_tools.py#L522) ## Arguments * `socket_name` optional tmux socket name. Default: `null`. * `window_id` required · string Window ID (e.g. '@1'). Required — no fallback resolution. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "description": "Window ID (e.g. '@1'). Required — no fallback resolution.", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # list_panes Source: https://libtmux.org/en/py/latest/mcp/tools/list_panes/ > List tmux panes (terminal multiplexer splits) in a window, session, or server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List tmux panes (terminal multiplexer splits) in a window, session, or server. Use for terminal panes — including ‘this pane’, ‘current pane’, ‘split pane’, ‘the bottom shell’ — not editor splits or browser panes. Only searches pane metadata (current command, title, working directory); to search the actual visible terminal text, use [search_panes](https://libtmux.org/en/py/latest/mcp/tools/search_panes/). [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/list_panes.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/window_tools.py#L501) ## Arguments * `filters` optional Django-style filters as a dict (e.g. \`\`{"pane_current_command__contains": "vim"}\`\`) or as a JSON string. Some MCP clients require the string form. Default: `null`. * `session_id` optional Session ID. If given without window params, lists all panes in the session. Default: `null`. * `session_name` optional Session name. If given without window params, lists all panes in the session. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID (e.g. '@1'). Scopes to a single window. Default: `null`. * `window_index` optional Window index within the session. Scopes to a single window. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "filters": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "string" }, { "type": "null" } ], "default": null, "description": "Django-style filters as a dict\n(e.g. ``{\"pane_current_command__contains\": \"vim\"}``)\nor as a JSON string. Some MCP clients require the string form." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID. If given without window params, lists all panes\nin the session." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name. If given without window params, lists all panes\nin the session." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID (e.g. '@1'). Scopes to a single window." }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index within the session. Scopes to a single window." } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "items": { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" }, "type": "array" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # list_servers Source: https://libtmux.org/en/py/latest/mcp/tools/list_servers/ > Discover live tmux servers under the current user's ``$TMUX_TMPDIR``. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Discover live tmux servers under the current user’s `$TMUX_TMPDIR`. Scans `${TMUX_TMPDIR:-/tmp}/tmux-/` for socket files — the canonical location where tmux creates per-server sockets (see tmux.c’s `expand_paths` + `TMUX_SOCK` template). Only sockets with a live listener are reported; stale inodes (a common case on long-running systems where `$TMUX_TMPDIR` can carry thousands of orphans) are silently filtered. **Scope caveat**: custom `tmux -S /some/path/...` servers that live OUTSIDE `$TMUX_TMPDIR` are not returned by the scan alone — there is no canonical registry for arbitrary socket paths. Supply known paths via `extra_socket_paths` to include them in the result, or pass the path to other tools via their `socket_name` / `socket_path` parameters once known. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/list_servers.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/server_tools.py#L367) ## Arguments * `extra_socket_paths` optional Additional filesystem paths to probe alongside the \`\`$TMUX_TMPDIR\`\` scan. Each path is checked for liveness (UNIX \`\`connect()\`\`) and queried for server metadata. Paths that do not exist, are not sockets, or have no listener are silently skipped. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "extra_socket_paths": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "default": null, "description": "Additional filesystem paths to probe alongside the\n``$TMUX_TMPDIR`` scan. Each path is checked for liveness (UNIX\n``connect()``) and queried for server metadata. Paths that do\nnot exist, are not sockets, or have no listener are silently\nskipped." } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "items": { "description": "Serialized tmux server info.", "properties": { "is_alive": { "description": "Whether the server is running", "type": "boolean" }, "session_count": { "description": "Number of sessions", "type": "integer" }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Socket name" }, "socket_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Socket path" }, "version": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux version" } }, "required": [ "is_alive", "session_count" ], "type": "object" }, "type": "array" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # list_sessions Source: https://libtmux.org/en/py/latest/mcp/tools/list_sessions/ > List tmux sessions (terminal workspaces) on a tmux server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List tmux sessions (terminal workspaces) on a tmux server. Use for tmux multiplexer sessions — ‘this session’, ‘my workspace’, ‘the dev session’ — not login sessions or HTTP sessions. The starting point for discovery — call this before targeting specific sessions, windows, or panes. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/list_sessions.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/server_tools.py#L362) ## Arguments * `filters` optional Django-style filters as a dict (e.g. \`\`{"session_name__contains": "dev"}\`\`) or as a JSON string. Some MCP clients require the string form. Default: `null`. * `socket_name` optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "filters": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "string" }, { "type": "null" } ], "default": null, "description": "Django-style filters as a dict (e.g. ``{\"session_name__contains\": \"dev\"}``)\nor as a JSON string. Some MCP clients require the string form." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name. Defaults to LIBTMUX_SOCKET env var." } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "items": { "description": "Serialized tmux session.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the session's active pane. Guaranteed non-None on ``create_session`` return (libtmux creates the session with one initial pane). May be None from ``list_sessions`` rows for sessions in transient teardown states where ``active_pane`` is unavailable." }, "session_attached": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Attached client count" }, "session_created": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Creation timestamp" }, "session_id": { "description": "Session ID (e.g. '$1')", "type": "string" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name" }, "window_count": { "description": "Number of windows", "type": "integer" } }, "required": [ "session_id", "window_count" ], "type": "object" }, "type": "array" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # list_windows Source: https://libtmux.org/en/py/latest/mcp/tools/list_windows/ > List tmux windows (terminal tabs) in a session, or across the server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List tmux windows (terminal tabs) in a session, or across the server. Use for tmux windows — ‘current window’, ‘this tab’ (when terminal- contextual) — not browser tabs or desktop windows. Only searches window metadata (name, index, layout); to search the actual visible terminal text, use [search_panes](https://libtmux.org/en/py/latest/mcp/tools/search_panes/). [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/list_windows.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/session_tools.py#L353) ## Arguments * `filters` optional Django-style filters as a dict (e.g. \`\`{"window_name__contains": "dev"}\`\`) or as a JSON string. Some MCP clients require the string form. Default: `null`. * `session_id` optional Session ID (e.g. '$1') to look up. Default: `null`. * `session_name` optional Session name to look up. If omitted along with session_id, returns windows from all sessions. Default: `null`. * `socket_name` optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "filters": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "string" }, { "type": "null" } ], "default": null, "description": "Django-style filters as a dict (e.g. ``{\"window_name__contains\": \"dev\"}``)\nor as a JSON string. Some MCP clients require the string form." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') to look up." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name to look up. If omitted along with session_id,\nreturns windows from all sessions." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name. Defaults to LIBTMUX_SOCKET env var." } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "items": { "description": "Serialized tmux window.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the window's active pane." }, "pane_count": { "description": "Number of panes", "type": "integer" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session name" }, "window_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "window_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "window_id": { "description": "Window ID (e.g. '@1')", "type": "string" }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index" }, "window_layout": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Layout string" }, "window_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window name" }, "window_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" } }, "required": [ "window_id", "pane_count" ], "type": "object" }, "type": "array" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # load_buffer Source: https://libtmux.org/en/py/latest/mcp/tools/load_buffer/ > Load text into a new agent-namespaced tmux paste buffer. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Load text into a new agent-namespaced tmux paste buffer. Each call allocates a fresh buffer name — two concurrent calls will land in distinct buffers even if they pass the same `logical_name`. Agents MUST use the returned :attr:`~libtmux_mcp.models.BufferRef.buffer_name` on subsequent paste/show/delete calls. **When to use this vs. [paste_text](https://libtmux.org/en/py/latest/mcp/tools/paste_text/):** `load_buffer` is the stage-then-fire path — you get a handle back and can inspect via [`show_buffer`](https://libtmux.org/en/py/latest/mcp/tools/show_buffer/), paste into multiple panes via [`paste_buffer`](https://libtmux.org/en/py/latest/mcp/tools/paste_buffer/), or hold the content for later. Use [`paste_text`](https://libtmux.org/en/py/latest/mcp/tools/paste_text/) for a simple one-shot paste with no follow-up. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/load_buffer.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/buffer_tools.py#L386) ## Arguments * `content` required · string The text to stage. Can be multi-line. Redacted in audit logs. * `logical_name` optional Short label for the buffer. Limited to \`\`\[A-Za-z0-9\_.-]{1,64}\`\` so the final name stays safe on the tmux command line. Empty or \`\`None\`\` uses \`\`"buf"\`\`. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "content": { "description": "The text to stage. Can be multi-line. Redacted in audit logs.", "type": "string" }, "logical_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Short label for the buffer. Limited to\n``[A-Za-z0-9_.-]{1,64}`` so the final name stays safe on the\ntmux command line. Empty or ``None`` uses ``\"buf\"``." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." } }, "required": [ "content" ], "type": "object" } ``` Output schema ```json { "description": "Handle returned by :func:`~libtmux_mcp.tools.buffer_tools.load_buffer`.\n\nAgent-created tmux paste buffers are namespaced with a per-call UUID\nto avoid collisions on the server-global buffer namespace when\nconcurrent agents (or parallel tool calls from a single agent) are\nstaging content. Callers must use the ``buffer_name`` this model\ncarries on subsequent\n:func:`~libtmux_mcp.tools.buffer_tools.paste_buffer`,\n:func:`~libtmux_mcp.tools.buffer_tools.show_buffer`, and\n:func:`~libtmux_mcp.tools.buffer_tools.delete_buffer` calls.", "properties": { "buffer_name": { "description": "The actual tmux buffer name (with prefix and UUID nonce). Pass this back to paste_buffer/show_buffer/delete_buffer.", "type": "string" }, "logical_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Optional logical name supplied by the caller, if any." } }, "required": [ "buffer_name" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # move_window Source: https://libtmux.org/en/py/latest/mcp/tools/move_window/ > Move a window to a different index or session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Move a window to a different index or session. Reorder windows within a session or move a window to another session. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/move_window.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/window_tools.py#L537) ## Arguments * `destination_index` optional · string Target window index. Default empty string (next available). Default: `""`. * `destination_session` optional Target session name or ID. Default is current session. Default: `null`. * `session_id` optional Source session ID. Default: `null`. * `session_name` optional Source session name. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID (e.g. '@1'). Default: `null`. * `window_index` optional Window index within the session. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "destination_index": { "default": "", "description": "Target window index. Default empty string (next available).", "type": "string" }, "destination_session": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Target session name or ID. Default is current session." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Source session ID." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Source session name." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID (e.g. '@1')." }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index within the session." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux window.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the window's active pane." }, "pane_count": { "description": "Number of panes", "type": "integer" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session name" }, "window_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "window_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "window_id": { "description": "Window ID (e.g. '@1')", "type": "string" }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index" }, "window_layout": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Layout string" }, "window_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window name" }, "window_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" } }, "required": [ "window_id", "pane_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # paste_buffer Source: https://libtmux.org/en/py/latest/mcp/tools/paste_buffer/ > Paste an MCP-owned buffer into a pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Paste an MCP-owned buffer into a pane. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/paste_buffer.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/buffer_tools.py#L391) ## Arguments * `bracket` optional · boolean Use tmux bracketed paste mode. Default True. Default: `true`. * `buffer_name` required · string Must match the full MCP-namespaced form returned by :func:\`\~libtmux_mcp.tools.buffer_tools.load_buffer\`. Non-MCP buffers are rejected so the tool cannot be turned into an arbitrary-buffer reader. * `pane_id` optional Target pane ID. Default: `null`. * `session_id` optional Pane resolution fallbacks. Default: `null`. * `session_name` optional Pane resolution fallbacks. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Pane resolution fallbacks. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "bracket": { "default": true, "description": "Use tmux bracketed paste mode. Default True.", "type": "boolean" }, "buffer_name": { "description": "Must match the full MCP-namespaced form returned by\n:func:`~libtmux_mcp.tools.buffer_tools.load_buffer`.\nNon-MCP buffers are rejected so the tool cannot be turned into\nan arbitrary-buffer reader.", "type": "string" }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Target pane ID." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane resolution fallbacks." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane resolution fallbacks." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane resolution fallbacks." } }, "required": [ "buffer_name" ], "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # paste_text Source: https://libtmux.org/en/py/latest/mcp/tools/paste_text/ > Paste multi-line text into a pane using tmux paste buffers. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Paste multi-line text into a pane using tmux paste buffers. Uses tmux’s load-buffer and paste-buffer for clean multi-line input, avoiding the issues of sending text line-by-line via [send_keys](https://libtmux.org/en/py/latest/mcp/tools/send_keys/). Supports bracketed paste mode for terminals that handle it. **When to use this vs. [load_buffer](https://libtmux.org/en/py/latest/mcp/tools/load_buffer/) + [paste_buffer](https://libtmux.org/en/py/latest/mcp/tools/paste_buffer/):** `paste_text` is the fire-and-forget path — the buffer is created, pasted, and deleted in one call. Use [`load_buffer`](https://libtmux.org/en/py/latest/mcp/tools/load_buffer/) + [`paste_buffer`](https://libtmux.org/en/py/latest/mcp/tools/paste_buffer/) when you need to stage content first, paste it into multiple panes, or inspect it with [`show_buffer`](https://libtmux.org/en/py/latest/mcp/tools/show_buffer/) before pasting. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/paste_text.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L194) ## Arguments * `bracket` optional · boolean Whether to use bracketed paste mode. Default True. Bracketed paste wraps the text in escape sequences that tell the terminal "this is pasted text, not typed input". Default: `true`. * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `text` required · string The text to paste. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "bracket": { "default": true, "description": "Whether to use bracketed paste mode. Default True.\nBracketed paste wraps the text in escape sequences that tell\nthe terminal \"this is pasted text, not typed input\".", "type": "boolean" }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "text": { "description": "The text to paste.", "type": "string" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "required": [ "text" ], "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # pipe_pane Source: https://libtmux.org/en/py/latest/mcp/tools/pipe_pane/ > Log a pane's live output to a file (or stop an active log). MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Log a pane’s live output to a file (or stop an active log). Streams everything written to the pane (stdout plus terminal control sequences) into a file on disk — the common use is `output_path="/tmp/pane.log"` to capture scrollback continuously while the agent watches for errors. When `output_path` is given, starts logging; when `output_path` is None, stops any active pipe for the pane. .. warning:: This tool writes to arbitrary filesystem paths chosen by the MCP client. There is no allow-list; the server will create files anywhere the server process has write access. Treat this as elevated-risk: it is the broadest-reach tool in `execute`. If you run libtmux-mcp on untrusted input, consider `LIBTMUX_TOOLSETS=inspect` or run the server under a user with a scoped home directory. See :doc:`/topics/trust` for the full footgun list. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/pipe_pane.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L174) ## Arguments * `append` optional · boolean Whether to append to the file. Default True. If False, overwrites. Default: `true`. * `output_path` optional File path to write output to. None stops piping. Default: `null`. * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "append": { "default": true, "description": "Whether to append to the file. Default True. If False, overwrites.", "type": "boolean" }, "output_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "File path to write output to. None stops piping." }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # rename_session Source: https://libtmux.org/en/py/latest/mcp/tools/rename_session/ > Rename a tmux session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Rename a tmux session. Use when a session’s purpose has changed. Existing pane_id references remain valid after renaming. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/rename_session.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/session_tools.py#L369) ## Arguments * `new_name` required · string New name for the session. * `session_id` optional Session ID (e.g. '$1') to look up. Default: `null`. * `session_name` optional Current session name to look up. Default: `null`. * `socket_name` optional tmux socket name. Defaults to LIBTMUX_SOCKET env var. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "new_name": { "description": "New name for the session.", "type": "string" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') to look up." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current session name to look up." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name. Defaults to LIBTMUX_SOCKET env var." } }, "required": [ "new_name" ], "type": "object" } ``` Output schema ```json { "description": "Serialized tmux session.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the session's active pane. Guaranteed non-None on ``create_session`` return (libtmux creates the session with one initial pane). May be None from ``list_sessions`` rows for sessions in transient teardown states where ``active_pane`` is unavailable." }, "session_attached": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Attached client count" }, "session_created": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Creation timestamp" }, "session_id": { "description": "Session ID (e.g. '$1')", "type": "string" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name" }, "window_count": { "description": "Number of windows", "type": "integer" } }, "required": [ "session_id", "window_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # rename_window Source: https://libtmux.org/en/py/latest/mcp/tools/rename_window/ > Rename a tmux window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Rename a tmux window. Use when a window’s purpose has changed. Existing window_id references remain valid after renaming. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/rename_window.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/window_tools.py#L517) ## Arguments * `new_name` required · string The new name for the window. * `session_id` optional Session ID. Default: `null`. * `session_name` optional Session name. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID (e.g. '@1'). Default: `null`. * `window_index` optional Window index within the session. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "new_name": { "description": "The new name for the window.", "type": "string" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID (e.g. '@1')." }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index within the session." } }, "required": [ "new_name" ], "type": "object" } ``` Output schema ```json { "description": "Serialized tmux window.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the window's active pane." }, "pane_count": { "description": "Number of panes", "type": "integer" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session name" }, "window_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "window_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "window_id": { "description": "Window ID (e.g. '@1')", "type": "string" }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index" }, "window_layout": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Layout string" }, "window_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window name" }, "window_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" } }, "required": [ "window_id", "pane_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # resize_pane Source: https://libtmux.org/en/py/latest/mcp/tools/resize_pane/ > Resize a tmux pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Resize a tmux pane. Use when adjusting layout for better readability or to fit content. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/resize_pane.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L111) ## Arguments * `height` optional New height in lines. Default: `null`. * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID (e.g. '$1') for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `width` optional New width in columns. Default: `null`. * `window_id` optional Window ID for pane resolution. Default: `null`. * `zoom` optional Toggle pane zoom. If True, zoom the pane. If False, unzoom. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "New height in lines." }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "width": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "New width in columns." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." }, "zoom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Toggle pane zoom. If True, zoom the pane. If False, unzoom." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # resize_window Source: https://libtmux.org/en/py/latest/mcp/tools/resize_window/ > Resize a tmux window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Resize a tmux window. Use to adjust the window dimensions. This affects all panes within the window. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/resize_window.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/window_tools.py#L532) ## Arguments * `height` optional New height in lines. Default: `null`. * `session_id` optional Session ID. Default: `null`. * `session_name` optional Session name. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `width` optional New width in columns. Default: `null`. * `window_id` optional Window ID (e.g. '@1'). Default: `null`. * `window_index` optional Window index within the session. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "New height in lines." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "width": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "New width in columns." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID (e.g. '@1')." }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index within the session." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux window.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the window's active pane." }, "pane_count": { "description": "Number of panes", "type": "integer" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session name" }, "window_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "window_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "window_id": { "description": "Window ID (e.g. '@1')", "type": "string" }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index" }, "window_layout": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Layout string" }, "window_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window name" }, "window_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" } }, "required": [ "window_id", "pane_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # respawn_pane Source: https://libtmux.org/en/py/latest/mcp/tools/respawn_pane/ > Restart a pane's process in place, preserving pane_id and layout. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Restart a pane’s process in place, preserving pane_id and layout. Use when a shell wedges (hung REPL, runaway process, bad terminal mode). The alternative — [kill_pane](https://libtmux.org/en/py/latest/mcp/tools/kill_pane/) + [split_window](https://libtmux.org/en/py/latest/mcp/tools/split_window/) — destroys pane_id references the agent may still be holding, and rearranges the layout. respawn-pane preserves both. With `kill=True` (the default), tmux kills the existing process before respawning. Optional `shell` replaces the command tmux relaunches; `start_directory` sets the working directory for the new process; `environment` sets per-process environment variables for the relaunched command (one `-e KEY=VALUE` flag per entry). `pane_id` is required — sibling pane tools accept a hierarchical fallback (`session_name` / `window_id` / `pane_index`) that resolves to “first pane in session/window”, but combined with default `kill=True` that fallback could silently kill an unrelated process. The signature deliberately omits the resolver fields so the FastMCP schema rejects them at the framework boundary. Resolve via [`list_panes`](https://libtmux.org/en/py/latest/mcp/tools/list_panes/) first. Tip: call [`get_pane_info`](https://libtmux.org/en/py/latest/mcp/tools/get_pane_info/) first if you need to capture `pane_current_command` before respawn — the new process loses its argv. Omitting `shell` makes tmux replay the original argv (good default for shells; may differ for processes spawned via custom shell at split time). [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/respawn_pane.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L121) ## Arguments * `environment` optional Environment variables to set for the relaunched process. Each item becomes one \`\`-e KEY=VALUE\`\` flag (tmux's \`\`cmd-respawn-pane.c\`\` supports the flag repeatedly). Values supplied in a mapping are redacted in the audit log on a per-key basis — keys like \`\`DATABASE_URL\`\` remain visible but their values are replaced by \`\`{len, sha256_prefix}\`\` digests. A JSON object string is redacted as one scalar digest, so its keys are not retained in the audit record. Values may still appear briefly in the OS process table while tmux spawns the new process; do not pass long-lived secrets here when a host-resident agent or other tenant could observe \`\`ps\`\`. Default: `null`. * `kill` optional · boolean When True (default), pass \`\`-k\`\` to tmux so the current process is killed before respawning. When False, respawn fails if the pane already has a running process. Default: `true`. * `pane_id` required · string Pane ID (e.g. '%1'). Required. * `shell` optional Replacement command for tmux to launch. When omitted, tmux replays the original argv (good default for shells; may differ for processes spawned via custom shell at split time). Matches the \`\`shell\`\` parameter on :func:\`split_window\` and the eventual upstream \`\`Pane.respawn(shell=)\`\` API. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `start_directory` optional Existing directory to start in. \`\`\~\`\` expands; a relative path resolves against the MCP server process's directory. Default: `null`. * `suppress_persistent_history` optional · boolean Whether to suppress persistent history for the spawned shell. Defaults to False for MCP and direct Python calls. This per-call option does not inherit LIBTMUX_SUPPRESS_HISTORY. Startup files may override these controls. Default: `false`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "environment": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "string" }, { "type": "null" } ], "default": null, "description": "Environment variables to set for the relaunched process. Each\nitem becomes one ``-e KEY=VALUE`` flag (tmux's\n``cmd-respawn-pane.c`` supports the flag repeatedly). Values\nsupplied in a mapping are redacted in the audit log on a\nper-key basis — keys like ``DATABASE_URL`` remain visible but\ntheir values are replaced by ``{len, sha256_prefix}`` digests.\nA JSON object string is redacted as one scalar digest, so its\nkeys are not retained in the audit record. Values may still\nappear briefly in the OS process table while tmux spawns the\nnew process; do not pass long-lived secrets here when a\nhost-resident agent or other tenant could observe ``ps``." }, "kill": { "default": true, "description": "When True (default), pass ``-k`` to tmux so the current\nprocess is killed before respawning. When False, respawn\nfails if the pane already has a running process.", "type": "boolean" }, "pane_id": { "description": "Pane ID (e.g. '%1'). Required.", "type": "string" }, "shell": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Replacement command for tmux to launch. When omitted, tmux\nreplays the original argv (good default for shells; may differ\nfor processes spawned via custom shell at split time). Matches\nthe ``shell`` parameter on :func:`split_window` and the\neventual upstream ``Pane.respawn(shell=)`` API." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "start_directory": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Existing directory to start in. ``~`` expands; a relative path\nresolves against the MCP server process's directory." }, "suppress_persistent_history": { "default": false, "description": "Whether to suppress persistent history for the spawned shell. Defaults\nto False for MCP and direct Python calls. This per-call option does not\ninherit LIBTMUX_SUPPRESS_HISTORY. Startup files may override these\ncontrols.", "type": "boolean" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # run_command Source: https://libtmux.org/en/py/latest/mcp/tools/run_command/ > Run a shell command in a pane, wait for completion, and capture output. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Run a shell command in a pane, wait for completion, and capture output. Use for the common terminal workflow: run this command, wait until it completes, then report whether it succeeded. The command is sent to the pane’s interactive shell, followed by a private `tmux wait-for` signal and a private pane option carrying the shell exit status. This is the AUTHORED-output path — the command you pass is what the wait synchronizes on. Reserve [`wait_for_text`](https://libtmux.org/en/py/latest/mcp/tools/wait_for_text/) for output you did not author: another process, a human, or a background job. The command runs in a subshell, so `cd`, `export` and other shell state changes do not persist to later calls. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/run_command.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L96) ## Arguments * `command` required · string Shell command to run in the target pane. * `max_lines` optional Maximum pane output lines to return. Defaults to all captured visible output; pass a small value for a tail-only summary. Default: `null`. * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID (e.g. '$1') for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `suppress_history` optional · boolean For MCP calls, omission uses the server's LIBTMUX_SUPPRESS_HISTORY default; an explicit value overrides it. Direct Python calls default to False. Best effort: the shell must honor space-prefixed history suppression. Suppression requires a single-line command; multiline commands remain available when suppression is false. Default: `true`. * `timeout` optional · number Maximum seconds to wait for command completion. Capped by the same server wait ceiling as \`\`wait_for_text\`\`; an over-large value is not an error — the wait returns at the ceiling and the timeout actually enforced is reported on \`\`RunCommandResult.effective_timeout\`\`. Default: `30`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "command": { "description": "Shell command to run in the target pane.", "type": "string" }, "max_lines": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Maximum pane output lines to return. Defaults to all captured\nvisible output; pass a small value for a tail-only summary." }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "suppress_history": { "default": true, "description": "For MCP calls, omission uses the server's LIBTMUX_SUPPRESS_HISTORY\ndefault; an explicit value overrides it. Direct Python calls default\nto False. Best effort: the shell must honor space-prefixed history\nsuppression. Suppression requires a single-line command; multiline\ncommands remain available when suppression is false.", "type": "boolean" }, "timeout": { "default": 30, "description": "Maximum seconds to wait for command completion. Capped by the\nsame server wait ceiling as ``wait_for_text``; an over-large\nvalue is not an error — the wait returns at the ceiling and\nthe timeout actually enforced is reported on\n``RunCommandResult.effective_timeout``.", "type": "number" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "required": [ "command" ], "type": "object" } ``` Output schema ```json { "description": "Result of running a shell command in a pane.", "properties": { "effective_timeout": { "description": "Seconds actually enforced for command completion. Server policy caps the requested ``timeout``; compare against what you passed to see a clamp.", "type": "number" }, "elapsed_seconds": { "description": "Time spent waiting in seconds", "type": "number" }, "exit_status": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Shell exit status, or None when the command timed out" }, "output": { "description": "Tail-preserved pane output after the wait completes", "items": { "type": "string" }, "type": "array" }, "output_truncated": { "default": false, "description": "True when output was tail-preserved to stay within max_lines", "type": "boolean" }, "output_truncated_lines": { "default": 0, "description": "Number of pane lines dropped from the head when truncating", "type": "integer" }, "pane_id": { "description": "Pane ID that received the command", "type": "string" }, "timed_out": { "description": "True when the wait timed out", "type": "boolean" } }, "required": [ "pane_id", "timed_out", "elapsed_seconds", "effective_timeout" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # search_panes Source: https://libtmux.org/en/py/latest/mcp/tools/search_panes/ > Search visible terminal text across all tmux panes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Search visible terminal text across all tmux panes. Use when the user asks what panes ‘contain’, ‘mention’, or ‘show’ — e.g. ‘find the pane with the pytest failure’. Searches each pane’s visible terminal scrollback content (not editor or browser text) and returns panes where the pattern is found, with matching lines. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/search_panes.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L146) ## Arguments * `content_end` optional End line for capture. Default: `null`. * `content_start` optional Start line for capture. Negative values reach into scrollback. Default: `null`. * `limit` optional Maximum matching panes returned on this call. Defaults to \`\`SEARCH_DEFAULT_LIMIT\`\`. Pass \`\`None\`\` to disable the cap. Default: `500`. * `match_case` optional · boolean Whether to match case. Default False (case-insensitive). Default: `false`. * `max_matched_lines_per_pane` optional · integer Per-pane cap on \`\`matched_lines\`\`. Defaults to \`\`SEARCH_DEFAULT_MAX_LINES_PER_PANE\`\`. Default: `50`. * `offset` optional · integer Skip this many matching panes from the start. Use with \`\`limit\`\` for pagination. Default: `0`. * `pattern` required · string Text to search for in pane contents. Treated as literal text by default. Set \`\`regex=True\`\` to interpret as a regular expression. * `regex` optional · boolean Whether to interpret pattern as a regular expression. Default False (literal text matching). Default: `false`. * `session_id` optional Limit search to panes in this session (by ID). Default: `null`. * `session_name` optional Limit search to panes in this session. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "content_end": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "End line for capture." }, "content_start": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Start line for capture. Negative values reach into scrollback." }, "limit": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": 500, "description": "Maximum matching panes returned on this call. Defaults to\n``SEARCH_DEFAULT_LIMIT``. Pass ``None`` to disable the cap." }, "match_case": { "default": false, "description": "Whether to match case. Default False (case-insensitive).", "type": "boolean" }, "max_matched_lines_per_pane": { "default": 50, "description": "Per-pane cap on ``matched_lines``. Defaults to\n``SEARCH_DEFAULT_MAX_LINES_PER_PANE``.", "type": "integer" }, "offset": { "default": 0, "description": "Skip this many matching panes from the start. Use with\n``limit`` for pagination.", "type": "integer" }, "pattern": { "description": "Text to search for in pane contents. Treated as literal text by\ndefault. Set ``regex=True`` to interpret as a regular expression.", "type": "string" }, "regex": { "default": false, "description": "Whether to interpret pattern as a regular expression. Default False\n(literal text matching).", "type": "boolean" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Limit search to panes in this session (by ID)." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Limit search to panes in this session." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." } }, "required": [ "pattern" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # select_layout Source: https://libtmux.org/en/py/latest/mcp/tools/select_layout/ > Set the layout of a tmux window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Set the layout of a tmux window. Choose from: even-horizontal, even-vertical, main-horizontal, main-vertical, or tiled. Rearranges all panes in the window. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/select_layout.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/window_tools.py#L527) ## Arguments * `layout` required · string Layout name or custom layout string. Built-in layouts: 'even-horizontal', 'even-vertical', 'main-horizontal', 'main-horizontal-mirrored', 'main-vertical', 'main-vertical-mirrored', 'tiled'. * `session_id` optional Session ID. Default: `null`. * `session_name` optional Session name. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID (e.g. '@1'). Default: `null`. * `window_index` optional Window index within the session. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "layout": { "description": "Layout name or custom layout string. Built-in layouts:\n'even-horizontal', 'even-vertical', 'main-horizontal',\n'main-horizontal-mirrored', 'main-vertical',\n'main-vertical-mirrored', 'tiled'.", "type": "string" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID (e.g. '@1')." }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index within the session." } }, "required": [ "layout" ], "type": "object" } ``` Output schema ```json { "description": "Serialized tmux window.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the window's active pane." }, "pane_count": { "description": "Number of panes", "type": "integer" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session name" }, "window_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "window_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "window_id": { "description": "Window ID (e.g. '@1')", "type": "string" }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index" }, "window_layout": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Layout string" }, "window_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window name" }, "window_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" } }, "required": [ "window_id", "pane_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # select_pane Source: https://libtmux.org/en/py/latest/mcp/tools/select_pane/ > Select (focus) a tmux pane by ID or direction. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Select (focus) a tmux pane by ID or direction. Use this to navigate between panes. Provide either pane_id for direct selection, or direction for relative navigation within a window. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/select_pane.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L164) ## Arguments * `direction` optional Relative direction: 'up', 'down', 'left', 'right', 'last' (previously active), 'next', or 'previous'. Default: `null`. * `pane_id` optional Pane ID (e.g. '%1') for direct selection. Default: `null`. * `session_id` optional Session ID for resolution. Default: `null`. * `session_name` optional Session name for resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID for directional navigation scope. Default: `null`. * `window_index` optional Window index for directional navigation scope. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "direction": { "anyOf": [ { "enum": [ "up", "down", "left", "right", "last", "next", "previous" ], "type": "string" }, { "type": "null" } ], "default": null, "description": "Relative direction: 'up', 'down', 'left', 'right', 'last'\n(previously active), 'next', or 'previous'." }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1') for direct selection." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID for resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for directional navigation scope." }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index for directional navigation scope." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # select_window Source: https://libtmux.org/en/py/latest/mcp/tools/select_window/ > Select (focus) a tmux window by ID, index, or direction. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Select (focus) a tmux window by ID, index, or direction. Use to navigate between windows. Provide window_id or window_index for direct selection, or direction for relative navigation. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/select_window.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/session_tools.py#L379) ## Arguments * `direction` optional Relative direction: 'next', 'previous', or 'last'. Default: `null`. * `session_id` optional Session ID for resolution. Default: `null`. * `session_name` optional Session name for resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID (e.g. '@1') for direct selection. Default: `null`. * `window_index` optional Window index for direct selection. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "direction": { "anyOf": [ { "enum": [ "next", "previous", "last" ], "type": "string" }, { "type": "null" } ], "default": null, "description": "Relative direction: 'next', 'previous', or 'last'." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID for resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID (e.g. '@1') for direct selection." }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index for direct selection." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux window.", "properties": { "active_pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane id (``%N``) of the window's active pane." }, "pane_count": { "description": "Number of panes", "type": "integer" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session name" }, "window_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "window_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "window_id": { "description": "Window ID (e.g. '@1')", "type": "string" }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index" }, "window_layout": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Layout string" }, "window_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window name" }, "window_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" } }, "required": [ "window_id", "pane_count" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # send_keys Source: https://libtmux.org/en/py/latest/mcp/tools/send_keys/ > Send keys (commands or text) to a tmux pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send keys (commands or text) to a tmux pane. Use this for raw interactive input: TUI keys, control sequences, partial shell input, or persistent shell state. Use [`send_keys_batch`](https://libtmux.org/en/py/latest/mcp/tools/send_keys_batch/) when you need several ordered raw-input operations. For authored shell commands that need completion, exit status, or captured output, use [`run_command`](https://libtmux.org/en/py/latest/mcp/tools/run_command/) instead. For custom completion outside that shape, compose `tmux wait-for -S ` into the shell command and call [`wait_for_channel`](https://libtmux.org/en/py/latest/mcp/tools/wait_for_channel/). For repeated observation after input, prefer [`capture_since`](https://libtmux.org/en/py/latest/mcp/tools/capture_since/); reserve [`wait_for_text`](https://libtmux.org/en/py/latest/mcp/tools/wait_for_text/) for output the agent does not author. Do NOT call [`capture_pane`](https://libtmux.org/en/py/latest/mcp/tools/capture_pane/) immediately — both the read and the pattern-match paths race the pane’s PTY draw. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/send_keys.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L82) ## Arguments * `enter` optional · boolean Whether to press Enter after sending keys. Default True. Default: `true`. * `keys` required · string The keys or text to send. * `literal` optional · boolean Whether to send keys literally (no tmux interpretation). Default False. Default: `false`. * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID (e.g. '$1') for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `suppress_history` optional · boolean Suppress shell history by prepending a space; only effective where the shell ignores space-prefixed commands. Default False. Default: `false`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enter": { "default": true, "description": "Whether to press Enter after sending keys. Default True.", "type": "boolean" }, "keys": { "description": "The keys or text to send.", "type": "string" }, "literal": { "default": false, "description": "Whether to send keys literally (no tmux interpretation). Default False.", "type": "boolean" }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "suppress_history": { "default": false, "description": "Suppress shell history by prepending a space; only effective where\nthe shell ignores space-prefixed commands. Default False.", "type": "boolean" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "required": [ "keys" ], "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # send_keys_batch Source: https://libtmux.org/en/py/latest/mcp/tools/send_keys_batch/ > Send an ordered batch of raw key/text operations to tmux panes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send an ordered batch of raw key/text operations to tmux panes. Use this for bulk TUI or persistent-shell input where each item is the same kind of low-level terminal interaction as :func:`~libtmux_mcp.tools.pane_tools.send_keys`. For authored shell commands that need exit status and captured output, use :func:`~libtmux_mcp.tools.pane_tools.run_command` instead. For repeated observation after sending input, use :func:`~libtmux_mcp.tools.pane_tools.capture_since` with its returned cursor. This tool intentionally does not compose heterogeneous operations such as send → wait → capture. Keeping the batch homogeneous preserves clear per-operation error attribution and avoids embedding a workflow DSL in the MCP tool surface. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/send_keys_batch.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L87) ## Arguments * `on_error` optional · string Whether to stop at the first failed operation or keep attempting later operations. Default "stop". Default: `"stop"`. * `operations` required · array Ordered raw-input operations to send. * `socket_name` optional tmux socket name. Default: `null`. * `timeout` optional Maximum time in seconds to allow the batch to run before aborting. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "on_error": { "default": "stop", "description": "Whether to stop at the first failed operation or keep attempting\nlater operations. Default \"stop\".", "enum": [ "stop", "continue" ], "type": "string" }, "operations": { "description": "Ordered raw-input operations to send.", "items": { "additionalProperties": false, "description": "One raw-input operation for batch sending.\n\nUsed by :func:`~libtmux_mcp.tools.pane_tools.send_keys_batch`.", "properties": { "enter": { "default": true, "description": "Whether to press Enter after sending keys.", "type": "boolean" }, "keys": { "description": "Keys or text to send.", "type": "string" }, "literal": { "default": false, "description": "Whether to send keys literally with no tmux key interpretation.", "type": "boolean" }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "suppress_history": { "default": false, "description": "Suppress shell history by prepending a space where the shell ignores space-prefixed commands.", "type": "boolean" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "required": [ "keys" ], "type": "object" }, "type": "array" }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "timeout": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "default": null, "description": "Maximum time in seconds to allow the batch to run before aborting." } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "description": "Structured result for a batch of raw-input send operations.", "properties": { "failed": { "description": "Number of operations that failed.", "type": "integer" }, "results": { "description": "Per-operation results in attempted order.", "items": { "description": "Per-operation result from batch sending.\n\nReturned by :func:`~libtmux_mcp.tools.pane_tools.send_keys_batch`.", "properties": { "elapsed_seconds": { "description": "Time spent on this operation.", "type": "number" }, "error": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Error message for this operation, if it failed." }, "index": { "description": "Zero-based index in the submitted operation list.", "type": "integer" }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Resolved pane ID, or None if target resolution failed." }, "success": { "description": "True when this operation sent successfully.", "type": "boolean" } }, "required": [ "index", "success", "elapsed_seconds" ], "type": "object" }, "type": "array" }, "stopped_at": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Index where processing stopped because on_error='stop', or None when all operations were attempted." }, "succeeded": { "description": "Number of operations sent successfully.", "type": "integer" } }, "required": [ "succeeded", "failed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # set_environment Source: https://libtmux.org/en/py/latest/mcp/tools/set_environment/ > Set a tmux environment variable. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Set a tmux environment variable. Use to set variables that will be inherited by new panes and windows. Changes do not affect already-running processes. Some variables control later shell execution. Bash sources the file named by `BASH_ENV`, POSIX shells may source the file named by `ENV`, and Bash evaluates `PROMPT_COMMAND` before displaying a prompt. .. warning:: Values set here propagate into **every** shell tmux later spawns in the targeted scope — including panes the user opens manually, not just panes the agent drives. A caller that writes `PATH`, `LD_PRELOAD`, or `AWS_*` variables can influence future commands the human user types directly. Treat this as elevated-risk within `execute`. The audit log redacts the `value` argument, but the side effects persist on disk/memory until tmux is restarted. Prefer `env VAR=value command` via :func:`~libtmux_mcp.tools.pane_tools.send_keys` when you only need the override for a single command. See :doc:`/topics/trust`. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/set_environment.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/env_tools.py#L130) ## Arguments * `name` required · string Environment variable name. * `session_id` optional Session ID to set environment for. Default: `null`. * `session_name` optional Session name to set environment for. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `value` required · string Environment variable value. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Environment variable name.", "type": "string" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID to set environment for." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name to set environment for." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "value": { "description": "Environment variable value.", "type": "string" } }, "required": [ "name", "value" ], "type": "object" } ``` Output schema ```json { "description": "Result of a set_environment call.", "properties": { "name": { "description": "Variable name", "type": "string" }, "status": { "description": "Operation status", "type": "string" }, "value": { "description": "Value that was set", "type": "string" } }, "required": [ "name", "value", "status" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # set_option Source: https://libtmux.org/en/py/latest/mcp/tools/set_option/ > Set a tmux option value. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Set a tmux option value. Some option values are executable. tmux runs a `#(...)` job inside the status formats when it draws them, and repeats it on the status interval; `default-command` and `default-shell` decide what every future pane runs, and `command-alias` rewrites later commands. The value is stored verbatim, so an option that interprets it later runs what is stored, not what this call did. Use to change tmux behavior at runtime. Common uses: adjusting history-limit, enabling mouse support, changing status bar format. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/set_option.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/option_tools.py#L158) ## Arguments * `global_` optional · boolean Whether to set the global option. Default: `false`. * `option` required · string The tmux option name to set. * `scope` optional Option scope. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `target` optional Target identifier. For session scope: session name (e.g. 'mysession'). For window scope: window ID (e.g. '@1'). For pane scope: pane ID (e.g. '%1'). Requires scope. Default: `null`. * `value` required · string The value to set. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "global_": { "default": false, "description": "Whether to set the global option.", "type": "boolean" }, "option": { "description": "The tmux option name to set.", "type": "string" }, "scope": { "anyOf": [ { "enum": [ "server", "session", "window", "pane" ], "type": "string" }, { "type": "null" } ], "default": null, "description": "Option scope." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "target": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Target identifier. For session scope: session name\n(e.g. 'mysession'). For window scope: window ID (e.g. '@1').\nFor pane scope: pane ID (e.g. '%1'). Requires scope." }, "value": { "description": "The value to set.", "type": "string" } }, "required": [ "option", "value" ], "type": "object" } ``` Output schema ```json { "description": "Result of a set_option call.", "properties": { "option": { "description": "Option name", "type": "string" }, "status": { "description": "Operation status", "type": "string" }, "value": { "description": "Value that was set", "type": "string" } }, "required": [ "option", "value", "status" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # set_pane_title Source: https://libtmux.org/en/py/latest/mcp/tools/set_pane_title/ > Set the title of a tmux pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Set the title of a tmux pane. Use titles to label panes for later identification via [list_panes](https://libtmux.org/en/py/latest/mcp/tools/list_panes/) or [get_pane_info](https://libtmux.org/en/py/latest/mcp/tools/get_pane_info/). [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/set_pane_title.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L126) ## Arguments * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID (e.g. '$1') for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `title` required · string The new pane title. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "title": { "description": "The new pane title.", "type": "string" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "required": [ "title" ], "type": "object" } ``` Output schema ```json { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # show_buffer Source: https://libtmux.org/en/py/latest/mcp/tools/show_buffer/ > Read back the contents of an MCP-owned buffer. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read back the contents of an MCP-owned buffer. Output is tail-preserved: when the buffer exceeds `max_lines` the oldest lines are dropped and :attr:`~libtmux_mcp.models.BufferContent.content_truncated` is set so the caller can tell truncation happened and opt in to a full read via `max_lines=None`. This mirrors [`capture_pane`](https://libtmux.org/en/py/latest/mcp/tools/capture_pane/) — one consistent bounded-output contract across read-heavy tools so a pathological [`load_buffer`](https://libtmux.org/en/py/latest/mcp/tools/load_buffer/) staging cannot blow the agent’s context window on a single `show_buffer` call. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/show_buffer.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/buffer_tools.py#L396) ## Arguments * `buffer_name` required · string Must match the full MCP-namespaced form. * `max_lines` optional Maximum number of lines to return. Defaults to :data:\`SHOW_BUFFER_DEFAULT_MAX_LINES\`. Pass \`\`None\`\` for no truncation. Default: `500`. * `socket_name` optional tmux socket name. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "buffer_name": { "description": "Must match the full MCP-namespaced form.", "type": "string" }, "max_lines": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": 500, "description": "Maximum number of lines to return. Defaults to\n:data:`SHOW_BUFFER_DEFAULT_MAX_LINES`. Pass ``None`` for no\ntruncation." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." } }, "required": [ "buffer_name" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # show_environment Source: https://libtmux.org/en/py/latest/mcp/tools/show_environment/ > Show tmux environment variables. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Show tmux environment variables. Use to inspect tmux environment variables that affect child processes. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/show_environment.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/env_tools.py#L125) ## Arguments * `session_id` optional Session ID to query environment for. Default: `null`. * `session_name` optional Session name to query environment for. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID to query environment for." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name to query environment for." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." } }, "type": "object" } ``` Output schema ```json { "description": "Result of a show_environment call.", "properties": { "variables": { "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "boolean" } ] }, "description": "Environment variable mapping", "type": "object" } }, "required": [ "variables" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # show_hook Source: https://libtmux.org/en/py/latest/mcp/tools/show_hook/ > Look up a specific tmux hook by name. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Look up a specific tmux hook by name. Returns a :class:`~libtmux_mcp.models.HookListResult` with zero or more :class:`~libtmux_mcp.models.HookEntry` rows — zero if the hook is unset, one if it is a scalar hook, and multiple if it is an array hook with sparse indices. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/show_hook.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/hook_tools.py#L248) ## Arguments * `global_` optional · boolean :func:\`\~libtmux_mcp.tools.hook_tools.show_hooks\`. Default: `false`. * `hook_name` required · string Hook to look up (e.g. \`\`"pane-exited"\`\`). * `scope` optional :func:\`\~libtmux_mcp.tools.hook_tools.show_hooks\`. Default: `null`. * `socket_name` optional :func:\`\~libtmux_mcp.tools.hook_tools.show_hooks\`. Default: `null`. * `target` optional :func:\`\~libtmux_mcp.tools.hook_tools.show_hooks\`. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "global_": { "default": false, "description": ":func:`~libtmux_mcp.tools.hook_tools.show_hooks`.", "type": "boolean" }, "hook_name": { "description": "Hook to look up (e.g. ``\"pane-exited\"``).", "type": "string" }, "scope": { "anyOf": [ { "enum": [ "server", "session", "window", "pane" ], "type": "string" }, { "type": "null" } ], "default": null, "description": ":func:`~libtmux_mcp.tools.hook_tools.show_hooks`." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": ":func:`~libtmux_mcp.tools.hook_tools.show_hooks`." }, "target": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": ":func:`~libtmux_mcp.tools.hook_tools.show_hooks`." } }, "required": [ "hook_name" ], "type": "object" } ``` Output schema ```json { "description": "Structured result for hook introspection.\n\nReturned by :func:`~libtmux_mcp.tools.hook_tools.show_hooks` and\n:func:`~libtmux_mcp.tools.hook_tools.show_hook`.\nFlat list of :class:`~libtmux_mcp.models.HookEntry` instances so\nMCP clients can iterate without caring whether the underlying tmux\nhook is scalar or array-shaped.", "properties": { "entries": { "items": { "description": "One entry in a tmux hook array.\n\nHooks like ``session-renamed`` are arrays — they can have multiple\ncommands registered at sparse indices.\n:class:`~libtmux_mcp.models.HookEntry` flattens one index+command\npair into a serialisable row.", "properties": { "command": { "description": "tmux command string registered at that index.", "type": "string" }, "hook_name": { "description": "Hook name (e.g. 'pane-exited').", "type": "string" }, "index": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Array index for array-style hooks (e.g. session-renamed[3]). ``None`` for scalar hooks." } }, "required": [ "hook_name", "command" ], "type": "object" }, "type": "array" } }, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # show_hooks Source: https://libtmux.org/en/py/latest/mcp/tools/show_hooks/ > List configured tmux hooks at the given scope. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List configured tmux hooks at the given scope. `scope="server"` enumerates hooks installed via `tmux set-hook -g ...`. tmux splits those globals across two options trees by hook category: session-level hooks (`session-closed`, `client-*`, etc.) live in the global-session tree enumerated by `show-hooks -g`, while pane/window-level hooks (`pane-focus-in`, `window-resized`, etc.) live in the global-window tree enumerated by `show-hooks -gw`. This tool consults both trees and merges the results so the enumeration matches what a name-targeted :func:`~libtmux_mcp.tools.hook_tools.show_hook` call would return. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/show_hooks.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/hook_tools.py#L243) ## Arguments * `global_` optional · boolean Pass \`\`-g\`\` to query global hooks. Default False. Default: `false`. * `scope` optional Hook scope (server/session/window/pane). Defaults to the calling object's scope when a \`\`target\`\` is given. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `target` optional Target identifier. For session scope: session name. For window scope: window ID. For pane scope: pane ID. Requires \`\`scope\`\`. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "global_": { "default": false, "description": "Pass ``-g`` to query global hooks. Default False.", "type": "boolean" }, "scope": { "anyOf": [ { "enum": [ "server", "session", "window", "pane" ], "type": "string" }, { "type": "null" } ], "default": null, "description": "Hook scope (server/session/window/pane). Defaults to the\ncalling object's scope when a ``target`` is given." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "target": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Target identifier. For session scope: session name. For window\nscope: window ID. For pane scope: pane ID. Requires ``scope``." } }, "type": "object" } ``` Output schema ```json { "description": "Structured result for hook introspection.\n\nReturned by :func:`~libtmux_mcp.tools.hook_tools.show_hooks` and\n:func:`~libtmux_mcp.tools.hook_tools.show_hook`.\nFlat list of :class:`~libtmux_mcp.models.HookEntry` instances so\nMCP clients can iterate without caring whether the underlying tmux\nhook is scalar or array-shaped.", "properties": { "entries": { "items": { "description": "One entry in a tmux hook array.\n\nHooks like ``session-renamed`` are arrays — they can have multiple\ncommands registered at sparse indices.\n:class:`~libtmux_mcp.models.HookEntry` flattens one index+command\npair into a serialisable row.", "properties": { "command": { "description": "tmux command string registered at that index.", "type": "string" }, "hook_name": { "description": "Hook name (e.g. 'pane-exited').", "type": "string" }, "index": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Array index for array-style hooks (e.g. session-renamed[3]). ``None`` for scalar hooks." } }, "required": [ "hook_name", "command" ], "type": "object" }, "type": "array" } }, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # show_option Source: https://libtmux.org/en/py/latest/mcp/tools/show_option/ > Show a tmux option value. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Show a tmux option value. Use to check tmux configuration values such as history-limit, mouse support, or status bar settings. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/show_option.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/option_tools.py#L153) ## Arguments * `global_` optional · boolean Whether to query the global option. Default: `false`. * `option` required · string The tmux option name to query. * `scope` optional Option scope. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `target` optional Target identifier. For session scope: session name (e.g. 'mysession'). For window scope: window ID (e.g. '@1'). For pane scope: pane ID (e.g. '%1'). Requires scope. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "global_": { "default": false, "description": "Whether to query the global option.", "type": "boolean" }, "option": { "description": "The tmux option name to query.", "type": "string" }, "scope": { "anyOf": [ { "enum": [ "server", "session", "window", "pane" ], "type": "string" }, { "type": "null" } ], "default": null, "description": "Option scope." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "target": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Target identifier. For session scope: session name\n(e.g. 'mysession'). For window scope: window ID (e.g. '@1').\nFor pane scope: pane ID (e.g. '%1'). Requires scope." } }, "required": [ "option" ], "type": "object" } ``` Output schema ```json { "description": "Result of a show_option call.", "properties": { "option": { "description": "Option name", "type": "string" }, "value": { "description": "Option value" } }, "required": [ "option", "value" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # signal_channel Source: https://libtmux.org/en/py/latest/mcp/tools/signal_channel/ > Signal a tmux ``wait-for`` channel, waking blocked waiters. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Signal a tmux `wait-for` channel, waking blocked waiters. With no current waiter, tmux records one pending signal for the next waiter to consume. Signalling that channel again clears it. A woken waiter continues whatever work follows its wait. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/signal_channel.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/wait_for_tools.py#L327) ## Arguments * `channel` required · string Channel name. Must match \`\`^\[A-Za-z0-9\_.:-]{1,128}$\`\`. * `socket_name` optional tmux socket name. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "Channel name. Must match ``^[A-Za-z0-9_.:-]{1,128}$``.", "type": "string" }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # snapshot_pane Source: https://libtmux.org/en/py/latest/mcp/tools/snapshot_pane/ > Snapshot a tmux pane: visible terminal output, cursor, mode, scroll. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Snapshot a tmux pane: visible terminal output, cursor, mode, scroll. Use for terminal-contents inspection — ‘what’s in my pane’, ‘the current shell output’ — not editor panes or browser viewports. Returns everything :func:`~libtmux_mcp.tools.pane_tools.capture_pane` and :func:`~libtmux_mcp.tools.pane_tools.get_pane_info` return, plus cursor position, copy-mode state, and scroll position — in a single call. Prefer this over separate [capture_pane](https://libtmux.org/en/py/latest/mcp/tools/capture_pane/) + [get_pane_info](https://libtmux.org/en/py/latest/mcp/tools/get_pane_info/) calls when you need to reason about cursor location or pane mode. The `content` field is tail-preserved: when the captured pane exceeds `max_lines`, the oldest lines are dropped and the result is reported via `content_truncated` / `content_truncated_lines` fields on the returned :class:`~libtmux_mcp.models.PaneSnapshot`. Pass `max_lines=None` to opt out of truncation entirely. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/snapshot_pane.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L158) ## Arguments * `max_lines` optional Maximum number of content lines to return. Defaults to \`\`CAPTURE_DEFAULT_MAX_LINES\`\`. Pass \`\`None\`\` to return the full capture untrimmed. Default: `500`. * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `session_id` optional Session ID (e.g. '$1') for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "max_lines": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": 500, "description": "Maximum number of content lines to return. Defaults to\n``CAPTURE_DEFAULT_MAX_LINES``.\nPass ``None`` to return the full capture untrimmed." }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # split_window Source: https://libtmux.org/en/py/latest/mcp/tools/split_window/ > Split a tmux window to create a new pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Split a tmux window to create a new pane. Creates a new pane by splitting an existing one. Use direction to choose above/below/left/right. Returns the new pane’s info including its pane_id. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/split_window.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/window_tools.py#L512) ## Arguments * `direction` optional Split direction. Default: `null`. * `environment` optional Per-process environment as a mapping or JSON object string. Values do not modify the tmux session environment. Each item becomes a tmux \`\`-e\`\` launch option. Values may be visible to host process inspection in the tmux client argv during launch and in the child environment afterward; MCP audit redaction does not hide either surface. Pass credential references, not literal credentials. Default: `null`. * `pane_id` optional Pane ID to split from. If given, splits adjacent to this pane. Default: `null`. * `session_id` optional Session ID (e.g. '$1'). Default: `null`. * `session_name` optional Session name. Default: `null`. * `shell` optional Shell command to run in the new pane. Default: `null`. * `size` optional Size of the new pane. Use a string with '%%' suffix for percentage (e.g. '50%%') or an integer for lines/columns. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `start_directory` optional Existing directory to start in. \`\`\~\`\` expands; a relative path resolves against the MCP server process's directory. Default: `null`. * `suppress_persistent_history` optional · boolean Whether to suppress persistent history for the spawned shell. Defaults to False for MCP and direct Python calls. This per-call option does not inherit LIBTMUX_SUPPRESS_HISTORY. Startup files may override these controls. Default: `false`. * `window_id` optional Window ID (e.g. '@1'). Default: `null`. * `window_index` optional Window index within the session. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "direction": { "anyOf": [ { "enum": [ "above", "below", "left", "right" ], "type": "string" }, { "type": "null" } ], "default": null, "description": "Split direction." }, "environment": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "string" }, { "type": "null" } ], "default": null, "description": "Per-process environment as a mapping or JSON object string. Values do\nnot modify the tmux session environment. Each item becomes a tmux\n``-e`` launch option. Values may be visible to host process inspection\nin the tmux client argv during launch and in the child environment\nafterward; MCP audit redaction does not hide either surface. Pass\ncredential references, not literal credentials." }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID to split from. If given, splits adjacent to this pane." }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1')." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name." }, "shell": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Shell command to run in the new pane." }, "size": { "anyOf": [ { "type": "string" }, { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Size of the new pane. Use a string with '%%' suffix for\npercentage (e.g. '50%%') or an integer for lines/columns." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "start_directory": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Existing directory to start in. ``~`` expands; a relative path\nresolves against the MCP server process's directory." }, "suppress_persistent_history": { "default": false, "description": "Whether to suppress persistent history for the spawned shell. Defaults\nto False for MCP and direct Python calls. This per-call option does not\ninherit LIBTMUX_SUPPRESS_HISTORY. Startup files may override these\ncontrols.", "type": "boolean" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID (e.g. '@1')." }, "window_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window index within the session." } }, "type": "object" } ``` Output schema ```json { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # swap_pane Source: https://libtmux.org/en/py/latest/mcp/tools/swap_pane/ > Swap the positions of two panes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Swap the positions of two panes. Exchanges the visual positions of two panes. Both panes must exist. Use this to rearrange pane layout without changing content. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/swap_pane.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L169) ## Arguments * `socket_name` optional tmux socket name. Default: `null`. * `source_pane_id` required · string Pane ID of the first pane (e.g. '%1'). * `target_pane_id` required · string Pane ID of the second pane (e.g. '%2'). ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "source_pane_id": { "description": "Pane ID of the first pane (e.g. '%1').", "type": "string" }, "target_pane_id": { "description": "Pane ID of the second pane (e.g. '%2').", "type": "string" } }, "required": [ "source_pane_id", "target_pane_id" ], "type": "object" } ``` Output schema ```json { "description": "Serialized tmux pane.", "properties": { "is_caller": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "MCP caller identity for this pane. ``True`` when the pane matches the caller's ``TMUX_PANE`` *and* lives on the same tmux socket as the caller's ``TMUX`` (verified via socket realpath); ``False`` otherwise, including the case where the pane id matches but the socket does not or cannot be proven to; ``None`` when the MCP process is not running inside tmux at all." }, "pane_active": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Active flag ('1' or '0')" }, "pane_at_bottom": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's bottom edge." }, "pane_at_left": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's left edge." }, "pane_at_right": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's right edge." }, "pane_at_top": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "True when the pane touches the window's top edge. tmux accounts for ``pane-border-status`` here, so the top row may be 1 instead of 0 when the status bar is at the top." }, "pane_bottom": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Bottom edge row (inclusive), window-relative." }, "pane_current_command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Running command" }, "pane_current_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Current working directory" }, "pane_height": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Height in rows" }, "pane_id": { "description": "Pane ID (e.g. '%1')", "type": "string" }, "pane_index": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane index" }, "pane_left": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Left edge column, 0-based and window-relative." }, "pane_pid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Process ID" }, "pane_right": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Right edge column (inclusive), window-relative." }, "pane_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane title" }, "pane_top": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Top edge row, 0-based and window-relative." }, "pane_tty": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "TTY device path of the pane (e.g. '/dev/pts/5')." }, "pane_width": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Width in columns" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent session ID" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Parent window ID" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # wait_for_channel Source: https://libtmux.org/en/py/latest/mcp/tools/wait_for_channel/ > Block until a tmux ``wait-for`` channel is signalled. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Block until a tmux `wait-for` channel is signalled. This is the AUTHORED-output synchronisation primitive: the channel only fires because your own composed shell command signals it. Reserve [`wait_for_text`](https://libtmux.org/en/py/latest/mcp/tools/wait_for_text/) for output you did not author. Agents can compose this with [`send_keys`](https://libtmux.org/en/py/latest/mcp/tools/send_keys/) to turn shell-side milestones into explicit synchronisation points:: ```plaintext send_keys( "pytest; tmux wait-for -S tests_done", pane_id=..., ) wait_for_channel("tests_done", timeout=60) ``` Shell `;` semantics fire `wait-for -S` whether the command succeeded or failed, so the edge-triggered signal never deadlocks on a crash. Do NOT chain `exit $status` after the signal — in an interactive shell that exits the shell itself, which destroys single-pane sessions. Exit-status preservation in interactive shells is out-of-scope; inspect the captured output for command-specific success markers. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/wait_for_channel.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/wait_for_tools.py#L322) ## Arguments * `channel` required · string Channel name. Must match \`\`^\[A-Za-z0-9\_.:-]{1,128}$\`\`. * `socket_name` optional tmux socket name. Default: `null`. * `timeout` optional · number Maximum seconds to wait. The underlying \`\`tmux wait-for\`\` has no built-in timeout — this wrapper enforces it by killing the tmux child, which also happens if the call is cancelled. Defaults to 30 seconds. Capped by the same server wait ceiling as \`\`wait_for_text\`\`; an over-large value is not an error, the wait returns at the ceiling and the confirmation message names the timeout that was actually enforced. Default: `30`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "Channel name. Must match ``^[A-Za-z0-9_.:-]{1,128}$``.", "type": "string" }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "timeout": { "default": 30, "description": "Maximum seconds to wait. The underlying ``tmux wait-for`` has\nno built-in timeout — this wrapper enforces it by killing the\ntmux child, which also happens if the call is cancelled.\nDefaults to 30 seconds. Capped by the same server wait ceiling\nas ``wait_for_text``; an over-large value is not an error, the\nwait returns at the ceiling and the confirmation message names\nthe timeout that was actually enforced.", "type": "number" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "properties": { "result": { "type": "string" } }, "required": [ "result" ], "type": "object", "x-fastmcp-wrap-result": true } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # wait_for_text Source: https://libtmux.org/en/py/latest/mcp/tools/wait_for_text/ > Wait for NEW output in a tmux pane, then return. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Wait for NEW output in a tmux pane, then return. Polls until one of `patterns` appears on a line written *after* this call starts, one of `stop` appears (immediate failure exit), or the timeout expires. Pass `patterns=null` to wait for any new output at all. Use this instead of polling [`capture_pane`](https://libtmux.org/en/py/latest/mcp/tools/capture_pane/) in a loop. Pre-existing scrollback is never matched, and neither is paint left below the cursor at entry — only rows written after the call began count. If a pattern was already on screen the result says so via `matched_at_entry`. **Last resort: reserve for output you did not author.** Commands you send are AUTHORED — use [`run_command`](https://libtmux.org/en/py/latest/mcp/tools/run_command/) (returns exit status) or compose `; tmux wait-for -S ` with [`wait_for_channel`](https://libtmux.org/en/py/latest/mcp/tools/wait_for_channel/) instead, both cheaper and exact. For unattributable recurring prompts or background log lines, bracket your own command with a unique sentinel (`cmd; echo __WAIT_$RANDOM__`) and wait for that. `stop` is the cheap way to avoid burning the whole budget: pass the failure markers you already know (`"error:"`, `"FAILED"`, `"Traceback"`) and a failed run returns in milliseconds instead of at the ceiling. The server caps `timeout`. An over-large value is not an error — the wait returns at the ceiling and reports `effective_timeout`. [All Python tools](https://libtmux.org/en/py/latest/mcp/tools/) · [JSON](https://libtmux.org/en/py/latest/mcp/tools/wait_for_text.json) · [Source](https://github.com/tmux-python/libtmux-mcp/blob/4daddc0dfca96c43bf521d818bf91564e1434760/src/libtmux_mcp/tools/pane_tools/__init__.py#L153) ## Arguments * `interval` optional · number Seconds between polls. Default 0.05 (50ms). Minimum 0.01. Default: `0.05`. * `match_case` optional · boolean Whether to match case. Default False (case-insensitive). Default: `false`. * `pane_id` optional Pane ID (e.g. '%1'). Default: `null`. * `patterns` optional Success patterns; the first one to match ends the wait. Literal text unless \`\`regex=True\`\`. Omit or pass \`\`null\`\` to wait for any new output. Default: `null`. * `regex` optional · boolean Interpret \`\`patterns\`\` and \`\`stop\`\` as regular expressions. Default False (literal text). Default: `false`. * `session_id` optional Session ID (e.g. '$1') for pane resolution. Default: `null`. * `session_name` optional Session name for pane resolution. Default: `null`. * `socket_name` optional tmux socket name. Default: `null`. * `stop` optional Failure patterns. A hit ends the wait immediately with \`\`outcome="stopped"\`\` and \`\`found=false\`\`; \`\`matched_index\`\` says which entry fired. Default: `null`. * `timeout` optional · number Requested seconds to wait. Default 8.0. Clamped by server policy; see \`\`effective_timeout\`\` in the result. Default: `8`. * `window_id` optional Window ID for pane resolution. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "interval": { "default": 0.05, "description": "Seconds between polls. Default 0.05 (50ms). Minimum 0.01.", "type": "number" }, "match_case": { "default": false, "description": "Whether to match case. Default False (case-insensitive).", "type": "boolean" }, "pane_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Pane ID (e.g. '%1')." }, "patterns": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "default": null, "description": "Success patterns; the first one to match ends the wait.\nLiteral text unless ``regex=True``. Omit or pass ``null`` to\nwait for any new output." }, "regex": { "default": false, "description": "Interpret ``patterns`` and ``stop`` as regular expressions.\nDefault False (literal text).", "type": "boolean" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session ID (e.g. '$1') for pane resolution." }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Session name for pane resolution." }, "socket_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "tmux socket name." }, "stop": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "default": null, "description": "Failure patterns. A hit ends the wait immediately with\n``outcome=\"stopped\"`` and ``found=false``; ``matched_index``\nsays which entry fired." }, "timeout": { "default": 8, "description": "Requested seconds to wait. Default 8.0. Clamped by server\npolicy; see ``effective_timeout`` in the result.", "type": "number" }, "window_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Window ID for pane resolution." } }, "type": "object" } ``` Output schema ```json { "description": "Result of a bounded wait for new pane output.\n\nDeliberately free of inference. Every field is something the tool\nobserved directly — a match, a clock reading, a tmux flag. There is\nno \"likely cause\", no \"next action\", no quiescence verdict: a\nconfidently-wrong diagnosis costs the agent more than an honest\n\"nothing appeared, here is what the pane shows\".\n\nField count is load-bearing. ``outputSchema`` is re-sent on every\nrequest of every session, so a field that no agent branches on is a\npermanent tax. ``outcome`` carries what three separate booleans\ncarried before it.", "properties": { "alternate_screen": { "default": false, "description": "True when the pane was on the terminal's alternate screen at any point during the wait.", "type": "boolean" }, "effective_timeout": { "description": "Seconds actually enforced. Server policy caps the requested ``timeout``; compare against what you passed to see a clamp.", "type": "number" }, "elapsed_seconds": { "description": "Time spent waiting in seconds", "type": "number" }, "found": { "description": "True when a ``patterns`` entry matched new output, or, with ``patterns=null``, when any new output appeared.", "type": "boolean" }, "matched_at_entry": { "default": false, "description": "True when ``patterns`` already matched on-screen text before the wait began and nothing new matched after. The wait holds out for a FRESH occurrence, so re-running a command whose output looks identical still works. Read it as: the text is there, but it predates your call.", "type": "boolean" }, "matched_index": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Zero-based index into ``patterns``, or into ``stop`` when ``outcome`` is ``stopped``. Null otherwise." }, "matched_lines": { "description": "Newly-written lines that matched (empty on timeout).", "items": { "type": "string" }, "type": "array" }, "outcome": { "description": "How the wait ended. ``matched``: a ``patterns`` entry hit. ``any_output``: ``patterns`` was omitted and something — possibly just a prompt repaint — was written; read it as 'the pane moved', never as 'the command finished'. ``stopped``: a ``stop`` failure marker hit. ``alternate_screen``: the pane was under a pager, editor, or full-screen TUI, which repaints the whole grid, so matching was suppressed — read the screen with snapshot_pane instead of retrying. ``timeout``: nothing matched in the budget.", "enum": [ "matched", "any_output", "stopped", "alternate_screen", "timeout" ], "type": "string" }, "pane_id": { "description": "Pane ID that was polled", "type": "string" }, "saw_new_output": { "default": false, "description": "True when content was written on or below the entry cursor row. Read it with ``found=false``: true means output arrived and did not match — read ``tail`` and fix the pattern; false means the pane was quiet — suspect the command never ran, or check ``alternate_screen``.", "type": "boolean" }, "tail": { "description": "Rows from the entry cursor row down at the final poll, tail-limited by lines and bytes. Includes stale rows excluded from matching, so it shows what the pane looks like, not what matched. On a timeout this usually already contains the answer — read it before retrying with a different pattern.", "items": { "type": "string" }, "type": "array" } }, "required": [ "found", "outcome", "pane_id", "elapsed_seconds", "effective_timeout" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # TypeScript MCP tools Source: https://libtmux.org/en/ts/latest/mcp/tools/ > Tools, resources, and prompts advertised by the TypeScript MCP server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Use the wire name shown here when calling a tool. The TypeScript server advertises 45 tools with the reference configuration below. Your client’s list follows the policy configured for its server. Read the [setup guide](https://libtmux.org/en/ts/latest/mcp/guides/) before choosing tool access. The [language API reference](https://libtmux.org/en/ts/latest/mcp/reference/) covers embedding and implementation types. [Download the protocol catalog as JSON](https://libtmux.org/en/ts/latest/mcp/tools.json). Reference configuration * `LIBTMUX_TOOLSETS` `inspect,manage,execute,teardown` Protocol version: `2025-11-25`. ## Tools * [`call_read_tools_batch`](https://libtmux.org/en/ts/latest/mcp/tools/call_read_tools_batch/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Invoke a serial batch of at most 16 inspect tools. One client approval covers every nested name; inner tools receive no separate approval. The structured result is capped below 1,000,000 bytes, preserves every operation row, and reports explicit stop and truncation accounting. * [`capture_pane`](https://libtmux.org/en/ts/latest/mcp/tools/capture_pane/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. The text a pane is showing, or its scrollback. Negative \`start\` reaches back into history (-100 is a hundred lines above the top of the screen). For repeated reads of the same pane use capture_since instead — it returns only what is new. * [`capture_since`](https://libtmux.org/en/ts/latest/mcp/tools/capture_since/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. What a pane has printed since you last looked. Call it once with no cursor to start watching and get the current screen; keep the cursor it returns and pass it back each time after that, and you are charged only for what is new. This is the tool for watching a build, a log, or a test run — not a capture_pane loop. Set waitMs to block until something arrives rather than returning empty. Reports the stream in the order it was written, so a program that draws by moving the cursor (a progress bar, a full-screen TUI) reads jumbled here — capture_pane renders those. * [`clear_pane_scrollback`](https://libtmux.org/en/ts/latest/mcp/tools/clear_pane_scrollback/) Delete tmux state; accepts no command payload. Discard the retained scrollback history for one pane. * [`create_session`](https://libtmux.org/en/ts/latest/mcp/tools/create_session/) Start a pane's configured process; accepts no command payload. Create a detached session and return it with its first window and pane, so you can start working without listing anything first. * [`create_window`](https://libtmux.org/en/ts/latest/mcp/tools/create_window/) Start a pane's configured process; accepts no command payload. Add a window to a session and return it with its pane. * [`find_pane_by_position`](https://libtmux.org/en/ts/latest/mcp/tools/find_pane_by_position/) Inspect tmux metadata; accepts no client-supplied executable input. Find the pane occupying a named corner of a window. * [`get_pane_info`](https://libtmux.org/en/ts/latest/mcp/tools/get_pane_info/) Inspect tmux metadata; accepts no client-supplied executable input. One pane's metadata: what it runs, where, how big, and whether it is yours or watched. Does not read its contents — capture_pane does that. * [`get_server_info`](https://libtmux.org/en/ts/latest/mcp/tools/get_server_info/) Inspect tmux metadata; accepts no client-supplied executable input. The tmux server this process drives: its socket, version, daemon pid, and totals. Check the version before using a feature that needs a recent tmux. * [`get_session_info`](https://libtmux.org/en/ts/latest/mcp/tools/get_session_info/) Inspect tmux metadata; accepts no client-supplied executable input. Return metadata for one session without listing every session. * [`get_tmux_variables`](https://libtmux.org/en/ts/latest/mcp/tools/get_tmux_variables/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Resolve validated tmux variable names without accepting raw format syntax. * [`get_window_info`](https://libtmux.org/en/ts/latest/mcp/tools/get_window_info/) Inspect tmux metadata; accepts no client-supplied executable input. Return metadata and placements for one window. * [`kill_pane`](https://libtmux.org/en/ts/latest/mcp/tools/kill_pane/) Delete tmux state; accepts no command payload. Close a pane and the process in it. Refuses the pane this server runs in and every pane a person is watching; force confirms only this server's exact caller pane. * [`kill_session`](https://libtmux.org/en/ts/latest/mcp/tools/kill_session/) Delete tmux state; accepts no command payload. Remove a session. Windows and panes shared with another session remain available there. * [`kill_window`](https://libtmux.org/en/ts/latest/mcp/tools/kill_window/) Delete tmux state; accepts no command payload. Close a window and every pane in it. * [`list_panes`](https://libtmux.org/en/ts/latest/mcp/tools/list_panes/) Inspect tmux metadata; accepts no client-supplied executable input. Panes on this server, with the command each is running and its directory. Marks the pane this server runs in (isCallerPane) and panes a person is watching (isAttended). Metadata only — search_panes reads their contents. * [`list_sessions`](https://libtmux.org/en/ts/latest/mcp/tools/list_sessions/) Inspect tmux metadata; accepts no client-supplied executable input. Every session on this server with its id, name, window count, and whether anyone is attached. Metadata only — for what a pane shows, use capture_pane or search_panes. * [`list_windows`](https://libtmux.org/en/ts/latest/mcp/tools/list_windows/) Inspect tmux metadata; accepts no client-supplied executable input. Windows on this server, optionally restricted to one session by id or name. * [`move_window`](https://libtmux.org/en/ts/latest/mcp/tools/move_window/) Change tmux state; no client-supplied executable input. Move a window to another index, or into another session. * [`paste_text`](https://libtmux.org/en/ts/latest/mcp/tools/paste_text/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Put text into a pane without tmux interpreting any of it as key names. Use for content — a password, a code block, anything with characters a key parser would claim. * [`rename_session`](https://libtmux.org/en/ts/latest/mcp/tools/rename_session/) Change tmux state; no client-supplied executable input. Rename a session. Its id does not change, so targets by id keep working. * [`rename_window`](https://libtmux.org/en/ts/latest/mcp/tools/rename_window/) Change tmux state; no client-supplied executable input. Rename a window. Its id does not change. * [`resize_pane`](https://libtmux.org/en/ts/latest/mcp/tools/resize_pane/) Change tmux state; no client-supplied executable input. Resize a pane, either to a size or by an amount in a direction. Give width/height for an absolute size, or direction with amount for a nudge. * [`resize_window`](https://libtmux.org/en/ts/latest/mcp/tools/resize_window/) Change tmux state; no client-supplied executable input. Set a window's size in cells. A detached window is whatever size tmux guessed, and a program that formats to its terminal width truncates to that at the source — no capture option recovers those columns, because they were never printed. resize_pane only redistributes space inside a window and cannot grow one. A client attached to the window will overwrite this when it next changes; window-size manual makes a size of your own stick. * [`respawn_pane`](https://libtmux.org/en/ts/latest/mcp/tools/respawn_pane/) Start a pane's configured process; accepts no command payload. Restart a pane's command in place, keeping the pane and its id. Use to recover a pane whose process died, rather than killing and re-splitting. * [`run_shell_command`](https://libtmux.org/en/ts/latest/mcp/tools/run_shell_command/) Run a shell command in a pane with your user's permissions. Run a shell command in a pane, wait for it to finish, and report its exit status and output. Prefer this over send_keys plus capture_pane: it frames the command so a pane's echo of what you typed can never be mistaken for what the command printed, and it knows when the command actually ended rather than guessing from the screen. The command runs in a subshell, so cd and export do not persist to a later call. A pane is effectively single-writer: this server reserves it until the command settles, but another process with the same tmux socket can still write into it. * [`search_panes`](https://libtmux.org/en/ts/latest/mcp/tools/search_panes/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Find which panes are showing something. Searches pane contents, not their names — use list_panes for metadata. Returns the matching lines with their pane, so you can target one without capturing them all. Literal matching stops at one 256 KiB aggregate UTF-8 byte budget. * [`select_layout`](https://libtmux.org/en/ts/latest/mcp/tools/select_layout/) Change tmux state; no client-supplied executable input. Rearrange a window's panes. Takes one of tmux's named layouts, or a layout string from an earlier window whose \`metadataComplete\` is true to reproduce it exactly. * [`select_pane`](https://libtmux.org/en/ts/latest/mcp/tools/select_pane/) Change tmux state; no client-supplied executable input. Make a pane the active one in its window. Moves the cursor of anyone attached to that window. * [`select_window`](https://libtmux.org/en/ts/latest/mcp/tools/select_window/) Change tmux state; no client-supplied executable input. Make a window the current one in its session. * [`send_keys`](https://libtmux.org/en/ts/latest/mcp/tools/send_keys/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send keystrokes to a pane. Use for TUIs, control keys (C-c), and partial lines. For a shell command whose result you want, use run_shell_command — it waits for completion and reports exit status, which this does not. * [`send_keys_batch`](https://libtmux.org/en/ts/latest/mcp/tools/send_keys_batch/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send an ordered batch of pane-input operations, resolving and checking each row's configured cohort immediately before input. Stop or continue on error. * [`set_history_limit`](https://libtmux.org/en/ts/latest/mcp/tools/set_history_limit/) Change tmux state; no client-supplied executable input. Set the default retained scrollback line limit through a bounded integer. * [`set_mouse_enabled`](https://libtmux.org/en/ts/latest/mcp/tools/set_mouse_enabled/) Change tmux state; no client-supplied executable input. Set the global tmux mouse option through a closed boolean schema. * [`set_pane_title`](https://libtmux.org/en/ts/latest/mcp/tools/set_pane_title/) Change tmux state; no client-supplied executable input. Give a pane a title. Useful for labelling what an agent put where, since the title shows in list_panes and survives the command changing. * [`set_synchronize_panes`](https://libtmux.org/en/ts/latest/mcp/tools/set_synchronize_panes/) Change tmux state; no client-supplied executable input. Set the window default for synchronized pane input. Pane overrides still determine each effective configured cohort. * [`show_environment`](https://libtmux.org/en/ts/latest/mcp/tools/show_environment/) Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. The environment tmux gives processes it starts, at server or session scope. This is what a new pane will inherit, not what a running one has. * [`show_hooks`](https://libtmux.org/en/ts/latest/mcp/tools/show_hooks/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read the hooks a server or session runs. Read-only: a hook set here would outlive this process and keep firing in somebody's tmux. Put hooks a server should keep in its config file. * [`show_option`](https://libtmux.org/en/ts/latest/mcp/tools/show_option/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read one named tmux option at server, session, window, or pane scope. * [`signal_channel`](https://libtmux.org/en/ts/latest/mcp/tools/signal_channel/) Change tmux state; no client-supplied executable input. Signal a tmux wait-for channel. * [`snapshot_pane`](https://libtmux.org/en/ts/latest/mcp/tools/snapshot_pane/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return bounded terminal content and pane metadata in one MCP response. The metadata and capture come from separate tmux requests and are not an atomic snapshot. * [`split_window`](https://libtmux.org/en/ts/latest/mcp/tools/split_window/) Start a pane's configured process; accepts no command payload. Split a pane and return the new one. Direction is where the new pane goes relative to the one you split. * [`swap_pane`](https://libtmux.org/en/ts/latest/mcp/tools/swap_pane/) Change tmux state; no client-supplied executable input. Exchange two panes' positions. Their ids and contents travel with them. * [`wait_for_channel`](https://libtmux.org/en/ts/latest/mcp/tools/wait_for_channel/) Change tmux state; no client-supplied executable input. Wait until a tmux wait-for channel is signalled. * [`wait_for_text`](https://libtmux.org/en/ts/latest/mcp/tools/wait_for_text/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Wait until a pane prints something, streaming tmux's notifications rather than polling. Use for output you did NOT author — another process, a person, a background job. For a command you wrote, use run_shell_command: it knows when the command ended and reports exit status, which no text match can. This discounts text this server itself typed into the pane, for as long as it is unsubmitted or was submitted within the last ten seconds, so a command you just sent cannot match its own echo — but a pane not yet reading input can still echo type-ahead back once it starts, so wait for a prompt before typing into a cold shell. Whatever happens you get back what the pane printed and why the wait ended — a timeout is never an empty answer. ## Resources * `tmux://capabilities` The frozen structured-tool surface and its capability declarations. ## Resource templates This server does not advertise resource templates in this configuration. ## Prompts This server does not advertise prompts in this configuration. Source revision: [libtmux/libtmux-ts@ecc3eaca0b4e05a77360da9d56790b409282c63b](https://github.com/libtmux/libtmux-ts/tree/ecc3eaca0b4e05a77360da9d56790b409282c63b). --- # call_read_tools_batch Source: https://libtmux.org/en/ts/latest/mcp/tools/call_read_tools_batch/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Invoke a serial batch of at most 16 inspect tools. One client approval covers every nested name; inner tools receive no separate approval. The structured result is capped below 1,000,000 bytes, preserves every operation row, and reports explicit stop and truncation accounting. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Invoke a serial batch of at most 16 inspect tools. One client approval covers every nested name; inner tools receive no separate approval. The structured result is capped below 1,000,000 bytes, preserves every operation row, and reports explicit stop and truncation accounting. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/call_read_tools_batch.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L618) ## Arguments * `onError` optional · string Whether a failed operation ends the batch. Defaults to stop. * `operations` required · array The read-only tool calls to run, in order, in one approval. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "onError": { "description": "Whether a failed operation ends the batch. Defaults to stop.", "enum": [ "stop", "continue" ], "type": "string" }, "operations": { "description": "The read-only tool calls to run, in order, in one approval.", "items": { "anyOf": [ { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `list_sessions`, exactly the shape it takes when called on its own.", "properties": {}, "type": "object" }, "tool": { "const": "list_sessions", "description": "Run `list_sessions` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `list_windows`, exactly the shape it takes when called on its own.", "properties": { "session": { "description": "Session id ($1) or name. Omit for all sessions.", "type": "string" } }, "type": "object" }, "tool": { "const": "list_windows", "description": "Run `list_windows` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `list_panes`, exactly the shape it takes when called on its own.", "properties": { "session": { "description": "Session id ($1) or name.", "type": "string" }, "window": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "type": "object" }, "tool": { "const": "list_panes", "description": "Run `list_panes` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `get_pane_info`, exactly the shape it takes when called on its own.", "properties": { "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "get_pane_info", "description": "Run `get_pane_info` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `get_server_info`, exactly the shape it takes when called on its own.", "properties": {}, "type": "object" }, "tool": { "const": "get_server_info", "description": "Run `get_server_info` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `capture_pane`, exactly the shape it takes when called on its own.", "properties": { "end": { "description": "Last line, on the same scale as start: 0 is the top of the visible screen and negative reaches back into history. It does not count back from the bottom, so end:-1 is one line above the screen top, not the last line of output.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "joinWrapped": { "description": "Rejoin lines tmux wrapped.", "type": "boolean" }, "maxLines": { "description": "Keep at most this many lines, from the end. Defaults to the server limit.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "start": { "description": "First line; negative reaches into scrollback.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "capture_pane", "description": "Run `capture_pane` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `capture_since`, exactly the shape it takes when called on its own.", "properties": { "cursor": { "description": "The cursor from your previous capture_since. Omit on the first call.", "pattern": "^ltxc1\\.[0-9a-f]{32}\\.(?:0|[1-9][0-9]*)$", "type": "string" }, "maxLines": { "description": "Keep at most this many lines, from the end. Defaults to the server limit.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "waitMs": { "description": "Wait up to this long for new output before answering. Default 0.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "capture_since", "description": "Run `capture_since` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `search_panes`, exactly the shape it takes when called on its own.", "properties": { "maxMatchesPerPane": { "description": "Stop after this many matches in each pane. Defaults to the server limit.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "pattern": { "description": "Non-empty literal text to find.", "minLength": 1, "type": "string" }, "regex": { "description": "Interpret pattern using libtmux's bounded regular-expression grammar.", "type": "boolean" }, "scrollbackLines": { "description": "How far above the visible screen to search. Default 0.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "session": { "description": "Restrict to one session by id or name.", "type": "string" } }, "required": [ "pattern" ], "type": "object" }, "tool": { "const": "search_panes", "description": "Run `search_panes` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `show_option`, exactly the shape it takes when called on its own.", "properties": { "name": { "description": "The tmux option to read, such as \"status-left\".", "type": "string" }, "scope": { "description": "Default server.", "enum": [ "server", "session", "global-session", "window", "global-window", "pane" ], "type": "string" }, "target": { "description": "Session id/name or pane id, for the matching scope.", "type": "string" } }, "required": [ "name" ], "type": "object" }, "tool": { "const": "show_option", "description": "Run `show_option` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `show_hooks`, exactly the shape it takes when called on its own.", "properties": { "session": { "description": "Session scope; omit for server scope.", "type": "string" } }, "type": "object" }, "tool": { "const": "show_hooks", "description": "Run `show_hooks` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `show_environment`, exactly the shape it takes when called on its own.", "properties": { "session": { "description": "Session id ($1) or name. Omit for the server environment.", "type": "string" } }, "type": "object" }, "tool": { "const": "show_environment", "description": "Run `show_environment` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `get_session_info`, exactly the shape it takes when called on its own.", "properties": { "session": { "description": "Session id ($1) or name.", "type": "string" } }, "required": [ "session" ], "type": "object" }, "tool": { "const": "get_session_info", "description": "Run `get_session_info` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `get_window_info`, exactly the shape it takes when called on its own.", "properties": { "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "windowId" ], "type": "object" }, "tool": { "const": "get_window_info", "description": "Run `get_window_info` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `find_pane_by_position`, exactly the shape it takes when called on its own.", "properties": { "corner": { "description": "Which corner of the window's layout to resolve.", "enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ], "type": "string" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "corner", "windowId" ], "type": "object" }, "tool": { "const": "find_pane_by_position", "description": "Run `find_pane_by_position` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `get_tmux_variables`, exactly the shape it takes when called on its own.", "properties": { "names": { "description": "Variable names to resolve, such as \"pane_current_command\" — bare names, not `#{…}` format syntax.", "items": { "pattern": "^[A-Za-z][A-Za-z0-9_]*$", "type": "string" }, "maxItems": 32, "minItems": 1, "type": "array", "x-libtmux-tmux-format": "validated-variable-name" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "names" ], "type": "object" }, "tool": { "const": "get_tmux_variables", "description": "Run `get_tmux_variables` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "Arguments for `snapshot_pane`, exactly the shape it takes when called on its own.", "properties": { "maxLines": { "description": "Keep at most this many lines, from the end. Defaults to the server limit.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "snapshot_pane", "description": "Run `snapshot_pane` as this step of the batch.", "type": "string" } }, "required": [ "tool" ], "type": "object" } ] }, "maxItems": 16, "minItems": 1, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "failed": { "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "onError": { "enum": [ "stop", "continue" ], "type": "string" }, "results": { "items": { "additionalProperties": false, "properties": { "error": { "type": [ "string", "null" ] }, "index": { "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "result": { "anyOf": [ { "additionalProperties": {}, "properties": { "content": { "items": {}, "type": "array" }, "isError": { "type": "boolean" }, "structuredContent": { "additionalProperties": {}, "propertyNames": { "type": "string" }, "type": "object" } }, "required": [ "content" ], "type": "object" }, { "type": "null" } ] }, "resultTruncated": { "type": "boolean" }, "success": { "type": "boolean" }, "tool": { "type": "string" } }, "required": [ "error", "index", "result", "resultTruncated", "success", "tool" ], "type": "object" }, "type": "array" }, "stoppedAt": { "anyOf": [ { "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, { "type": "null" } ] }, "succeeded": { "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "maximum": 9007199254740991, "minimum": 0, "type": "integer" } }, "required": [ "failed", "onError", "results", "stoppedAt", "succeeded", "truncated", "truncatedBytes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # capture_pane Source: https://libtmux.org/en/ts/latest/mcp/tools/capture_pane/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. The text a pane is showing, or its scrollback. Negative `start` reaches back into history (-100 is a hundred lines above the top of the screen). For repeated reads of the same pane use capture_since instead — it returns only what is new. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. The text a pane is showing, or its scrollback. Negative `start` reaches back into history (-100 is a hundred lines above the top of the screen). For repeated reads of the same pane use [capture_since](https://libtmux.org/en/ts/latest/mcp/tools/capture_since/) instead — it returns only what is new. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/capture_pane.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/capture.ts#L27) ## Arguments * `end` optional · integer Last line, on the same scale as start: 0 is the top of the visible screen and negative reaches back into history. It does not count back from the bottom, so end:-1 is one line above the screen top, not the last line of output. * `joinWrapped` optional · boolean Rejoin lines tmux wrapped. * `maxLines` optional · integer Keep at most this many lines, from the end. Defaults to the server limit. * `paneId` required · string Stable pane id, e.g. %1. * `start` optional · integer First line; negative reaches into scrollback. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "end": { "description": "Last line, on the same scale as start: 0 is the top of the visible screen and negative reaches back into history. It does not count back from the bottom, so end:-1 is one line above the screen top, not the last line of output.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "joinWrapped": { "description": "Rejoin lines tmux wrapped.", "type": "boolean" }, "maxLines": { "description": "Keep at most this many lines, from the end. Defaults to the server limit.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "start": { "description": "First line; negative reaches into scrollback.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "byteClamped": { "description": "Whether the byte ceiling shortened the capture.", "type": "boolean" }, "droppedLines": { "description": "Lines cut from the front to fit maxLines.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "effectiveEnd": { "anyOf": [ { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, { "type": "null" } ] }, "effectiveStart": { "anyOf": [ { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, { "type": "null" } ] }, "omittedBytes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "rangeClamped": { "description": "Whether a result ceiling shortened the range.", "type": "boolean" }, "returnedBytes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "text": { "type": "string" }, "totalLines": { "description": "How many lines the capture held before trimming.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "byteClamped", "droppedLines", "effectiveEnd", "effectiveStart", "omittedBytes", "paneId", "rangeClamped", "returnedBytes", "text", "totalLines" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # capture_since Source: https://libtmux.org/en/ts/latest/mcp/tools/capture_since/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. What a pane has printed since you last looked. Call it once with no cursor to start watching and get the current screen; keep the cursor it returns and pass it back each time after that, and you are charged only for what is new. This is the tool for watching a build, a log, or a test run — not a capture_pane loop. Set waitMs to block until something arrives rather than returning empty. Reports the stream in the order it was written, so a program that draws by moving the cursor (a progress bar, a full-screen TUI) reads jumbled here — capture_pane renders those. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. What a pane has printed since you last looked. Call it once with no cursor to start watching and get the current screen; keep the cursor it returns and pass it back each time after that, and you are charged only for what is new. This is the tool for watching a build, a log, or a test run — not a [capture_pane](https://libtmux.org/en/ts/latest/mcp/tools/capture_pane/) loop. Set waitMs to block until something arrives rather than returning empty. Reports the stream in the order it was written, so a program that draws by moving the cursor (a progress bar, a full-screen TUI) reads jumbled here — [capture_pane](https://libtmux.org/en/ts/latest/mcp/tools/capture_pane/) renders those. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/capture_since.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/capture.ts#L132) ## Arguments * `cursor` optional · string The cursor from your previous capture_since. Omit on the first call. * `maxLines` optional · integer Keep at most this many lines, from the end. Defaults to the server limit. * `paneId` required · string Stable pane id, e.g. %1. * `waitMs` optional · integer Wait up to this long for new output before answering. Default 0. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "cursor": { "description": "The cursor from your previous capture_since. Omit on the first call.", "pattern": "^ltxc1\\.[0-9a-f]{32}\\.(?:0|[1-9][0-9]*)$", "type": "string" }, "maxLines": { "description": "Keep at most this many lines, from the end. Defaults to the server limit.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "waitMs": { "description": "Wait up to this long for new output before answering. Default 0.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "byteClamped": { "description": "Whether the byte ceiling shortened this result.", "type": "boolean" }, "cursor": { "anyOf": [ { "pattern": "^ltxc1\\.[0-9a-f]{32}\\.(?:0|[1-9][0-9]*)$", "type": "string" }, { "type": "null" } ], "description": "Pass this to the next capture_since call; null means streaming was unavailable." }, "droppedLines": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "effectiveTimeoutMs": { "description": "The wait ceiling applied; zero when this call did not wait on a live stream.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "missedBytes": { "description": "Output that scrolled past before this read reached it. Non-zero means you fell behind.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "omittedBytes": { "description": "Result bytes omitted after capture or streaming.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "rangeClamped": { "description": "Whether result limits shortened a grid capture.", "type": "boolean" }, "returnedBytes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "seeded": { "description": "True when this call started the watch and returned the screen.", "type": "boolean" }, "streaming": { "description": "False when no control connection was available and this fell back to capturing.", "type": "boolean" }, "text": { "type": "string" } }, "required": [ "byteClamped", "cursor", "droppedLines", "effectiveTimeoutMs", "missedBytes", "paneId", "omittedBytes", "rangeClamped", "returnedBytes", "seeded", "streaming", "text" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # clear_pane_scrollback Source: https://libtmux.org/en/ts/latest/mcp/tools/clear_pane_scrollback/ > Delete tmux state; accepts no command payload. Discard the retained scrollback history for one pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Discard the retained scrollback history for one pane. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/clear_pane_scrollback.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L575) ## Arguments * `paneId` required · string Stable pane id, e.g. %1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "cleared": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "cleared" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # create_session Source: https://libtmux.org/en/ts/latest/mcp/tools/create_session/ > Start a pane's configured process; accepts no command payload. Create a detached session and return it with its first window and pane, so you can start working without listing anything first. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Create a detached session and return it with its first window and pane, so you can start working without listing anything first. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/create_session.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/lifecycle.ts#L68) ## Arguments * `height` optional · integer Rows. Default 24, because a detached session has no client to size it. * `name` optional · string Session name; tmux picks a number when omitted. * `startDirectory` optional · string Working directory for the first pane. Defaults to the server's. * `width` optional · integer Columns. Default 80, and a program that formats to its terminal width — ps, git log --graph, docker ps — truncates to that at the source, where no capture option can recover it. * `windowName` optional · string Name for the first window, so the session does not open with a stray shell. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "height": { "description": "Rows. Default 24, because a detached session has no client to size it.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "name": { "description": "Session name; tmux picks a number when omitted.", "type": "string", "x-libtmux-tmux-format": "literalized-once" }, "startDirectory": { "description": "Working directory for the first pane. Defaults to the server's.", "type": "string", "x-libtmux-tmux-format": "literalized-once" }, "width": { "description": "Columns. Default 80, and a program that formats to its terminal width — ps, git log --graph, docker ps — truncates to that at the source, where no capture option can recover it.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "windowName": { "description": "Name for the first window, so the session does not open with a stray shell.", "type": "string", "x-libtmux-tmux-format": "literalized-once" } }, "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "paneId": { "description": "The new session's first pane. Target this.", "pattern": "^%\\d+$", "type": "string" }, "session": { "additionalProperties": false, "properties": { "attachedClients": { "description": "Raw client count from tmux; 0 means detached. Includes control-mode clients - this server's own wait_for_text or other live read holds one open while it runs, and another program on this socket may hold others. See humanAttachedClients for a person-only count.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "humanAttachedClients": { "description": "attachedClients minus every control-mode client, this server's own included.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "metadataComplete": { "description": "Whether the session name is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from the session name.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "windows": { "description": "How many windows it holds.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "attachedClients", "humanAttachedClients", "id", "metadataComplete", "name", "omittedMetadataBytes", "windows" ], "type": "object" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "paneId", "session", "windowId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # create_window Source: https://libtmux.org/en/ts/latest/mcp/tools/create_window/ > Start a pane's configured process; accepts no command payload. Add a window to a session and return it with its pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Add a window to a session and return it with its pane. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/create_window.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/lifecycle.ts#L147) ## Arguments * `name` optional · string Name for the new window. * `session` required · string Session id ($1) or name. * `startDirectory` optional · string Working directory for the new pane. Defaults to the session's. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "name": { "description": "Name for the new window.", "type": "string", "x-libtmux-tmux-format": "literalized-once" }, "session": { "description": "Session id ($1) or name.", "type": "string" }, "startDirectory": { "description": "Working directory for the new pane. Defaults to the session's.", "type": "string", "x-libtmux-tmux-format": "literalized-once" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "window": { "additionalProperties": false, "properties": { "id": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "layout": { "description": "tmux's layout string; feed it back only when metadataComplete is true.", "type": "string" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "panes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "placements": { "description": "Retained sessions and indexes where this window is linked.", "items": { "additionalProperties": false, "properties": { "active": { "description": "Whether this placement is current in its session.", "type": "boolean" }, "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName", "active" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "zoomed": { "type": "boolean" } }, "required": [ "id", "layout", "metadataComplete", "name", "omittedMetadataBytes", "panes", "omittedPlacements", "placements", "placementsComplete", "zoomed" ], "type": "object" } }, "required": [ "paneId", "window" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # find_pane_by_position Source: https://libtmux.org/en/ts/latest/mcp/tools/find_pane_by_position/ > Inspect tmux metadata; accepts no client-supplied executable input. Find the pane occupying a named corner of a window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Find the pane occupying a named corner of a window. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/find_pane_by_position.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L233) ## Arguments * `corner` required · string Which corner of the window's layout to resolve. * `windowId` required · string Stable window id, e.g. @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "corner": { "description": "Which corner of the window's layout to resolve.", "enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ], "type": "string" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "corner", "windowId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "pane": { "additionalProperties": false, "properties": { "active": { "description": "Whether this is its window's active pane.", "type": "boolean" }, "command": { "description": "The command tmux reports running in it.", "type": "string" }, "cwd": { "description": "Its current working directory.", "type": "string" }, "dead": { "description": "Whether its process exited and remain-on-exit kept it.", "type": "boolean" }, "height": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable pane id. Prefer this for entity-scoped targeting.", "pattern": "^%\\d+$", "type": "string" }, "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "isAttended": { "description": "A person is currently looking at this pane.", "type": "boolean" }, "isCallerPane": { "description": "This is the pane this MCP server runs in.", "type": "boolean" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "placements": { "description": "Retained session and window indexes through which this pane is reachable.", "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "title": { "type": "string" }, "width": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "windowName": { "type": "string" } }, "required": [ "active", "command", "cwd", "dead", "height", "id", "index", "isAttended", "isCallerPane", "metadataComplete", "omittedMetadataBytes", "omittedPlacements", "placements", "placementsComplete", "title", "width", "windowId", "windowName" ], "type": "object" } }, "required": [ "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # get_pane_info Source: https://libtmux.org/en/ts/latest/mcp/tools/get_pane_info/ > Inspect tmux metadata; accepts no client-supplied executable input. One pane's metadata: what it runs, where, how big, and whether it is yours or watched. Does not read its contents — capture_pane does that. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. One pane’s metadata: what it runs, where, how big, and whether it is yours or watched. Does not read its contents — [capture_pane](https://libtmux.org/en/ts/latest/mcp/tools/capture_pane/) does that. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/get_pane_info.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/discovery.ts#L196) ## Arguments * `paneId` required · string Stable pane id, e.g. %1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "pane": { "additionalProperties": false, "properties": { "active": { "description": "Whether this is its window's active pane.", "type": "boolean" }, "command": { "description": "The command tmux reports running in it.", "type": "string" }, "cwd": { "description": "Its current working directory.", "type": "string" }, "dead": { "description": "Whether its process exited and remain-on-exit kept it.", "type": "boolean" }, "height": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable pane id. Prefer this for entity-scoped targeting.", "pattern": "^%\\d+$", "type": "string" }, "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "isAttended": { "description": "A person is currently looking at this pane.", "type": "boolean" }, "isCallerPane": { "description": "This is the pane this MCP server runs in.", "type": "boolean" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "placements": { "description": "Retained session and window indexes through which this pane is reachable.", "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "title": { "type": "string" }, "width": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "windowName": { "type": "string" } }, "required": [ "active", "command", "cwd", "dead", "height", "id", "index", "isAttended", "isCallerPane", "metadataComplete", "omittedMetadataBytes", "omittedPlacements", "placements", "placementsComplete", "title", "width", "windowId", "windowName" ], "type": "object" } }, "required": [ "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # get_server_info Source: https://libtmux.org/en/ts/latest/mcp/tools/get_server_info/ > Inspect tmux metadata; accepts no client-supplied executable input. The tmux server this process drives: its socket, version, daemon pid, and totals. Check the version before using a feature that needs a recent tmux. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. The tmux server this process drives: its socket, version, daemon pid, and totals. Check the version before using a feature that needs a recent tmux. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/get_server_info.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/discovery.ts#L216) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": {}, "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "panes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "pid": { "type": [ "string", "null" ] }, "sessions": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "socketPath": { "type": [ "string", "null" ] }, "version": { "type": "string" }, "windows": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "panes", "pid", "sessions", "socketPath", "version", "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # get_session_info Source: https://libtmux.org/en/ts/latest/mcp/tools/get_session_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Return metadata for one session without listing every session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Return metadata for one session without listing every session. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/get_session_info.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L190) ## Arguments * `session` required · string Session id ($1) or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "session": { "description": "Session id ($1) or name.", "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "session": { "additionalProperties": false, "properties": { "attachedClients": { "description": "Raw client count from tmux; 0 means detached. Includes control-mode clients - this server's own wait_for_text or other live read holds one open while it runs, and another program on this socket may hold others. See humanAttachedClients for a person-only count.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "humanAttachedClients": { "description": "attachedClients minus every control-mode client, this server's own included.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "metadataComplete": { "description": "Whether the session name is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from the session name.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "windows": { "description": "How many windows it holds.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "attachedClients", "humanAttachedClients", "id", "metadataComplete", "name", "omittedMetadataBytes", "windows" ], "type": "object" } }, "required": [ "session" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # get_tmux_variables Source: https://libtmux.org/en/ts/latest/mcp/tools/get_tmux_variables/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Resolve validated tmux variable names without accepting raw format syntax. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Resolve validated tmux variable names without accepting raw format syntax. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/get_tmux_variables.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L263) ## Arguments * `names` required · array Variable names to resolve, such as "pane_current_command" — bare names, not \`#{…}\` format syntax. * `paneId` optional · string Stable pane id, e.g. %1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "names": { "description": "Variable names to resolve, such as \"pane_current_command\" — bare names, not `#{…}` format syntax.", "items": { "pattern": "^[A-Za-z][A-Za-z0-9_]*$", "type": "string" }, "maxItems": 32, "minItems": 1, "type": "array", "x-libtmux-tmux-format": "validated-variable-name" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "names" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "values": { "additionalProperties": { "type": "string" }, "propertyNames": { "type": "string" }, "type": "object" } }, "required": [ "values" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # get_window_info Source: https://libtmux.org/en/ts/latest/mcp/tools/get_window_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Return metadata and placements for one window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Return metadata and placements for one window. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/get_window_info.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L216) ## Arguments * `windowId` required · string Stable window id, e.g. @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "window": { "additionalProperties": false, "properties": { "id": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "layout": { "description": "tmux's layout string; feed it back only when metadataComplete is true.", "type": "string" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "panes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "placements": { "description": "Retained sessions and indexes where this window is linked.", "items": { "additionalProperties": false, "properties": { "active": { "description": "Whether this placement is current in its session.", "type": "boolean" }, "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName", "active" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "zoomed": { "type": "boolean" } }, "required": [ "id", "layout", "metadataComplete", "name", "omittedMetadataBytes", "panes", "omittedPlacements", "placements", "placementsComplete", "zoomed" ], "type": "object" } }, "required": [ "window" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # kill_pane Source: https://libtmux.org/en/ts/latest/mcp/tools/kill_pane/ > Delete tmux state; accepts no command payload. Close a pane and the process in it. Refuses the pane this server runs in and every pane a person is watching; force confirms only this server's exact caller pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Close a pane and the process in it. Refuses the pane this server runs in and every pane a person is watching; force confirms only this server’s exact caller pane. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/kill_pane.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/lifecycle.ts#L323) ## Arguments * `force` optional · boolean Allow this to target the pane this server itself was called from, which is otherwise refused. It does not override the refusal to touch a pane a person is watching. * `paneId` required · string Stable pane id, e.g. %1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "force": { "description": "Allow this to target the pane this server itself was called from, which is otherwise refused. It does not override the refusal to touch a pane a person is watching.", "type": "boolean" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "killed": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "killed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # kill_session Source: https://libtmux.org/en/ts/latest/mcp/tools/kill_session/ > Delete tmux state; accepts no command payload. Remove a session. Windows and panes shared with another session remain available there. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Remove a session. Windows and panes shared with another session remain available there. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/kill_session.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/lifecycle.ts#L386) ## Arguments * `force` optional · boolean Allow this to target the pane this server itself was called from, which is otherwise refused. It does not override the refusal to touch a pane a person is watching. * `session` required · string Session id ($1) or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "force": { "description": "Allow this to target the pane this server itself was called from, which is otherwise refused. It does not override the refusal to touch a pane a person is watching.", "type": "boolean" }, "session": { "description": "Session id ($1) or name.", "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "killed": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" } }, "required": [ "killed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # kill_window Source: https://libtmux.org/en/ts/latest/mcp/tools/kill_window/ > Delete tmux state; accepts no command payload. Close a window and every pane in it. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Close a window and every pane in it. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/kill_window.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/lifecycle.ts#L352) ## Arguments * `force` optional · boolean Allow this to target the pane this server itself was called from, which is otherwise refused. It does not override the refusal to touch a pane a person is watching. * `windowId` required · string Stable window id, e.g. @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "force": { "description": "Allow this to target the pane this server itself was called from, which is otherwise refused. It does not override the refusal to touch a pane a person is watching.", "type": "boolean" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "killed": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "killed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # list_panes Source: https://libtmux.org/en/ts/latest/mcp/tools/list_panes/ > Inspect tmux metadata; accepts no client-supplied executable input. Panes on this server, with the command each is running and its directory. Marks the pane this server runs in (isCallerPane) and panes a person is watching (isAttended). Metadata only — search_panes reads their contents. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Panes on this server, with the command each is running and its directory. Marks the pane this server runs in (isCallerPane) and panes a person is watching (isAttended). Metadata only — [search_panes](https://libtmux.org/en/ts/latest/mcp/tools/search_panes/) reads their contents. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/list_panes.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/discovery.ts#L150) ## Arguments * `session` optional · string Session id ($1) or name. * `window` optional · string Stable window id, e.g. @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "session": { "description": "Session id ($1) or name.", "type": "string" }, "window": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "complete": { "type": "boolean" }, "omittedEntries": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "panes": { "items": { "additionalProperties": false, "properties": { "active": { "description": "Whether this is its window's active pane.", "type": "boolean" }, "command": { "description": "The command tmux reports running in it.", "type": "string" }, "cwd": { "description": "Its current working directory.", "type": "string" }, "dead": { "description": "Whether its process exited and remain-on-exit kept it.", "type": "boolean" }, "height": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable pane id. Prefer this for entity-scoped targeting.", "pattern": "^%\\d+$", "type": "string" }, "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "isAttended": { "description": "A person is currently looking at this pane.", "type": "boolean" }, "isCallerPane": { "description": "This is the pane this MCP server runs in.", "type": "boolean" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "placements": { "description": "Retained session and window indexes through which this pane is reachable.", "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "title": { "type": "string" }, "width": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "windowName": { "type": "string" } }, "required": [ "active", "command", "cwd", "dead", "height", "id", "index", "isAttended", "isCallerPane", "metadataComplete", "omittedMetadataBytes", "omittedPlacements", "placements", "placementsComplete", "title", "width", "windowId", "windowName" ], "type": "object" }, "type": "array" } }, "required": [ "complete", "omittedEntries", "panes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # list_sessions Source: https://libtmux.org/en/ts/latest/mcp/tools/list_sessions/ > Inspect tmux metadata; accepts no client-supplied executable input. Every session on this server with its id, name, window count, and whether anyone is attached. Metadata only — for what a pane shows, use capture_pane or search_panes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Every session on this server with its id, name, window count, and whether anyone is attached. Metadata only — for what a pane shows, use [capture_pane](https://libtmux.org/en/ts/latest/mcp/tools/capture_pane/) or [search_panes](https://libtmux.org/en/ts/latest/mcp/tools/search_panes/). [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/list_sessions.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/discovery.ts#L60) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": {}, "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "complete": { "type": "boolean" }, "omittedEntries": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessions": { "items": { "additionalProperties": false, "properties": { "attachedClients": { "description": "Raw client count from tmux; 0 means detached. Includes control-mode clients - this server's own wait_for_text or other live read holds one open while it runs, and another program on this socket may hold others. See humanAttachedClients for a person-only count.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "humanAttachedClients": { "description": "attachedClients minus every control-mode client, this server's own included.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "metadataComplete": { "description": "Whether the session name is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from the session name.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "windows": { "description": "How many windows it holds.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "attachedClients", "humanAttachedClients", "id", "metadataComplete", "name", "omittedMetadataBytes", "windows" ], "type": "object" }, "type": "array" } }, "required": [ "complete", "omittedEntries", "sessions" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # list_windows Source: https://libtmux.org/en/ts/latest/mcp/tools/list_windows/ > Inspect tmux metadata; accepts no client-supplied executable input. Windows on this server, optionally restricted to one session by id or name. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Windows on this server, optionally restricted to one session by id or name. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/list_windows.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/discovery.ts#L105) ## Arguments * `session` optional · string Session id ($1) or name. Omit for all sessions. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "session": { "description": "Session id ($1) or name. Omit for all sessions.", "type": "string" } }, "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "complete": { "type": "boolean" }, "omittedEntries": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windows": { "items": { "additionalProperties": false, "properties": { "id": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "layout": { "description": "tmux's layout string; feed it back only when metadataComplete is true.", "type": "string" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "panes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "placements": { "description": "Retained sessions and indexes where this window is linked.", "items": { "additionalProperties": false, "properties": { "active": { "description": "Whether this placement is current in its session.", "type": "boolean" }, "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName", "active" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "zoomed": { "type": "boolean" } }, "required": [ "id", "layout", "metadataComplete", "name", "omittedMetadataBytes", "panes", "omittedPlacements", "placements", "placementsComplete", "zoomed" ], "type": "object" }, "type": "array" } }, "required": [ "complete", "omittedEntries", "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # move_window Source: https://libtmux.org/en/ts/latest/mcp/tools/move_window/ > Change tmux state; no client-supplied executable input. Move a window to another index, or into another session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Move a window to another index, or into another session. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/move_window.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/layout.ts#L304) ## Arguments * `index` optional · integer Destination index. Defaults to the next free one. * `session` optional · string Destination session id or name. * `sourceIndex` optional · integer Source window index. Required when the session has several placements of the id. * `sourceSession` optional · string Source session id or name. Required when the id has several placements. * `windowId` required · string Stable window id, e.g. @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "index": { "description": "Destination index. Defaults to the next free one.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "session": { "description": "Destination session id or name.", "type": "string" }, "sourceIndex": { "description": "Source window index. Required when the session has several placements of the id.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "sourceSession": { "description": "Source session id or name. Required when the id has several placements.", "type": "string" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "window": { "additionalProperties": false, "properties": { "id": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "layout": { "description": "tmux's layout string; feed it back only when metadataComplete is true.", "type": "string" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "panes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "placements": { "description": "Retained sessions and indexes where this window is linked.", "items": { "additionalProperties": false, "properties": { "active": { "description": "Whether this placement is current in its session.", "type": "boolean" }, "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName", "active" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "zoomed": { "type": "boolean" } }, "required": [ "id", "layout", "metadataComplete", "name", "omittedMetadataBytes", "panes", "omittedPlacements", "placements", "placementsComplete", "zoomed" ], "type": "object" } }, "required": [ "window" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # paste_text Source: https://libtmux.org/en/ts/latest/mcp/tools/paste_text/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Put text into a pane without tmux interpreting any of it as key names. Use for content — a password, a code block, anything with characters a key parser would claim. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Put text into a pane without tmux interpreting any of it as key names. Use for content — a password, a code block, anything with characters a key parser would claim. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/paste_text.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/input.ts#L189) ## Arguments * `enter` optional · boolean Press Enter afterwards. Default false. * `force` optional · boolean Allow writing to the pane this server itself was called from, which is otherwise refused. It does not override the refusal to write to a pane a person is watching — a pane an attached client has on screen is still refused with force. * `paneId` required · string Stable pane id, e.g. %1. * `text` required · string Text to paste. Sent through a tmux buffer, so a shell's line editor does not redraw on every character. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "enter": { "description": "Press Enter afterwards. Default false.", "type": "boolean" }, "force": { "description": "Allow writing to the pane this server itself was called from, which is otherwise refused. It does not override the refusal to write to a pane a person is watching — a pane an attached client has on screen is still refused with force.", "type": "boolean" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "text": { "description": "Text to paste. Sent through a tmux buffer, so a shell's line editor does not redraw on every character.", "type": "string" } }, "required": [ "paneId", "text" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "bytes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "bytes", "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # rename_session Source: https://libtmux.org/en/ts/latest/mcp/tools/rename_session/ > Change tmux state; no client-supplied executable input. Rename a session. Its id does not change, so targets by id keep working. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Rename a session. Its id does not change, so targets by id keep working. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/rename_session.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/lifecycle.ts#L234) ## Arguments * `name` required · string The session's new name. * `session` required · string Session id ($1) or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "name": { "description": "The session's new name.", "type": "string", "x-libtmux-tmux-format": "literalized-once" }, "session": { "description": "Session id ($1) or name.", "type": "string" } }, "required": [ "name", "session" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "session": { "additionalProperties": false, "properties": { "attachedClients": { "description": "Raw client count from tmux; 0 means detached. Includes control-mode clients - this server's own wait_for_text or other live read holds one open while it runs, and another program on this socket may hold others. See humanAttachedClients for a person-only count.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "humanAttachedClients": { "description": "attachedClients minus every control-mode client, this server's own included.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "metadataComplete": { "description": "Whether the session name is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from the session name.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "windows": { "description": "How many windows it holds.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "attachedClients", "humanAttachedClients", "id", "metadataComplete", "name", "omittedMetadataBytes", "windows" ], "type": "object" } }, "required": [ "session" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # rename_window Source: https://libtmux.org/en/ts/latest/mcp/tools/rename_window/ > Change tmux state; no client-supplied executable input. Rename a window. Its id does not change. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Rename a window. Its id does not change. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/rename_window.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/lifecycle.ts#L260) ## Arguments * `name` required · string The window's new name. * `windowId` required · string Stable window id, e.g. @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "name": { "description": "The window's new name.", "type": "string", "x-libtmux-tmux-format": "literalized-once" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "name", "windowId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "window": { "additionalProperties": false, "properties": { "id": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "layout": { "description": "tmux's layout string; feed it back only when metadataComplete is true.", "type": "string" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "panes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "placements": { "description": "Retained sessions and indexes where this window is linked.", "items": { "additionalProperties": false, "properties": { "active": { "description": "Whether this placement is current in its session.", "type": "boolean" }, "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName", "active" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "zoomed": { "type": "boolean" } }, "required": [ "id", "layout", "metadataComplete", "name", "omittedMetadataBytes", "panes", "omittedPlacements", "placements", "placementsComplete", "zoomed" ], "type": "object" } }, "required": [ "window" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # resize_pane Source: https://libtmux.org/en/ts/latest/mcp/tools/resize_pane/ > Change tmux state; no client-supplied executable input. Resize a pane, either to a size or by an amount in a direction. Give width/height for an absolute size, or direction with amount for a nudge. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Resize a pane, either to a size or by an amount in a direction. Give width/height for an absolute size, or direction with amount for a nudge. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/resize_pane.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/layout.ts#L112) ## Arguments * `amount` optional · integer Cells to move by. Needs direction. * `direction` optional · string Adjust by an amount in this direction instead of setting a size. * `height` optional · integer Set the pane height, in rows. * `paneId` required · string Stable pane id, e.g. %1. * `width` optional · integer Set the width, in columns. * `zoom` optional · boolean true makes this pane fill its window, false restores the layout. A state, not a toggle: sending the same value twice is a no-op. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "amount": { "description": "Cells to move by. Needs direction.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "direction": { "description": "Adjust by an amount in this direction instead of setting a size.", "enum": [ "up", "down", "left", "right" ], "type": "string" }, "height": { "description": "Set the pane height, in rows.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "width": { "description": "Set the width, in columns.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "zoom": { "description": "true makes this pane fill its window, false restores the layout. A state, not a toggle: sending the same value twice is a no-op.", "type": "boolean" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "pane": { "additionalProperties": false, "properties": { "active": { "description": "Whether this is its window's active pane.", "type": "boolean" }, "command": { "description": "The command tmux reports running in it.", "type": "string" }, "cwd": { "description": "Its current working directory.", "type": "string" }, "dead": { "description": "Whether its process exited and remain-on-exit kept it.", "type": "boolean" }, "height": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable pane id. Prefer this for entity-scoped targeting.", "pattern": "^%\\d+$", "type": "string" }, "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "isAttended": { "description": "A person is currently looking at this pane.", "type": "boolean" }, "isCallerPane": { "description": "This is the pane this MCP server runs in.", "type": "boolean" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "placements": { "description": "Retained session and window indexes through which this pane is reachable.", "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "title": { "type": "string" }, "width": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "windowName": { "type": "string" } }, "required": [ "active", "command", "cwd", "dead", "height", "id", "index", "isAttended", "isCallerPane", "metadataComplete", "omittedMetadataBytes", "omittedPlacements", "placements", "placementsComplete", "title", "width", "windowId", "windowName" ], "type": "object" } }, "required": [ "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # resize_window Source: https://libtmux.org/en/ts/latest/mcp/tools/resize_window/ > Change tmux state; no client-supplied executable input. Set a window's size in cells. A detached window is whatever size tmux guessed, and a program that formats to its terminal width truncates to that at the source — no capture option recovers those columns, because they were never printed. resize_pane only redistributes space inside a window and cannot grow one. A client attached to the window will overwrite this when it next changes; window-size manual makes a size of your own stick. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set a window’s size in cells. A detached window is whatever size tmux guessed, and a program that formats to its terminal width truncates to that at the source — no capture option recovers those columns, because they were never printed. [resize_pane](https://libtmux.org/en/ts/latest/mcp/tools/resize_pane/) only redistributes space inside a window and cannot grow one. A client attached to the window will overwrite this when it next changes; window-size manual makes a size of your own stick. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/resize_window.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/layout.ts#L347) ## Arguments * `height` optional · integer Set the height, in rows. * `width` optional · integer Set the width, in columns. * `windowId` required · string Stable window id, e.g. @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "height": { "description": "Set the height, in rows.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "width": { "description": "Set the width, in columns.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "window": { "additionalProperties": false, "properties": { "id": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "layout": { "description": "tmux's layout string; feed it back only when metadataComplete is true.", "type": "string" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "panes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "placements": { "description": "Retained sessions and indexes where this window is linked.", "items": { "additionalProperties": false, "properties": { "active": { "description": "Whether this placement is current in its session.", "type": "boolean" }, "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName", "active" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "zoomed": { "type": "boolean" } }, "required": [ "id", "layout", "metadataComplete", "name", "omittedMetadataBytes", "panes", "omittedPlacements", "placements", "placementsComplete", "zoomed" ], "type": "object" } }, "required": [ "window" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # respawn_pane Source: https://libtmux.org/en/ts/latest/mcp/tools/respawn_pane/ > Start a pane's configured process; accepts no command payload. Restart a pane's command in place, keeping the pane and its id. Use to recover a pane whose process died, rather than killing and re-splitting. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Restart a pane’s command in place, keeping the pane and its id. Use to recover a pane whose process died, rather than killing and re-splitting. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/respawn_pane.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/lifecycle.ts#L282) ## Arguments * `force` optional · boolean Allow this to target the pane this server itself was called from, which is otherwise refused. It does not override the refusal to touch a pane a person is watching. * `killFirst` optional · boolean Replace a still-running process. Default false. * `paneId` required · string Stable pane id, e.g. %1. * `startDirectory` optional · string Working directory for the restarted command. Defaults to the pane's. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "force": { "description": "Allow this to target the pane this server itself was called from, which is otherwise refused. It does not override the refusal to touch a pane a person is watching.", "type": "boolean" }, "killFirst": { "description": "Replace a still-running process. Default false.", "type": "boolean" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "startDirectory": { "description": "Working directory for the restarted command. Defaults to the pane's.", "type": "string", "x-libtmux-tmux-format": "literalized-once" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "pane": { "additionalProperties": false, "properties": { "active": { "description": "Whether this is its window's active pane.", "type": "boolean" }, "command": { "description": "The command tmux reports running in it.", "type": "string" }, "cwd": { "description": "Its current working directory.", "type": "string" }, "dead": { "description": "Whether its process exited and remain-on-exit kept it.", "type": "boolean" }, "height": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable pane id. Prefer this for entity-scoped targeting.", "pattern": "^%\\d+$", "type": "string" }, "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "isAttended": { "description": "A person is currently looking at this pane.", "type": "boolean" }, "isCallerPane": { "description": "This is the pane this MCP server runs in.", "type": "boolean" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "placements": { "description": "Retained session and window indexes through which this pane is reachable.", "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "title": { "type": "string" }, "width": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "windowName": { "type": "string" } }, "required": [ "active", "command", "cwd", "dead", "height", "id", "index", "isAttended", "isCallerPane", "metadataComplete", "omittedMetadataBytes", "omittedPlacements", "placements", "placementsComplete", "title", "width", "windowId", "windowName" ], "type": "object" } }, "required": [ "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # run_shell_command Source: https://libtmux.org/en/ts/latest/mcp/tools/run_shell_command/ > Run a shell command in a pane with your user's permissions. Run a shell command in a pane, wait for it to finish, and report its exit status and output. Prefer this over send_keys plus capture_pane: it frames the command so a pane's echo of what you typed can never be mistaken for what the command printed, and it knows when the command actually ended rather than guessing from the screen. The command runs in a subshell, so cd and export do not persist to a later call. A pane is effectively single-writer: this server reserves it until the command settles, but another process with the same tmux socket can still write into it. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Run a shell command in a pane with your user’s permissions. Run a shell command in a pane, wait for it to finish, and report its exit status and output. Prefer this over [send_keys](https://libtmux.org/en/ts/latest/mcp/tools/send_keys/) plus [capture_pane](https://libtmux.org/en/ts/latest/mcp/tools/capture_pane/): it frames the command so a pane’s echo of what you typed can never be mistaken for what the command printed, and it knows when the command actually ended rather than guessing from the screen. The command runs in a subshell, so cd and export do not persist to a later call. A pane is effectively single-writer: this server reserves it until the command settles, but another process with the same tmux socket can still write into it. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/run_shell_command.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/input.ts#L304) ## Arguments * `command` required · string The shell command to run. * `force` optional · boolean Allow writing to the pane this server itself was called from, which is otherwise refused. It does not override the refusal to write to a pane a person is watching — a pane an attached client has on screen is still refused with force. * `maxLines` optional · integer Keep at most this many lines, from the end. Defaults to the server limit. * `paneId` required · string Stable pane id, e.g. %1. * `timeoutMs` optional · integer How long to wait. Clamped by the server ceiling; the result says what was used. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "command": { "description": "The shell command to run.", "type": "string" }, "force": { "description": "Allow writing to the pane this server itself was called from, which is otherwise refused. It does not override the refusal to write to a pane a person is watching — a pane an attached client has on screen is still refused with force.", "type": "boolean" }, "maxLines": { "description": "Keep at most this many lines, from the end. Defaults to the server limit.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "timeoutMs": { "description": "How long to wait. Clamped by the server ceiling; the result says what was used.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" } }, "required": [ "command", "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "droppedLines": { "description": "Lines of output withheld by maxLines. The text half says so in a notice; a caller reading only the structured half would otherwise take the tail for the whole.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "effectiveTimeoutMs": { "description": "The timeout actually enforced.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "exitStatus": { "anyOf": [ { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, { "type": "null" } ], "description": "The command's exit status; null if it did not finish." }, "foreignOutputSuspected": { "description": "Another writer printed into this pane while the command ran. Output that could be attributed to them was removed; what is left may still include theirs. False means no foreign marker was seen, not that the output is certainly this command's.", "type": "boolean" }, "missedBytes": { "description": "Output that fell out of the pane's buffer before this read reached it. Nonzero means the command printed more than was kept, so the output here starts partway through it.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "omittedBytes": { "description": "Output bytes omitted by the result ceiling.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "outcome": { "description": "Why this returned. Read it rather than inferring from the text.", "enum": [ "completed", "timed_out", "pane_died", "cancelled" ], "type": "string" }, "output": { "description": "The bounded tail of the command's output.", "type": "string" }, "outputComplete": { "description": "False when capture or result limits omitted any command output.", "type": "boolean" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "returnedBytes": { "description": "UTF-8 output bytes returned.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "stillRunning": { "description": "Whether the command may still be running after this call returned.", "type": "boolean" } }, "required": [ "effectiveTimeoutMs", "droppedLines", "missedBytes", "omittedBytes", "foreignOutputSuspected", "exitStatus", "outcome", "output", "outputComplete", "paneId", "returnedBytes", "stillRunning" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # search_panes Source: https://libtmux.org/en/ts/latest/mcp/tools/search_panes/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Find which panes are showing something. Searches pane contents, not their names — use list_panes for metadata. Returns the matching lines with their pane, so you can target one without capturing them all. Literal matching stops at one 256 KiB aggregate UTF-8 byte budget. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Find which panes are showing something. Searches pane contents, not their names — use [list_panes](https://libtmux.org/en/ts/latest/mcp/tools/list_panes/) for metadata. Returns the matching lines with their pane, so you can target one without capturing them all. Literal matching stops at one 256 KiB aggregate UTF-8 byte budget. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/search_panes.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/search.ts#L78) ## Arguments * `maxMatchesPerPane` optional · integer Stop after this many matches in each pane. Defaults to the server limit. * `pattern` required · string Non-empty literal text to find. * `regex` optional · boolean Interpret pattern using libtmux's bounded regular-expression grammar. * `scrollbackLines` optional · integer How far above the visible screen to search. Default 0. * `session` optional · string Restrict to one session by id or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "maxMatchesPerPane": { "description": "Stop after this many matches in each pane. Defaults to the server limit.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "pattern": { "description": "Non-empty literal text to find.", "minLength": 1, "type": "string" }, "regex": { "description": "Interpret pattern using libtmux's bounded regular-expression grammar.", "type": "boolean" }, "scrollbackLines": { "description": "How far above the visible screen to search. Default 0.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "session": { "description": "Restrict to one session by id or name.", "type": "string" } }, "required": [ "pattern" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "capturesByteClamped": { "type": "boolean" }, "effectiveScrollbackLines": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "matches": { "items": { "additionalProperties": false, "properties": { "lineNumber": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "placements": { "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "text": { "type": "string" }, "windowName": { "type": "string" } }, "required": [ "lineNumber", "paneId", "placements", "text", "windowName" ], "type": "object" }, "type": "array" }, "matchesTruncated": { "type": "boolean" }, "matchingByteClamped": { "type": "boolean" }, "matchingLineClamped": { "type": "boolean" }, "matchingTimeClamped": { "type": "boolean" }, "paneLimitClamped": { "type": "boolean" }, "panesFailed": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "panesSearched": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "scrollbackClamped": { "type": "boolean" } }, "required": [ "capturesByteClamped", "effectiveScrollbackLines", "matches", "matchingByteClamped", "matchingLineClamped", "matchingTimeClamped", "matchesTruncated", "paneLimitClamped", "panesFailed", "panesSearched", "scrollbackClamped" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # select_layout Source: https://libtmux.org/en/ts/latest/mcp/tools/select_layout/ > Change tmux state; no client-supplied executable input. Rearrange a window's panes. Takes one of tmux's named layouts, or a layout string from an earlier window whose `metadataComplete` is true to reproduce it exactly. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Rearrange a window’s panes. Takes one of tmux’s named layouts, or a layout string from an earlier window whose `metadataComplete` is true to reproduce it exactly. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/select_layout.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/layout.ts#L228) ## Arguments * `layout` required · string One of even-horizontal, even-vertical, main-horizontal, main-vertical, tiled, or a tmux layout string. * `windowId` required · string Stable window id, e.g. @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "layout": { "description": "One of even-horizontal, even-vertical, main-horizontal, main-vertical, tiled, or a tmux layout string.", "type": "string" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "layout", "windowId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "window": { "additionalProperties": false, "properties": { "id": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "layout": { "description": "tmux's layout string; feed it back only when metadataComplete is true.", "type": "string" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "panes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "placements": { "description": "Retained sessions and indexes where this window is linked.", "items": { "additionalProperties": false, "properties": { "active": { "description": "Whether this placement is current in its session.", "type": "boolean" }, "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName", "active" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "zoomed": { "type": "boolean" } }, "required": [ "id", "layout", "metadataComplete", "name", "omittedMetadataBytes", "panes", "omittedPlacements", "placements", "placementsComplete", "zoomed" ], "type": "object" } }, "required": [ "window" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # select_pane Source: https://libtmux.org/en/ts/latest/mcp/tools/select_pane/ > Change tmux state; no client-supplied executable input. Make a pane the active one in its window. Moves the cursor of anyone attached to that window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Make a pane the active one in its window. Moves the cursor of anyone attached to that window. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/select_pane.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/layout.ts#L178) ## Arguments * `paneId` required · string Stable pane id, e.g. %1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "pane": { "additionalProperties": false, "properties": { "active": { "description": "Whether this is its window's active pane.", "type": "boolean" }, "command": { "description": "The command tmux reports running in it.", "type": "string" }, "cwd": { "description": "Its current working directory.", "type": "string" }, "dead": { "description": "Whether its process exited and remain-on-exit kept it.", "type": "boolean" }, "height": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable pane id. Prefer this for entity-scoped targeting.", "pattern": "^%\\d+$", "type": "string" }, "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "isAttended": { "description": "A person is currently looking at this pane.", "type": "boolean" }, "isCallerPane": { "description": "This is the pane this MCP server runs in.", "type": "boolean" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "placements": { "description": "Retained session and window indexes through which this pane is reachable.", "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "title": { "type": "string" }, "width": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "windowName": { "type": "string" } }, "required": [ "active", "command", "cwd", "dead", "height", "id", "index", "isAttended", "isCallerPane", "metadataComplete", "omittedMetadataBytes", "omittedPlacements", "placements", "placementsComplete", "title", "width", "windowId", "windowName" ], "type": "object" } }, "required": [ "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # select_window Source: https://libtmux.org/en/ts/latest/mcp/tools/select_window/ > Change tmux state; no client-supplied executable input. Make a window the current one in its session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Make a window the current one in its session. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/select_window.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/layout.ts#L200) ## Arguments * `sourceIndex` optional · integer Source window index. Required when the session has several placements of the id. * `sourceSession` optional · string Source session id or name. Required when the id has several placements. * `windowId` required · string Stable window id, e.g. @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "sourceIndex": { "description": "Source window index. Required when the session has several placements of the id.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "sourceSession": { "description": "Source session id or name. Required when the id has several placements.", "type": "string" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "window": { "additionalProperties": false, "properties": { "id": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "layout": { "description": "tmux's layout string; feed it back only when metadataComplete is true.", "type": "string" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "name": { "type": "string" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "panes": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "placements": { "description": "Retained sessions and indexes where this window is linked.", "items": { "additionalProperties": false, "properties": { "active": { "description": "Whether this placement is current in its session.", "type": "boolean" }, "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName", "active" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "zoomed": { "type": "boolean" } }, "required": [ "id", "layout", "metadataComplete", "name", "omittedMetadataBytes", "panes", "omittedPlacements", "placements", "placementsComplete", "zoomed" ], "type": "object" } }, "required": [ "window" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # send_keys Source: https://libtmux.org/en/ts/latest/mcp/tools/send_keys/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send keystrokes to a pane. Use for TUIs, control keys (C-c), and partial lines. For a shell command whose result you want, use run_shell_command — it waits for completion and reports exit status, which this does not. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Send keystrokes to a pane. Use for TUIs, control keys (C-c), and partial lines. For a shell command whose result you want, use [run_shell_command](https://libtmux.org/en/ts/latest/mcp/tools/run_shell_command/) — it waits for completion and reports exit status, which this does not. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/send_keys.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/input.ts#L116) ## Arguments * `enter` optional · boolean Press Enter afterwards. Default true. * `force` optional · boolean Allow writing to the pane this server itself was called from, which is otherwise refused. It does not override the refusal to write to a pane a person is watching — a pane an attached client has on screen is still refused with force. * `keys` required · string Keys to send. tmux key names like C-c work unless literal is true. * `literal` optional · boolean Send the text as-is, without resolving key names. * `paneId` required · string Stable pane id, e.g. %1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "enter": { "description": "Press Enter afterwards. Default true.", "type": "boolean" }, "force": { "description": "Allow writing to the pane this server itself was called from, which is otherwise refused. It does not override the refusal to write to a pane a person is watching — a pane an attached client has on screen is still refused with force.", "type": "boolean" }, "keys": { "description": "Keys to send. tmux key names like C-c work unless literal is true.", "type": "string" }, "literal": { "description": "Send the text as-is, without resolving key names.", "type": "boolean" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "keys", "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "attended": { "description": "A person is watching a configured cohort member.", "type": "boolean" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "resolvedPaneIds": { "description": "Configured cohort at the immediate preflight, not a delivery receipt.", "items": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "type": "array" }, "sent": { "type": "boolean" } }, "required": [ "attended", "paneId", "resolvedPaneIds", "sent" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # send_keys_batch Source: https://libtmux.org/en/ts/latest/mcp/tools/send_keys_batch/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send an ordered batch of pane-input operations, resolving and checking each row's configured cohort immediately before input. Stop or continue on error. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Send an ordered batch of pane-input operations, resolving and checking each row’s configured cohort immediately before input. Stop or continue on error. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/send_keys_batch.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L468) ## Arguments * `onError` optional · string Whether a failed operation ends the batch. Defaults to stop. * `operations` required · array The key sends to run, in order, one pane each. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "onError": { "description": "Whether a failed operation ends the batch. Defaults to stop.", "enum": [ "stop", "continue" ], "type": "string" }, "operations": { "description": "The key sends to run, in order, one pane each.", "items": { "properties": { "enter": { "description": "Press Enter afterwards. Default true.", "type": "boolean" }, "force": { "description": "Allow this server's own caller pane, as on `send_keys`.", "type": "boolean" }, "keys": { "description": "Keys for this pane, as on `send_keys`.", "type": "string" }, "literal": { "description": "Send the text literally rather than resolving key names.", "type": "boolean" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "keys", "paneId" ], "type": "object" }, "maxItems": 64, "minItems": 1, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "completed": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "failures": { "items": { "additionalProperties": false, "properties": { "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "reason": { "type": "string" } }, "required": [ "index", "reason" ], "type": "object" }, "type": "array" }, "targets": { "items": { "additionalProperties": false, "properties": { "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "resolvedPaneIds": { "items": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "type": "array" } }, "required": [ "index", "resolvedPaneIds" ], "type": "object" }, "type": "array" } }, "required": [ "completed", "failures", "targets" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # set_history_limit Source: https://libtmux.org/en/ts/latest/mcp/tools/set_history_limit/ > Change tmux state; no client-supplied executable input. Set the default retained scrollback line limit through a bounded integer. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set the default retained scrollback line limit through a bounded integer. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/set_history_limit.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L420) ## Arguments * `lines` required · integer Scrollback lines each new pane keeps. Applies to panes made after this. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "lines": { "description": "Scrollback lines each new pane keeps. Applies to panes made after this.", "maximum": 2000000, "minimum": 0, "type": "integer" } }, "required": [ "lines" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "lines": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "lines" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # set_mouse_enabled Source: https://libtmux.org/en/ts/latest/mcp/tools/set_mouse_enabled/ > Change tmux state; no client-supplied executable input. Set the global tmux mouse option through a closed boolean schema. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set the global tmux mouse option through a closed boolean schema. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/set_mouse_enabled.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L404) ## Arguments * `enabled` required · boolean Whether tmux should report mouse events. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "enabled": { "description": "Whether tmux should report mouse events.", "type": "boolean" } }, "required": [ "enabled" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "enabled": { "type": "boolean" } }, "required": [ "enabled" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # set_pane_title Source: https://libtmux.org/en/ts/latest/mcp/tools/set_pane_title/ > Change tmux state; no client-supplied executable input. Give a pane a title. Useful for labelling what an agent put where, since the title shows in list_panes and survives the command changing. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Give a pane a title. Useful for labelling what an agent put where, since the title shows in [list_panes](https://libtmux.org/en/ts/latest/mcp/tools/list_panes/) and survives the command changing. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/set_pane_title.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/layout.ts#L386) ## Arguments * `paneId` required · string Stable pane id, e.g. %1. * `title` required · string The pane's new title. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "title": { "description": "The pane's new title.", "type": "string", "x-libtmux-tmux-format": "literalized-once" } }, "required": [ "paneId", "title" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "pane": { "additionalProperties": false, "properties": { "active": { "description": "Whether this is its window's active pane.", "type": "boolean" }, "command": { "description": "The command tmux reports running in it.", "type": "string" }, "cwd": { "description": "Its current working directory.", "type": "string" }, "dead": { "description": "Whether its process exited and remain-on-exit kept it.", "type": "boolean" }, "height": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable pane id. Prefer this for entity-scoped targeting.", "pattern": "^%\\d+$", "type": "string" }, "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "isAttended": { "description": "A person is currently looking at this pane.", "type": "boolean" }, "isCallerPane": { "description": "This is the pane this MCP server runs in.", "type": "boolean" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "placements": { "description": "Retained session and window indexes through which this pane is reachable.", "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "title": { "type": "string" }, "width": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "windowName": { "type": "string" } }, "required": [ "active", "command", "cwd", "dead", "height", "id", "index", "isAttended", "isCallerPane", "metadataComplete", "omittedMetadataBytes", "omittedPlacements", "placements", "placementsComplete", "title", "width", "windowId", "windowName" ], "type": "object" } }, "required": [ "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # set_synchronize_panes Source: https://libtmux.org/en/ts/latest/mcp/tools/set_synchronize_panes/ > Change tmux state; no client-supplied executable input. Set the window default for synchronized pane input. Pane overrides still determine each effective configured cohort. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set the window default for synchronized pane input. Pane overrides still determine each effective configured cohort. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/set_synchronize_panes.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L441) ## Arguments * `enabled` required · boolean Whether typing into one pane of this window types into all of them. * `windowId` required · string Stable window id, e.g. @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "enabled": { "description": "Whether typing into one pane of this window types into all of them.", "type": "boolean" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "enabled", "windowId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "enabled": { "type": "boolean" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" } }, "required": [ "enabled", "windowId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # show_environment Source: https://libtmux.org/en/ts/latest/mcp/tools/show_environment/ > Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. The environment tmux gives processes it starts, at server or session scope. This is what a new pane will inherit, not what a running one has. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. The environment tmux gives processes it starts, at server or session scope. This is what a new pane will inherit, not what a running one has. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/show_environment.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/settings.ts#L199) ## Arguments * `session` optional · string Session id ($1) or name. Omit for the server environment. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "session": { "description": "Session id ($1) or name. Omit for the server environment.", "type": "string" } }, "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "complete": { "type": "boolean" }, "environment": { "additionalProperties": { "type": [ "string", "null" ] }, "propertyNames": { "type": "string" }, "type": "object" }, "omittedEntries": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "complete", "environment", "omittedEntries" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # show_hooks Source: https://libtmux.org/en/ts/latest/mcp/tools/show_hooks/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read the hooks a server or session runs. Read-only: a hook set here would outlive this process and keep firing in somebody's tmux. Put hooks a server should keep in its config file. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read the hooks a server or session runs. Read-only: a hook set here would outlive this process and keep firing in somebody’s tmux. Put hooks a server should keep in its config file. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/show_hooks.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/settings.ts#L138) ## Arguments * `session` optional · string Session scope; omit for server scope. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "session": { "description": "Session scope; omit for server scope.", "type": "string" } }, "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "complete": { "type": "boolean" }, "hooks": { "additionalProperties": { "type": "string" }, "propertyNames": { "type": "string" }, "type": "object" }, "omittedEntries": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "unset": { "description": "Hook names tmux defines that carry no command, and so are not listed.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "complete", "hooks", "omittedEntries", "unset" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # show_option Source: https://libtmux.org/en/ts/latest/mcp/tools/show_option/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read one named tmux option at server, session, window, or pane scope. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read one named tmux option at server, session, window, or pane scope. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/show_option.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/settings.ts#L105) ## Arguments * `name` required · string The tmux option to read, such as "status-left". * `scope` optional · string Default server. * `target` optional · string Session id/name or pane id, for the matching scope. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "name": { "description": "The tmux option to read, such as \"status-left\".", "type": "string" }, "scope": { "description": "Default server.", "enum": [ "server", "session", "global-session", "window", "global-window", "pane" ], "type": "string" }, "target": { "description": "Session id/name or pane id, for the matching scope.", "type": "string" } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "name": { "type": "string" }, "scope": { "type": "string" }, "value": { "type": [ "string", "null" ] } }, "required": [ "name", "scope", "value" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # signal_channel Source: https://libtmux.org/en/ts/latest/mcp/tools/signal_channel/ > Change tmux state; no client-supplied executable input. Signal a tmux wait-for channel. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Signal a tmux wait-for channel. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/signal_channel.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L386) ## Arguments * `channel` required · string The tmux wait-for channel to signal. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "channel": { "description": "The tmux wait-for channel to signal.", "type": "string" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "channel": { "type": "string" }, "signalled": { "type": "boolean" } }, "required": [ "channel", "signalled" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # snapshot_pane Source: https://libtmux.org/en/ts/latest/mcp/tools/snapshot_pane/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return bounded terminal content and pane metadata in one MCP response. The metadata and capture come from separate tmux requests and are not an atomic snapshot. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return bounded terminal content and pane metadata in one MCP response. The metadata and capture come from separate tmux requests and are not an atomic snapshot. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/snapshot_pane.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L305) ## Arguments * `maxLines` optional · integer Keep at most this many lines, from the end. Defaults to the server limit. * `paneId` required · string Stable pane id, e.g. %1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "maxLines": { "description": "Keep at most this many lines, from the end. Defaults to the server limit.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "content": { "type": "string" }, "cursorX": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "cursorY": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "droppedLines": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "inMode": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "pane": { "additionalProperties": false, "properties": { "active": { "description": "Whether this is its window's active pane.", "type": "boolean" }, "command": { "description": "The command tmux reports running in it.", "type": "string" }, "cwd": { "description": "Its current working directory.", "type": "string" }, "dead": { "description": "Whether its process exited and remain-on-exit kept it.", "type": "boolean" }, "height": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable pane id. Prefer this for entity-scoped targeting.", "pattern": "^%\\d+$", "type": "string" }, "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "isAttended": { "description": "A person is currently looking at this pane.", "type": "boolean" }, "isCallerPane": { "description": "This is the pane this MCP server runs in.", "type": "boolean" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "placements": { "description": "Retained session and window indexes through which this pane is reachable.", "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "title": { "type": "string" }, "width": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "windowName": { "type": "string" } }, "required": [ "active", "command", "cwd", "dead", "height", "id", "index", "isAttended", "isCallerPane", "metadataComplete", "omittedMetadataBytes", "omittedPlacements", "placements", "placementsComplete", "title", "width", "windowId", "windowName" ], "type": "object" }, "scrollPosition": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" } }, "required": [ "content", "cursorX", "cursorY", "droppedLines", "inMode", "pane", "scrollPosition" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # split_window Source: https://libtmux.org/en/ts/latest/mcp/tools/split_window/ > Start a pane's configured process; accepts no command payload. Split a pane and return the new one. Direction is where the new pane goes relative to the one you split. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Split a pane and return the new one. Direction is where the new pane goes relative to the one you split. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/split_window.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/lifecycle.ts#L190) ## Arguments * `direction` optional · string Default below. * `paneId` required · string Stable pane id, e.g. %1. * `startDirectory` optional · string Defaults to the directory the pane being split is in. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "direction": { "description": "Default below.", "enum": [ "above", "below", "left", "right" ], "type": "string" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "startDirectory": { "description": "Defaults to the directory the pane being split is in.", "type": "string", "x-libtmux-tmux-format": "literalized-once" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "pane": { "additionalProperties": false, "properties": { "active": { "description": "Whether this is its window's active pane.", "type": "boolean" }, "command": { "description": "The command tmux reports running in it.", "type": "string" }, "cwd": { "description": "Its current working directory.", "type": "string" }, "dead": { "description": "Whether its process exited and remain-on-exit kept it.", "type": "boolean" }, "height": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable pane id. Prefer this for entity-scoped targeting.", "pattern": "^%\\d+$", "type": "string" }, "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "isAttended": { "description": "A person is currently looking at this pane.", "type": "boolean" }, "isCallerPane": { "description": "This is the pane this MCP server runs in.", "type": "boolean" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "placements": { "description": "Retained session and window indexes through which this pane is reachable.", "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "title": { "type": "string" }, "width": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "windowName": { "type": "string" } }, "required": [ "active", "command", "cwd", "dead", "height", "id", "index", "isAttended", "isCallerPane", "metadataComplete", "omittedMetadataBytes", "omittedPlacements", "placements", "placementsComplete", "title", "width", "windowId", "windowName" ], "type": "object" } }, "required": [ "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # swap_pane Source: https://libtmux.org/en/ts/latest/mcp/tools/swap_pane/ > Change tmux state; no client-supplied executable input. Exchange two panes' positions. Their ids and contents travel with them. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Exchange two panes’ positions. Their ids and contents travel with them. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/swap_pane.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/layout.ts#L266) ## Arguments * `otherPaneId` required · string Stable pane id, e.g. %1. * `paneId` required · string Stable pane id, e.g. %1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "otherPaneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" } }, "required": [ "otherPaneId", "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "complete": { "type": "boolean" }, "omittedEntries": { "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "panes": { "items": { "additionalProperties": false, "properties": { "active": { "description": "Whether this is its window's active pane.", "type": "boolean" }, "command": { "description": "The command tmux reports running in it.", "type": "string" }, "cwd": { "description": "Its current working directory.", "type": "string" }, "dead": { "description": "Whether its process exited and remain-on-exit kept it.", "type": "boolean" }, "height": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "id": { "description": "Stable pane id. Prefer this for entity-scoped targeting.", "pattern": "^%\\d+$", "type": "string" }, "index": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "isAttended": { "description": "A person is currently looking at this pane.", "type": "boolean" }, "isCallerPane": { "description": "This is the pane this MCP server runs in.", "type": "boolean" }, "metadataComplete": { "description": "Whether every projected metadata string is complete.", "type": "boolean" }, "omittedMetadataBytes": { "description": "UTF-8 bytes omitted from projected metadata strings.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "omittedPlacements": { "description": "Later placements omitted.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "placements": { "description": "Retained session and window indexes through which this pane is reachable.", "items": { "additionalProperties": false, "properties": { "index": { "description": "The window index in this session.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "sessionId": { "description": "Stable session id, e.g. $1.", "pattern": "^\\$\\d+$", "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "index", "sessionId", "sessionName" ], "type": "object" }, "type": "array" }, "placementsComplete": { "description": "Whether placements contains every placement.", "type": "boolean" }, "title": { "type": "string" }, "width": { "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "windowId": { "description": "Stable window id, e.g. @1.", "pattern": "^@\\d+$", "type": "string" }, "windowName": { "type": "string" } }, "required": [ "active", "command", "cwd", "dead", "height", "id", "index", "isAttended", "isCallerPane", "metadataComplete", "omittedMetadataBytes", "omittedPlacements", "placements", "placementsComplete", "title", "width", "windowId", "windowName" ], "type": "object" }, "type": "array" } }, "required": [ "complete", "omittedEntries", "panes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # wait_for_channel Source: https://libtmux.org/en/ts/latest/mcp/tools/wait_for_channel/ > Change tmux state; no client-supplied executable input. Wait until a tmux wait-for channel is signalled. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Wait until a tmux wait-for channel is signalled. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/wait_for_channel.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/target.ts#L358) ## Arguments * `channel` required · string The tmux wait-for channel name. * `timeoutMs` optional · integer Give up after this long. Defaults to the server's wait ceiling. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "channel": { "description": "The tmux wait-for channel name.", "type": "string" }, "timeoutMs": { "description": "Give up after this long. Defaults to the server's wait ceiling.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "channel": { "type": "string" }, "signalled": { "type": "boolean" } }, "required": [ "channel", "signalled" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # wait_for_text Source: https://libtmux.org/en/ts/latest/mcp/tools/wait_for_text/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Wait until a pane prints something, streaming tmux's notifications rather than polling. Use for output you did NOT author — another process, a person, a background job. For a command you wrote, use run_shell_command: it knows when the command ended and reports exit status, which no text match can. This discounts text this server itself typed into the pane, for as long as it is unsubmitted or was submitted within the last ten seconds, so a command you just sent cannot match its own echo — but a pane not yet reading input can still echo type-ahead back once it starts, so wait for a prompt before typing into a cold shell. Whatever happens you get back what the pane printed and why the wait ended — a timeout is never an empty answer. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Wait until a pane prints something, streaming tmux’s notifications rather than polling. Use for output you did NOT author — another process, a person, a background job. For a command you wrote, use [run_shell_command](https://libtmux.org/en/ts/latest/mcp/tools/run_shell_command/): it knows when the command ended and reports exit status, which no text match can. This discounts text this server itself typed into the pane, for as long as it is unsubmitted or was submitted within the last ten seconds, so a command you just sent cannot match its own echo — but a pane not yet reading input can still echo type-ahead back once it starts, so wait for a prompt before typing into a cold shell. Whatever happens you get back what the pane printed and why the wait ended — a timeout is never an empty answer. [All TypeScript tools](https://libtmux.org/en/ts/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ts/latest/mcp/tools/wait_for_text.json) · [Source](https://github.com/libtmux/libtmux-ts/blob/3fe1ca654b81b8cbf4a13b777a001a3298c87a6f/packages/mcp/src/tools/wait.ts#L503) ## Arguments * `cursor` optional · string Start from a cursor an earlier capture_since or wait returned. * `maxLines` optional · integer Keep at most this many lines, from the end. Defaults to the server limit. * `paneId` required · string Stable pane id, e.g. %1. * `patterns` optional · array Any one of these ends the wait. Omit to wait for any output at all. * `regex` optional · boolean Interpret patterns using libtmux's bounded regular-expression grammar. * `timeoutMs` optional · integer Clamped by the server ceiling; the result reports what was used. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { "cursor": { "description": "Start from a cursor an earlier capture_since or wait returned.", "pattern": "^ltxc1\\.[0-9a-f]{32}\\.(?:0|[1-9][0-9]*)$", "type": "string" }, "maxLines": { "description": "Keep at most this many lines, from the end. Defaults to the server limit.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "patterns": { "description": "Any one of these ends the wait. Omit to wait for any output at all.", "items": { "minLength": 1, "type": "string" }, "maxItems": 64, "type": "array" }, "regex": { "description": "Interpret patterns using libtmux's bounded regular-expression grammar.", "type": "boolean" }, "timeoutMs": { "description": "Clamped by the server ceiling; the result reports what was used.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "alreadyOnScreen": { "description": "The pattern is on the pane now but printed before this wait began, so the wait could not match it. Read it with capture_pane rather than waiting again.", "type": "boolean" }, "cursor": { "anyOf": [ { "pattern": "^ltxc1\\.[0-9a-f]{32}\\.(?:0|[1-9][0-9]*)$", "type": "string" }, { "type": "null" } ], "description": "Pass to capture_since or another wait; null means the live stream cannot be resumed." }, "droppedLines": { "description": "Output lines omitted by the result limit.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "effectiveTimeoutMs": { "description": "The timeout actually enforced, after clamping.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "matched": { "description": "The text that matched, or null.", "type": [ "string", "null" ] }, "missedBytes": { "description": "Retained output lost before this read; non-zero means the result is incomplete.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "omittedBytes": { "description": "Output bytes omitted by the result ceiling.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "outcome": { "description": "Why the wait ended. Read this rather than guessing from the output.", "enum": [ "matched", "timed_out", "pane_died", "no_stream", "cancelled", "output_lost", "stream_lost" ], "type": "string" }, "output": { "description": "The bounded tail of what the pane printed while waiting.", "type": "string" }, "paneId": { "description": "Stable pane id, e.g. %1.", "pattern": "^%\\d+$", "type": "string" }, "returnedBytes": { "description": "UTF-8 bytes returned across output and screen.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "screen": { "description": "What the pane shows now after a miss, unless result limits omit it; see screenClamped.", "type": "string" }, "screenClamped": { "description": "Whether result limits shortened the pane screen.", "type": "boolean" }, "streamFailure": { "anyOf": [ { "enum": [ "connection_lost", "events_dropped", "expired", "hub_closed", "topology_changed" ], "type": "string" }, { "type": "null" } ], "description": "Why the live stream ended, or null while it remained valid." } }, "required": [ "alreadyOnScreen", "cursor", "droppedLines", "effectiveTimeoutMs", "matched", "missedBytes", "omittedBytes", "outcome", "output", "paneId", "returnedBytes", "screen", "screenClamped", "streamFailure" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false } ``` --- # Rust MCP tools Source: https://libtmux.org/en/rs/latest/mcp/tools/ > Tools, resources, and prompts advertised by the Rust MCP server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Use the wire name shown here when calling a tool. The Rust server advertises 45 tools with the reference configuration below. Your client’s list follows the policy configured for its server. Read the [setup guide](https://libtmux.org/en/rs/latest/mcp/guides/) before choosing tool access. The [language API reference](https://libtmux.org/en/rs/latest/mcp/reference/) covers embedding and implementation types. [Download the protocol catalog as JSON](https://libtmux.org/en/rs/latest/mcp/tools.json). Reference configuration * `LIBTMUX_TOOLSETS` `inspect,manage,execute,teardown` Protocol version: `2025-11-25`. ## Tools * [`call_read_tools_batch`](https://libtmux.org/en/rs/latest/mcp/tools/call_read_tools_batch/) Call a serial batch of at most sixteen enabled inspect tools. One approval for this batch covers every enabled nested name; inner tools do not receive separate client approval. The complete JSON-RPC response line, including its request ID and newline, is capped at 1,000,000 bytes; truncated payloads and omitted bytes are explicit. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`capture_pane`](https://libtmux.org/en/rs/latest/mcp/tools/capture_pane/) Read a pane's contents. Reads the visible screen by default; set history to reach output that has scrolled off, or give a start and end line. Set last_command to get only what the last command printed, which is usually what you want and is far shorter -- it needs tmux 3.7 and a shell that marks its prompts, and says so when it cannot. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`capture_since`](https://libtmux.org/en/rs/latest/mcp/tools/capture_since/) Read what a pane wrote since the previous call. The first call, with no cursor, starts watching and returns a cursor; later calls pass it back and receive only what is new, as the raw output stream, not the rendered screen: a line redrawn in place repeats; capture_pane shows the screen. Use this to follow a pane over several turns without re-reading the whole screen. The answer says missed=true if the cursor no longer names retained output, including when the pane outran the buffer, its live tail was evicted, or the server restarted. Starting a tail owns a retained observer until the tail is evicted or the server stops. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`clear_pane_scrollback`](https://libtmux.org/en/rs/latest/mcp/tools/clear_pane_scrollback/) Discard a pane's scrollback, so the next capture_pane returns only what happens next. Use this before running something whose output you want to read cleanly: it is far cheaper than reading past the old output every time. The visible screen is left alone. Delete tmux state; accepts no command payload. * [`create_session`](https://libtmux.org/en/rs/latest/mcp/tools/create_session/) Create a new detached tmux session. Start a pane's configured process; accepts no command payload. * [`create_window`](https://libtmux.org/en/rs/latest/mcp/tools/create_window/) Create a window running its configured process. Start a pane's configured process; accepts no command payload. * [`find_pane_by_position`](https://libtmux.org/en/rs/latest/mcp/tools/find_pane_by_position/) Find the pane touching a named window corner. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_pane_info`](https://libtmux.org/en/rs/latest/mcp/tools/get_pane_info/) Return metadata for one pane. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_server_info`](https://libtmux.org/en/rs/latest/mcp/tools/get_server_info/) Report every session with its windows and panes, in one call. Prefer this over calling the three listing tools separately: it costs tmux four commands rather than one per object. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_session_info`](https://libtmux.org/en/rs/latest/mcp/tools/get_session_info/) Return metadata for one session. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_tmux_variables`](https://libtmux.org/en/rs/latest/mcp/tools/get_tmux_variables/) Read a bounded set of tmux variables against one pane. tmux reads a name it does not know as a format from its environment, so a name the server or session environment holds is refused unless the operator listed it in LIBTMUX_ENVIRONMENT_VALUES at startup. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. * [`get_window_info`](https://libtmux.org/en/rs/latest/mcp/tools/get_window_info/) Return metadata for one window. Inspect tmux metadata; accepts no client-supplied executable input. * [`kill_pane`](https://libtmux.org/en/rs/latest/mcp/tools/kill_pane/) Kill a pane. Killing a window's last pane closes the window. Delete tmux state; accepts no command payload. * [`kill_session`](https://libtmux.org/en/rs/latest/mcp/tools/kill_session/) Kill a tmux session and everything in it. Delete tmux state; accepts no command payload. * [`kill_window`](https://libtmux.org/en/rs/latest/mcp/tools/kill_window/) Kill a window, closing it in every session that links it. Delete tmux state; accepts no command payload. * [`list_panes`](https://libtmux.org/en/rs/latest/mcp/tools/list_panes/) List every pane on the server. Inspect tmux metadata; accepts no client-supplied executable input. * [`list_sessions`](https://libtmux.org/en/rs/latest/mcp/tools/list_sessions/) List every tmux session on the server. Inspect tmux metadata; accepts no client-supplied executable input. * [`list_windows`](https://libtmux.org/en/rs/latest/mcp/tools/list_windows/) List every window on the server. A window linked into several sessions appears once per link, so an id can repeat with a different session_id. Inspect tmux metadata; accepts no client-supplied executable input. * [`move_window`](https://libtmux.org/en/rs/latest/mcp/tools/move_window/) Move one window to a session and index. Change tmux state; no client-supplied executable input. * [`paste_text`](https://libtmux.org/en/rs/latest/mcp/tools/paste_text/) Put text into a pane through a tmux paste buffer instead of typing it key by key. Use this for anything long or awkward: send_keys types the text, so a shell reading it can react to each character, and a bracketed-paste aware program treats a paste as one block. Optional Enter is appended to that same block. Empty text without Enter is a guarded buffer-free no-op. Paste targets only the named pane, even when synchronized input is enabled. A dead, input-disabled, mode-owned, terminal-attended, or inherited-caller target is refused before setup and again immediately before paste. The private buffer is deleted after setup, refusal, and paste outcomes; observations can still race with tmux. A submitted paste is remembered briefly so wait_for_text can discount its own echo. Send input to a pane's program; a shell that receives it runs it with your user's permissions. * [`rename_session`](https://libtmux.org/en/rs/latest/mcp/tools/rename_session/) Rename one session. Change tmux state; no client-supplied executable input. * [`rename_window`](https://libtmux.org/en/rs/latest/mcp/tools/rename_window/) Rename one window. Change tmux state; no client-supplied executable input. * [`resize_pane`](https://libtmux.org/en/rs/latest/mcp/tools/resize_pane/) Move one edge of a pane by a number of rows or columns. Change tmux state; no client-supplied executable input. * [`resize_window`](https://libtmux.org/en/rs/latest/mcp/tools/resize_window/) Resize one window to exact cell dimensions. Change tmux state; no client-supplied executable input. * [`respawn_pane`](https://libtmux.org/en/rs/latest/mcp/tools/respawn_pane/) Restart a pane's configured process with no command payload. Start a pane's configured process; accepts no command payload. * [`run_shell_command`](https://libtmux.org/en/rs/latest/mcp/tools/run_shell_command/) Run a shell command in a pane, wait for it to finish, and report its exit status with everything it wrote. This is the tool for "run this and tell me if it worked". Output is the pane's raw output stream, not the rendered screen: nothing is missed, the shell prompt is not included, and a line redrawn in place repeats; capture_pane shows the screen. The command runs in a subshell, so cd and export do not persist and invalid syntax completes with a nonzero status. Valid inherited Bash and zsh ERR and DEBUG traps remain visible to the command while parent-shell traps and options remain unchanged. It requires one configured input recipient and observes its mode, liveness, input-off state, attended-client state, cohort, inherited-caller relation, known POSIX shell, and resolved route before watcher setup and again before dispatch. A process-wide endpoint-and-pane reservation blocks other MCP pane input until the completion marker or pane closure is proved. The resolved tmux executable and socket path must contain no ASCII terminal-control bytes. The reservation serializes this MCP's input, but tmux observations can still race with dispatch. The pane shell, tmux server, and configuration must be trusted. Reaching the deadline, cancelling, or an uncertain dispatch stops this request while its watcher keeps the reservation until completion is proved. To stop the command, send_keys with keys \["C-c"] alone passes the reservation, and the command reports completion when it ends; respawn_pane with kill_first replaces a program that ignores C-c and C-\\. Run a shell command in a pane with your user's permissions. * [`search_panes`](https://libtmux.org/en/rs/latest/mcp/tools/search_panes/) Search what panes are displaying with Rust's linear-time regex engine. Accept at most 4,096 pattern bytes; search at most 64 panes, 8,192 lines, and 1 MiB; spend at most 250 ms matching and five seconds capturing. Report the pane and line of every match. Use this to find where something is -- which pane has the failing test, which one printed the error -- instead of capturing panes one at a time. Searches the visible screen by default; set history to include scrollback. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`select_layout`](https://libtmux.org/en/rs/latest/mcp/tools/select_layout/) Rearrange a window's panes using a saved tmux layout or a named layout and its unique abbreviation. Names follow the running daemon's version; mirrored main layouts require tmux 3.5. Invalid syntax is refused before window lookup. Return the saved layout tmux actually applied. Change tmux state; no client-supplied executable input. * [`select_pane`](https://libtmux.org/en/rs/latest/mcp/tools/select_pane/) Select a pane, making it its window's active pane. Give a direction to move relative to it instead: up, down, left, and right follow the layout, last returns to the previously active pane, and next and previous step through the window in order. Change tmux state; no client-supplied executable input. * [`select_window`](https://libtmux.org/en/rs/latest/mcp/tools/select_window/) Select a window, making it its session's active window. Give a direction to move relative to it instead: next and previous step through the session in index order, and last returns to the previously active window. Change tmux state; no client-supplied executable input. * [`send_keys`](https://libtmux.org/en/rs/latest/mcp/tools/send_keys/) Type text into a pane, press named keys in it, or both. \`text\` is sent literally, so C-c in it types those three characters. Use \`keys\` for anything without a character of its own -- C-c to interrupt a running command, Escape, Up, C-d -- which are tmux key names and are interpreted. Text, keys, and optional Enter keep that order in one tmux dispatch. Before input, the configured synchronized-pane cohort is observed; a dead, input-disabled, mode-owned, terminal-attended, or inherited-caller member refuses the whole call, and so does an active run_shell_command, except for keys C-c or C-\ sent alone, which interrupt it. Returned pane IDs describe configured membership, not confirmed delivery. The observation can race with tmux processing the input. A submitted line is remembered briefly so wait_for_text can discount its own echo; an unrecognized key stops that for the pane's current line rather than mask it inaccurately. Send input to a pane's program; a shell that receives it runs it with your user's permissions. * [`send_keys_batch`](https://libtmux.org/en/rs/latest/mcp/tools/send_keys_batch/) Send an ordered batch of input operations to panes. Each executed row repeats send_keys' effective synchronized-cohort, dead-pane, input-off, pane-mode, attended-client, and inherited-caller preflight, then crosses one tmux dispatch. These observations can race with tmux processing the input. Send input to a pane's program; a shell that receives it runs it with your user's permissions. * [`set_history_limit`](https://libtmux.org/en/rs/latest/mcp/tools/set_history_limit/) Set the scrollback history limit for a session or its global default. From tmux 3.7 existing panes take it too, and lowering it discards their scrollback past the new limit. Delete tmux state; accepts no command payload. * [`set_mouse_enabled`](https://libtmux.org/en/rs/latest/mcp/tools/set_mouse_enabled/) Set mouse handling for a session or the global session default. Change tmux state; no client-supplied executable input. * [`set_pane_title`](https://libtmux.org/en/rs/latest/mcp/tools/set_pane_title/) Set one pane's title. Change tmux state; no client-supplied executable input. * [`set_synchronize_panes`](https://libtmux.org/en/rs/latest/mcp/tools/set_synchronize_panes/) Set the window default for synchronized pane input. Individual pane overrides still determine the effective configured cohort, so enabling this can amplify what one send_keys call reaches. Change tmux state; no client-supplied executable input. * [`show_environment`](https://libtmux.org/en/rs/latest/mcp/tools/show_environment/) List the variables tmux hands to processes it starts, for the server or for one session, and whether each is set or marked for removal. Values are withheld: a tmux server inherits the environment of the shell that started it, tokens and keys included. A value is returned only for a name the operator listed in LIBTMUX_ENVIRONMENT_VALUES at startup, and is then returned in clear. This is not the environment of anything already running: a pane started before a change keeps what it was given. Read the tmux environment; accepts no client-supplied executable input. Values are withheld unless the operator allowed the name. * [`show_hooks`](https://libtmux.org/en/rs/latest/mcp/tools/show_hooks/) List the hooks tmux runs when something happens on the server, such as a pane exiting. This tool does not set hooks. Hooks set through another path remain in their server or session until unset; configuration files persist them across server restarts. Reach for this when tmux does something no tool here asked for. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. * [`show_option`](https://libtmux.org/en/rs/latest/mcp/tools/show_option/) Read a tmux option, such as history-limit or a user option like @theme. Name the scope the option lives in; global-session is what tmux uses when a command names no target. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. * [`signal_channel`](https://libtmux.org/en/rs/latest/mcp/tools/signal_channel/) Signal a tmux wait-for channel, releasing every current waiter. With no waiter, one signal is latched; signalling the same channel again clears that latch. Change tmux state; no client-supplied executable input. * [`snapshot_pane`](https://libtmux.org/en/rs/latest/mcp/tools/snapshot_pane/) Read pane content with cursor position, mode state, and scroll position in one reply. The state query and capture are separate, so the result is not atomic. Prefer this over capture_pane when you need to reason about where the pane is rather than only what it says -- a cursor at column zero on a fresh line is a shell waiting, and a pane in a mode may route keys to tmux instead of the workload. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`split_window`](https://libtmux.org/en/rs/latest/mcp/tools/split_window/) Split a window and start the configured process with no command payload. Start a pane's configured process; accepts no command payload. * [`swap_pane`](https://libtmux.org/en/rs/latest/mcp/tools/swap_pane/) Swap the positions of two panes. Change tmux state; no client-supplied executable input. * [`wait_for_channel`](https://libtmux.org/en/rs/latest/mcp/tools/wait_for_channel/) Block until something signals a tmux wait-for channel. A pending signal is consumed. Pair this with a shell command that ends in \`tmux wait-for -S \\` to synchronise with work this server did not start. Change tmux state; no client-supplied executable input. * [`wait_for_text`](https://libtmux.org/en/rs/latest/mcp/tools/wait_for_text/) Wait until a pane writes matching text. Reads the pane's live output stream, so text that scrolls past between checks is still seen. The returned text is that raw stream, not the rendered screen: a line redrawn in place repeats; capture_pane shows the screen. Prefer run_shell_command for commands you are sending yourself: it reports an exit status instead of guessing from output. Use this for output you did not author, such as a server logging that it is ready. A line this server itself types and submits -- with send_keys, paste_text, or run_shell_command's own dispatch -- is discounted from a match for a short time afterward, so waiting for text you just sent does not match its own echo; output that happens to repeat the same words still does. A submitted line that wrapped across terminal rows when it was typed is not discounted. A pattern still on the row being typed into, not yet submitted, reports outcome pending instead of matched, and one already on a completed row before this call attached reports present_at_entry. Waiting owns an observer client until the wait ends. Each list accepts at most 32 patterns, each at most 4,096 bytes, using Rust's linear-time regex engine. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. ## Resources * `tmux://capabilities` The startup-frozen effective tool surface and each tool's direct authority. ## Resource templates This server does not advertise resource templates in this configuration. ## Prompts This server does not advertise prompts in this configuration. Source revision: [libtmux/libtmux-rs@a6fc2a65674177b92b17fa380757155d2ba150fd](https://github.com/libtmux/libtmux-rs/tree/a6fc2a65674177b92b17fa380757155d2ba150fd). --- # call_read_tools_batch Source: https://libtmux.org/en/rs/latest/mcp/tools/call_read_tools_batch/ > Call a serial batch of at most sixteen enabled inspect tools. One approval for this batch covers every enabled nested name; inner tools do not receive separate client approval. The complete JSON-RPC response line, including its request ID and newline, is capped at 1,000,000 bytes; truncated payloads and omitted bytes are explicit. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Call a serial batch of at most sixteen enabled inspect tools. One approval for this batch covers every enabled nested name; inner tools do not receive separate client approval. The complete JSON-RPC response line, including its request ID and newline, is capped at 1,000,000 bytes; truncated payloads and omitted bytes are explicit. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/call_read_tools_batch.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L1145) ## Arguments * `on_error` optional \`stop\`, the default, ends at the first failed call; \`continue\` makes the rest. Default: `"stop"`. * `operations` required · array The inspect calls to make, in order. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$defs": { "OnError": { "enum": [ "stop", "continue" ], "type": "string" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "on_error": { "$ref": "#/$defs/OnError", "default": "stop", "description": "`stop`, the default, ends at the first failed call; `continue` makes\nthe rest." }, "operations": { "description": "The inspect calls to make, in order.", "items": { "oneOf": [ { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "end": { "description": "End at this line. Omit for the bottom of the screen.", "format": "int32", "type": [ "integer", "null" ] }, "history": { "default": false, "description": "Read the whole history rather than the visible screen.", "type": "boolean" }, "last_command": { "default": false, "description": "Return only the last command's output, when the shell marks its\nprompts.\n\nAnswers far less than the history, because it starts where the last\ncommand's output began. When the pane's shell does not mark its\nprompts -- fish does, bash and zsh do not -- this reports\n`marks: \"absent\"` and returns the visible screen instead.", "type": "boolean" }, "pane": { "description": "The `%`-prefixed pane id.", "type": "string" }, "start": { "description": "Start at this line. Zero is the top of the screen, negative is\nscrollback. Omit for the top of the screen, or of the scrollback with\n`history`.", "format": "int32", "type": [ "integer", "null" ] } }, "required": [ "pane" ], "type": "object" }, "tool": { "const": "capture_pane", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "cursor": { "description": "The cursor from the previous call. Omit to start watching.", "type": [ "string", "null" ] }, "pane": { "description": "The `%`-prefixed pane to read.", "type": "string" } }, "required": [ "pane" ], "type": "object" }, "tool": { "const": "capture_since", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "corner": { "description": "`top-left`, `top-right`, `bottom-left`, or `bottom-right`.", "type": "string" }, "window": { "description": "The `@`-prefixed window id.", "type": "string" } }, "required": [ "window", "corner" ], "type": "object" }, "tool": { "const": "find_pane_by_position", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "pane": { "description": "The `%`-prefixed pane id, as `list_panes` reports it.", "type": "string" } }, "required": [ "pane" ], "type": "object" }, "tool": { "const": "get_pane_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "That tool's arguments.", "properties": {}, "type": "object" }, "tool": { "const": "get_server_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "session": { "description": "The session, by `$`-prefixed id as `list_sessions` reports it, or by\nname.", "type": "string" } }, "required": [ "session" ], "type": "object" }, "tool": { "const": "get_session_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "names": { "description": "tmux format variable names, such as `pane_current_path`.", "items": { "pattern": "^[A-Za-z][A-Za-z0-9_]*$", "type": "string" }, "maxItems": 32, "minItems": 1, "type": "array" }, "pane": { "description": "The `%`-prefixed pane to read them against. Omit to let tmux pick\nits current pane.", "type": [ "string", "null" ] } }, "required": [ "names" ], "type": "object" }, "tool": { "const": "get_tmux_variables", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "window": { "description": "The `@`-prefixed window id, as `list_windows` reports it.", "type": "string" } }, "required": [ "window" ], "type": "object" }, "tool": { "const": "get_window_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "That tool's arguments.", "properties": {}, "type": "object" }, "tool": { "const": "list_panes", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "That tool's arguments.", "properties": {}, "type": "object" }, "tool": { "const": "list_sessions", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "description": "That tool's arguments.", "properties": {}, "type": "object" }, "tool": { "const": "list_windows", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "history": { "default": false, "description": "Search scrollback as well as the visible screen.", "type": "boolean" }, "match_case": { "default": false, "description": "Match case. Off by default.", "type": "boolean" }, "pattern": { "description": "The text to look for.", "maxLength": 4096, "type": "string" }, "regex": { "default": false, "description": "Read the pattern as a regular expression rather than literal text.", "type": "boolean" }, "session": { "description": "Only search panes in this session, by `$`-prefixed id or name. Omit\nfor every session.", "type": [ "string", "null" ] }, "window": { "description": "Only search panes in this window, by `@`-prefixed id. Omit for every\nwindow.", "type": [ "string", "null" ] } }, "required": [ "pattern" ], "type": "object" }, "tool": { "const": "search_panes", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "session": { "description": "The session whose environment to read, by `$`-prefixed id or name.\n\nOmit for the server's own.", "type": [ "string", "null" ] } }, "type": "object" }, "tool": { "const": "show_environment", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "session": { "description": "The session whose hooks to read, by `$`-prefixed id or name. Omit for\nthe server's own.", "type": [ "string", "null" ] } }, "type": "object" }, "tool": { "const": "show_hooks", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "name": { "description": "The option name, such as `history-limit` or a user option like `@theme`.", "type": "string" }, "scope": { "anyOf": [ { "enum": [ "server", "global-session", "global-window", "session", "window", "pane" ], "type": "string" }, { "type": "null" } ], "description": "Which tmux object the option belongs to.\n\nOne of `server`, `global-session`, `global-window`, `session`,\n`window`, or `pane`. Defaults to `global-session`, which is what\nsetting an option without a target means in tmux." }, "target": { "description": "The `$`, `@` or `%`-prefixed id, for the scopes that need one. Omit\nfor the others.", "type": [ "string", "null" ] } }, "required": [ "name" ], "type": "object" }, "tool": { "const": "show_option", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "That tool's arguments.", "properties": { "history": { "default": false, "description": "Include scrollback rather than only the visible screen.", "type": "boolean" }, "max_lines": { "description": "The most content lines to return, oldest dropped first.\n\nDefaults to the whole visible screen. The end of a pane is what says\nwhat just happened, so a limit keeps the end.", "minimum": 0, "type": [ "integer", "null" ] }, "pane": { "description": "The `%`-prefixed pane id.", "type": "string" } }, "required": [ "pane" ], "type": "object" }, "tool": { "const": "snapshot_pane", "type": "string" } }, "required": [ "tool" ], "type": "object" } ] }, "maxItems": 16, "minItems": 1, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "$defs": { "BatchItem": { "properties": { "error": { "anyOf": [ { "$ref": "#/$defs/ErrorData" }, { "type": "null" } ] }, "index": { "minimum": 0, "type": "integer" }, "result": true, "resultTruncated": { "type": "boolean" }, "success": { "type": "boolean" }, "tool": { "type": "string" } }, "required": [ "index", "tool", "success", "resultTruncated" ], "type": "object" }, "ErrorCode": { "description": "Standard JSON-RPC error codes used throughout the MCP protocol.\n\nThese codes follow the JSON-RPC 2.0 specification and provide\nstandardized error reporting across all MCP implementations.", "format": "int32", "type": "integer" }, "ErrorData": { "description": "Error information for JSON-RPC error responses.\n\nThis structure follows the JSON-RPC 2.0 specification for error reporting,\nproviding a standardized way to communicate errors between clients and servers.", "properties": { "code": { "$ref": "#/$defs/ErrorCode", "description": "The error type that occurred (using standard JSON-RPC error codes)" }, "data": { "description": "Additional information about the error. The value of this member is defined by the\nsender (e.g. detailed error information, nested errors etc.)." }, "message": { "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", "type": "string" } }, "required": [ "code", "message" ], "type": "object" }, "OnError": { "enum": [ "stop", "continue" ], "type": "string" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "failed": { "minimum": 0, "type": "integer" }, "onError": { "$ref": "#/$defs/OnError" }, "results": { "items": { "$ref": "#/$defs/BatchItem" }, "type": "array" }, "stoppedAt": { "minimum": 0, "type": [ "integer", "null" ] }, "succeeded": { "minimum": 0, "type": "integer" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "minimum": 0, "type": "integer" } }, "required": [ "results", "succeeded", "failed", "truncated", "truncatedBytes", "onError" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": true, "readOnlyHint": true, "title": "Call Read Tools Batch" } ``` --- # capture_pane Source: https://libtmux.org/en/rs/latest/mcp/tools/capture_pane/ > Read a pane's contents. Reads the visible screen by default; set history to reach output that has scrolled off, or give a start and end line. Set last_command to get only what the last command printed, which is usually what you want and is far shorter -- it needs tmux 3.7 and a shell that marks its prompts, and says so when it cannot. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read a pane’s contents. Reads the visible screen by default; set history to reach output that has scrolled off, or give a start and end line. Set last_command to get only what the last command printed, which is usually what you want and is far shorter — it needs tmux 3.7 and a shell that marks its prompts, and says so when it cannot. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/capture_pane.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/inspect.rs#L196) ## Arguments * `end` optional · integer | null End at this line. Omit for the bottom of the screen. * `history` optional · boolean Read the whole history rather than the visible screen. Default: `false`. * `last_command` optional · boolean Return only the last command's output, when the shell marks its prompts. Answers far less than the history, because it starts where the last command's output began. When the pane's shell does not mark its prompts -- fish does, bash and zsh do not -- this reports \`marks: "absent"\` and returns the visible screen instead. Default: `false`. * `pane` required · string The \`%\`-prefixed pane id. * `start` optional · integer | null Start at this line. Zero is the top of the screen, negative is scrollback. Omit for the top of the screen, or of the scrollback with \`history\`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "end": { "description": "End at this line. Omit for the bottom of the screen.", "format": "int32", "type": [ "integer", "null" ] }, "history": { "default": false, "description": "Read the whole history rather than the visible screen.", "type": "boolean" }, "last_command": { "default": false, "description": "Return only the last command's output, when the shell marks its\nprompts.\n\nAnswers far less than the history, because it starts where the last\ncommand's output began. When the pane's shell does not mark its\nprompts -- fish does, bash and zsh do not -- this reports\n`marks: \"absent\"` and returns the visible screen instead.", "type": "boolean" }, "pane": { "description": "The `%`-prefixed pane id.", "type": "string" }, "start": { "description": "Start at this line. Zero is the top of the screen, negative is\nscrollback. Omit for the top of the screen, or of the scrollback with\n`history`.", "format": "int32", "type": [ "integer", "null" ] } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$defs": { "Marks": { "description": "Whether tmux knew where the last command's output began.\n\nReported rather than inferred: an answer that fell back to the whole\nscreen looks exactly like a command that printed a great deal.", "oneOf": [ { "const": "present", "description": "The prompt marks were there, so the text is one command's output.", "type": "string" }, { "const": "absent", "description": "tmux has the marks but this pane has none, because its shell does not\nemit OSC 133. fish does; bash and zsh need shell integration. The\nvisible screen came back instead -- not the history, which would\nanswer a request for one command with everything the pane ever wrote.", "type": "string" }, { "const": "unsupported", "description": "This tmux predates `capture-pane -F`, which arrived in 3.7. The\nvisible screen came back instead.", "type": "string" }, { "const": "not_asked", "description": "The caller did not ask for the last command, so nothing was looked up.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "lines": { "description": "How many lines that is.", "minimum": 0, "type": "integer" }, "marks": { "$ref": "#/$defs/Marks", "description": "Whether the text is one command's output, and why it is not." }, "pane": { "description": "The pane that was read.", "type": "string" }, "text": { "description": "The text, with lines separated by newlines.", "type": "string" } }, "required": [ "pane", "text", "lines", "marks" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": true, "readOnlyHint": true, "title": "Read Pane Contents" } ``` --- # capture_since Source: https://libtmux.org/en/rs/latest/mcp/tools/capture_since/ > Read what a pane wrote since the previous call. The first call, with no cursor, starts watching and returns a cursor; later calls pass it back and receive only what is new, as the raw output stream, not the rendered screen: a line redrawn in place repeats; capture_pane shows the screen. Use this to follow a pane over several turns without re-reading the whole screen. The answer says missed=true if the cursor no longer names retained output, including when the pane outran the buffer, its live tail was evicted, or the server restarted. Starting a tail owns a retained observer until the tail is evicted or the server stops. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read what a pane wrote since the previous call. The first call, with no cursor, starts watching and returns a cursor; later calls pass it back and receive only what is new, as the raw output stream, not the rendered screen: a line redrawn in place repeats; [capture_pane](https://libtmux.org/en/rs/latest/mcp/tools/capture_pane/) shows the screen. Use this to follow a pane over several turns without re-reading the whole screen. The answer says missed=true if the cursor no longer names retained output, including when the pane outran the buffer, its live tail was evicted, or the server restarted. Starting a tail owns a retained observer until the tail is evicted or the server stops. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/capture_since.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/observe.rs#L434) ## Arguments * `cursor` optional · string | null The cursor from the previous call. Omit to start watching. * `pane` required · string The \`%\`-prefixed pane to read. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "cursor": { "description": "The cursor from the previous call. Omit to start watching.", "type": [ "string", "null" ] }, "pane": { "description": "The `%`-prefixed pane to read.", "type": "string" } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "closed": { "description": "Whether the pane has stopped writing for good.", "type": "boolean" }, "cursor": { "description": "The cursor to pass back next time.", "type": "string" }, "first": { "description": "Whether this is the first answer, which reports the visible screen\nrather than what is new.", "type": "boolean" }, "missed": { "description": "Whether output between the previous cursor and this text was lost.", "type": "boolean" }, "pane": { "description": "The pane that was read.", "type": "string" }, "text": { "description": "The text, with escape sequences removed.\n\nAfter the first answer this is the raw output stream, not the rendered\nscreen: a line redrawn in place repeats. `capture_pane` shows the\nscreen.", "type": "string" } }, "required": [ "pane", "text", "cursor", "missed", "closed", "first" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": true, "readOnlyHint": true, "title": "Read New Pane Output" } ``` --- # clear_pane_scrollback Source: https://libtmux.org/en/rs/latest/mcp/tools/clear_pane_scrollback/ > Discard a pane's scrollback, so the next capture_pane returns only what happens next. Use this before running something whose output you want to read cleanly: it is far cheaper than reading past the old output every time. The visible screen is left alone. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Discard a pane’s scrollback, so the next [capture_pane](https://libtmux.org/en/rs/latest/mcp/tools/capture_pane/) returns only what happens next. Use this before running something whose output you want to read cleanly: it is far cheaper than reading past the old output every time. The visible screen is left alone. Delete tmux state; accepts no command payload. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/clear_pane_scrollback.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L584) ## Arguments * `pane` required · string The \`%\`-prefixed pane id, as \`list_panes\` reports it. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "pane": { "description": "The `%`-prefixed pane id, as `list_panes` reports it.", "type": "string" } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "pane": { "description": "The pane that changed.", "type": "string" } }, "required": [ "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Clear Pane History" } ``` --- # create_session Source: https://libtmux.org/en/rs/latest/mcp/tools/create_session/ > Create a new detached tmux session. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Create a new detached tmux session. Start a pane’s configured process; accepts no command payload. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/create_session.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L249) ## Arguments * `name` required · string The name for the new session. It must not already exist. * `start_directory` optional · string | null The first window's working directory. Omit for the directory this MCP server started in. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "name": { "description": "The name for the new session. It must not already exist.", "type": "string" }, "start_directory": { "description": "The first window's working directory. Omit for the directory this MCP\nserver started in.", "type": [ "string", "null" ] } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "attached": { "description": "Whether any client is attached.", "type": "boolean" }, "id": { "description": "The `$`-prefixed tmux identity.", "type": "string" }, "name": { "description": "The session name, absent when tmux reported none.", "type": "string" }, "windows": { "description": "How many windows the session holds.", "minimum": 0, "type": "integer" } }, "required": [ "id", "name", "windows", "attached" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Create Session" } ``` --- # create_window Source: https://libtmux.org/en/rs/latest/mcp/tools/create_window/ > Create a window running its configured process. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Create a window running its configured process. Start a pane’s configured process; accepts no command payload. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/create_window.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L927) ## Arguments * `name` optional · string | null The window name. Omit to let tmux name it after its running command. * `session` required · string The session to create the window in, by \`$\`-prefixed id or name. * `start_directory` optional · string | null The window's working directory. Omit for the directory this MCP server started in. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "name": { "description": "The window name. Omit to let tmux name it after its running command.", "type": [ "string", "null" ] }, "session": { "description": "The session to create the window in, by `$`-prefixed id or name.", "type": "string" }, "start_directory": { "description": "The window's working directory. Omit for the directory this MCP\nserver started in.", "type": [ "string", "null" ] } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the session's active window.", "type": "boolean" }, "id": { "description": "The `@`-prefixed tmux identity.", "type": "string" }, "index": { "description": "The window's index within that session.", "format": "int32", "type": "integer" }, "linked": { "description": "Whether more than one session links this window.", "type": "boolean" }, "name": { "description": "The window name.", "type": "string" }, "panes": { "description": "How many panes the window holds.", "minimum": 0, "type": "integer" }, "session_id": { "description": "The session this window was reached through.", "type": "string" } }, "required": [ "id", "session_id", "index", "name", "panes", "active", "linked" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Create Window" } ``` --- # find_pane_by_position Source: https://libtmux.org/en/rs/latest/mcp/tools/find_pane_by_position/ > Find the pane touching a named window corner. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Find the pane touching a named window corner. Inspect tmux metadata; accepts no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/find_pane_by_position.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L609) ## Arguments * `corner` required · string \`top-left\`, \`top-right\`, \`bottom-left\`, or \`bottom-right\`. * `window` required · string The \`@\`-prefixed window id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "corner": { "description": "`top-left`, `top-right`, `bottom-left`, or `bottom-right`.", "type": "string" }, "window": { "description": "The `@`-prefixed window id.", "type": "string" } }, "required": [ "window", "corner" ], "type": "object" } ``` Output schema ```json { "$defs": { "Relation": { "description": "How a pane relates to the process answering the request.\n\nThree values rather than a boolean, because \"not the caller's pane\" and\n\"there is no caller\" are different answers and an agent acts differently on\neach.", "oneOf": [ { "const": "unknown", "description": "This process is not running inside tmux, so no pane is its own.", "type": "string" }, { "const": "self", "description": "Confirmed: the same tmux server, and the same pane.", "type": "string" }, { "const": "other", "description": "Some other pane, or a pane this crate cannot prove is the caller's.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the window's active pane.", "type": "boolean" }, "caller": { "$ref": "#/$defs/Relation", "description": "Whether this is the pane the MCP server itself runs in.\n\n`self` only on a confirmed match of both socket and pane id; `other`\nfor every pane that is not, including one this crate cannot prove\neither way; `unknown` when the server is not running inside tmux, so\nthe question has no answer." }, "command": { "description": "The command currently running.", "type": [ "string", "null" ] }, "id": { "description": "The `%`-prefixed tmux identity.", "type": "string" }, "path": { "description": "The pane's working directory.", "type": [ "string", "null" ] }, "window_id": { "description": "The window that contains the pane.", "type": "string" } }, "required": [ "id", "window_id", "active", "caller" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "Find Pane By Position" } ``` --- # get_pane_info Source: https://libtmux.org/en/rs/latest/mcp/tools/get_pane_info/ > Return metadata for one pane. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return metadata for one pane. Inspect tmux metadata; accepts no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/get_pane_info.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L593) ## Arguments * `pane` required · string The \`%\`-prefixed pane id, as \`list_panes\` reports it. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "pane": { "description": "The `%`-prefixed pane id, as `list_panes` reports it.", "type": "string" } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$defs": { "Relation": { "description": "How a pane relates to the process answering the request.\n\nThree values rather than a boolean, because \"not the caller's pane\" and\n\"there is no caller\" are different answers and an agent acts differently on\neach.", "oneOf": [ { "const": "unknown", "description": "This process is not running inside tmux, so no pane is its own.", "type": "string" }, { "const": "self", "description": "Confirmed: the same tmux server, and the same pane.", "type": "string" }, { "const": "other", "description": "Some other pane, or a pane this crate cannot prove is the caller's.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the window's active pane.", "type": "boolean" }, "caller": { "$ref": "#/$defs/Relation", "description": "Whether this is the pane the MCP server itself runs in.\n\n`self` only on a confirmed match of both socket and pane id; `other`\nfor every pane that is not, including one this crate cannot prove\neither way; `unknown` when the server is not running inside tmux, so\nthe question has no answer." }, "command": { "description": "The command currently running.", "type": [ "string", "null" ] }, "id": { "description": "The `%`-prefixed tmux identity.", "type": "string" }, "path": { "description": "The pane's working directory.", "type": [ "string", "null" ] }, "window_id": { "description": "The window that contains the pane.", "type": "string" } }, "required": [ "id", "window_id", "active", "caller" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "Get Pane Info" } ``` --- # get_server_info Source: https://libtmux.org/en/rs/latest/mcp/tools/get_server_info/ > Report every session with its windows and panes, in one call. Prefer this over calling the three listing tools separately: it costs tmux four commands rather than one per object. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Report every session with its windows and panes, in one call. Prefer this over calling the three listing tools separately: it costs tmux four commands rather than one per object. Inspect tmux metadata; accepts no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/get_server_info.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/inspect.rs#L149) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "type": "object" } ``` Output schema ```json { "$defs": { "Branch": { "description": "One session with everything under it.", "properties": { "attached": { "description": "Whether any client is attached.", "type": "boolean" }, "id": { "description": "The `$`-prefixed tmux identity.", "type": "string" }, "name": { "description": "The session name.", "type": "string" }, "windows": { "description": "The windows it holds.", "items": { "$ref": "#/$defs/BranchWindow" }, "type": "array" } }, "required": [ "id", "name", "attached", "windows" ], "type": "object" }, "BranchPane": { "description": "One pane inside a described window.", "properties": { "active": { "description": "Whether this is the window's active pane.", "type": "boolean" }, "command": { "description": "The command currently running.", "type": [ "string", "null" ] }, "id": { "description": "The `%`-prefixed tmux identity.", "type": "string" } }, "required": [ "id", "active" ], "type": "object" }, "BranchWindow": { "description": "One window inside a described session.", "properties": { "active": { "description": "Whether this is the session's active window.", "type": "boolean" }, "id": { "description": "The `@`-prefixed tmux identity.", "type": "string" }, "index": { "description": "The window's index within its session.", "format": "int32", "type": "integer" }, "linked": { "description": "Whether more than one session links this window.", "type": "boolean" }, "name": { "description": "The window name.", "type": "string" }, "panes": { "description": "The panes it holds.", "items": { "$ref": "#/$defs/BranchPane" }, "type": "array" } }, "required": [ "id", "index", "name", "active", "linked", "panes" ], "type": "object" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "sessions": { "description": "Every session, with its windows and their panes.", "items": { "$ref": "#/$defs/Branch" }, "type": "array" } }, "required": [ "sessions" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "Describe Server" } ``` --- # get_session_info Source: https://libtmux.org/en/rs/latest/mcp/tools/get_session_info/ > Return metadata for one session. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return metadata for one session. Inspect tmux metadata; accepts no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/get_session_info.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L555) ## Arguments * `session` required · string The session, by \`$\`-prefixed id as \`list_sessions\` reports it, or by name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "session": { "description": "The session, by `$`-prefixed id as `list_sessions` reports it, or by\nname.", "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "attached": { "description": "Whether any client is attached.", "type": "boolean" }, "id": { "description": "The `$`-prefixed tmux identity.", "type": "string" }, "name": { "description": "The session name, absent when tmux reported none.", "type": "string" }, "windows": { "description": "How many windows the session holds.", "minimum": 0, "type": "integer" } }, "required": [ "id", "name", "windows", "attached" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "Get Session Info" } ``` --- # get_tmux_variables Source: https://libtmux.org/en/rs/latest/mcp/tools/get_tmux_variables/ > Read a bounded set of tmux variables against one pane. tmux reads a name it does not know as a format from its environment, so a name the server or session environment holds is refused unless the operator listed it in LIBTMUX_ENVIRONMENT_VALUES at startup. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read a bounded set of tmux variables against one pane. tmux reads a name it does not know as a format from its environment, so a name the server or session environment holds is refused unless the operator listed it in LIBTMUX_ENVIRONMENT_VALUES at startup. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/get_tmux_variables.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L652) ## Arguments * `names` required · array tmux format variable names, such as \`pane_current_path\`. * `pane` optional · string | null The \`%\`-prefixed pane to read them against. Omit to let tmux pick its current pane. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "names": { "description": "tmux format variable names, such as `pane_current_path`.", "items": { "pattern": "^[A-Za-z][A-Za-z0-9_]*$", "type": "string" }, "maxItems": 32, "minItems": 1, "type": "array" }, "pane": { "description": "The `%`-prefixed pane to read them against. Omit to let tmux pick\nits current pane.", "type": [ "string", "null" ] } }, "required": [ "names" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "values": { "additionalProperties": { "type": "string" }, "type": "object" } }, "required": [ "values" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "Get tmux Variables" } ``` --- # get_window_info Source: https://libtmux.org/en/rs/latest/mcp/tools/get_window_info/ > Return metadata for one window. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return metadata for one window. Inspect tmux metadata; accepts no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/get_window_info.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L579) ## Arguments * `window` required · string The \`@\`-prefixed window id, as \`list_windows\` reports it. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "window": { "description": "The `@`-prefixed window id, as `list_windows` reports it.", "type": "string" } }, "required": [ "window" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the session's active window.", "type": "boolean" }, "id": { "description": "The `@`-prefixed tmux identity.", "type": "string" }, "index": { "description": "The window's index within that session.", "format": "int32", "type": "integer" }, "linked": { "description": "Whether more than one session links this window.", "type": "boolean" }, "name": { "description": "The window name.", "type": "string" }, "panes": { "description": "How many panes the window holds.", "minimum": 0, "type": "integer" }, "session_id": { "description": "The session this window was reached through.", "type": "string" } }, "required": [ "id", "session_id", "index", "name", "panes", "active", "linked" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "Get Window Info" } ``` --- # kill_pane Source: https://libtmux.org/en/rs/latest/mcp/tools/kill_pane/ > Kill a pane. Killing a window's last pane closes the window. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Kill a pane. Killing a window’s last pane closes the window. Delete tmux state; accepts no command payload. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/kill_pane.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L227) ## Arguments * `pane` required · string The \`%\`-prefixed pane id, as \`list_panes\` reports it. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "pane": { "description": "The `%`-prefixed pane id, as `list_panes` reports it.", "type": "string" } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "id": { "description": "The id of what was destroyed.", "type": "string" } }, "required": [ "id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Kill Pane" } ``` --- # kill_session Source: https://libtmux.org/en/rs/latest/mcp/tools/kill_session/ > Kill a tmux session and everything in it. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Kill a tmux session and everything in it. Delete tmux state; accepts no command payload. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/kill_session.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L299) ## Arguments * `session` required · string The session, by \`$\`-prefixed id as \`list_sessions\` reports it, or by name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "session": { "description": "The session, by `$`-prefixed id as `list_sessions` reports it, or by\nname.", "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "id": { "description": "The id of what was destroyed.", "type": "string" } }, "required": [ "id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Kill Session" } ``` --- # kill_window Source: https://libtmux.org/en/rs/latest/mcp/tools/kill_window/ > Kill a window, closing it in every session that links it. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Kill a window, closing it in every session that links it. Delete tmux state; accepts no command payload. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/kill_window.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L207) ## Arguments * `window` required · string The \`@\`-prefixed window id, as \`list_windows\` reports it. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "window": { "description": "The `@`-prefixed window id, as `list_windows` reports it.", "type": "string" } }, "required": [ "window" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "id": { "description": "The id of what was destroyed.", "type": "string" } }, "required": [ "id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Kill Window" } ``` --- # list_panes Source: https://libtmux.org/en/rs/latest/mcp/tools/list_panes/ > List every pane on the server. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List every pane on the server. Inspect tmux metadata; accepts no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/list_panes.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/inspect.rs#L137) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "type": "object" } ``` Output schema ```json { "$defs": { "PaneView": { "description": "One pane, as the protocol sees it.", "properties": { "active": { "description": "Whether this is the window's active pane.", "type": "boolean" }, "caller": { "$ref": "#/$defs/Relation", "description": "Whether this is the pane the MCP server itself runs in.\n\n`self` only on a confirmed match of both socket and pane id; `other`\nfor every pane that is not, including one this crate cannot prove\neither way; `unknown` when the server is not running inside tmux, so\nthe question has no answer." }, "command": { "description": "The command currently running.", "type": [ "string", "null" ] }, "id": { "description": "The `%`-prefixed tmux identity.", "type": "string" }, "path": { "description": "The pane's working directory.", "type": [ "string", "null" ] }, "window_id": { "description": "The window that contains the pane.", "type": "string" } }, "required": [ "id", "window_id", "active", "caller" ], "type": "object" }, "Relation": { "description": "How a pane relates to the process answering the request.\n\nThree values rather than a boolean, because \"not the caller's pane\" and\n\"there is no caller\" are different answers and an agent acts differently on\neach.", "oneOf": [ { "const": "unknown", "description": "This process is not running inside tmux, so no pane is its own.", "type": "string" }, { "const": "self", "description": "Confirmed: the same tmux server, and the same pane.", "type": "string" }, { "const": "other", "description": "Some other pane, or a pane this crate cannot prove is the caller's.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "panes": { "description": "The panes, in tmux's own order.", "items": { "$ref": "#/$defs/PaneView" }, "type": "array" } }, "required": [ "panes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "List Panes" } ``` --- # list_sessions Source: https://libtmux.org/en/rs/latest/mcp/tools/list_sessions/ > List every tmux session on the server. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List every tmux session on the server. Inspect tmux metadata; accepts no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/list_sessions.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/inspect.rs#L110) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "type": "object" } ``` Output schema ```json { "$defs": { "SessionView": { "description": "One session, as the protocol sees it.", "properties": { "attached": { "description": "Whether any client is attached.", "type": "boolean" }, "id": { "description": "The `$`-prefixed tmux identity.", "type": "string" }, "name": { "description": "The session name, absent when tmux reported none.", "type": "string" }, "windows": { "description": "How many windows the session holds.", "minimum": 0, "type": "integer" } }, "required": [ "id", "name", "windows", "attached" ], "type": "object" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "sessions": { "description": "The sessions, in tmux's own order.", "items": { "$ref": "#/$defs/SessionView" }, "type": "array" } }, "required": [ "sessions" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "List Sessions" } ``` --- # list_windows Source: https://libtmux.org/en/rs/latest/mcp/tools/list_windows/ > List every window on the server. A window linked into several sessions appears once per link, so an id can repeat with a different session_id. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List every window on the server. A window linked into several sessions appears once per link, so an id can repeat with a different session_id. Inspect tmux metadata; accepts no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/list_windows.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/inspect.rs#L125) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "type": "object" } ``` Output schema ```json { "$defs": { "WindowView": { "description": "One window, as the protocol sees it.", "properties": { "active": { "description": "Whether this is the session's active window.", "type": "boolean" }, "id": { "description": "The `@`-prefixed tmux identity.", "type": "string" }, "index": { "description": "The window's index within that session.", "format": "int32", "type": "integer" }, "linked": { "description": "Whether more than one session links this window.", "type": "boolean" }, "name": { "description": "The window name.", "type": "string" }, "panes": { "description": "How many panes the window holds.", "minimum": 0, "type": "integer" }, "session_id": { "description": "The session this window was reached through.", "type": "string" } }, "required": [ "id", "session_id", "index", "name", "panes", "active", "linked" ], "type": "object" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "windows": { "description": "The windows, in tmux's own order.", "items": { "$ref": "#/$defs/WindowView" }, "type": "array" } }, "required": [ "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "List Windows" } ``` --- # move_window Source: https://libtmux.org/en/rs/latest/mcp/tools/move_window/ > Move one window to a session and index. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Move one window to a session and index. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/move_window.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L791) ## Arguments * `destination_index` required · integer The window index there. tmux refuses one already in use. * `destination_session` required · string The session to move the window into, by \`$\`-prefixed id or name. * `window` required · string The \`@\`-prefixed window id to move. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "destination_index": { "description": "The window index there. tmux refuses one already in use.", "format": "int32", "type": "integer" }, "destination_session": { "description": "The session to move the window into, by `$`-prefixed id or name.", "type": "string" }, "window": { "description": "The `@`-prefixed window id to move.", "type": "string" } }, "required": [ "window", "destination_session", "destination_index" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the session's active window.", "type": "boolean" }, "id": { "description": "The `@`-prefixed tmux identity.", "type": "string" }, "index": { "description": "The window's index within that session.", "format": "int32", "type": "integer" }, "linked": { "description": "Whether more than one session links this window.", "type": "boolean" }, "name": { "description": "The window name.", "type": "string" }, "panes": { "description": "How many panes the window holds.", "minimum": 0, "type": "integer" }, "session_id": { "description": "The session this window was reached through.", "type": "string" } }, "required": [ "id", "session_id", "index", "name", "panes", "active", "linked" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false, "title": "Move Window" } ``` --- # paste_text Source: https://libtmux.org/en/rs/latest/mcp/tools/paste_text/ > Put text into a pane through a tmux paste buffer instead of typing it key by key. Use this for anything long or awkward: send_keys types the text, so a shell reading it can react to each character, and a bracketed-paste aware program treats a paste as one block. Optional Enter is appended to that same block. Empty text without Enter is a guarded buffer-free no-op. Paste targets only the named pane, even when synchronized input is enabled. A dead, input-disabled, mode-owned, terminal-attended, or inherited-caller target is refused before setup and again immediately before paste. The private buffer is deleted after setup, refusal, and paste outcomes; observations can still race with tmux. A submitted paste is remembered briefly so wait_for_text can discount its own echo. Send input to a pane's program; a shell that receives it runs it with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Put text into a pane through a tmux paste buffer instead of typing it key by key. Use this for anything long or awkward: [send_keys](https://libtmux.org/en/rs/latest/mcp/tools/send_keys/) types the text, so a shell reading it can react to each character, and a bracketed-paste aware program treats a paste as one block. Optional Enter is appended to that same block. Empty text without Enter is a guarded buffer-free no-op. Paste targets only the named pane, even when synchronized input is enabled. A dead, input-disabled, mode-owned, terminal-attended, or inherited-caller target is refused before setup and again immediately before paste. The private buffer is deleted after setup, refusal, and paste outcomes; observations can still race with tmux. A submitted paste is remembered briefly so [wait_for_text](https://libtmux.org/en/rs/latest/mcp/tools/wait_for_text/) can discount its own echo. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/paste_text.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L608) ## Arguments * `enter` optional · boolean Whether to append Enter to the same paste block. Default: `false`. * `pane` required · string The \`%\`-prefixed pane to paste into. * `text` required · string The text to deliver. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "enter": { "default": false, "description": "Whether to append Enter to the same paste block.", "type": "boolean" }, "pane": { "description": "The `%`-prefixed pane to paste into.", "type": "string" }, "text": { "description": "The text to deliver.", "type": "string" } }, "required": [ "pane", "text" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "bytes": { "description": "How many bytes came from `text`, excluding optional Enter.", "minimum": 0, "type": "integer" }, "pane": { "description": "The pane it went into.", "type": "string" } }, "required": [ "pane", "bytes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Paste Text Into Pane" } ``` --- # rename_session Source: https://libtmux.org/en/rs/latest/mcp/tools/rename_session/ > Rename one session. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Rename one session. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/rename_session.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L713) ## Arguments * `name` required · string The new name. tmux refuses one another session has. * `session` required · string The session to rename, by \`$\`-prefixed id or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "name": { "description": "The new name. tmux refuses one another session has.", "type": "string" }, "session": { "description": "The session to rename, by `$`-prefixed id or name.", "type": "string" } }, "required": [ "session", "name" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "attached": { "description": "Whether any client is attached.", "type": "boolean" }, "id": { "description": "The `$`-prefixed tmux identity.", "type": "string" }, "name": { "description": "The session name, absent when tmux reported none.", "type": "string" }, "windows": { "description": "How many windows the session holds.", "minimum": 0, "type": "integer" } }, "required": [ "id", "name", "windows", "attached" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Rename Session" } ``` --- # rename_window Source: https://libtmux.org/en/rs/latest/mcp/tools/rename_window/ > Rename one window. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Rename one window. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/rename_window.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L745) ## Arguments * `name` required · string The new name. tmux then stops renaming the window automatically. * `window` required · string The \`@\`-prefixed window id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "name": { "description": "The new name. tmux then stops renaming the window automatically.", "type": "string" }, "window": { "description": "The `@`-prefixed window id.", "type": "string" } }, "required": [ "window", "name" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the session's active window.", "type": "boolean" }, "id": { "description": "The `@`-prefixed tmux identity.", "type": "string" }, "index": { "description": "The window's index within that session.", "format": "int32", "type": "integer" }, "linked": { "description": "Whether more than one session links this window.", "type": "boolean" }, "name": { "description": "The window name.", "type": "string" }, "panes": { "description": "How many panes the window holds.", "minimum": 0, "type": "integer" }, "session_id": { "description": "The session this window was reached through.", "type": "string" } }, "required": [ "id", "session_id", "index", "name", "panes", "active", "linked" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Rename Window" } ``` --- # resize_pane Source: https://libtmux.org/en/rs/latest/mcp/tools/resize_pane/ > Move one edge of a pane by a number of rows or columns. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Move one edge of a pane by a number of rows or columns. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/resize_pane.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L319) ## Arguments * `cells` required · integer How many rows or columns to move it by. * `direction` required Which edge to move: \`up\`, \`down\`, \`left\`, or \`right\`. * `pane` required · string The \`%\`-prefixed pane id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$defs": { "ResizeDirectionSchema": { "enum": [ "up", "down", "left", "right" ], "type": "string" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "cells": { "description": "How many rows or columns to move it by.", "minimum": 0, "type": "integer" }, "direction": { "$ref": "#/$defs/ResizeDirectionSchema", "description": "Which edge to move: `up`, `down`, `left`, or `right`." }, "pane": { "description": "The `%`-prefixed pane id.", "type": "string" } }, "required": [ "pane", "direction", "cells" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "height": { "description": "How tall it is now, in rows.", "minimum": 0, "type": "integer" }, "pane": { "description": "The pane that was resized.", "type": "string" }, "width": { "description": "How wide it is now, in columns.", "minimum": 0, "type": "integer" } }, "required": [ "pane", "width", "height" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false, "title": "Resize Pane" } ``` --- # resize_window Source: https://libtmux.org/en/rs/latest/mcp/tools/resize_window/ > Resize one window to exact cell dimensions. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Resize one window to exact cell dimensions. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/resize_window.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L768) ## Arguments * `height` required · integer Height in rows. * `width` required · integer Width in columns. * `window` required · string The \`@\`-prefixed window id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "height": { "description": "Height in rows.", "minimum": 0, "type": "integer" }, "width": { "description": "Width in columns.", "minimum": 0, "type": "integer" }, "window": { "description": "The `@`-prefixed window id.", "type": "string" } }, "required": [ "window", "width", "height" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the session's active window.", "type": "boolean" }, "id": { "description": "The `@`-prefixed tmux identity.", "type": "string" }, "index": { "description": "The window's index within that session.", "format": "int32", "type": "integer" }, "linked": { "description": "Whether more than one session links this window.", "type": "boolean" }, "name": { "description": "The window name.", "type": "string" }, "panes": { "description": "How many panes the window holds.", "minimum": 0, "type": "integer" }, "session_id": { "description": "The session this window was reached through.", "type": "string" } }, "required": [ "id", "session_id", "index", "name", "panes", "active", "linked" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Resize Window" } ``` --- # respawn_pane Source: https://libtmux.org/en/rs/latest/mcp/tools/respawn_pane/ > Restart a pane's configured process with no command payload. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Restart a pane’s configured process with no command payload. Start a pane’s configured process; accepts no command payload. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/respawn_pane.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L1020) ## Arguments * `kill_first` optional · boolean Kill a running process first. Defaults to \`false\`, which respawns only a dead pane. Default: `false`. * `pane` required · string The \`%\`-prefixed pane id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "kill_first": { "default": false, "description": "Kill a running process first. Defaults to `false`, which respawns\nonly a dead pane.", "type": "boolean" }, "pane": { "description": "The `%`-prefixed pane id.", "type": "string" } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$defs": { "Relation": { "description": "How a pane relates to the process answering the request.\n\nThree values rather than a boolean, because \"not the caller's pane\" and\n\"there is no caller\" are different answers and an agent acts differently on\neach.", "oneOf": [ { "const": "unknown", "description": "This process is not running inside tmux, so no pane is its own.", "type": "string" }, { "const": "self", "description": "Confirmed: the same tmux server, and the same pane.", "type": "string" }, { "const": "other", "description": "Some other pane, or a pane this crate cannot prove is the caller's.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the window's active pane.", "type": "boolean" }, "caller": { "$ref": "#/$defs/Relation", "description": "Whether this is the pane the MCP server itself runs in.\n\n`self` only on a confirmed match of both socket and pane id; `other`\nfor every pane that is not, including one this crate cannot prove\neither way; `unknown` when the server is not running inside tmux, so\nthe question has no answer." }, "command": { "description": "The command currently running.", "type": [ "string", "null" ] }, "id": { "description": "The `%`-prefixed tmux identity.", "type": "string" }, "path": { "description": "The pane's working directory.", "type": [ "string", "null" ] }, "window_id": { "description": "The window that contains the pane.", "type": "string" } }, "required": [ "id", "window_id", "active", "caller" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Respawn Pane" } ``` --- # run_shell_command Source: https://libtmux.org/en/rs/latest/mcp/tools/run_shell_command/ > Run a shell command in a pane, wait for it to finish, and report its exit status with everything it wrote. This is the tool for "run this and tell me if it worked". Output is the pane's raw output stream, not the rendered screen: nothing is missed, the shell prompt is not included, and a line redrawn in place repeats; capture_pane shows the screen. The command runs in a subshell, so cd and export do not persist and invalid syntax completes with a nonzero status. Valid inherited Bash and zsh ERR and DEBUG traps remain visible to the command while parent-shell traps and options remain unchanged. It requires one configured input recipient and observes its mode, liveness, input-off state, attended-client state, cohort, inherited-caller relation, known POSIX shell, and resolved route before watcher setup and again before dispatch. A process-wide endpoint-and-pane reservation blocks other MCP pane input until the completion marker or pane closure is proved. The resolved tmux executable and socket path must contain no ASCII terminal-control bytes. The reservation serializes this MCP's input, but tmux observations can still race with dispatch. The pane shell, tmux server, and configuration must be trusted. Reaching the deadline, cancelling, or an uncertain dispatch stops this request while its watcher keeps the reservation until completion is proved. To stop the command, send_keys with keys ["C-c"] alone passes the reservation, and the command reports completion when it ends; respawn_pane with kill_first replaces a program that ignores C-c and C-\. Run a shell command in a pane with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Run a shell command in a pane, wait for it to finish, and report its exit status with everything it wrote. This is the tool for “run this and tell me if it worked”. Output is the pane’s raw output stream, not the rendered screen: nothing is missed, the shell prompt is not included, and a line redrawn in place repeats; [capture_pane](https://libtmux.org/en/rs/latest/mcp/tools/capture_pane/) shows the screen. The command runs in a subshell, so cd and export do not persist and invalid syntax completes with a nonzero status. Valid inherited Bash and zsh ERR and DEBUG traps remain visible to the command while parent-shell traps and options remain unchanged. It requires one configured input recipient and observes its mode, liveness, input-off state, attended-client state, cohort, inherited-caller relation, known POSIX shell, and resolved route before watcher setup and again before dispatch. A process-wide endpoint-and-pane reservation blocks other MCP pane input until the completion marker or pane closure is proved. The resolved tmux executable and socket path must contain no ASCII terminal-control bytes. The reservation serializes this MCP’s input, but tmux observations can still race with dispatch. The pane shell, tmux server, and configuration must be trusted. Reaching the deadline, cancelling, or an uncertain dispatch stops this request while its watcher keeps the reservation until completion is proved. To stop the command, [send_keys](https://libtmux.org/en/rs/latest/mcp/tools/send_keys/) with keys \[“C-c”] alone passes the reservation, and the command reports completion when it ends; [respawn_pane](https://libtmux.org/en/rs/latest/mcp/tools/respawn_pane/) with kill_first replaces a program that ignores C-c and C-. Run a shell command in a pane with your user’s permissions. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/run_shell_command.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/observe.rs#L208) ## Arguments * `command` required · string The command for the pane's trusted POSIX-compatible shell. Shell reserved words and special builtins must retain their standard meanings. The command runs inside a subshell, so several lines are fine and a bare \`exit\` does not end the pane's own shell. Invalid syntax is contained and completes with the shell's nonzero status. Valid inherited Bash and zsh \`ERR\` and \`DEBUG\` traps remain visible to the command while the pane's parent-shell traps and options remain unchanged. * `pane` required · string The \`%\`-prefixed pane to run in. * `seconds` optional · integer | null How long to allow, in seconds. Defaults to 30, capped at 600. * `suppress_history` optional · boolean Whether to keep the command out of the shell's history. Default: `false`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "command": { "description": "The command for the pane's trusted POSIX-compatible shell.\n\nShell reserved words and special builtins must retain their standard\nmeanings. The command runs inside a subshell, so several lines are fine\nand a bare `exit` does not end the pane's own shell. Invalid syntax is\ncontained and completes with the shell's nonzero status. Valid inherited\nBash and zsh `ERR` and `DEBUG` traps remain visible to the command while\nthe pane's parent-shell traps and options remain unchanged.", "type": "string" }, "pane": { "description": "The `%`-prefixed pane to run in.", "type": "string" }, "seconds": { "description": "How long to allow, in seconds. Defaults to 30, capped at 600.", "minimum": 0, "type": [ "integer", "null" ] }, "suppress_history": { "default": false, "description": "Whether to keep the command out of the shell's history.", "type": "boolean" } }, "required": [ "pane", "command" ], "type": "object" } ``` Output schema ```json { "$defs": { "RunOutcome": { "description": "How a run finished.\n\nSplit from the wait outcomes rather than shared with them: a run cannot\nmatch a pattern and a wait cannot report a missing shell, and a vocabulary\ncarrying both would have an agent checking for answers that never come.", "oneOf": [ { "const": "completed", "description": "The command ran to completion and reported its status.", "type": "string" }, { "const": "deadline", "description": "The time the caller allowed ran out.\n\nThis ends the waiting, not the command. The pane stays reserved for it\nuntil it ends, so other pane input is refused; `send_keys` with keys\n`[\"C-c\"]` alone interrupts it.", "type": "string" }, { "const": "pane_closed", "description": "The pane stopped writing for good.", "type": "string" }, { "const": "cancelled", "description": "The client withdrew the request while the run was still going.", "type": "string" }, { "const": "no_shell", "description": "The pane never acknowledged the command.\n\nThe keys were sent but the opening sentinel never came back. That is\nwhat a pane looks like when it is not at a shell prompt: sitting in an\neditor or a REPL, or still running something an earlier call left\nbehind. The text was typed into whatever is there.\n\nThe evidence is absence, so a deadline too short for the pane's shell\nto have echoed anything yet looks the same. Read it as \"nothing came\nback in the time allowed\" and check the pane with `snapshot_pane`\nbefore concluding it is stuck.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "bytes": { "description": "How many bytes that was, before any truncation.", "minimum": 0, "type": "integer" }, "exit_status": { "description": "The command's exit status, when it completed.\n\nAbsent when the run did not complete, and when the command was killed\nby a signal rather than exiting.", "format": "int32", "type": [ "integer", "null" ] }, "outcome": { "$ref": "#/$defs/RunOutcome", "description": "How the run finished." }, "output": { "description": "Everything the command wrote, stdout and stderr interleaved in the\norder the program wrote them.\n\nThis is the raw output stream with escape sequences removed, not the\nrendered screen: a line redrawn in place, such as a progress bar,\nrepeats. `capture_pane` shows the screen.", "type": "string" }, "pane": { "description": "The pane the command ran in.", "type": "string" }, "truncated": { "description": "Whether the output was truncated from the front.", "type": "boolean" } }, "required": [ "pane", "outcome", "output", "bytes", "truncated" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Run Command In Pane" } ``` --- # search_panes Source: https://libtmux.org/en/rs/latest/mcp/tools/search_panes/ > Search what panes are displaying with Rust's linear-time regex engine. Accept at most 4,096 pattern bytes; search at most 64 panes, 8,192 lines, and 1 MiB; spend at most 250 ms matching and five seconds capturing. Report the pane and line of every match. Use this to find where something is -- which pane has the failing test, which one printed the error -- instead of capturing panes one at a time. Searches the visible screen by default; set history to include scrollback. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Search what panes are displaying with Rust’s linear-time regex engine. Accept at most 4,096 pattern bytes; search at most 64 panes, 8,192 lines, and 1 MiB; spend at most 250 ms matching and five seconds capturing. Report the pane and line of every match. Use this to find where something is — which pane has the failing test, which one printed the error — instead of capturing panes one at a time. Searches the visible screen by default; set history to include scrollback. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/search_panes.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/inspect.rs#L344) ## Arguments * `history` optional · boolean Search scrollback as well as the visible screen. Default: `false`. * `match_case` optional · boolean Match case. Off by default. Default: `false`. * `pattern` required · string The text to look for. * `regex` optional · boolean Read the pattern as a regular expression rather than literal text. Default: `false`. * `session` optional · string | null Only search panes in this session, by \`$\`-prefixed id or name. Omit for every session. * `window` optional · string | null Only search panes in this window, by \`@\`-prefixed id. Omit for every window. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "history": { "default": false, "description": "Search scrollback as well as the visible screen.", "type": "boolean" }, "match_case": { "default": false, "description": "Match case. Off by default.", "type": "boolean" }, "pattern": { "description": "The text to look for.", "maxLength": 4096, "type": "string" }, "regex": { "default": false, "description": "Read the pattern as a regular expression rather than literal text.", "type": "boolean" }, "session": { "description": "Only search panes in this session, by `$`-prefixed id or name. Omit\nfor every session.", "type": [ "string", "null" ] }, "window": { "description": "Only search panes in this window, by `@`-prefixed id. Omit for every\nwindow.", "type": [ "string", "null" ] } }, "required": [ "pattern" ], "type": "object" } ``` Output schema ```json { "$defs": { "MatchView": { "description": "One line of one pane that matched a search.", "properties": { "line": { "description": "Which line of the capture matched, counting from the top.", "minimum": 0, "type": "integer" }, "pane": { "description": "The pane the line was found in.", "type": "string" }, "text": { "description": "The line itself.", "type": "string" }, "window_id": { "description": "The window that pane belongs to.", "type": "string" } }, "required": [ "pane", "window_id", "line", "text" ], "type": "object" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "capped": { "description": "Whether the match ceiling was reached, so there may be more.", "type": "boolean" }, "matches": { "description": "Every matching line, in the order the panes were read.", "items": { "$ref": "#/$defs/MatchView" }, "type": "array" }, "panes_searched": { "description": "How many panes were read to answer this.", "minimum": 0, "type": "integer" } }, "required": [ "matches", "panes_searched", "capped" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": true, "readOnlyHint": true, "title": "Search Pane Contents" } ``` --- # select_layout Source: https://libtmux.org/en/rs/latest/mcp/tools/select_layout/ > Rearrange a window's panes using a saved tmux layout or a named layout and its unique abbreviation. Names follow the running daemon's version; mirrored main layouts require tmux 3.5. Invalid syntax is refused before window lookup. Return the saved layout tmux actually applied. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Rearrange a window’s panes using a saved tmux layout or a named layout and its unique abbreviation. Names follow the running daemon’s version; mirrored main layouts require tmux 3.5. Invalid syntax is refused before window lookup. Return the saved layout tmux actually applied. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/select_layout.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L551) ## Arguments * `layout` required · string A saved tmux layout, or a named layout and its unique abbreviation. The names are \`even-horizontal\`, \`even-vertical\`, \`main-horizontal\`, \`main-vertical\` and \`tiled\`. The running daemon determines which names and abbreviations are supported; mirrored main layouts require tmux 3.5. * `window` required · string The \`@\`-prefixed window to arrange. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "layout": { "description": "A saved tmux layout, or a named layout and its unique abbreviation.\n\nThe names are `even-horizontal`, `even-vertical`, `main-horizontal`,\n`main-vertical` and `tiled`. The running daemon determines which names\nand abbreviations are supported; mirrored main layouts require tmux 3.5.", "type": "string" }, "window": { "description": "The `@`-prefixed window to arrange.", "type": "string" } }, "required": [ "window", "layout" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "layout": { "description": "The layout it now has, in tmux's own syntax.", "type": "string" }, "window": { "description": "The window that was arranged.", "type": "string" } }, "required": [ "window", "layout" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Arrange Window Panes" } ``` --- # select_pane Source: https://libtmux.org/en/rs/latest/mcp/tools/select_pane/ > Select a pane, making it its window's active pane. Give a direction to move relative to it instead: up, down, left, and right follow the layout, last returns to the previously active pane, and next and previous step through the window in order. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Select a pane, making it its window’s active pane. Give a direction to move relative to it instead: up, down, left, and right follow the layout, last returns to the previously active pane, and next and previous step through the window in order. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/select_pane.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L388) ## Arguments * `direction` optional Move relative to that pane instead of selecting it. \`up\`, \`down\`, \`left\`, and \`right\` follow the layout, so \`up\` selects whatever pane is drawn above. \`last\` returns to the previously active pane, and \`next\` and \`previous\` step through the window's panes in order. Omit to select the named pane itself. * `pane` required · string The \`%\`-prefixed pane to select, or to move relative to. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$defs": { "SelectPaneDirectionSchema": { "enum": [ "up", "down", "left", "right", "last", "next", "previous" ], "type": "string" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "direction": { "anyOf": [ { "$ref": "#/$defs/SelectPaneDirectionSchema" }, { "type": "null" } ], "description": "Move relative to that pane instead of selecting it.\n\n`up`, `down`, `left`, and `right` follow the layout, so `up` selects\nwhatever pane is drawn above. `last` returns to the previously active\npane, and `next` and `previous` step through the window's panes in\norder. Omit to select the named pane itself." }, "pane": { "description": "The `%`-prefixed pane to select, or to move relative to.", "type": "string" } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$defs": { "Relation": { "description": "How a pane relates to the process answering the request.\n\nThree values rather than a boolean, because \"not the caller's pane\" and\n\"there is no caller\" are different answers and an agent acts differently on\neach.", "oneOf": [ { "const": "unknown", "description": "This process is not running inside tmux, so no pane is its own.", "type": "string" }, { "const": "self", "description": "Confirmed: the same tmux server, and the same pane.", "type": "string" }, { "const": "other", "description": "Some other pane, or a pane this crate cannot prove is the caller's.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the window's active pane.", "type": "boolean" }, "caller": { "$ref": "#/$defs/Relation", "description": "Whether this is the pane the MCP server itself runs in.\n\n`self` only on a confirmed match of both socket and pane id; `other`\nfor every pane that is not, including one this crate cannot prove\neither way; `unknown` when the server is not running inside tmux, so\nthe question has no answer." }, "command": { "description": "The command currently running.", "type": [ "string", "null" ] }, "id": { "description": "The `%`-prefixed tmux identity.", "type": "string" }, "path": { "description": "The pane's working directory.", "type": [ "string", "null" ] }, "window_id": { "description": "The window that contains the pane.", "type": "string" } }, "required": [ "id", "window_id", "active", "caller" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false, "title": "Select Pane" } ``` --- # select_window Source: https://libtmux.org/en/rs/latest/mcp/tools/select_window/ > Select a window, making it its session's active window. Give a direction to move relative to it instead: next and previous step through the session in index order, and last returns to the previously active window. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Select a window, making it its session’s active window. Give a direction to move relative to it instead: next and previous step through the session in index order, and last returns to the previously active window. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/select_window.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L475) ## Arguments * `direction` optional Move relative to that window instead of selecting it. \`next\` and \`previous\` step through the session in index order, and \`last\` returns to the previously active window. Omit to select the named window itself. * `window` required · string The \`@\`-prefixed window to select, or to move relative to. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$defs": { "SelectWindowDirectionSchema": { "enum": [ "next", "previous", "last" ], "type": "string" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "direction": { "anyOf": [ { "$ref": "#/$defs/SelectWindowDirectionSchema" }, { "type": "null" } ], "description": "Move relative to that window instead of selecting it.\n\n`next` and `previous` step through the session in index order, and\n`last` returns to the previously active window. Omit to select the\nnamed window itself." }, "window": { "description": "The `@`-prefixed window to select, or to move relative to.", "type": "string" } }, "required": [ "window" ], "type": "object" } ``` Output schema ```json { "$defs": { "WindowView": { "description": "One window, as the protocol sees it.", "properties": { "active": { "description": "Whether this is the session's active window.", "type": "boolean" }, "id": { "description": "The `@`-prefixed tmux identity.", "type": "string" }, "index": { "description": "The window's index within that session.", "format": "int32", "type": "integer" }, "linked": { "description": "Whether more than one session links this window.", "type": "boolean" }, "name": { "description": "The window name.", "type": "string" }, "panes": { "description": "How many panes the window holds.", "minimum": 0, "type": "integer" }, "session_id": { "description": "The session this window was reached through.", "type": "string" } }, "required": [ "id", "session_id", "index", "name", "panes", "active", "linked" ], "type": "object" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "windows": { "description": "The windows, in tmux's own order.", "items": { "$ref": "#/$defs/WindowView" }, "type": "array" } }, "required": [ "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false, "title": "Select Window" } ``` --- # send_keys Source: https://libtmux.org/en/rs/latest/mcp/tools/send_keys/ > Type text into a pane, press named keys in it, or both. `text` is sent literally, so C-c in it types those three characters. Use `keys` for anything without a character of its own -- C-c to interrupt a running command, Escape, Up, C-d -- which are tmux key names and are interpreted. Text, keys, and optional Enter keep that order in one tmux dispatch. Before input, the configured synchronized-pane cohort is observed; a dead, input-disabled, mode-owned, terminal-attended, or inherited-caller member refuses the whole call, and so does an active run_shell_command, except for keys C-c or C-\ sent alone, which interrupt it. Returned pane IDs describe configured membership, not confirmed delivery. The observation can race with tmux processing the input. A submitted line is remembered briefly so wait_for_text can discount its own echo; an unrecognized key stops that for the pane's current line rather than mask it inaccurately. Send input to a pane's program; a shell that receives it runs it with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Type text into a pane, press named keys in it, or both. `text` is sent literally, so C-c in it types those three characters. Use `keys` for anything without a character of its own — C-c to interrupt a running command, Escape, Up, C-d — which are tmux key names and are interpreted. Text, keys, and optional Enter keep that order in one tmux dispatch. Before input, the configured synchronized-pane cohort is observed; a dead, input-disabled, mode-owned, terminal-attended, or inherited-caller member refuses the whole call, and so does an active [run_shell_command](https://libtmux.org/en/rs/latest/mcp/tools/run_shell_command/), except for keys C-c or C-\ sent alone, which interrupt it. Returned pane IDs describe configured membership, not confirmed delivery. The observation can race with tmux processing the input. A submitted line is remembered briefly so [wait_for_text](https://libtmux.org/en/rs/latest/mcp/tools/wait_for_text/) can discount its own echo; an unrecognized key stops that for the pane’s current line rather than mask it inaccurately. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/send_keys.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L356) ## Arguments * `enter` optional · boolean Whether to press Enter afterwards. Default: `false`. * `keys` optional · array | null tmux key names to press, in order, after any text. These are interpreted rather than typed, which is the only way to send a key that has no character: \`C-c\` to interrupt, \`Escape\`, \`Up\`, \`C-d\`. Sending \`C-c\` as \`text\` would type those three characters. Omit to press none. * `pane` required · string The \`%\`-prefixed pane id. * `text` optional · string | null Text typed literally into the pane. Key names are not interpreted. Omit to type none. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "enter": { "default": false, "description": "Whether to press Enter afterwards.", "type": "boolean" }, "keys": { "description": "tmux key names to press, in order, after any text.\n\nThese are interpreted rather than typed, which is the only way to send\na key that has no character: `C-c` to interrupt, `Escape`, `Up`,\n`C-d`. Sending `C-c` as `text` would type those three characters.\nOmit to press none.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "pane": { "description": "The `%`-prefixed pane id.", "type": "string" }, "text": { "description": "Text typed literally into the pane. Key names are not interpreted. Omit\nto type none.", "type": [ "string", "null" ] } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "pane": { "description": "The pane the caller targeted.", "type": "string" }, "panes": { "description": "The effective configured recipient IDs observed before dispatch.\n\nMembership does not confirm delivery and may change after observation.", "items": { "type": "string" }, "type": "array" } }, "required": [ "pane", "panes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Send Keys To Pane" } ``` --- # send_keys_batch Source: https://libtmux.org/en/rs/latest/mcp/tools/send_keys_batch/ > Send an ordered batch of input operations to panes. Each executed row repeats send_keys' effective synchronized-cohort, dead-pane, input-off, pane-mode, attended-client, and inherited-caller preflight, then crosses one tmux dispatch. These observations can race with tmux processing the input. Send input to a pane's program; a shell that receives it runs it with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send an ordered batch of input operations to panes. Each executed row repeats [send_keys](https://libtmux.org/en/rs/latest/mcp/tools/send_keys/)’ effective synchronized-cohort, dead-pane, input-off, pane-mode, attended-client, and inherited-caller preflight, then crosses one tmux dispatch. These observations can race with tmux processing the input. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/send_keys_batch.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L1078) ## Arguments * `on_error` optional \`stop\`, the default, ends at the first refused row; \`continue\` sends the rest. Default: `"stop"`. * `operations` required · array The rows to send, in order, 1 to 64. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$defs": { "OnError": { "enum": [ "stop", "continue" ], "type": "string" }, "SendOperation": { "additionalProperties": false, "properties": { "enter": { "default": false, "description": "Whether to press Enter afterwards.", "type": "boolean" }, "keys": { "description": "tmux key names to press, in order, after any text, such as `C-c`. Omit\nto press none.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "pane": { "description": "The `%`-prefixed pane id.", "type": "string" }, "text": { "description": "Text typed literally. Key names are not interpreted. Omit to type\nnone.", "type": [ "string", "null" ] } }, "required": [ "pane" ], "type": "object" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "on_error": { "$ref": "#/$defs/OnError", "default": "stop", "description": "`stop`, the default, ends at the first refused row; `continue` sends\nthe rest." }, "operations": { "description": "The rows to send, in order, 1 to 64.", "items": { "$ref": "#/$defs/SendOperation" }, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "$defs": { "BatchItem": { "properties": { "error": { "anyOf": [ { "$ref": "#/$defs/ErrorData" }, { "type": "null" } ] }, "index": { "minimum": 0, "type": "integer" }, "result": true, "resultTruncated": { "type": "boolean" }, "success": { "type": "boolean" }, "tool": { "type": "string" } }, "required": [ "index", "tool", "success", "resultTruncated" ], "type": "object" }, "ErrorCode": { "description": "Standard JSON-RPC error codes used throughout the MCP protocol.\n\nThese codes follow the JSON-RPC 2.0 specification and provide\nstandardized error reporting across all MCP implementations.", "format": "int32", "type": "integer" }, "ErrorData": { "description": "Error information for JSON-RPC error responses.\n\nThis structure follows the JSON-RPC 2.0 specification for error reporting,\nproviding a standardized way to communicate errors between clients and servers.", "properties": { "code": { "$ref": "#/$defs/ErrorCode", "description": "The error type that occurred (using standard JSON-RPC error codes)" }, "data": { "description": "Additional information about the error. The value of this member is defined by the\nsender (e.g. detailed error information, nested errors etc.)." }, "message": { "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", "type": "string" } }, "required": [ "code", "message" ], "type": "object" }, "OnError": { "enum": [ "stop", "continue" ], "type": "string" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "failed": { "minimum": 0, "type": "integer" }, "onError": { "$ref": "#/$defs/OnError" }, "results": { "items": { "$ref": "#/$defs/BatchItem" }, "type": "array" }, "stoppedAt": { "minimum": 0, "type": [ "integer", "null" ] }, "succeeded": { "minimum": 0, "type": "integer" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "minimum": 0, "type": "integer" } }, "required": [ "results", "succeeded", "failed", "truncated", "truncatedBytes", "onError" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Send Keys Batch" } ``` --- # set_history_limit Source: https://libtmux.org/en/rs/latest/mcp/tools/set_history_limit/ > Set the scrollback history limit for a session or its global default. From tmux 3.7 existing panes take it too, and lowering it discards their scrollback past the new limit. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Set the scrollback history limit for a session or its global default. From tmux 3.7 existing panes take it too, and lowering it discards their scrollback past the new limit. Delete tmux state; accepts no command payload. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/set_history_limit.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L895) ## Arguments * `limit` required · integer Lines of scrollback to keep per pane. * `session` optional · string | null The session to change, by \`$\`-prefixed id or name. Omit to change the global default. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "limit": { "description": "Lines of scrollback to keep per pane.", "minimum": 0, "type": "integer" }, "session": { "description": "The session to change, by `$`-prefixed id or name. Omit to change the\nglobal default.", "type": [ "string", "null" ] } }, "required": [ "limit" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "name": { "type": "string" }, "target": { "type": [ "string", "null" ] }, "value": { "type": "string" } }, "required": [ "name", "value" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Set History Limit" } ``` --- # set_mouse_enabled Source: https://libtmux.org/en/rs/latest/mcp/tools/set_mouse_enabled/ > Set mouse handling for a session or the global session default. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Set mouse handling for a session or the global session default. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/set_mouse_enabled.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L864) ## Arguments * `enabled` required · boolean \`true\` turns mouse handling on; \`false\` turns it off. * `session` optional · string | null The session to change, by \`$\`-prefixed id or name. Omit to change the global default. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "enabled": { "description": "`true` turns mouse handling on; `false` turns it off.", "type": "boolean" }, "session": { "description": "The session to change, by `$`-prefixed id or name. Omit to change the\nglobal default.", "type": [ "string", "null" ] } }, "required": [ "enabled" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "name": { "type": "string" }, "target": { "type": [ "string", "null" ] }, "value": { "type": "string" } }, "required": [ "name", "value" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Set Mouse Enabled" } ``` --- # set_pane_title Source: https://libtmux.org/en/rs/latest/mcp/tools/set_pane_title/ > Set one pane's title. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Set one pane’s title. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/set_pane_title.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L841) ## Arguments * `pane` required · string The \`%\`-prefixed pane id. * `title` required · string The new title, stored as given. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "pane": { "description": "The `%`-prefixed pane id.", "type": "string" }, "title": { "description": "The new title, stored as given.", "type": "string" } }, "required": [ "pane", "title" ], "type": "object" } ``` Output schema ```json { "$defs": { "Relation": { "description": "How a pane relates to the process answering the request.\n\nThree values rather than a boolean, because \"not the caller's pane\" and\n\"there is no caller\" are different answers and an agent acts differently on\neach.", "oneOf": [ { "const": "unknown", "description": "This process is not running inside tmux, so no pane is its own.", "type": "string" }, { "const": "self", "description": "Confirmed: the same tmux server, and the same pane.", "type": "string" }, { "const": "other", "description": "Some other pane, or a pane this crate cannot prove is the caller's.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the window's active pane.", "type": "boolean" }, "caller": { "$ref": "#/$defs/Relation", "description": "Whether this is the pane the MCP server itself runs in.\n\n`self` only on a confirmed match of both socket and pane id; `other`\nfor every pane that is not, including one this crate cannot prove\neither way; `unknown` when the server is not running inside tmux, so\nthe question has no answer." }, "command": { "description": "The command currently running.", "type": [ "string", "null" ] }, "id": { "description": "The `%`-prefixed tmux identity.", "type": "string" }, "path": { "description": "The pane's working directory.", "type": [ "string", "null" ] }, "window_id": { "description": "The window that contains the pane.", "type": "string" } }, "required": [ "id", "window_id", "active", "caller" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Set Pane Title" } ``` --- # set_synchronize_panes Source: https://libtmux.org/en/rs/latest/mcp/tools/set_synchronize_panes/ > Set the window default for synchronized pane input. Individual pane overrides still determine the effective configured cohort, so enabling this can amplify what one send_keys call reaches. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Set the window default for synchronized pane input. Individual pane overrides still determine the effective configured cohort, so enabling this can amplify what one [send_keys](https://libtmux.org/en/rs/latest/mcp/tools/send_keys/) call reaches. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/set_synchronize_panes.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L1045) ## Arguments * `enabled` required · boolean \`true\` turns synchronized input on; \`false\` turns it off. * `window` required · string The \`@\`-prefixed window id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "enabled": { "description": "`true` turns synchronized input on; `false` turns it off.", "type": "boolean" }, "window": { "description": "The `@`-prefixed window id.", "type": "string" } }, "required": [ "window", "enabled" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "name": { "type": "string" }, "target": { "type": [ "string", "null" ] }, "value": { "type": "string" } }, "required": [ "name", "value" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": false, "title": "Set Synchronize Panes" } ``` --- # show_environment Source: https://libtmux.org/en/rs/latest/mcp/tools/show_environment/ > List the variables tmux hands to processes it starts, for the server or for one session, and whether each is set or marked for removal. Values are withheld: a tmux server inherits the environment of the shell that started it, tokens and keys included. A value is returned only for a name the operator listed in LIBTMUX_ENVIRONMENT_VALUES at startup, and is then returned in clear. This is not the environment of anything already running: a pane started before a change keeps what it was given. Read the tmux environment; accepts no client-supplied executable input. Values are withheld unless the operator allowed the name. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List the variables tmux hands to processes it starts, for the server or for one session, and whether each is set or marked for removal. Values are withheld: a tmux server inherits the environment of the shell that started it, tokens and keys included. A value is returned only for a name the operator listed in LIBTMUX_ENVIRONMENT_VALUES at startup, and is then returned in clear. This is not the environment of anything already running: a pane started before a change keeps what it was given. Read the tmux environment; accepts no client-supplied executable input. Values are withheld unless the operator allowed the name. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/show_environment.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/inspect.rs#L510) ## Arguments * `session` optional · string | null The session whose environment to read, by \`$\`-prefixed id or name. Omit for the server's own. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "session": { "description": "The session whose environment to read, by `$`-prefixed id or name.\n\nOmit for the server's own.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "$defs": { "EnvironmentEntry": { "description": "One tmux environment entry.", "properties": { "name": { "description": "The variable name.", "type": "string" }, "state": { "$ref": "#/$defs/EnvironmentState", "description": "Whether the name holds a value or is marked for removal." }, "value": { "description": "The value, only for a set variable whose name the operator allowed in\n`LIBTMUX_ENVIRONMENT_VALUES` at startup.", "type": [ "string", "null" ] }, "withheld": { "description": "True for a set variable whose value was not returned because the\noperator did not allow its name.", "type": "boolean" } }, "required": [ "name", "state", "withheld" ], "type": "object" }, "EnvironmentState": { "description": "What tmux holds under one environment name.", "oneOf": [ { "const": "set", "description": "tmux holds a value and hands it to processes it starts.", "type": "string" }, { "const": "removed", "description": "tmux removes the name from the environment of processes it starts.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "entries": { "description": "The entries, in tmux's own order.", "items": { "$ref": "#/$defs/EnvironmentEntry" }, "type": "array" }, "session": { "description": "The session the environment belongs to, or absent for the server's.", "type": [ "string", "null" ] } }, "required": [ "entries" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "Show tmux Environment" } ``` --- # show_hooks Source: https://libtmux.org/en/rs/latest/mcp/tools/show_hooks/ > List the hooks tmux runs when something happens on the server, such as a pane exiting. This tool does not set hooks. Hooks set through another path remain in their server or session until unset; configuration files persist them across server restarts. Reach for this when tmux does something no tool here asked for. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List the hooks tmux runs when something happens on the server, such as a pane exiting. This tool does not set hooks. Hooks set through another path remain in their server or session until unset; configuration files persist them across server restarts. Reach for this when tmux does something no tool here asked for. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/show_hooks.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/inspect.rs#L560) ## Arguments * `session` optional · string | null The session whose hooks to read, by \`$\`-prefixed id or name. Omit for the server's own. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "session": { "description": "The session whose hooks to read, by `$`-prefixed id or name. Omit for\nthe server's own.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "$defs": { "Hook": { "description": "One tmux hook.", "properties": { "command": { "description": "The command tmux runs.", "type": "string" }, "index": { "description": "Its index, when the hook is an array.", "minimum": 0, "type": [ "integer", "null" ] }, "name": { "description": "The hook name, such as `pane-exited`.", "type": "string" } }, "required": [ "name", "command" ], "type": "object" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "hooks": { "description": "The hooks, in tmux's own order.", "items": { "$ref": "#/$defs/Hook" }, "type": "array" } }, "required": [ "hooks" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "Show tmux Hooks" } ``` --- # show_option Source: https://libtmux.org/en/rs/latest/mcp/tools/show_option/ > Read a tmux option, such as history-limit or a user option like @theme. Name the scope the option lives in; global-session is what tmux uses when a command names no target. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read a tmux option, such as history-limit or a user option like @theme. Name the scope the option lives in; global-session is what tmux uses when a command names no target. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/show_option.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/inspect.rs#L457) ## Arguments * `name` required · string The option name, such as \`history-limit\` or a user option like \`@theme\`. * `scope` optional Which tmux object the option belongs to. One of \`server\`, \`global-session\`, \`global-window\`, \`session\`, \`window\`, or \`pane\`. Defaults to \`global-session\`, which is what setting an option without a target means in tmux. * `target` optional · string | null The \`$\`, \`@\` or \`%\`-prefixed id, for the scopes that need one. Omit for the others. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$defs": { "OptionScopeSchema": { "enum": [ "server", "global-session", "global-window", "session", "window", "pane" ], "type": "string" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "name": { "description": "The option name, such as `history-limit` or a user option like `@theme`.", "type": "string" }, "scope": { "anyOf": [ { "$ref": "#/$defs/OptionScopeSchema" }, { "type": "null" } ], "description": "Which tmux object the option belongs to.\n\nOne of `server`, `global-session`, `global-window`, `session`,\n`window`, or `pane`. Defaults to `global-session`, which is what\nsetting an option without a target means in tmux." }, "target": { "description": "The `$`, `@` or `%`-prefixed id, for the scopes that need one. Omit\nfor the others.", "type": [ "string", "null" ] } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "name": { "description": "The option name.", "type": "string" }, "value": { "description": "Its value, absent when it has never been set at that scope.", "type": [ "string", "null" ] } }, "required": [ "name" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": false, "readOnlyHint": true, "title": "Read tmux Option" } ``` --- # signal_channel Source: https://libtmux.org/en/rs/latest/mcp/tools/signal_channel/ > Signal a tmux wait-for channel, releasing every current waiter. With no waiter, one signal is latched; signalling the same channel again clears that latch. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Signal a tmux wait-for channel, releasing every current waiter. With no waiter, one signal is latched; signalling the same channel again clears that latch. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/signal_channel.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/control.rs#L733) ## Arguments * `channel` required · string The channel name, which is any string both sides agree on. * `seconds` optional · integer | null How long to wait, in seconds. Defaults to 30, capped at 600. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "channel": { "description": "The channel name, which is any string both sides agree on.", "type": "string" }, "seconds": { "description": "How long to wait, in seconds. Defaults to 30, capped at 600.", "minimum": 0, "type": [ "integer", "null" ] } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "channel": { "description": "The channel that was signalled.", "type": "string" } }, "required": [ "channel" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false, "title": "Signal Channel" } ``` --- # snapshot_pane Source: https://libtmux.org/en/rs/latest/mcp/tools/snapshot_pane/ > Read pane content with cursor position, mode state, and scroll position in one reply. The state query and capture are separate, so the result is not atomic. Prefer this over capture_pane when you need to reason about where the pane is rather than only what it says -- a cursor at column zero on a fresh line is a shell waiting, and a pane in a mode may route keys to tmux instead of the workload. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane content with cursor position, mode state, and scroll position in one reply. The state query and capture are separate, so the result is not atomic. Prefer this over [capture_pane](https://libtmux.org/en/rs/latest/mcp/tools/capture_pane/) when you need to reason about where the pane is rather than only what it says — a cursor at column zero on a fresh line is a shell waiting, and a pane in a mode may route keys to tmux instead of the workload. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/snapshot_pane.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/inspect.rs#L257) ## Arguments * `history` optional · boolean Include scrollback rather than only the visible screen. Default: `false`. * `max_lines` optional · integer | null The most content lines to return, oldest dropped first. Defaults to the whole visible screen. The end of a pane is what says what just happened, so a limit keeps the end. * `pane` required · string The \`%\`-prefixed pane id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "history": { "default": false, "description": "Include scrollback rather than only the visible screen.", "type": "boolean" }, "max_lines": { "description": "The most content lines to return, oldest dropped first.\n\nDefaults to the whole visible screen. The end of a pane is what says\nwhat just happened, so a limit keeps the end.", "minimum": 0, "type": [ "integer", "null" ] }, "pane": { "description": "The `%`-prefixed pane id.", "type": "string" } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$defs": { "PaneView": { "description": "One pane, as the protocol sees it.", "properties": { "active": { "description": "Whether this is the window's active pane.", "type": "boolean" }, "caller": { "$ref": "#/$defs/Relation", "description": "Whether this is the pane the MCP server itself runs in.\n\n`self` only on a confirmed match of both socket and pane id; `other`\nfor every pane that is not, including one this crate cannot prove\neither way; `unknown` when the server is not running inside tmux, so\nthe question has no answer." }, "command": { "description": "The command currently running.", "type": [ "string", "null" ] }, "id": { "description": "The `%`-prefixed tmux identity.", "type": "string" }, "path": { "description": "The pane's working directory.", "type": [ "string", "null" ] }, "window_id": { "description": "The window that contains the pane.", "type": "string" } }, "required": [ "id", "window_id", "active", "caller" ], "type": "object" }, "Relation": { "description": "How a pane relates to the process answering the request.\n\nThree values rather than a boolean, because \"not the caller's pane\" and\n\"there is no caller\" are different answers and an agent acts differently on\neach.", "oneOf": [ { "const": "unknown", "description": "This process is not running inside tmux, so no pane is its own.", "type": "string" }, { "const": "self", "description": "Confirmed: the same tmux server, and the same pane.", "type": "string" }, { "const": "other", "description": "Some other pane, or a pane this crate cannot prove is the caller's.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "content": { "description": "What the pane is showing.", "type": "string" }, "cursor_x": { "description": "Where the cursor sits, counting from the left.", "minimum": 0, "type": [ "integer", "null" ] }, "cursor_y": { "description": "Where the cursor sits, counting from the top.", "minimum": 0, "type": [ "integer", "null" ] }, "dead": { "description": "Whether the process in it has ended.", "type": "boolean" }, "dropped": { "description": "How many older lines were dropped to honour `max_lines`.", "minimum": 0, "type": "integer" }, "height": { "description": "How tall it is, in rows.", "minimum": 0, "type": "integer" }, "in_mode": { "description": "Whether the pane is in a mode, where keys navigate rather than type.", "type": "boolean" }, "lines": { "description": "How many lines of it are reported.", "minimum": 0, "type": "integer" }, "mode": { "description": "Which mode, when it is in one.", "type": [ "string", "null" ] }, "pane": { "$ref": "#/$defs/PaneView", "description": "The pane itself." }, "scroll_position": { "description": "How far it is scrolled back, when it is in copy mode.", "format": "int32", "type": [ "integer", "null" ] }, "width": { "description": "How wide it is, in columns.", "minimum": 0, "type": "integer" } }, "required": [ "pane", "width", "height", "in_mode", "dead", "content", "lines", "dropped" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": true, "readOnlyHint": true, "title": "Snapshot Pane State" } ``` --- # split_window Source: https://libtmux.org/en/rs/latest/mcp/tools/split_window/ > Split a window and start the configured process with no command payload. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Split a window and start the configured process with no command payload. Start a pane’s configured process; accepts no command payload. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/split_window.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L964) ## Arguments * `direction` optional Where the new pane goes relative to \`pane\`. Defaults to \`below\`. * `pane` required · string The \`%\`-prefixed pane to split. * `percent` optional · integer | null The new pane's share of the split, 1 to 100. Defaults to half. * `start_directory` optional · string | null The new pane's working directory. Omit for the directory this MCP server started in, not \`pane\`'s current directory. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$defs": { "SplitDirectionSchema": { "enum": [ "above", "below", "left", "right" ], "type": "string" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "direction": { "anyOf": [ { "$ref": "#/$defs/SplitDirectionSchema" }, { "type": "null" } ], "description": "Where the new pane goes relative to `pane`. Defaults to `below`." }, "pane": { "description": "The `%`-prefixed pane to split.", "type": "string" }, "percent": { "description": "The new pane's share of the split, 1 to 100. Defaults to half.", "minimum": 0, "type": [ "integer", "null" ] }, "start_directory": { "description": "The new pane's working directory. Omit for the directory this MCP\nserver started in, not `pane`'s current directory.", "type": [ "string", "null" ] } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$defs": { "Relation": { "description": "How a pane relates to the process answering the request.\n\nThree values rather than a boolean, because \"not the caller's pane\" and\n\"there is no caller\" are different answers and an agent acts differently on\neach.", "oneOf": [ { "const": "unknown", "description": "This process is not running inside tmux, so no pane is its own.", "type": "string" }, { "const": "self", "description": "Confirmed: the same tmux server, and the same pane.", "type": "string" }, { "const": "other", "description": "Some other pane, or a pane this crate cannot prove is the caller's.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the window's active pane.", "type": "boolean" }, "caller": { "$ref": "#/$defs/Relation", "description": "Whether this is the pane the MCP server itself runs in.\n\n`self` only on a confirmed match of both socket and pane id; `other`\nfor every pane that is not, including one this crate cannot prove\neither way; `unknown` when the server is not running inside tmux, so\nthe question has no answer." }, "command": { "description": "The command currently running.", "type": [ "string", "null" ] }, "id": { "description": "The `%`-prefixed tmux identity.", "type": "string" }, "path": { "description": "The pane's working directory.", "type": [ "string", "null" ] }, "window_id": { "description": "The window that contains the pane.", "type": "string" } }, "required": [ "id", "window_id", "active", "caller" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Split Window" } ``` --- # swap_pane Source: https://libtmux.org/en/rs/latest/mcp/tools/swap_pane/ > Swap the positions of two panes. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Swap the positions of two panes. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/swap_pane.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/contract.rs#L817) ## Arguments * `source_pane` required · string The \`%\`-prefixed pane id to move; the result describes it. * `target_pane` required · string The \`%\`-prefixed pane id it trades places with. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "source_pane": { "description": "The `%`-prefixed pane id to move; the result describes it.", "type": "string" }, "target_pane": { "description": "The `%`-prefixed pane id it trades places with.", "type": "string" } }, "required": [ "source_pane", "target_pane" ], "type": "object" } ``` Output schema ```json { "$defs": { "Relation": { "description": "How a pane relates to the process answering the request.\n\nThree values rather than a boolean, because \"not the caller's pane\" and\n\"there is no caller\" are different answers and an agent acts differently on\neach.", "oneOf": [ { "const": "unknown", "description": "This process is not running inside tmux, so no pane is its own.", "type": "string" }, { "const": "self", "description": "Confirmed: the same tmux server, and the same pane.", "type": "string" }, { "const": "other", "description": "Some other pane, or a pane this crate cannot prove is the caller's.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "active": { "description": "Whether this is the window's active pane.", "type": "boolean" }, "caller": { "$ref": "#/$defs/Relation", "description": "Whether this is the pane the MCP server itself runs in.\n\n`self` only on a confirmed match of both socket and pane id; `other`\nfor every pane that is not, including one this crate cannot prove\neither way; `unknown` when the server is not running inside tmux, so\nthe question has no answer." }, "command": { "description": "The command currently running.", "type": [ "string", "null" ] }, "id": { "description": "The `%`-prefixed tmux identity.", "type": "string" }, "path": { "description": "The pane's working directory.", "type": [ "string", "null" ] }, "window_id": { "description": "The window that contains the pane.", "type": "string" } }, "required": [ "id", "window_id", "active", "caller" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false, "title": "Swap Panes" } ``` --- # wait_for_channel Source: https://libtmux.org/en/rs/latest/mcp/tools/wait_for_channel/ > Block until something signals a tmux wait-for channel. A pending signal is consumed. Pair this with a shell command that ends in `tmux wait-for -S ` to synchronise with work this server did not start. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Block until something signals a tmux wait-for channel. A pending signal is consumed. Pair this with a shell command that ends in `tmux wait-for -S ` to synchronise with work this server did not start. Change tmux state; no client-supplied executable input. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/wait_for_channel.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/observe.rs#L490) ## Arguments * `channel` required · string The channel name, which is any string both sides agree on. * `seconds` optional · integer | null How long to wait, in seconds. Defaults to 30, capped at 600. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "channel": { "description": "The channel name, which is any string both sides agree on.", "type": "string" }, "seconds": { "description": "How long to wait, in seconds. Defaults to 30, capped at 600.", "minimum": 0, "type": [ "integer", "null" ] } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "$defs": { "ChannelWaitOutcomeSchema": { "enum": [ "signalled", "deadline" ], "type": "string" } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "channel": { "description": "The channel that was waited on.", "type": "string" }, "outcome": { "$ref": "#/$defs/ChannelWaitOutcomeSchema", "description": "`signalled` or `deadline`." } }, "required": [ "channel", "outcome" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false, "title": "Wait For Channel" } ``` --- # wait_for_text Source: https://libtmux.org/en/rs/latest/mcp/tools/wait_for_text/ > Wait until a pane writes matching text. Reads the pane's live output stream, so text that scrolls past between checks is still seen. The returned text is that raw stream, not the rendered screen: a line redrawn in place repeats; capture_pane shows the screen. Prefer run_shell_command for commands you are sending yourself: it reports an exit status instead of guessing from output. Use this for output you did not author, such as a server logging that it is ready. A line this server itself types and submits -- with send_keys, paste_text, or run_shell_command's own dispatch -- is discounted from a match for a short time afterward, so waiting for text you just sent does not match its own echo; output that happens to repeat the same words still does. A submitted line that wrapped across terminal rows when it was typed is not discounted. A pattern still on the row being typed into, not yet submitted, reports outcome pending instead of matched, and one already on a completed row before this call attached reports present_at_entry. Waiting owns an observer client until the wait ends. Each list accepts at most 32 patterns, each at most 4,096 bytes, using Rust's linear-time regex engine. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Wait until a pane writes matching text. Reads the pane’s live output stream, so text that scrolls past between checks is still seen. The returned text is that raw stream, not the rendered screen: a line redrawn in place repeats; [capture_pane](https://libtmux.org/en/rs/latest/mcp/tools/capture_pane/) shows the screen. Prefer [run_shell_command](https://libtmux.org/en/rs/latest/mcp/tools/run_shell_command/) for commands you are sending yourself: it reports an exit status instead of guessing from output. Use this for output you did not author, such as a server logging that it is ready. A line this server itself types and submits — with [send_keys](https://libtmux.org/en/rs/latest/mcp/tools/send_keys/), [paste_text](https://libtmux.org/en/rs/latest/mcp/tools/paste_text/), or [run_shell_command](https://libtmux.org/en/rs/latest/mcp/tools/run_shell_command/)’s own dispatch — is discounted from a match for a short time afterward, so waiting for text you just sent does not match its own echo; output that happens to repeat the same words still does. A submitted line that wrapped across terminal rows when it was typed is not discounted. A pattern still on the row being typed into, not yet submitted, reports outcome pending instead of matched, and one already on a completed row before this call attached reports present_at_entry. Waiting owns an observer client until the wait ends. Each list accepts at most 32 patterns, each at most 4,096 bytes, using Rust’s linear-time regex engine. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Rust tools](https://libtmux.org/en/rs/latest/mcp/tools/) · [JSON](https://libtmux.org/en/rs/latest/mcp/tools/wait_for_text.json) · [Source](https://github.com/libtmux/libtmux-rs/blob/a6fc2a65674177b92b17fa380757155d2ba150fd/crates/tmux-mcp/src/tools/observe.rs#L344) ## Arguments * `match_case` optional · boolean Match case. Off by default. Default: `false`. * `pane` required · string The \`%\`-prefixed pane to watch. * `patterns` optional · array | null Text that ends the wait successfully. Omit to wait for any output. * `regex` optional · boolean Read both lists as regular expressions rather than literal text. Default: `false`. * `seconds` optional · integer | null How long to wait, in seconds. Defaults to 30, capped at 600. * `stop` optional · array | null Text that ends the wait as a failure, reported as \`stopped\`. Omit for none. Give the failure markers you already know — \`error:\`, \`Traceback\` — and a failed run returns at once instead of at the deadline. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "match_case": { "default": false, "description": "Match case. Off by default.", "type": "boolean" }, "pane": { "description": "The `%`-prefixed pane to watch.", "type": "string" }, "patterns": { "description": "Text that ends the wait successfully. Omit to wait for any output.", "items": { "type": "string" }, "maxItems": 32, "type": [ "array", "null" ] }, "regex": { "default": false, "description": "Read both lists as regular expressions rather than literal text.", "type": "boolean" }, "seconds": { "description": "How long to wait, in seconds. Defaults to 30, capped at 600.", "minimum": 0, "type": [ "integer", "null" ] }, "stop": { "description": "Text that ends the wait as a failure, reported as `stopped`. Omit for\nnone.\n\nGive the failure markers you already know — `error:`, `Traceback` — and\na failed run returns at once instead of at the deadline.", "items": { "type": "string" }, "maxItems": 32, "type": [ "array", "null" ] } }, "required": [ "pane" ], "type": "object" } ``` Output schema ```json { "$defs": { "WaitOutcome": { "description": "How a wait for text finished.", "oneOf": [ { "const": "present_at_entry", "description": "A wanted pattern was already in the pane's output before this began\nwatching, on a row above the one still being typed into, and is not\na line this server itself submitted moments earlier.\n\nA wait only sees what a pane writes after it starts, so this is never\nfolded into [`Self::Matched`]: the same pattern printed moments\nearlier -- an earlier command's own output, say -- can already be\nsitting there, and a caller that treated that as a fresh match would\nact on something that happened before this call, not because of it.\nA line this server typed and submitted with `send_keys` is discounted\nrather than reported here or as [`Self::Matched`], for a short time\nafter it was submitted.", "type": "string" }, { "const": "pending", "description": "A wanted pattern's only occurrence is the row still being typed\ninto: text this server (or a person sharing the pane) sent and has\nnot submitted, not anything that has run.\n\nSubmit it, then wait again: the next wait sees the command's own\noutput on a row above a new one still being typed into, which is\n[`Self::PresentAtEntry`] or [`Self::Matched`] depending on when it\narrived, never this -- and never the submitted line's own echo,\nwhich stays discounted for a short time after.", "type": "string" }, { "const": "matched", "description": "A pattern matched, in output that arrived after the wait attached.", "type": "string" }, { "const": "stopped", "description": "A stop pattern matched, so the wait ended early.", "type": "string" }, { "const": "deadline", "description": "The time the caller allowed ran out.", "type": "string" }, { "const": "pane_closed", "description": "The pane stopped writing for good.", "type": "string" }, { "const": "cancelled", "description": "The client withdrew the request while the wait was still running.", "type": "string" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "bytes": { "description": "How many bytes arrived, before filtering or truncation.", "minimum": 0, "type": "integer" }, "matched_index": { "description": "Which pattern matched, indexed into the list it came from.", "minimum": 0, "type": [ "integer", "null" ] }, "matched_pattern": { "description": "The pattern that matched, as it was given.", "type": [ "string", "null" ] }, "outcome": { "$ref": "#/$defs/WaitOutcome", "description": "How the wait finished." }, "pane": { "description": "The pane that was watched.", "type": "string" }, "text": { "description": "What the pane wrote, with escape sequences removed.\n\nThis is the raw output stream, not the rendered screen: a line redrawn\nin place, such as a line editor's echo, repeats. `capture_pane` shows\nthe screen.", "type": "string" } }, "required": [ "pane", "outcome", "text", "bytes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": true, "openWorldHint": true, "readOnlyHint": true, "title": "Wait For Pane Text" } ``` --- # Go MCP tools Source: https://libtmux.org/en/go/latest/mcp/tools/ > Tools, resources, and prompts advertised by the Go MCP server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Use the wire name shown here when calling a tool. The Go server advertises 45 tools with the reference configuration below. Your client’s list follows the policy configured for its server. Read the [setup guide](https://libtmux.org/en/go/latest/mcp/guides/) before choosing tool access. The [language API reference](https://libtmux.org/en/go/latest/mcp/reference/) covers embedding and implementation types. [Download the protocol catalog as JSON](https://libtmux.org/en/go/latest/mcp/tools.json). Reference configuration * `LIBTMUX_TOOLSETS` `inspect,manage,execute,teardown` Protocol version: `2025-11-25`. ## Tools * [`call_read_tools_batch`](https://libtmux.org/en/go/latest/mcp/tools/call_read_tools_batch/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Calls up to sixteen eligible inspect tools serially; inner tools receive no separate approval. Retained rows contain full nested envelopes, oversized results are marked resultTruncated, and the complete JSON-RPC response is at most 1,000,000 bytes. * [`capture_pane`](https://libtmux.org/en/go/latest/mcp/tools/capture_pane/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Returns bounded pane content and a cursor. * [`capture_since`](https://libtmux.org/en/go/latest/mcp/tools/capture_since/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Returns pane output produced after a cursor. * [`clear_pane_scrollback`](https://libtmux.org/en/go/latest/mcp/tools/clear_pane_scrollback/) Delete tmux state; accepts no command payload. Deletes retained scrollback from one pane. * [`create_session`](https://libtmux.org/en/go/latest/mcp/tools/create_session/) Start a pane's configured process; accepts no command payload. Creates a detached session whose first pane runs the configured process. * [`create_window`](https://libtmux.org/en/go/latest/mcp/tools/create_window/) Start a pane's configured process; accepts no command payload. Creates a window whose first pane runs the configured process. * [`find_pane_by_position`](https://libtmux.org/en/go/latest/mcp/tools/find_pane_by_position/) Inspect tmux metadata; accepts no client-supplied executable input. Finds a pane at one of a window's four corners. * [`get_pane_info`](https://libtmux.org/en/go/latest/mcp/tools/get_pane_info/) Inspect tmux metadata; accepts no client-supplied executable input. Returns metadata for one pane. * [`get_server_info`](https://libtmux.org/en/go/latest/mcp/tools/get_server_info/) Inspect tmux metadata; accepts no client-supplied executable input. Reports whether the pinned server exists and its version. * [`get_session_info`](https://libtmux.org/en/go/latest/mcp/tools/get_session_info/) Inspect tmux metadata; accepts no client-supplied executable input. Returns metadata for one session. * [`get_tmux_variables`](https://libtmux.org/en/go/latest/mcp/tools/get_tmux_variables/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Reads a capped list of validated tmux variable names, not free-form formats. * [`get_window_info`](https://libtmux.org/en/go/latest/mcp/tools/get_window_info/) Inspect tmux metadata; accepts no client-supplied executable input. Returns metadata for one window. * [`kill_pane`](https://libtmux.org/en/go/latest/mcp/tools/kill_pane/) Delete tmux state; accepts no command payload. Deletes one pane and ends its process. * [`kill_session`](https://libtmux.org/en/go/latest/mcp/tools/kill_session/) Delete tmux state; accepts no command payload. Deletes one session and every window and pane in it. * [`kill_window`](https://libtmux.org/en/go/latest/mcp/tools/kill_window/) Delete tmux state; accepts no command payload. Deletes one window and every pane in it. * [`list_panes`](https://libtmux.org/en/go/latest/mcp/tools/list_panes/) Inspect tmux metadata; accepts no client-supplied executable input. Lists pane metadata and stable pane IDs. * [`list_sessions`](https://libtmux.org/en/go/latest/mcp/tools/list_sessions/) Inspect tmux metadata; accepts no client-supplied executable input. Lists sessions on the pinned tmux server. * [`list_windows`](https://libtmux.org/en/go/latest/mcp/tools/list_windows/) Inspect tmux metadata; accepts no client-supplied executable input. Lists windows, optionally only those in one named session. * [`move_window`](https://libtmux.org/en/go/latest/mcp/tools/move_window/) Change tmux state; no client-supplied executable input. Moves a window to another session, optionally at an index. * [`paste_text`](https://libtmux.org/en/go/latest/mcp/tools/paste_text/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Pastes literal text only to its target; optional Enter appends one newline to the same private buffer. * [`rename_session`](https://libtmux.org/en/go/latest/mcp/tools/rename_session/) Change tmux state; no client-supplied executable input. Replaces a session's name. * [`rename_window`](https://libtmux.org/en/go/latest/mcp/tools/rename_window/) Change tmux state; no client-supplied executable input. Replaces a window's name. * [`resize_pane`](https://libtmux.org/en/go/latest/mcp/tools/resize_pane/) Change tmux state; no client-supplied executable input. Sets a pane's width, height, or both. * [`resize_window`](https://libtmux.org/en/go/latest/mcp/tools/resize_window/) Change tmux state; no client-supplied executable input. Sets a window's width, height, or both. * [`respawn_pane`](https://libtmux.org/en/go/latest/mcp/tools/respawn_pane/) Start a pane's configured process; accepts no command payload. Kills the pane's current process and starts its configured process again. * [`run_shell_command`](https://libtmux.org/en/go/latest/mcp/tools/run_shell_command/) Run a shell command in a pane with your user's permissions. Runs one command you author in a pane that is not synchronized with others, rechecks the pane just before sending, and waits for it to finish, reporting its exit status. * [`search_panes`](https://libtmux.org/en/go/latest/mcp/tools/search_panes/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Searches the visible output of every pane. * [`select_layout`](https://libtmux.org/en/go/latest/mcp/tools/select_layout/) Change tmux state; no client-supplied executable input. Applies a named layout, a unique abbreviation for the running tmux version, or a saved layout from get_window_info. Invalid syntax is rejected before window lookup; tmux validates geometry when applying the layout. * [`select_pane`](https://libtmux.org/en/go/latest/mcp/tools/select_pane/) Change tmux state; no client-supplied executable input. Makes one pane active. * [`select_window`](https://libtmux.org/en/go/latest/mcp/tools/select_window/) Change tmux state; no client-supplied executable input. Makes one window active. * [`send_keys`](https://libtmux.org/en/go/latest/mcp/tools/send_keys/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Sends keys to a pane and to every pane synchronize-panes links it with; the ids reported are the panes checked before sending, not proof that each one received the keys. * [`send_keys_batch`](https://libtmux.org/en/go/latest/mcp/tools/send_keys_batch/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Sends up to sixty-four key sequences in order, rechecking before each one which panes synchronize-panes links to its target. * [`set_history_limit`](https://libtmux.org/en/go/latest/mcp/tools/set_history_limit/) Change tmux state; no client-supplied executable input. Sets a bounded integer scrollback limit for future panes in a session. * [`set_mouse_enabled`](https://libtmux.org/en/go/latest/mcp/tools/set_mouse_enabled/) Change tmux state; no client-supplied executable input. Enables or disables tmux mouse handling. * [`set_pane_title`](https://libtmux.org/en/go/latest/mcp/tools/set_pane_title/) Change tmux state; no client-supplied executable input. Replaces a pane's literal title. * [`set_synchronize_panes`](https://libtmux.org/en/go/latest/mcp/tools/set_synchronize_panes/) Change tmux state; no client-supplied executable input. Sets the window synchronization default (synchronize-panes); pane-level overrides still decide which panes receive later input. * [`show_environment`](https://libtmux.org/en/go/latest/mcp/tools/show_environment/) Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. Reads the environment tmux passes to processes. * [`show_hooks`](https://libtmux.org/en/go/latest/mcp/tools/show_hooks/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Reads configured tmux hooks. * [`show_option`](https://libtmux.org/en/go/latest/mcp/tools/show_option/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Reads one named tmux option. * [`signal_channel`](https://libtmux.org/en/go/latest/mcp/tools/signal_channel/) Change tmux state; no client-supplied executable input. Signals one server-wide tmux channel. * [`snapshot_pane`](https://libtmux.org/en/go/latest/mcp/tools/snapshot_pane/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Returns pane metadata and bounded terminal content together. * [`split_window`](https://libtmux.org/en/go/latest/mcp/tools/split_window/) Start a pane's configured process; accepts no command payload. Creates a pane whose configured process starts after the split. * [`swap_pane`](https://libtmux.org/en/go/latest/mcp/tools/swap_pane/) Change tmux state; no client-supplied executable input. Swaps the positions of two panes. * [`wait_for_channel`](https://libtmux.org/en/go/latest/mcp/tools/wait_for_channel/) Change tmux state; no client-supplied executable input. Waits on tmux's channel state with a bounded timeout. * [`wait_for_text`](https://libtmux.org/en/go/latest/mcp/tools/wait_for_text/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Waits for new pane output without accepting executable input. ## Resources * `tmux://capabilities` The selected socket, effective tools, schemas, input literalization, and aggregate authority. ## Resource templates This server does not advertise resource templates in this configuration. ## Prompts This server does not advertise prompts in this configuration. Source revision: [libtmux/libtmux-go@6f3df55f8a41999e41225eefb3940545b834e6a2](https://github.com/libtmux/libtmux-go/tree/6f3df55f8a41999e41225eefb3940545b834e6a2). --- # call_read_tools_batch Source: https://libtmux.org/en/go/latest/mcp/tools/call_read_tools_batch/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Calls up to sixteen eligible inspect tools serially; inner tools receive no separate approval. Retained rows contain full nested envelopes, oversized results are marked resultTruncated, and the complete JSON-RPC response is at most 1,000,000 bytes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Calls up to sixteen eligible inspect tools serially; inner tools receive no separate approval. Retained rows contain full nested envelopes, oversized results are marked resultTruncated, and the complete JSON-RPC response is at most 1,000,000 bytes. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/call_read_tools_batch.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L303) ## Arguments * `on_error` optional · string stop or continue; defaults to stop * `operations` required · null | array up to sixteen inspect operations ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "on_error": { "description": "stop or continue; defaults to stop", "enum": [ "stop", "continue" ], "type": "string" }, "operations": { "description": "up to sixteen inspect operations", "items": { "oneOf": [ { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "type": "object" }, "tool": { "const": "list_sessions", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "description": "only windows in this session name", "type": "string" } }, "type": "object" }, "tool": { "const": "list_windows", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "type": "object" }, "tool": { "const": "list_panes", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "type": "object" }, "tool": { "const": "get_server_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session_id": { "description": "the session id, such as $1", "type": "string" } }, "required": [ "session_id" ], "type": "object" }, "tool": { "const": "get_session_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id" ], "type": "object" }, "tool": { "const": "get_window_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" }, "tool": { "const": "get_pane_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "history": { "description": "include scrollback as well as the visible screen", "type": "boolean" }, "max_lines": { "description": "maximum lines, keeping the newest", "type": "integer" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" }, "tool": { "const": "capture_pane", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "cursor": { "description": "a cursor returned by an earlier capture", "type": "string" }, "max_lines": { "description": "maximum new lines, keeping the newest", "type": "integer" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" }, "tool": { "const": "capture_since", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "history": { "description": "include scrollback as well as the visible screen", "type": "boolean" }, "max_lines": { "description": "maximum lines, keeping the newest", "type": "integer" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" }, "tool": { "const": "snapshot_pane", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "max_lines": { "description": "maximum matching panes to return", "maximum": 200, "type": "integer" }, "max_matches_per_pane": { "description": "maximum matching lines per pane", "maximum": 200, "type": "integer" }, "pattern": { "description": "bounded text or regular expression to search for", "maxLength": 4096, "type": "string" }, "regex": { "description": "treat pattern as a regular expression", "type": "boolean" } }, "required": [ "pattern" ], "type": "object" }, "tool": { "const": "search_panes", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "position": { "description": "top-left, top-right, bottom-left, or bottom-right", "enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ], "type": "string" }, "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id", "position" ], "type": "object" }, "tool": { "const": "find_pane_by_position", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "names": { "description": "variable names matching [A-Za-z][A-Za-z0-9_]*", "items": { "type": "string" }, "type": [ "null", "array" ] } }, "required": [ "names" ], "type": "object" }, "tool": { "const": "get_tmux_variables", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "effective": { "description": "include an inherited value", "type": "boolean" }, "name": { "description": "the exact option name", "type": "string" }, "scope": { "description": "global, server, session, window, or pane", "enum": [ "", "global", "server", "session", "window", "pane" ], "type": "string" }, "target": { "description": "the target required by session, window, and pane scopes", "type": "string" } }, "required": [ "name" ], "type": "object" }, "tool": { "const": "show_option", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "description": "a session name; omit for the only session", "type": "string" } }, "type": "object" }, "tool": { "const": "show_environment", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "name": { "description": "one hook name; omit to read all hooks in the scope", "type": "string" }, "scope": { "description": "global, server, session, window, or pane", "enum": [ "", "global", "server", "session", "window", "pane" ], "type": "string" }, "target": { "description": "the target required by session, window, and pane scopes", "type": "string" } }, "type": "object" }, "tool": { "const": "show_hooks", "type": "string" } }, "required": [ "tool" ], "type": "object" } ] }, "maxItems": 16, "minItems": 1, "type": [ "null", "array" ] } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "failed": { "type": "integer" }, "onError": { "type": "string" }, "results": { "items": { "additionalProperties": false, "properties": { "error": { "type": [ "null", "string" ] }, "index": { "type": "integer" }, "result": true, "resultTruncated": { "type": "boolean" }, "success": { "type": "boolean" }, "tool": { "type": "string" } }, "required": [ "index", "tool", "success", "error", "result", "resultTruncated" ], "type": "object" }, "type": [ "array" ] }, "stoppedAt": { "type": [ "null", "integer" ] }, "succeeded": { "type": "integer" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "type": "integer" } }, "required": [ "results", "onError", "succeeded", "failed", "stoppedAt", "truncated", "truncatedBytes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Call read tools in a batch" } ``` --- # capture_pane Source: https://libtmux.org/en/go/latest/mcp/tools/capture_pane/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Returns bounded pane content and a cursor. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Returns bounded pane content and a cursor. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/capture_pane.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L191) ## Arguments * `history` optional · boolean include scrollback as well as the visible screen * `max_lines` optional · integer maximum lines, keeping the newest * `pane_id` required · string the pane id, such as %1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "history": { "description": "include scrollback as well as the visible screen", "type": "boolean" }, "max_lines": { "description": "maximum lines, keeping the newest", "type": "integer" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "lines": { "items": { "type": "string" }, "type": [ "array" ] }, "paneId": { "type": "string" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "type": "integer" }, "truncatedLines": { "type": "integer" } }, "required": [ "paneId", "truncated" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Capture a pane" } ``` --- # capture_since Source: https://libtmux.org/en/go/latest/mcp/tools/capture_since/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Returns pane output produced after a cursor. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Returns pane output produced after a cursor. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/capture_since.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L199) ## Arguments * `cursor` optional · string a cursor returned by an earlier capture * `max_lines` optional · integer maximum new lines, keeping the newest * `pane_id` required · string the pane id, such as %1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "cursor": { "description": "a cursor returned by an earlier capture", "type": "string" }, "max_lines": { "description": "maximum new lines, keeping the newest", "type": "integer" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "cursor": { "type": "string" }, "lines": { "items": { "type": "string" }, "type": [ "array" ] }, "linesMissed": { "type": "boolean" }, "paneId": { "type": "string" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "type": "integer" }, "truncatedLines": { "type": "integer" } }, "required": [ "paneId", "cursor", "lines", "linesMissed", "truncated" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Capture new pane output" } ``` --- # clear_pane_scrollback Source: https://libtmux.org/en/go/latest/mcp/tools/clear_pane_scrollback/ > Delete tmux state; accepts no command payload. Deletes retained scrollback from one pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Deletes retained scrollback from one pane. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/clear_pane_scrollback.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L565) ## Arguments * `pane_id` required · string the pane id, such as %1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "pane_id": { "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Clear pane scrollback" } ``` --- # create_session Source: https://libtmux.org/en/go/latest/mcp/tools/create_session/ > Start a pane's configured process; accepts no command payload. Creates a detached session whose first pane runs the configured process. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Creates a detached session whose first pane runs the configured process. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/create_session.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L435) ## Arguments * `height` optional · integer initial height; supply with width * `session_name` optional · string a literal session name * `start_directory` optional · string an absolute literal start directory * `width` optional · integer initial width; supply with height * `window_name` optional · string a literal first-window name ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "description": "initial height; supply with width", "type": "integer" }, "session_name": { "description": "a literal session name", "type": "string" }, "start_directory": { "description": "an absolute literal start directory", "type": "string" }, "width": { "description": "initial width; supply with height", "type": "integer" }, "window_name": { "description": "a literal first-window name", "type": "string" } }, "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "sessionId": { "type": "string" }, "sessionName": { "type": "string" } }, "required": [ "sessionId", "sessionName" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Create a session" } ``` --- # create_window Source: https://libtmux.org/en/go/latest/mcp/tools/create_window/ > Start a pane's configured process; accepts no command payload. Creates a window whose first pane runs the configured process. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Creates a window whose first pane runs the configured process. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/create_window.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L452) ## Arguments * `attach` optional · boolean make the new window active * `direction` optional · string before or after * `session_id` required · string the session id, such as $1 * `start_directory` optional · string an absolute literal start directory * `window_name` optional · string a literal window name ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "attach": { "description": "make the new window active", "type": "boolean" }, "direction": { "description": "before or after", "enum": [ "before", "after" ], "type": "string" }, "session_id": { "description": "the session id, such as $1", "type": "string" }, "start_directory": { "description": "an absolute literal start directory", "type": "string" }, "window_name": { "description": "a literal window name", "type": "string" } }, "required": [ "session_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "paneId": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "windowId", "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Create a window" } ``` --- # find_pane_by_position Source: https://libtmux.org/en/go/latest/mcp/tools/find_pane_by_position/ > Inspect tmux metadata; accepts no client-supplied executable input. Finds a pane at one of a window's four corners. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Finds a pane at one of a window’s four corners. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/find_pane_by_position.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L229) ## Arguments * `position` required · string top-left, top-right, bottom-left, or bottom-right * `window_id` required · string the window id, such as @1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "position": { "description": "top-left, top-right, bottom-left, or bottom-right", "enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ], "type": "string" }, "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id", "position" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "found": { "type": "boolean" }, "geometry": { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "left": { "type": "integer" }, "top": { "type": "integer" }, "width": { "type": "integer" } }, "required": [ "left", "top", "width", "height" ], "type": "object" }, "paneId": { "type": "string" } }, "required": [ "paneId", "found", "geometry" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Find pane by position" } ``` --- # get_pane_info Source: https://libtmux.org/en/go/latest/mcp/tools/get_pane_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Returns metadata for one pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Returns metadata for one pane. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/get_pane_info.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L174) ## Arguments * `pane_id` required · string the pane id, such as %1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "dead": { "type": "boolean" }, "exitStatus": { "type": [ "null", "integer" ] }, "historyLimit": { "type": "integer" }, "historyLines": { "type": "integer" }, "inMode": { "type": "boolean" }, "pane": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "currentCommand": { "type": "string" }, "geometry": { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "left": { "type": "integer" }, "top": { "type": "integer" }, "width": { "type": "integer" } }, "required": [ "left", "top", "width", "height" ], "type": "object" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isCaller": { "type": [ "null", "boolean" ] }, "session": { "type": "string" }, "window": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "id", "session", "window", "windowId", "index", "currentCommand", "active", "geometry", "isCaller" ], "type": "object" }, "path": { "type": "string" }, "pid": { "type": "integer" }, "title": { "type": "string" }, "zoomed": { "type": "boolean" } }, "required": [ "pane", "title", "path", "pid", "dead", "zoomed", "inMode", "historyLines", "historyLimit" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Get pane info" } ``` --- # get_server_info Source: https://libtmux.org/en/go/latest/mcp/tools/get_server_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Reports whether the pinned server exists and its version. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Reports whether the pinned server exists and its version. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/get_server_info.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L151) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "alive": { "type": "boolean" }, "attachedClients": { "items": { "additionalProperties": false, "properties": { "controlMode": { "type": "boolean" }, "name": { "type": "string" }, "session": { "type": "string" }, "tty": { "type": "string" } }, "required": [ "name", "controlMode" ], "type": "object" }, "type": [ "array" ] }, "callerPaneId": { "type": "string" }, "clients": { "type": "integer" }, "insideThisServer": { "type": "boolean" }, "messages": { "items": { "type": "string" }, "type": [ "array" ] }, "messagesUnavailable": { "type": "string" }, "panes": { "type": "integer" }, "sessions": { "type": "integer" }, "socketPath": { "type": "string" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "type": "integer" }, "truncatedLines": { "type": "integer" }, "version": { "type": "string" }, "windows": { "type": "integer" } }, "required": [ "socketPath", "version", "alive", "sessions", "windows", "panes", "clients", "attachedClients", "insideThisServer", "truncated" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Get server info" } ``` --- # get_session_info Source: https://libtmux.org/en/go/latest/mcp/tools/get_session_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Returns metadata for one session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Returns metadata for one session. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/get_session_info.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L158) ## Arguments * `session_id` required · string the session id, such as $1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session_id": { "description": "the session id, such as $1", "type": "string" } }, "required": [ "session_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "activeWindowId": { "type": "string" }, "created": { "type": "string" }, "path": { "type": "string" }, "session": { "additionalProperties": false, "properties": { "attached": { "type": "integer" }, "id": { "type": "string" }, "name": { "type": "string" }, "windows": { "type": "integer" } }, "required": [ "id", "name", "windows", "attached" ], "type": "object" }, "windows": { "items": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "id": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" }, "panes": { "type": "integer" }, "session": { "type": "string" } }, "required": [ "id", "session", "name", "index", "panes", "active" ], "type": "object" }, "type": [ "array" ] } }, "required": [ "session", "path", "created", "activeWindowId", "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Get session info" } ``` --- # get_tmux_variables Source: https://libtmux.org/en/go/latest/mcp/tools/get_tmux_variables/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Reads a capped list of validated tmux variable names, not free-form formats. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Reads a capped list of validated tmux variable names, not free-form formats. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/get_tmux_variables.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L251) ## Arguments * `names` required · null | array variable names matching \[A-Za-z]\[A-Za-z0-9\_]\* ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "names": { "description": "variable names matching [A-Za-z][A-Za-z0-9_]*", "items": { "type": "string" }, "type": [ "null", "array" ] } }, "required": [ "names" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "values": { "additionalProperties": { "type": "string" }, "type": "object" } }, "required": [ "values" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Get tmux variables" } ``` --- # get_window_info Source: https://libtmux.org/en/go/latest/mcp/tools/get_window_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Returns metadata for one window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Returns metadata for one window. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/get_window_info.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L166) ## Arguments * `window_id` required · string the window id, such as @1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "layout": { "type": "string" }, "panes": { "items": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "currentCommand": { "type": "string" }, "geometry": { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "left": { "type": "integer" }, "top": { "type": "integer" }, "width": { "type": "integer" } }, "required": [ "left", "top", "width", "height" ], "type": "object" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isCaller": { "type": [ "null", "boolean" ] }, "session": { "type": "string" }, "window": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "id", "session", "window", "windowId", "index", "currentCommand", "active", "geometry", "isCaller" ], "type": "object" }, "type": [ "array" ] }, "width": { "type": "integer" }, "window": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "id": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" }, "panes": { "type": "integer" }, "session": { "type": "string" } }, "required": [ "id", "session", "name", "index", "panes", "active" ], "type": "object" }, "zoomed": { "type": "boolean" } }, "required": [ "window", "layout", "width", "height", "zoomed", "panes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Get window info" } ``` --- # kill_pane Source: https://libtmux.org/en/go/latest/mcp/tools/kill_pane/ > Delete tmux state; accepts no command payload. Deletes one pane and ends its process. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Deletes one pane and ends its process. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/kill_pane.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L570) ## Arguments * `confirm_self` optional · boolean permit ending the pane this MCP process runs in * `pane_id` required · string the pane id, such as %1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "confirm_self": { "description": "permit ending the pane this MCP process runs in", "type": "boolean" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "killed": { "type": "string" }, "windowEnded": { "type": "boolean" } }, "required": [ "killed", "windowEnded" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Kill a pane" } ``` --- # kill_session Source: https://libtmux.org/en/go/latest/mcp/tools/kill_session/ > Delete tmux state; accepts no command payload. Deletes one session and every window and pane in it. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Deletes one session and every window and pane in it. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/kill_session.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L578) ## Arguments * `confirm_self` optional · boolean permit ending the pane this MCP process runs in * `session_id` required · string the session id, such as $1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "confirm_self": { "description": "permit ending the pane this MCP process runs in", "type": "boolean" }, "session_id": { "description": "the session id, such as $1", "type": "string" } }, "required": [ "session_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "killed": { "type": "string" } }, "required": [ "killed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Kill a session" } ``` --- # kill_window Source: https://libtmux.org/en/go/latest/mcp/tools/kill_window/ > Delete tmux state; accepts no command payload. Deletes one window and every pane in it. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Deletes one window and every pane in it. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/kill_window.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L574) ## Arguments * `confirm_self` optional · boolean permit ending the pane this MCP process runs in * `window_id` required · string the window id, such as @1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "confirm_self": { "description": "permit ending the pane this MCP process runs in", "type": "boolean" }, "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "killed": { "type": "string" }, "sessionEnded": { "type": "boolean" } }, "required": [ "killed", "sessionEnded" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Kill a window" } ``` --- # list_panes Source: https://libtmux.org/en/go/latest/mcp/tools/list_panes/ > Inspect tmux metadata; accepts no client-supplied executable input. Lists pane metadata and stable pane IDs. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Lists pane metadata and stable pane IDs. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/list_panes.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L143) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "panes": { "items": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "currentCommand": { "type": "string" }, "geometry": { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "left": { "type": "integer" }, "top": { "type": "integer" }, "width": { "type": "integer" } }, "required": [ "left", "top", "width", "height" ], "type": "object" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isCaller": { "type": [ "null", "boolean" ] }, "session": { "type": "string" }, "status": { "additionalProperties": false, "properties": { "dead": { "type": "boolean" }, "exitStatus": { "type": [ "null", "integer" ] }, "historyLines": { "type": "integer" }, "inMode": { "type": "boolean" }, "path": { "type": "string" }, "title": { "type": "string" } }, "required": [ "dead", "historyLines", "inMode" ], "type": [ "null", "object" ] }, "window": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "id", "session", "window", "windowId", "index", "currentCommand", "active", "geometry", "isCaller" ], "type": "object" }, "type": [ "array" ] }, "serverNote": { "type": "string" }, "skipped": { "type": "integer" }, "total": { "type": "integer" } }, "required": [ "panes", "total" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "List panes" } ``` --- # list_sessions Source: https://libtmux.org/en/go/latest/mcp/tools/list_sessions/ > Inspect tmux metadata; accepts no client-supplied executable input. Lists sessions on the pinned tmux server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Lists sessions on the pinned tmux server. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/list_sessions.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L127) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "serverNote": { "type": "string" }, "sessions": { "items": { "additionalProperties": false, "properties": { "attached": { "type": "integer" }, "id": { "type": "string" }, "name": { "type": "string" }, "windows": { "type": "integer" } }, "required": [ "id", "name", "windows", "attached" ], "type": "object" }, "type": [ "array" ] }, "skipped": { "type": "integer" }, "total": { "type": "integer" } }, "required": [ "sessions", "total" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "List sessions" } ``` --- # list_windows Source: https://libtmux.org/en/go/latest/mcp/tools/list_windows/ > Inspect tmux metadata; accepts no client-supplied executable input. Lists windows, optionally only those in one named session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Lists windows, optionally only those in one named session. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/list_windows.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L135) ## Arguments * `session` optional · string only windows in this session name ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "only windows in this session name", "type": "string" } }, "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "serverNote": { "type": "string" }, "skipped": { "type": "integer" }, "total": { "type": "integer" }, "windows": { "items": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "id": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" }, "panes": { "type": "integer" }, "session": { "type": "string" } }, "required": [ "id", "session", "name", "index", "panes", "active" ], "type": "object" }, "type": [ "array" ] } }, "required": [ "windows", "total" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "List windows" } ``` --- # move_window Source: https://libtmux.org/en/go/latest/mcp/tools/move_window/ > Change tmux state; no client-supplied executable input. Moves a window to another session, optionally at an index. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Moves a window to another session, optionally at an index. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/move_window.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L379) ## Arguments * `index` optional · null | integer a destination window index; omit for tmux's choice * `session_id` required · string the destination session id, such as $1 * `window_id` required · string the window id, such as @1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "index": { "description": "a destination window index; omit for tmux's choice", "type": [ "null", "integer" ] }, "session_id": { "description": "the destination session id, such as $1", "type": "string" }, "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id", "session_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "index": { "type": "integer" }, "session": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "windowId", "session", "index" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Move a window" } ``` --- # paste_text Source: https://libtmux.org/en/go/latest/mcp/tools/paste_text/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Pastes literal text only to its target; optional Enter appends one newline to the same private buffer. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Pastes literal text only to its target; optional Enter appends one newline to the same private buffer. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/paste_text.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L527) ## Arguments * `enter` optional · boolean append a newline that submits the text * `pane_id` required · string the pane id, such as %1 * `text` required · string the literal text to paste ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enter": { "description": "append a newline that submits the text", "type": "boolean" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" }, "text": { "description": "the literal text to paste", "type": "string" } }, "required": [ "pane_id", "text" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "bytes": { "type": "integer" }, "pane_id": { "type": "string" } }, "required": [ "pane_id", "bytes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Paste text" } ``` --- # rename_session Source: https://libtmux.org/en/go/latest/mcp/tools/rename_session/ > Change tmux state; no client-supplied executable input. Replaces a session's name. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Replaces a session’s name. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/rename_session.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L333) ## Arguments * `new_name` required · string the literal new session name * `session_id` required · string the session id, such as $1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "new_name": { "description": "the literal new session name", "type": "string" }, "session_id": { "description": "the session id, such as $1", "type": "string" } }, "required": [ "session_id", "new_name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "name": { "type": "string" }, "sessionId": { "type": "string" } }, "required": [ "sessionId", "name" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Rename a session" } ``` --- # rename_window Source: https://libtmux.org/en/go/latest/mcp/tools/rename_window/ > Change tmux state; no client-supplied executable input. Replaces a window's name. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Replaces a window’s name. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/rename_window.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L341) ## Arguments * `new_name` required · string the literal new window name * `window_id` required · string the window id, such as @1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "new_name": { "description": "the literal new window name", "type": "string" }, "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id", "new_name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "name": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "windowId", "name" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Rename a window" } ``` --- # resize_pane Source: https://libtmux.org/en/go/latest/mcp/tools/resize_pane/ > Change tmux state; no client-supplied executable input. Sets a pane's width, height, or both. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Sets a pane’s width, height, or both. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/resize_pane.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L372) ## Arguments * `height` optional · integer height in terminal cells; omit to retain it * `pane_id` required · string the pane id, such as %1 * `width` optional · integer width in terminal cells; omit to retain it ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "description": "height in terminal cells; omit to retain it", "type": "integer" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" }, "width": { "description": "width in terminal cells; omit to retain it", "type": "integer" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "paneId": { "type": "string" }, "width": { "type": "integer" } }, "required": [ "paneId", "width", "height" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Resize a pane" } ``` --- # resize_window Source: https://libtmux.org/en/go/latest/mcp/tools/resize_window/ > Change tmux state; no client-supplied executable input. Sets a window's width, height, or both. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Sets a window’s width, height, or both. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/resize_window.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L365) ## Arguments * `height` optional · integer height in terminal cells; omit to retain it * `width` optional · integer width in terminal cells; omit to retain it * `window_id` required · string the window id, such as @1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "description": "height in terminal cells; omit to retain it", "type": "integer" }, "width": { "description": "width in terminal cells; omit to retain it", "type": "integer" }, "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "width": { "type": "integer" }, "windowId": { "type": "string" } }, "required": [ "windowId", "width", "height" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Resize a window" } ``` --- # respawn_pane Source: https://libtmux.org/en/go/latest/mcp/tools/respawn_pane/ > Start a pane's configured process; accepts no command payload. Kills the pane's current process and starts its configured process again. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Kills the pane’s current process and starts its configured process again. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/respawn_pane.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L481) ## Arguments * `pane_id` required · string the pane id, such as %1 * `start_directory` optional · string an absolute literal start directory ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "the pane id, such as %1", "type": "string" }, "start_directory": { "description": "an absolute literal start directory", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "gone": { "type": "boolean" }, "paneId": { "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Respawn a pane" } ``` --- # run_shell_command Source: https://libtmux.org/en/go/latest/mcp/tools/run_shell_command/ > Run a shell command in a pane with your user's permissions. Runs one command you author in a pane that is not synchronized with others, rechecks the pane just before sending, and waits for it to finish, reporting its exit status. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Run a shell command in a pane with your user’s permissions. Runs one command you author in a pane that is not synchronized with others, rechecks the pane just before sending, and waits for it to finish, reporting its exit status. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/run_shell_command.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L493) ## Arguments * `command` required · string the shell command run in the pane's interactive shell * `max_lines` optional · integer maximum output lines, keeping the newest * `pane_id` required · string the pane id, such as %1 * `suppress_history` optional · boolean best-effort persistent history suppression * `timeout` optional · number seconds to wait before giving up ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "command": { "description": "the shell command run in the pane's interactive shell", "type": "string" }, "max_lines": { "description": "maximum output lines, keeping the newest", "minimum": 0, "type": "integer" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" }, "suppress_history": { "description": "best-effort persistent history suppression", "type": "boolean" }, "timeout": { "description": "seconds to wait before giving up", "minimum": 0, "type": "number" } }, "required": [ "pane_id", "command" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "effective_timeout_seconds": { "type": "integer" }, "exit_status": { "type": [ "null", "integer" ] }, "lines_missed": { "type": "boolean" }, "output": { "items": { "type": "string" }, "type": [ "array" ] }, "output_unavailable": { "type": "string" }, "pane_id": { "type": "string" }, "resolved_pane_ids": { "items": { "type": "string" }, "type": [ "array" ] }, "running": { "type": "string" }, "timed_out": { "type": "boolean" }, "timeout_clamped": { "type": "boolean" } }, "required": [ "pane_id", "resolved_pane_ids", "timed_out", "output" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Run a shell command" } ``` --- # search_panes Source: https://libtmux.org/en/go/latest/mcp/tools/search_panes/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Searches the visible output of every pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Searches the visible output of every pane. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/search_panes.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L218) ## Arguments * `max_lines` optional · integer maximum matching panes to return * `max_matches_per_pane` optional · integer maximum matching lines per pane * `pattern` required · string bounded text or regular expression to search for * `regex` optional · boolean treat pattern as a regular expression ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "max_lines": { "description": "maximum matching panes to return", "maximum": 200, "type": "integer" }, "max_matches_per_pane": { "description": "maximum matching lines per pane", "maximum": 200, "type": "integer" }, "pattern": { "description": "bounded text or regular expression to search for", "maxLength": 4096, "type": "string" }, "regex": { "description": "treat pattern as a regular expression", "type": "boolean" } }, "required": [ "pattern" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "bytesInspected": { "type": "integer" }, "linesInspected": { "type": "integer" }, "morePanes": { "type": "integer" }, "panes": { "items": { "additionalProperties": false, "properties": { "matches": { "items": { "additionalProperties": false, "properties": { "row": { "type": "integer" }, "text": { "type": "string" } }, "required": [ "row", "text" ], "type": "object" }, "type": [ "array" ] }, "moreMatches": { "type": "integer" }, "pane": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "currentCommand": { "type": "string" }, "geometry": { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "left": { "type": "integer" }, "top": { "type": "integer" }, "width": { "type": "integer" } }, "required": [ "left", "top", "width", "height" ], "type": "object" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isCaller": { "type": [ "null", "boolean" ] }, "session": { "type": "string" }, "window": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "id", "session", "window", "windowId", "index", "currentCommand", "active", "geometry", "isCaller" ], "type": "object" } }, "required": [ "pane", "matches" ], "type": "object" }, "type": [ "array" ] }, "panesInspected": { "type": "integer" }, "workLimited": { "type": "boolean" }, "workTimeLimitSeconds": { "type": "number" } }, "required": [ "panes", "panesInspected", "linesInspected", "bytesInspected", "workLimited", "workTimeLimitSeconds" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Search panes" } ``` --- # select_layout Source: https://libtmux.org/en/go/latest/mcp/tools/select_layout/ > Change tmux state; no client-supplied executable input. Applies a named layout, a unique abbreviation for the running tmux version, or a saved layout from get_window_info. Invalid syntax is rejected before window lookup; tmux validates geometry when applying the layout. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Applies a named layout, a unique abbreviation for the running tmux version, or a saved layout from [get_window_info](https://libtmux.org/en/go/latest/mcp/tools/get_window_info/). Invalid syntax is rejected before window lookup; tmux validates geometry when applying the layout. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/select_layout.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L357) ## Arguments * `layout` required · string a named layout, a unique abbreviation for the running tmux version, or a saved layout from get_window_info * `window_id` required · string the window id, such as @1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "layout": { "description": "a named layout, a unique abbreviation for the running tmux version, or a saved layout from get_window_info", "type": "string" }, "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id", "layout" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "layout": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "windowId", "layout" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Select a layout" } ``` --- # select_pane Source: https://libtmux.org/en/go/latest/mcp/tools/select_pane/ > Change tmux state; no client-supplied executable input. Makes one pane active. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Makes one pane active. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/select_pane.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L353) ## Arguments * `pane_id` required · string the pane id, such as %1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "paneId": { "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Select a pane" } ``` --- # select_window Source: https://libtmux.org/en/go/latest/mcp/tools/select_window/ > Change tmux state; no client-supplied executable input. Makes one window active. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Makes one window active. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/select_window.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L349) ## Arguments * `window_id` required · string the window id, such as @1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "windowId": { "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Select a window" } ``` --- # send_keys Source: https://libtmux.org/en/go/latest/mcp/tools/send_keys/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Sends keys to a pane and to every pane synchronize-panes links it with; the ids reported are the panes checked before sending, not proof that each one received the keys. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Sends keys to a pane and to every pane synchronize-panes links it with; the ids reported are the panes checked before sending, not proof that each one received the keys. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/send_keys.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L506) ## Arguments * `enter` optional · boolean press Enter after keys, as a real key press, to submit them * `keys` required · null | array key names or literal strings to send; do not put "Enter" here when literal is true, it types the five letters - set enter instead * `literal` optional · boolean send strings literally instead of as key names * `pane_id` required · string the pane id, such as %1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enter": { "description": "press Enter after keys, as a real key press, to submit them", "type": "boolean" }, "keys": { "description": "key names or literal strings to send; do not put \"Enter\" here when literal is true, it types the five letters - set enter instead", "items": { "type": "string" }, "type": [ "null", "array" ] }, "literal": { "description": "send strings literally instead of as key names", "type": "boolean" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id", "keys" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "pane_id": { "type": "string" }, "resolved_pane_ids": { "items": { "type": "string" }, "type": [ "array" ] }, "sent": { "type": "integer" } }, "required": [ "pane_id", "resolved_pane_ids", "sent" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Send keys" } ``` --- # send_keys_batch Source: https://libtmux.org/en/go/latest/mcp/tools/send_keys_batch/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Sends up to sixty-four key sequences in order, rechecking before each one which panes synchronize-panes links to its target. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Sends up to sixty-four key sequences in order, rechecking before each one which panes synchronize-panes links to its target. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/send_keys_batch.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L517) ## Arguments * `on_error` optional · string stop or continue; defaults to stop * `operations` required · null | array up to sixty-four ordered pane-input operations ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "on_error": { "description": "stop or continue; defaults to stop", "enum": [ "stop", "continue" ], "type": "string" }, "operations": { "description": "up to sixty-four ordered pane-input operations", "items": { "additionalProperties": false, "properties": { "enter": { "type": "boolean" }, "keys": { "items": { "type": "string" }, "type": [ "null", "array" ] }, "literal": { "type": "boolean" }, "pane_id": { "type": "string" } }, "required": [ "pane_id", "keys" ], "type": "object" }, "type": [ "null", "array" ] } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "completed": { "type": "integer" }, "failed": { "type": "integer" }, "results": { "items": { "additionalProperties": false, "properties": { "error": { "type": "string" }, "pane_id": { "type": "string" }, "resolved_pane_ids": { "items": { "type": "string" }, "type": [ "array" ] }, "sent": { "type": "integer" } }, "required": [ "pane_id", "resolved_pane_ids", "sent" ], "type": "object" }, "type": [ "array" ] } }, "required": [ "results", "completed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Send keys in a batch" } ``` --- # set_history_limit Source: https://libtmux.org/en/go/latest/mcp/tools/set_history_limit/ > Change tmux state; no client-supplied executable input. Sets a bounded integer scrollback limit for future panes in a session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Sets a bounded integer scrollback limit for future panes in a session. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/set_history_limit.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L422) ## Arguments * `lines` required · integer the nonnegative retained line count * `session_id` required · string the session id, such as $1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "lines": { "description": "the nonnegative retained line count", "type": "integer" }, "session_id": { "description": "the session id, such as $1", "type": "string" } }, "required": [ "session_id", "lines" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "enabled": { "type": [ "null", "boolean" ] }, "name": { "type": "string" }, "target": { "type": "string" }, "value": { "type": "string" } }, "required": [ "name" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Set history limit" } ``` --- # set_mouse_enabled Source: https://libtmux.org/en/go/latest/mcp/tools/set_mouse_enabled/ > Change tmux state; no client-supplied executable input. Enables or disables tmux mouse handling. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Enables or disables tmux mouse handling. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/set_mouse_enabled.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L417) ## Arguments * `enabled` optional · boolean whether the setting is enabled ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enabled": { "description": "whether the setting is enabled", "type": "boolean" } }, "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "enabled": { "type": [ "null", "boolean" ] }, "name": { "type": "string" }, "target": { "type": "string" }, "value": { "type": "string" } }, "required": [ "name" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Set mouse handling" } ``` --- # set_pane_title Source: https://libtmux.org/en/go/latest/mcp/tools/set_pane_title/ > Change tmux state; no client-supplied executable input. Replaces a pane's literal title. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Replaces a pane’s literal title. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/set_pane_title.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L391) ## Arguments * `pane_id` required · string the pane id, such as %1 * `title` required · string the literal title ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "the pane id, such as %1", "type": "string" }, "title": { "description": "the literal title", "type": "string" } }, "required": [ "pane_id", "title" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "paneId": { "type": "string" }, "title": { "type": "string" } }, "required": [ "paneId", "title" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Set pane title" } ``` --- # set_synchronize_panes Source: https://libtmux.org/en/go/latest/mcp/tools/set_synchronize_panes/ > Change tmux state; no client-supplied executable input. Sets the window synchronization default (synchronize-panes); pane-level overrides still decide which panes receive later input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Sets the window synchronization default (synchronize-panes); pane-level overrides still decide which panes receive later input. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/set_synchronize_panes.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L538) ## Arguments * `enabled` optional · boolean whether pane input is synchronized * `window_id` required · string the window id, such as @1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enabled": { "description": "whether pane input is synchronized", "type": "boolean" }, "window_id": { "description": "the window id, such as @1", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "enabled": { "type": [ "null", "boolean" ] }, "name": { "type": "string" }, "target": { "type": "string" }, "value": { "type": "string" } }, "required": [ "name" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Set synchronized panes" } ``` --- # show_environment Source: https://libtmux.org/en/go/latest/mcp/tools/show_environment/ > Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. Reads the environment tmux passes to processes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. Reads the environment tmux passes to processes. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/show_environment.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L275) ## Arguments * `session` optional · string a session name; omit for the only session ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "a session name; omit for the only session", "type": "string" } }, "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "sessionName": { "type": "string" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "type": "integer" }, "truncatedLines": { "type": "integer" }, "valuesWithheld": { "type": "boolean" }, "variables": { "items": { "additionalProperties": false, "properties": { "name": { "type": "string" }, "removed": { "type": "boolean" }, "scope": { "type": "string" }, "value": { "type": "string" } }, "required": [ "name", "scope" ], "type": "object" }, "type": [ "array" ] } }, "required": [ "sessionName", "variables", "truncated" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Show tmux environment" } ``` --- # show_hooks Source: https://libtmux.org/en/go/latest/mcp/tools/show_hooks/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Reads configured tmux hooks. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Reads configured tmux hooks. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/show_hooks.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L283) ## Arguments * `name` optional · string one hook name; omit to read all hooks in the scope * `scope` optional · string global, server, session, window, or pane * `target` optional · string the target required by session, window, and pane scopes ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "one hook name; omit to read all hooks in the scope", "type": "string" }, "scope": { "description": "global, server, session, window, or pane", "enum": [ "", "global", "server", "session", "window", "pane" ], "type": "string" }, "target": { "description": "the target required by session, window, and pane scopes", "type": "string" } }, "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "hooks": { "items": { "additionalProperties": false, "properties": { "command": { "type": "string" }, "name": { "type": "string" } }, "required": [ "name", "command" ], "type": "object" }, "type": [ "array" ] }, "scope": { "type": "string" } }, "required": [ "scope", "hooks" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Show hooks" } ``` --- # show_option Source: https://libtmux.org/en/go/latest/mcp/tools/show_option/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Reads one named tmux option. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Reads one named tmux option. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/show_option.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L263) ## Arguments * `effective` optional · boolean include an inherited value * `name` required · string the exact option name * `scope` optional · string global, server, session, window, or pane * `target` optional · string the target required by session, window, and pane scopes ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "effective": { "description": "include an inherited value", "type": "boolean" }, "name": { "description": "the exact option name", "type": "string" }, "scope": { "description": "global, server, session, window, or pane", "enum": [ "", "global", "server", "session", "window", "pane" ], "type": "string" }, "target": { "description": "the target required by session, window, and pane scopes", "type": "string" } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "inherited": { "type": "boolean" }, "name": { "type": "string" }, "scope": { "type": "string" }, "set": { "type": "boolean" }, "value": { "type": "string" } }, "required": [ "name", "scope", "value", "set" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Show one option" } ``` --- # signal_channel Source: https://libtmux.org/en/go/latest/mcp/tools/signal_channel/ > Change tmux state; no client-supplied executable input. Signals one server-wide tmux channel. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Signals one server-wide tmux channel. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/signal_channel.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L412) ## Arguments * `channel` required · string the tmux wait-for channel to signal ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "the tmux wait-for channel to signal", "type": "string" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "channel": { "type": "string" } }, "required": [ "channel" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Signal a channel" } ``` --- # snapshot_pane Source: https://libtmux.org/en/go/latest/mcp/tools/snapshot_pane/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Returns pane metadata and bounded terminal content together. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Returns pane metadata and bounded terminal content together. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/snapshot_pane.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L210) ## Arguments * `history` optional · boolean include scrollback as well as the visible screen * `max_lines` optional · integer maximum lines, keeping the newest * `pane_id` required · string the pane id, such as %1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "history": { "description": "include scrollback as well as the visible screen", "type": "boolean" }, "max_lines": { "description": "maximum lines, keeping the newest", "type": "integer" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "dead": { "type": "boolean" }, "exitStatus": { "type": [ "null", "integer" ] }, "lines": { "items": { "type": "string" }, "type": [ "array" ] }, "pane": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "currentCommand": { "type": "string" }, "geometry": { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "left": { "type": "integer" }, "top": { "type": "integer" }, "width": { "type": "integer" } }, "required": [ "left", "top", "width", "height" ], "type": "object" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isCaller": { "type": [ "null", "boolean" ] }, "session": { "type": "string" }, "window": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "id", "session", "window", "windowId", "index", "currentCommand", "active", "geometry", "isCaller" ], "type": "object" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "type": "integer" }, "truncatedLines": { "type": "integer" } }, "required": [ "lines", "pane", "dead", "truncated" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Snapshot a pane" } ``` --- # split_window Source: https://libtmux.org/en/go/latest/mcp/tools/split_window/ > Start a pane's configured process; accepts no command payload. Creates a pane whose configured process starts after the split. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Creates a pane whose configured process starts after the split. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/split_window.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L468) ## Arguments * `direction` optional · string below, above, left, or right * `pane_id` required · string the pane id, such as %1 * `percent` optional · integer share of the split occupied by the new pane * `start_directory` optional · string an absolute literal start directory ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "direction": { "description": "below, above, left, or right", "enum": [ "", "below", "above", "right", "left" ], "type": "string" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" }, "percent": { "description": "share of the split occupied by the new pane", "type": "integer" }, "start_directory": { "description": "an absolute literal start directory", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "paneId": { "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Split a window" } ``` --- # swap_pane Source: https://libtmux.org/en/go/latest/mcp/tools/swap_pane/ > Change tmux state; no client-supplied executable input. Swaps the positions of two panes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Swaps the positions of two panes. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/swap_pane.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L386) ## Arguments * `other_pane_id` required · string the other pane id, such as %2 * `pane_id` required · string one pane id, such as %1 ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "other_pane_id": { "description": "the other pane id, such as %2", "type": "string" }, "pane_id": { "description": "one pane id, such as %1", "type": "string" } }, "required": [ "pane_id", "other_pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "paneId": { "type": "string" }, "withPaneId": { "type": "string" } }, "required": [ "paneId", "withPaneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Swap panes" } ``` --- # wait_for_channel Source: https://libtmux.org/en/go/latest/mcp/tools/wait_for_channel/ > Change tmux state; no client-supplied executable input. Waits on tmux's channel state with a bounded timeout. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Waits on tmux’s channel state with a bounded timeout. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/wait_for_channel.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L402) ## Arguments * `channel` required · string a server-wide tmux channel name * `drain_first` optional · boolean consume a pending signal before waiting * `timeout` optional · number seconds to wait before giving up ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "a server-wide tmux channel name", "type": "string" }, "drain_first": { "description": "consume a pending signal before waiting", "type": "boolean" }, "timeout": { "description": "seconds to wait before giving up", "minimum": 0, "type": "number" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "effectiveTimeoutSeconds": { "type": "integer" }, "signalled": { "type": "boolean" }, "timeoutClamped": { "type": "boolean" } }, "required": [ "signalled", "effectiveTimeoutSeconds" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Wait for a channel" } ``` --- # wait_for_text Source: https://libtmux.org/en/go/latest/mcp/tools/wait_for_text/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Waits for new pane output without accepting executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Waits for new pane output without accepting executable input. [All Go tools](https://libtmux.org/en/go/latest/mcp/tools/) · [JSON](https://libtmux.org/en/go/latest/mcp/tools/wait_for_text.json) · [Source](https://github.com/libtmux/libtmux-go/blob/6f3df55f8a41999e41225eefb3940545b834e6a2/mcp/manifest_catalog.go#L239) ## Arguments * `cursor` optional · string a cursor returned by an earlier capture * `max_lines` optional · integer maximum observed lines to return * `pane_id` required · string the pane id, such as %1 * `patterns` optional · null | array text to wait for; any one ends the wait * `regex` optional · boolean treat patterns and stops as regular expressions * `stop` optional · null | array failure text; any one ends the wait * `timeout` optional · number seconds to wait before giving up ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "cursor": { "description": "a cursor returned by an earlier capture", "type": "string" }, "max_lines": { "description": "maximum observed lines to return", "type": "integer" }, "pane_id": { "description": "the pane id, such as %1", "type": "string" }, "patterns": { "description": "text to wait for; any one ends the wait", "items": { "maxLength": 4096, "type": "string" }, "maxItems": 32, "type": [ "null", "array" ] }, "regex": { "description": "treat patterns and stops as regular expressions", "type": "boolean" }, "stop": { "description": "failure text; any one ends the wait", "items": { "maxLength": 4096, "type": "string" }, "maxItems": 32, "type": [ "null", "array" ] }, "timeout": { "description": "seconds to wait before giving up", "minimum": 0, "type": "number" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "effectiveTimeoutSeconds": { "type": "integer" }, "elapsedSeconds": { "type": "number" }, "entryNote": { "type": "string" }, "found": { "type": "boolean" }, "lines": { "items": { "type": "string" }, "type": [ "array" ] }, "matched": { "type": "string" }, "matchedAtEntry": { "type": "boolean" }, "outcome": { "type": "string" }, "paneId": { "type": "string" }, "pendingInputOnly": { "type": "boolean" }, "timeoutClamped": { "type": "boolean" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "type": "integer" }, "truncatedLines": { "type": "integer" } }, "required": [ "paneId", "outcome", "found", "matchedAtEntry", "pendingInputOnly", "elapsedSeconds", "effectiveTimeoutSeconds", "truncated" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "openWorldHint": true, "title": "Wait for pane text" } ``` --- # Java MCP tools Source: https://libtmux.org/en/java/latest/mcp/tools/ > Tools, resources, and prompts advertised by the Java MCP server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Use the wire name shown here when calling a tool. The Java server advertises 45 tools with the reference configuration below. Your client’s list follows the policy configured for its server. Read the [setup guide](https://libtmux.org/en/java/latest/mcp/guides/) before choosing tool access. The [language API reference](https://libtmux.org/en/java/latest/mcp/reference/) covers embedding and implementation types. [Download the protocol catalog as JSON](https://libtmux.org/en/java/latest/mcp/tools.json). Reference configuration * `LIBTMUX_TOOLSETS` `inspect,manage,execute,teardown` Protocol version: `2025-11-25`. ## Tools * [`call_read_tools_batch`](https://libtmux.org/en/java/latest/mcp/tools/call_read_tools_batch/) Calls up to sixteen eligible inspect tools serially; inner tools receive no separate approval, and its nested authority is disclosed. The complete JSON-RPC response is capped at 1,000,000 bytes; a removed nested envelope is marked on its row and counted in truncatedBytes. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`capture_pane`](https://libtmux.org/en/java/latest/mcp/tools/capture_pane/) Returns what a pane shows now, its newest lines first to go when bounded, and a cursor for capture_since. Use it to read a pane once. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`capture_since`](https://libtmux.org/en/java/latest/mcp/tools/capture_since/) Returns only the output a pane produced after a cursor from capture_pane or an earlier capture_since. Use it to follow a pane across turns without rereading it. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`clear_pane_scrollback`](https://libtmux.org/en/java/latest/mcp/tools/clear_pane_scrollback/) Deletes retained scrollback from one pane. Delete tmux state; accepts no command payload. * [`create_session`](https://libtmux.org/en/java/latest/mcp/tools/create_session/) Creates a detached session whose first pane runs the configured process. Start a pane's configured process; accepts no command payload. * [`create_window`](https://libtmux.org/en/java/latest/mcp/tools/create_window/) Creates a window whose first pane runs the configured process. Start a pane's configured process; accepts no command payload. * [`find_pane_by_position`](https://libtmux.org/en/java/latest/mcp/tools/find_pane_by_position/) Finds a pane at one of a window's four corners. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_pane_info`](https://libtmux.org/en/java/latest/mcp/tools/get_pane_info/) Returns metadata for one pane. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_server_info`](https://libtmux.org/en/java/latest/mcp/tools/get_server_info/) Reports whether the pinned server exists and its version. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_session_info`](https://libtmux.org/en/java/latest/mcp/tools/get_session_info/) Returns metadata for one session. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_tmux_variables`](https://libtmux.org/en/java/latest/mcp/tools/get_tmux_variables/) Reads a capped list of validated tmux variable names, not free-form formats. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. * [`get_window_info`](https://libtmux.org/en/java/latest/mcp/tools/get_window_info/) Returns metadata for one window. Inspect tmux metadata; accepts no client-supplied executable input. * [`kill_pane`](https://libtmux.org/en/java/latest/mcp/tools/kill_pane/) Deletes one pane and ends its process. Delete tmux state; accepts no command payload. * [`kill_session`](https://libtmux.org/en/java/latest/mcp/tools/kill_session/) Deletes one session and every window and pane in it. Delete tmux state; accepts no command payload. * [`kill_window`](https://libtmux.org/en/java/latest/mcp/tools/kill_window/) Deletes one window and every pane in it. Delete tmux state; accepts no command payload. * [`list_panes`](https://libtmux.org/en/java/latest/mcp/tools/list_panes/) Lists pane metadata and stable pane IDs. No filter; use the 'command' field to find a pane by what it runs. Inspect tmux metadata; accepts no client-supplied executable input. * [`list_sessions`](https://libtmux.org/en/java/latest/mcp/tools/list_sessions/) Lists sessions on the pinned tmux server. Inspect tmux metadata; accepts no client-supplied executable input. * [`list_windows`](https://libtmux.org/en/java/latest/mcp/tools/list_windows/) Lists windows, optionally only those in one session, named by ID or by name. Inspect tmux metadata; accepts no client-supplied executable input. * [`move_window`](https://libtmux.org/en/java/latest/mcp/tools/move_window/) Moves a window to another session, optionally at an index. Change tmux state; no client-supplied executable input. * [`paste_text`](https://libtmux.org/en/java/latest/mcp/tools/paste_text/) Pastes one literal text block into one target pane through an ephemeral buffer; paste-buffer input does not fan out to synchronized peers. The target cannot be caller or attended. Send input to a pane's program; a shell that receives it runs it with your user's permissions. * [`rename_session`](https://libtmux.org/en/java/latest/mcp/tools/rename_session/) Replaces a session's name. Change tmux state; no client-supplied executable input. * [`rename_window`](https://libtmux.org/en/java/latest/mcp/tools/rename_window/) Replaces a window's name. Change tmux state; no client-supplied executable input. * [`resize_pane`](https://libtmux.org/en/java/latest/mcp/tools/resize_pane/) Sets a pane's width, height or both. Change tmux state; no client-supplied executable input. * [`resize_window`](https://libtmux.org/en/java/latest/mcp/tools/resize_window/) Sets a window's width, height or both. Change tmux state; no client-supplied executable input. * [`respawn_pane`](https://libtmux.org/en/java/latest/mcp/tools/respawn_pane/) Kills the pane's current process and starts its configured process again. Start a pane's configured process; accepts no command payload. * [`run_shell_command`](https://libtmux.org/en/java/latest/mcp/tools/run_shell_command/) Runs one authored command in a trusted pane shell and waits for singular framed output and completion. Its two preflights refuse caller or attended panes and an effective cohort larger than one. Pre-existing exact-client-path, trap, eval, or exit functions are outside the supported boundary; marker display-message commands honor the trusted server's command aliases and hooks. Run a shell command in a pane with your user's permissions. * [`search_panes`](https://libtmux.org/en/java/latest/mcp/tools/search_panes/) Searches the visible output of every pane. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`select_layout`](https://libtmux.org/en/java/latest/mcp/tools/select_layout/) Applies a named tmux layout, a unique abbreviation or a checksummed saved layout. Names follow the running daemon's version; mirrored main layouts require tmux 3.5. Malformed syntax is refused before window lookup; tmux validates geometry. Change tmux state; no client-supplied executable input. * [`select_pane`](https://libtmux.org/en/java/latest/mcp/tools/select_pane/) Makes one pane active. Change tmux state; no client-supplied executable input. * [`select_window`](https://libtmux.org/en/java/latest/mcp/tools/select_window/) Makes one window active. Change tmux state; no client-supplied executable input. * [`send_keys`](https://libtmux.org/en/java/latest/mcp/tools/send_keys/) Sends input to the target's configured effective synchronized cohort without waiting for output. Every configured member must be live, nonmodal, and neither caller nor attended. Reports configured pane ids observed before dispatch, not delivery receipts. wait_for_text discounts recognized input; wait for the prompt before typing into a cold shell. Send input to a pane's program; a shell that receives it runs it with your user's permissions. * [`send_keys_batch`](https://libtmux.org/en/java/latest/mcp/tools/send_keys_batch/) Sends up to sixty-four ordered pane-input operations, resolving and guarding the configured effective cohort separately for each ordered operation. A later policy or dispatch failure retains observed membership. Send input to a pane's program; a shell that receives it runs it with your user's permissions. * [`set_history_limit`](https://libtmux.org/en/java/latest/mcp/tools/set_history_limit/) Sets a bounded integer scrollback limit for future panes in a session. Change tmux state; no client-supplied executable input. * [`set_mouse_enabled`](https://libtmux.org/en/java/latest/mcp/tools/set_mouse_enabled/) Enables or disables tmux mouse handling. Change tmux state; no client-supplied executable input. * [`set_pane_title`](https://libtmux.org/en/java/latest/mcp/tools/set_pane_title/) Replaces a pane's literal title. Change tmux state; no client-supplied executable input. * [`set_synchronize_panes`](https://libtmux.org/en/java/latest/mcp/tools/set_synchronize_panes/) When enabled, sets the inherited window default; pane-level overrides determine each pane's effective synchronized value. Change tmux state; no client-supplied executable input. * [`show_environment`](https://libtmux.org/en/java/latest/mcp/tools/show_environment/) Reads the environment tmux passes to processes. Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. * [`show_hooks`](https://libtmux.org/en/java/latest/mcp/tools/show_hooks/) Reads configured tmux hooks. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. * [`show_option`](https://libtmux.org/en/java/latest/mcp/tools/show_option/) Reads one named tmux option. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. * [`signal_channel`](https://libtmux.org/en/java/latest/mcp/tools/signal_channel/) Signals one server-wide tmux channel. Change tmux state; no client-supplied executable input. * [`snapshot_pane`](https://libtmux.org/en/java/latest/mcp/tools/snapshot_pane/) Returns what a pane shows and its metadata, as list_panes describes a pane, in one call. Use it when both are needed; capture_pane alone reads less. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`split_window`](https://libtmux.org/en/java/latest/mcp/tools/split_window/) Creates a pane whose configured process starts after the split. Start a pane's configured process; accepts no command payload. * [`swap_pane`](https://libtmux.org/en/java/latest/mcp/tools/swap_pane/) Swaps the positions of two panes. Change tmux state; no client-supplied executable input. * [`wait_for_channel`](https://libtmux.org/en/java/latest/mcp/tools/wait_for_channel/) Waits on tmux's channel state with a bounded timeout. Change tmux state; no client-supplied executable input. * [`wait_for_text`](https://libtmux.org/en/java/latest/mcp/tools/wait_for_text/) Waits for new pane output without accepting executable input. Discounts recognized input from this server while pending and for ten seconds after submission. Output identical to that input and partially redrawn echoes are ambiguous; use run_shell_command for commands you start. Wait for the prompt before typing into a cold shell. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. ## Resources * `tmux://capabilities` The startup-frozen effective tool surface and selected tmux socket. ## Resource templates This server does not advertise resource templates in this configuration. ## Prompts This server does not advertise prompts in this configuration. Source revision: [libtmux/libtmux-java@a0ecbc16da00140e2520462d478a2af470878272](https://github.com/libtmux/libtmux-java/tree/a0ecbc16da00140e2520462d478a2af470878272). --- # call_read_tools_batch Source: https://libtmux.org/en/java/latest/mcp/tools/call_read_tools_batch/ > Calls up to sixteen eligible inspect tools serially; inner tools receive no separate approval, and its nested authority is disclosed. The complete JSON-RPC response is capped at 1,000,000 bytes; a removed nested envelope is marked on its row and counted in truncatedBytes. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Calls up to sixteen eligible inspect tools serially; inner tools receive no separate approval, and its nested authority is disclosed. The complete JSON-RPC response is capped at 1,000,000 bytes; a removed nested envelope is marked on its row and counted in truncatedBytes. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/call_read_tools_batch.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L391) ## Arguments * `onError` optional · string stop or continue; defaults to stop. * `operations` required · array Typed calls within the disclosed nested authority. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "onError": { "description": "stop or continue; defaults to stop.", "enum": [ "stop", "continue" ], "type": "string" }, "operations": { "description": "Typed calls within the disclosed nested authority.", "items": { "oneOf": [ { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": {}, "required": [], "type": "object" }, "tool": { "const": "list_sessions", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session_id": { "description": "Only windows in this session, such as $1.", "type": "string" }, "session_name": { "description": "Only windows in the session with this exact name.", "type": "string" } }, "required": [], "type": "object" }, "tool": { "const": "list_windows", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": {}, "required": [], "type": "object" }, "tool": { "const": "list_panes", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": {}, "required": [], "type": "object" }, "tool": { "const": "get_server_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session_id": { "description": "The session ID, such as $1.", "type": "string" } }, "required": [ "session_id" ], "type": "object" }, "tool": { "const": "get_session_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id" ], "type": "object" }, "tool": { "const": "get_window_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" }, "tool": { "const": "get_pane_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "history": { "default": false, "description": "Include scrollback rather than only the visible screen. Defaults to false.", "type": "boolean" }, "max_lines": { "default": 200, "description": "Maximum lines, keeping the newest. Defaults to 200.", "type": "integer" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" }, "tool": { "const": "capture_pane", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "cursor": { "description": "A cursor returned by an earlier capture.", "type": "string" }, "max_lines": { "default": 200, "description": "Maximum new lines, keeping the newest. Defaults to 200.", "type": "integer" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" }, "tool": { "const": "capture_since", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "history": { "default": false, "description": "Include scrollback rather than only the visible screen. Defaults to false.", "type": "boolean" }, "max_lines": { "default": 200, "description": "Maximum lines, keeping the newest. Defaults to 200.", "type": "integer" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" }, "tool": { "const": "snapshot_pane", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "max_lines": { "default": 200, "description": "Maximum matches across all panes. Defaults to 200.", "type": "integer" }, "max_matches_per_pane": { "default": 5, "description": "Maximum matching lines per pane. Defaults to 5.", "type": "integer" }, "pattern": { "description": "The bounded text or regular expression to search for.", "maxLength": 4096, "type": "string" }, "regex": { "default": false, "description": "Treat pattern as a regular expression. Defaults to false.", "type": "boolean" } }, "required": [ "pattern" ], "type": "object" }, "tool": { "const": "search_panes", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "position": { "description": "top-left, top-right, bottom-left or bottom-right.", "type": "string" }, "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id", "position" ], "type": "object" }, "tool": { "const": "find_pane_by_position", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "names": { "description": "One to thirty-two variable names matching [A-Za-z][A-Za-z0-9_]*. One value may be sent on its own, without a list.", "items": { "maxLength": 128, "type": "string" }, "maxItems": 32, "type": [ "array", "string" ] }, "pane": { "description": "An optional pane context.", "type": "string" } }, "required": [ "names" ], "type": "object" }, "tool": { "const": "get_tmux_variables", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "effective": { "default": true, "description": "Include an inherited value. Defaults to true.", "type": "boolean" }, "name": { "description": "The exact option name.", "type": "string" }, "scope": { "description": "global, server, session, window or pane.", "type": "string" }, "target": { "description": "Required for session scope (an ID such as $1, or a name), window scope (@1) and pane scope (%1).", "type": "string" } }, "required": [ "name" ], "type": "object" }, "tool": { "const": "show_option", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session_id": { "description": "A session, such as $1; omit both for the global environment.", "type": "string" }, "session_name": { "description": "A session's exact name, in place of session_id.", "type": "string" } }, "required": [], "type": "object" }, "tool": { "const": "show_environment", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "name": { "description": "One hook name; omit to read all hooks in the scope.", "type": "string" }, "scope": { "description": "global, server, session, window or pane.", "type": "string" }, "target": { "description": "Required for session scope (an ID such as $1, or a name), window scope (@1) and pane scope (%1).", "type": "string" } }, "required": [], "type": "object" }, "tool": { "const": "show_hooks", "type": "string" } }, "required": [ "tool" ], "type": "object" } ] }, "maxItems": 16, "minItems": 1, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "failed": { "type": "integer" }, "onError": { "type": "string" }, "results": { "items": { "additionalProperties": false, "properties": { "error": { "oneOf": [ { "type": "string" }, { "type": "null" } ] }, "index": { "type": "integer" }, "result": { "oneOf": [ { "additionalProperties": false, "properties": { "_meta": { "type": "object" }, "content": { "items": { "type": "object" }, "type": "array" }, "isError": { "type": "boolean" }, "structuredContent": { "type": "object" } }, "required": [ "content", "isError" ], "type": "object" }, { "type": "null" } ] }, "resultTruncated": { "type": "boolean" }, "success": { "type": "boolean" }, "tool": { "type": "string" } }, "required": [ "index", "tool", "success", "error", "result", "resultTruncated" ], "type": "object" }, "type": "array" }, "stoppedAt": { "oneOf": [ { "type": "integer" }, { "type": "null" } ] }, "succeeded": { "type": "integer" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "type": "integer" } }, "required": [ "results", "succeeded", "failed", "stoppedAt", "truncated", "truncatedBytes", "onError" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Call read tools in a batch" } ``` --- # capture_pane Source: https://libtmux.org/en/java/latest/mcp/tools/capture_pane/ > Returns what a pane shows now, its newest lines first to go when bounded, and a cursor for capture_since. Use it to read a pane once. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Returns what a pane shows now, its newest lines first to go when bounded, and a cursor for [capture_since](https://libtmux.org/en/java/latest/mcp/tools/capture_since/). Use it to read a pane once. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/capture_pane.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L134) ## Arguments * `history` optional · boolean Include scrollback rather than only the visible screen. Defaults to false. Default: `false`. * `max_lines` optional · integer Maximum lines, keeping the newest. Defaults to 200. Default: `200`. * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "history": { "default": false, "description": "Include scrollback rather than only the visible screen. Defaults to false.", "type": "boolean" }, "max_lines": { "default": 200, "description": "Maximum lines, keeping the newest. Defaults to 200.", "type": "integer" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "content": { "items": { "type": "string" }, "type": "array" }, "cursor": { "type": "string" }, "lines": { "type": "integer" }, "lines_dropped": { "type": "integer" }, "note": { "type": "string" }, "pane_id": { "type": "string" }, "truncated": { "type": "boolean" } }, "required": [ "pane_id", "lines", "content", "truncated", "lines_dropped", "cursor" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Capture a pane" } ``` --- # capture_since Source: https://libtmux.org/en/java/latest/mcp/tools/capture_since/ > Returns only the output a pane produced after a cursor from capture_pane or an earlier capture_since. Use it to follow a pane across turns without rereading it. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Returns only the output a pane produced after a cursor from [capture_pane](https://libtmux.org/en/java/latest/mcp/tools/capture_pane/) or an earlier capture_since. Use it to follow a pane across turns without rereading it. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/capture_since.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L153) ## Arguments * `cursor` optional · string A cursor returned by an earlier capture. * `max_lines` optional · integer Maximum new lines, keeping the newest. Defaults to 200. Default: `200`. * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "cursor": { "description": "A cursor returned by an earlier capture.", "type": "string" }, "max_lines": { "default": 200, "description": "Maximum new lines, keeping the newest. Defaults to 200.", "type": "integer" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "content": { "items": { "type": "string" }, "type": "array" }, "continuous": { "type": "boolean" }, "cursor": { "type": "string" }, "lines_dropped": { "type": "integer" }, "new_lines": { "type": "integer" }, "note": { "type": "string" }, "pane_id": { "type": "string" }, "truncated": { "type": "boolean" } }, "required": [ "pane_id", "new_lines", "content", "cursor", "continuous", "truncated", "lines_dropped" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Capture new pane output" } ``` --- # clear_pane_scrollback Source: https://libtmux.org/en/java/latest/mcp/tools/clear_pane_scrollback/ > Deletes retained scrollback from one pane. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Deletes retained scrollback from one pane. Delete tmux state; accepts no command payload. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/clear_pane_scrollback.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/TeardownTools.java#L25) ## Arguments * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "cleared": { "type": "boolean" }, "pane_id": { "type": "string" } }, "required": [ "pane_id", "cleared" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Clear pane scrollback" } ``` --- # create_session Source: https://libtmux.org/en/java/latest/mcp/tools/create_session/ > Creates a detached session whose first pane runs the configured process. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Creates a detached session whose first pane runs the configured process. Start a pane’s configured process; accepts no command payload. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/create_session.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ExecuteTools.java#L39) ## Arguments * `height` optional · integer Initial height; supply with width. Defaults to -1. Default: `-1`. * `session_name` optional · string A literal session name. * `start_directory` optional · string An absolute literal start directory. * `width` optional · integer Initial width; supply with height. Defaults to -1. Default: `-1`. * `window_name` optional · string A literal first-window name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "default": -1, "description": "Initial height; supply with width. Defaults to -1.", "type": "integer" }, "session_name": { "description": "A literal session name.", "type": "string" }, "start_directory": { "description": "An absolute literal start directory.", "type": "string" }, "width": { "default": -1, "description": "Initial width; supply with height. Defaults to -1.", "type": "integer" }, "window_name": { "description": "A literal first-window name.", "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "attached": { "type": "boolean" }, "id": { "type": "string" }, "name": { "type": "string" }, "windows": { "type": "integer" } }, "required": [ "id", "name", "attached", "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Create a session" } ``` --- # create_window Source: https://libtmux.org/en/java/latest/mcp/tools/create_window/ > Creates a window whose first pane runs the configured process. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Creates a window whose first pane runs the configured process. Start a pane’s configured process; accepts no command payload. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/create_window.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ExecuteTools.java#L67) ## Arguments * `attach` optional · boolean Make the new window active. Defaults to false. Default: `false`. * `direction` optional · string before or after. * `session_id` required · string The session ID, such as $1. * `start_directory` optional · string An absolute literal start directory. * `window_name` optional · string A literal window name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "attach": { "default": false, "description": "Make the new window active. Defaults to false.", "type": "boolean" }, "direction": { "description": "before or after.", "type": "string" }, "session_id": { "description": "The session ID, such as $1.", "type": "string" }, "start_directory": { "description": "An absolute literal start directory.", "type": "string" }, "window_name": { "description": "A literal window name.", "type": "string" } }, "required": [ "session_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "id": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" }, "panes": { "type": "integer" }, "session_id": { "type": "string" }, "size": { "type": "string" } }, "required": [ "id", "index", "name", "session_id", "active", "panes", "size" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Create a window" } ``` --- # find_pane_by_position Source: https://libtmux.org/en/java/latest/mcp/tools/find_pane_by_position/ > Finds a pane at one of a window's four corners. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Finds a pane at one of a window’s four corners. Inspect tmux metadata; accepts no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/find_pane_by_position.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L219) ## Arguments * `position` required · string top-left, top-right, bottom-left or bottom-right. * `window_id` required · string The window ID, such as @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "position": { "description": "top-left, top-right, bottom-left or bottom-right.", "type": "string" }, "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id", "position" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "command": { "type": "string" }, "id": { "type": "string" }, "index": { "type": "integer" }, "path": { "type": "string" }, "session_id": { "type": "string" }, "size": { "type": "string" }, "title": { "type": "string" }, "window_id": { "type": "string" } }, "required": [ "id", "index", "window_id", "session_id", "active", "command", "path", "title", "size" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Find pane by position" } ``` --- # get_pane_info Source: https://libtmux.org/en/java/latest/mcp/tools/get_pane_info/ > Returns metadata for one pane. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Returns metadata for one pane. Inspect tmux metadata; accepts no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/get_pane_info.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L117) ## Arguments * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "command": { "type": "string" }, "id": { "type": "string" }, "index": { "type": "integer" }, "path": { "type": "string" }, "session_id": { "type": "string" }, "size": { "type": "string" }, "title": { "type": "string" }, "window_id": { "type": "string" } }, "required": [ "id", "index", "window_id", "session_id", "active", "command", "path", "title", "size" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get pane info" } ``` --- # get_server_info Source: https://libtmux.org/en/java/latest/mcp/tools/get_server_info/ > Reports whether the pinned server exists and its version. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Reports whether the pinned server exists and its version. Inspect tmux metadata; accepts no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/get_server_info.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L89) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "identity": { "type": "string" }, "running": { "type": "boolean" }, "sessions": { "type": "integer" }, "version": { "type": "string" } }, "required": [ "running", "identity", "version", "sessions" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get server info" } ``` --- # get_session_info Source: https://libtmux.org/en/java/latest/mcp/tools/get_session_info/ > Returns metadata for one session. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Returns metadata for one session. Inspect tmux metadata; accepts no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/get_session_info.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L101) ## Arguments * `session_id` required · string The session ID, such as $1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session_id": { "description": "The session ID, such as $1.", "type": "string" } }, "required": [ "session_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "attached": { "type": "boolean" }, "id": { "type": "string" }, "name": { "type": "string" }, "windows": { "type": "integer" } }, "required": [ "id", "name", "attached", "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get session info" } ``` --- # get_tmux_variables Source: https://libtmux.org/en/java/latest/mcp/tools/get_tmux_variables/ > Reads a capped list of validated tmux variable names, not free-form formats. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Reads a capped list of validated tmux variable names, not free-form formats. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/get_tmux_variables.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L272) ## Arguments * `names` required · array | string One to thirty-two variable names matching \[A-Za-z]\[A-Za-z0-9\_]\*. One value may be sent on its own, without a list. * `pane` optional · string An optional pane context. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "names": { "description": "One to thirty-two variable names matching [A-Za-z][A-Za-z0-9_]*. One value may be sent on its own, without a list.", "items": { "maxLength": 128, "type": "string" }, "maxItems": 32, "type": [ "array", "string" ] }, "pane": { "description": "An optional pane context.", "type": "string" } }, "required": [ "names" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "values": { "type": "object" } }, "required": [ "values" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get tmux variables" } ``` --- # get_window_info Source: https://libtmux.org/en/java/latest/mcp/tools/get_window_info/ > Returns metadata for one window. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Returns metadata for one window. Inspect tmux metadata; accepts no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/get_window_info.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L109) ## Arguments * `window_id` required · string The window ID, such as @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "id": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" }, "panes": { "type": "integer" }, "session_id": { "type": "string" }, "size": { "type": "string" } }, "required": [ "id", "index", "name", "session_id", "active", "panes", "size" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get window info" } ``` --- # kill_pane Source: https://libtmux.org/en/java/latest/mcp/tools/kill_pane/ > Deletes one pane and ends its process. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Deletes one pane and ends its process. Delete tmux state; accepts no command payload. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/kill_pane.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/TeardownTools.java#L33) ## Arguments * `confirm_self` optional · boolean Permit ending the pane this MCP process runs in. Defaults to false. Default: `false`. * `pane_id` required · string The pane ID, such as %1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "confirm_self": { "default": false, "description": "Permit ending the pane this MCP process runs in. Defaults to false.", "type": "boolean" }, "pane_id": { "description": "The pane ID, such as %1.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "id": { "type": "string" }, "kind": { "type": "string" }, "note": { "type": "string" } }, "required": [ "kind", "id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill a pane" } ``` --- # kill_session Source: https://libtmux.org/en/java/latest/mcp/tools/kill_session/ > Deletes one session and every window and pane in it. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Deletes one session and every window and pane in it. Delete tmux state; accepts no command payload. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/kill_session.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/TeardownTools.java#L52) ## Arguments * `confirm_self` optional · boolean Permit ending the pane this MCP process runs in. Defaults to false. Default: `false`. * `session_id` required · string The session ID, such as $1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "confirm_self": { "default": false, "description": "Permit ending the pane this MCP process runs in. Defaults to false.", "type": "boolean" }, "session_id": { "description": "The session ID, such as $1.", "type": "string" } }, "required": [ "session_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "id": { "type": "string" }, "kind": { "type": "string" }, "note": { "type": "string" } }, "required": [ "kind", "id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill a session" } ``` --- # kill_window Source: https://libtmux.org/en/java/latest/mcp/tools/kill_window/ > Deletes one window and every pane in it. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Deletes one window and every pane in it. Delete tmux state; accepts no command payload. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/kill_window.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/TeardownTools.java#L42) ## Arguments * `confirm_self` optional · boolean Permit ending the pane this MCP process runs in. Defaults to false. Default: `false`. * `window_id` required · string The window ID, such as @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "confirm_self": { "default": false, "description": "Permit ending the pane this MCP process runs in. Defaults to false.", "type": "boolean" }, "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "id": { "type": "string" }, "kind": { "type": "string" }, "note": { "type": "string" } }, "required": [ "kind", "id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill a window" } ``` --- # list_panes Source: https://libtmux.org/en/java/latest/mcp/tools/list_panes/ > Lists pane metadata and stable pane IDs. No filter; use the 'command' field to find a pane by what it runs. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Lists pane metadata and stable pane IDs. No filter; use the ‘command’ field to find a pane by what it runs. Inspect tmux metadata; accepts no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/list_panes.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L69) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "count": { "type": "integer" }, "note": { "type": "string" }, "panes": { "items": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "caller": { "type": "boolean" }, "command": { "type": "string" }, "id": { "type": "string" }, "path": { "type": "string" }, "session": { "type": "string" }, "size": { "type": "string" }, "window": { "type": "string" }, "window_id": { "type": "string" } }, "required": [ "id", "session", "window", "window_id", "command", "path", "size", "active" ], "type": "object" }, "type": "array" } }, "required": [ "count", "panes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List panes" } ``` --- # list_sessions Source: https://libtmux.org/en/java/latest/mcp/tools/list_sessions/ > Lists sessions on the pinned tmux server. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Lists sessions on the pinned tmux server. Inspect tmux metadata; accepts no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/list_sessions.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L39) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "count": { "type": "integer" }, "note": { "type": "string" }, "sessions": { "items": { "additionalProperties": false, "properties": { "attached": { "type": "boolean" }, "id": { "type": "string" }, "name": { "type": "string" }, "window_names": { "items": { "type": "string" }, "type": "array" }, "windows": { "type": "integer" } }, "required": [ "id", "name", "attached", "windows", "window_names" ], "type": "object" }, "type": "array" } }, "required": [ "count", "sessions" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List sessions" } ``` --- # list_windows Source: https://libtmux.org/en/java/latest/mcp/tools/list_windows/ > Lists windows, optionally only those in one session, named by ID or by name. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Lists windows, optionally only those in one session, named by ID or by name. Inspect tmux metadata; accepts no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/list_windows.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L53) ## Arguments * `session_id` optional · string Only windows in this session, such as $1. * `session_name` optional · string Only windows in the session with this exact name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session_id": { "description": "Only windows in this session, such as $1.", "type": "string" }, "session_name": { "description": "Only windows in the session with this exact name.", "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "count": { "type": "integer" }, "note": { "type": "string" }, "windows": { "items": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "id": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" }, "panes": { "type": "integer" }, "session": { "type": "string" } }, "required": [ "id", "index", "name", "session", "active", "panes" ], "type": "object" }, "type": "array" } }, "required": [ "count", "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List windows" } ``` --- # move_window Source: https://libtmux.org/en/java/latest/mcp/tools/move_window/ > Moves a window to another session, optionally at an index. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Moves a window to another session, optionally at an index. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/move_window.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L121) ## Arguments * `index` optional · integer A destination window index; omit for tmux's choice. Defaults to -1. Default: `-1`. * `session_id` required · string The destination session ID, such as $1. * `window_id` required · string The window ID, such as @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "index": { "default": -1, "description": "A destination window index; omit for tmux's choice. Defaults to -1.", "type": "integer" }, "session_id": { "description": "The destination session ID, such as $1.", "type": "string" }, "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id", "session_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "index": { "type": "integer" }, "session_id": { "type": "string" }, "window_id": { "type": "string" } }, "required": [ "window_id", "session_id", "index" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Move a window" } ``` --- # paste_text Source: https://libtmux.org/en/java/latest/mcp/tools/paste_text/ > Pastes one literal text block into one target pane through an ephemeral buffer; paste-buffer input does not fan out to synchronized peers. The target cannot be caller or attended. Send input to a pane's program; a shell that receives it runs it with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Pastes one literal text block into one target pane through an ephemeral buffer; paste-buffer input does not fan out to synchronized peers. The target cannot be caller or attended. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/paste_text.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ExecuteTools.java#L218) ## Arguments * `enter` optional · boolean Append a newline that submits the text. Defaults to false. Default: `false`. * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. * `text` required · string The literal text to paste. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enter": { "default": false, "description": "Append a newline that submits the text. Defaults to false.", "type": "boolean" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" }, "text": { "description": "The literal text to paste.", "type": "string" } }, "required": [ "pane_id", "text" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "characters": { "type": "integer" }, "lines": { "type": "integer" }, "note": { "type": "string" }, "pane_id": { "type": "string" } }, "required": [ "pane_id", "characters", "lines" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Paste text" } ``` --- # rename_session Source: https://libtmux.org/en/java/latest/mcp/tools/rename_session/ > Replaces a session's name. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replaces a session’s name. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/rename_session.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L31) ## Arguments * `new_name` required · string The literal new session name. * `session_id` required · string The session ID, such as $1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "new_name": { "description": "The literal new session name.", "type": "string" }, "session_id": { "description": "The session ID, such as $1.", "type": "string" } }, "required": [ "session_id", "new_name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "attached": { "type": "boolean" }, "id": { "type": "string" }, "name": { "type": "string" }, "windows": { "type": "integer" } }, "required": [ "id", "name", "attached", "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Rename a session" } ``` --- # rename_window Source: https://libtmux.org/en/java/latest/mcp/tools/rename_window/ > Replaces a window's name. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replaces a window’s name. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/rename_window.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L44) ## Arguments * `new_name` required · string The literal new window name. * `window_id` required · string The window ID, such as @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "new_name": { "description": "The literal new window name.", "type": "string" }, "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id", "new_name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "id": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" }, "panes": { "type": "integer" }, "session_id": { "type": "string" }, "size": { "type": "string" } }, "required": [ "id", "index", "name", "session_id", "active", "panes", "size" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Rename a window" } ``` --- # resize_pane Source: https://libtmux.org/en/java/latest/mcp/tools/resize_pane/ > Sets a pane's width, height or both. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Sets a pane’s width, height or both. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/resize_pane.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L106) ## Arguments * `height` optional · integer Height in terminal cells; omit to retain it. Defaults to 0. Default: `0`. * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. * `width` optional · integer Width in terminal cells; omit to retain it. Defaults to 0. Default: `0`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "default": 0, "description": "Height in terminal cells; omit to retain it. Defaults to 0.", "type": "integer" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" }, "width": { "default": 0, "description": "Width in terminal cells; omit to retain it. Defaults to 0.", "type": "integer" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "id": { "type": "string" }, "kind": { "type": "string" }, "note": { "type": "string" }, "what": { "type": "string" } }, "required": [ "kind", "id", "what" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Resize a pane" } ``` --- # resize_window Source: https://libtmux.org/en/java/latest/mcp/tools/resize_window/ > Sets a window's width, height or both. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Sets a window’s width, height or both. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/resize_window.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L91) ## Arguments * `height` optional · integer Height in terminal cells; omit to retain it. Defaults to 0. Default: `0`. * `width` optional · integer Width in terminal cells; omit to retain it. Defaults to 0. Default: `0`. * `window_id` required · string The window ID, such as @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "default": 0, "description": "Height in terminal cells; omit to retain it. Defaults to 0.", "type": "integer" }, "width": { "default": 0, "description": "Width in terminal cells; omit to retain it. Defaults to 0.", "type": "integer" }, "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "id": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" }, "panes": { "type": "integer" }, "session_id": { "type": "string" }, "size": { "type": "string" } }, "required": [ "id", "index", "name", "session_id", "active", "panes", "size" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Resize a window" } ``` --- # respawn_pane Source: https://libtmux.org/en/java/latest/mcp/tools/respawn_pane/ > Kills the pane's current process and starts its configured process again. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Kills the pane’s current process and starts its configured process again. Start a pane’s configured process; accepts no command payload. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/respawn_pane.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ExecuteTools.java#L118) ## Arguments * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. * `start_directory` optional · string An absolute literal start directory. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" }, "start_directory": { "description": "An absolute literal start directory.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "pane_id": { "type": "string" }, "restarted": { "type": "boolean" } }, "required": [ "pane_id", "restarted" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Respawn a pane" } ``` --- # run_shell_command Source: https://libtmux.org/en/java/latest/mcp/tools/run_shell_command/ > Runs one authored command in a trusted pane shell and waits for singular framed output and completion. Its two preflights refuse caller or attended panes and an effective cohort larger than one. Pre-existing exact-client-path, trap, eval, or exit functions are outside the supported boundary; marker display-message commands honor the trusted server's command aliases and hooks. Run a shell command in a pane with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Runs one authored command in a trusted pane shell and waits for singular framed output and completion. Its two preflights refuse caller or attended panes and an effective cohort larger than one. Pre-existing exact-client-path, trap, eval, or exit functions are outside the supported boundary; marker display-message commands honor the trusted server’s command aliases and hooks. Run a shell command in a pane with your user’s permissions. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/run_shell_command.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ExecuteTools.java#L142) ## Arguments * `command` required · string The shell command, run in the pane's interactive shell. * `max_lines` optional · integer Maximum output lines, keeping the newest. Defaults to 200. Default: `200`. * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. * `suppress_history` optional · boolean Best-effort persistent history suppression. Defaults to true. Default: `true`. * `timeout` optional · number Seconds to wait before giving up. Defaults to 30.0. Default: `30`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "command": { "description": "The shell command, run in the pane's interactive shell.", "type": "string" }, "max_lines": { "default": 200, "description": "Maximum output lines, keeping the newest. Defaults to 200.", "type": "integer" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" }, "suppress_history": { "default": true, "description": "Best-effort persistent history suppression. Defaults to true.", "type": "boolean" }, "timeout": { "default": 30, "description": "Seconds to wait before giving up. Defaults to 30.0.", "type": "number" } }, "required": [ "pane_id", "command" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "effective_timeout": { "type": "number" }, "exit_status": { "type": "integer" }, "framed": { "type": "boolean" }, "lines_dropped": { "type": "integer" }, "note": { "type": "string" }, "outcome": { "type": "string" }, "output": { "items": { "type": "string" }, "type": "array" }, "pane_id": { "type": "string" }, "seconds": { "type": "number" }, "truncated": { "type": "boolean" } }, "required": [ "pane_id", "outcome", "output", "truncated", "lines_dropped", "framed", "seconds", "effective_timeout" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Run a shell command" } ``` --- # search_panes Source: https://libtmux.org/en/java/latest/mcp/tools/search_panes/ > Searches the visible output of every pane. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Searches the visible output of every pane. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/search_panes.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L201) ## Arguments * `max_lines` optional · integer Maximum matches across all panes. Defaults to 200. Default: `200`. * `max_matches_per_pane` optional · integer Maximum matching lines per pane. Defaults to 5. Default: `5`. * `pattern` required · string The bounded text or regular expression to search for. * `regex` optional · boolean Treat pattern as a regular expression. Defaults to false. Default: `false`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "max_lines": { "default": 200, "description": "Maximum matches across all panes. Defaults to 200.", "type": "integer" }, "max_matches_per_pane": { "default": 5, "description": "Maximum matching lines per pane. Defaults to 5.", "type": "integer" }, "pattern": { "description": "The bounded text or regular expression to search for.", "maxLength": 4096, "type": "string" }, "regex": { "default": false, "description": "Treat pattern as a regular expression. Defaults to false.", "type": "boolean" } }, "required": [ "pattern" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "bytes_searched": { "type": "integer" }, "count": { "type": "integer" }, "lines_searched": { "type": "integer" }, "matches": { "items": { "additionalProperties": false, "properties": { "line": { "type": "string" }, "pane_id": { "type": "string" }, "session": { "type": "string" }, "window": { "type": "string" } }, "required": [ "pane_id", "session", "window", "line" ], "type": "object" }, "type": "array" }, "note": { "type": "string" }, "panes_searched": { "type": "integer" }, "truncated": { "type": "boolean" }, "work_seconds": { "type": "number" } }, "required": [ "count", "panes_searched", "lines_searched", "bytes_searched", "work_seconds", "truncated", "matches" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Search panes" } ``` --- # select_layout Source: https://libtmux.org/en/java/latest/mcp/tools/select_layout/ > Applies a named tmux layout, a unique abbreviation or a checksummed saved layout. Names follow the running daemon's version; mirrored main layouts require tmux 3.5. Malformed syntax is refused before window lookup; tmux validates geometry. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Applies a named tmux layout, a unique abbreviation or a checksummed saved layout. Names follow the running daemon’s version; mirrored main layouts require tmux 3.5. Malformed syntax is refused before window lookup; tmux validates geometry. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/select_layout.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L75) ## Arguments * `layout` required · string A built-in name, unique abbreviation or saved tmux layout. Existing enum-style names are also accepted. * `window_id` required · string The window ID, such as @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "layout": { "description": "A built-in name, unique abbreviation or saved tmux layout. Existing enum-style names are also accepted.", "type": "string" }, "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id", "layout" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "id": { "type": "string" }, "kind": { "type": "string" }, "note": { "type": "string" }, "what": { "type": "string" } }, "required": [ "kind", "id", "what" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select a layout" } ``` --- # select_pane Source: https://libtmux.org/en/java/latest/mcp/tools/select_pane/ > Makes one pane active. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Makes one pane active. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/select_pane.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L66) ## Arguments * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "command": { "type": "string" }, "id": { "type": "string" }, "index": { "type": "integer" }, "path": { "type": "string" }, "session_id": { "type": "string" }, "size": { "type": "string" }, "title": { "type": "string" }, "window_id": { "type": "string" } }, "required": [ "id", "index", "window_id", "session_id", "active", "command", "path", "title", "size" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select a pane" } ``` --- # select_window Source: https://libtmux.org/en/java/latest/mcp/tools/select_window/ > Makes one window active. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Makes one window active. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/select_window.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L57) ## Arguments * `window_id` required · string The window ID, such as @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "id": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" }, "panes": { "type": "integer" }, "session_id": { "type": "string" }, "size": { "type": "string" } }, "required": [ "id", "index", "name", "session_id", "active", "panes", "size" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select a window" } ``` --- # send_keys Source: https://libtmux.org/en/java/latest/mcp/tools/send_keys/ > Sends input to the target's configured effective synchronized cohort without waiting for output. Every configured member must be live, nonmodal, and neither caller nor attended. Reports configured pane ids observed before dispatch, not delivery receipts. wait_for_text discounts recognized input; wait for the prompt before typing into a cold shell. Send input to a pane's program; a shell that receives it runs it with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Sends input to the target’s configured effective synchronized cohort without waiting for output. Every configured member must be live, nonmodal, and neither caller nor attended. Reports configured pane ids observed before dispatch, not delivery receipts. [wait_for_text](https://libtmux.org/en/java/latest/mcp/tools/wait_for_text/) discounts recognized input; wait for the prompt before typing into a cold shell. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/send_keys.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ExecuteTools.java#L176) ## Arguments * `enter` optional · boolean Press Enter afterward, as a real keypress. Unlike a key named "Enter" sent under literal:true, which types the four letters, this always submits. Defaults to false. Default: `false`. * `keys` optional · array | string The key names or literal strings to send. One value may be sent on its own, without a list. * `literal` optional · boolean Send strings literally instead of as key names. Defaults to false. Default: `false`. * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enter": { "default": false, "description": "Press Enter afterward, as a real keypress. Unlike a key named \"Enter\" sent under literal:true, which types the four letters, this always submits. Defaults to false.", "type": "boolean" }, "keys": { "description": "The key names or literal strings to send. One value may be sent on its own, without a list.", "items": { "type": "string" }, "type": [ "array", "string" ] }, "literal": { "default": false, "description": "Send strings literally instead of as key names. Defaults to false.", "type": "boolean" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "keys": { "type": "integer" }, "literal": { "type": "boolean" }, "note": { "type": "string" }, "pane_id": { "type": "string" }, "resolved_pane_ids": { "items": { "type": "string" }, "type": "array" } }, "required": [ "pane_id", "keys", "literal", "resolved_pane_ids" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Send keys" } ``` --- # send_keys_batch Source: https://libtmux.org/en/java/latest/mcp/tools/send_keys_batch/ > Sends up to sixty-four ordered pane-input operations, resolving and guarding the configured effective cohort separately for each ordered operation. A later policy or dispatch failure retains observed membership. Send input to a pane's program; a shell that receives it runs it with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Sends up to sixty-four ordered pane-input operations, resolving and guarding the configured effective cohort separately for each ordered operation. A later policy or dispatch failure retains observed membership. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/send_keys_batch.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ExecuteTools.java#L197) ## Arguments * `onError` optional · string stop or continue; defaults to stop. * `operations` required · array Objects with pane_id, keys and optional literal and enter fields. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "onError": { "description": "stop or continue; defaults to stop.", "type": "string" }, "operations": { "description": "Objects with pane_id, keys and optional literal and enter fields.", "items": { "type": "object" }, "maxItems": 64, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "completed": { "type": "integer" }, "results": { "items": { "additionalProperties": false, "properties": { "error": { "type": "string" }, "error_code": { "type": "string" }, "index": { "type": "integer" }, "pane_id": { "type": "string" }, "resolved_pane_ids": { "items": { "type": "string" }, "type": "array" }, "retryable": { "type": "boolean" }, "success": { "type": "boolean" } }, "required": [ "index", "pane_id", "resolved_pane_ids", "success" ], "type": "object" }, "type": "array" } }, "required": [ "results", "completed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Send keys in a batch" } ``` --- # set_history_limit Source: https://libtmux.org/en/java/latest/mcp/tools/set_history_limit/ > Sets a bounded integer scrollback limit for future panes in a session. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Sets a bounded integer scrollback limit for future panes in a session. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/set_history_limit.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L198) ## Arguments * `lines` required · integer The nonnegative retained line count. * `session_id` required · string The session ID, such as $1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "lines": { "description": "The nonnegative retained line count.", "type": "integer" }, "session_id": { "description": "The session ID, such as $1.", "type": "string" } }, "required": [ "session_id", "lines" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "lines": { "type": "integer" }, "session_id": { "type": "string" } }, "required": [ "session_id", "lines" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set history limit" } ``` --- # set_mouse_enabled Source: https://libtmux.org/en/java/latest/mcp/tools/set_mouse_enabled/ > Enables or disables tmux mouse handling. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Enables or disables tmux mouse handling. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/set_mouse_enabled.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L189) ## Arguments * `enabled` optional · boolean Whether mouse handling is enabled. Defaults to false. Default: `false`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enabled": { "default": false, "description": "Whether mouse handling is enabled. Defaults to false.", "type": "boolean" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "enabled": { "type": "boolean" } }, "required": [ "enabled" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set mouse handling" } ``` --- # set_pane_title Source: https://libtmux.org/en/java/latest/mcp/tools/set_pane_title/ > Replaces a pane's literal title. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replaces a pane’s literal title. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/set_pane_title.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L148) ## Arguments * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. * `title` required · string The literal title. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" }, "title": { "description": "The literal title.", "type": "string" } }, "required": [ "pane_id", "title" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "command": { "type": "string" }, "id": { "type": "string" }, "index": { "type": "integer" }, "path": { "type": "string" }, "session_id": { "type": "string" }, "size": { "type": "string" }, "title": { "type": "string" }, "window_id": { "type": "string" } }, "required": [ "id", "index", "window_id", "session_id", "active", "command", "path", "title", "size" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set pane title" } ``` --- # set_synchronize_panes Source: https://libtmux.org/en/java/latest/mcp/tools/set_synchronize_panes/ > When enabled, sets the inherited window default; pane-level overrides determine each pane's effective synchronized value. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. When enabled, sets the inherited window default; pane-level overrides determine each pane’s effective synchronized value. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/set_synchronize_panes.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ExecuteTools.java#L239) ## Arguments * `enabled` optional · boolean Whether pane input is synchronized. Defaults to false. Default: `false`. * `window_id` required · string The window ID, such as @1. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enabled": { "default": false, "description": "Whether pane input is synchronized. Defaults to false.", "type": "boolean" }, "window_id": { "description": "The window ID, such as @1.", "type": "string" } }, "required": [ "window_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "enabled": { "type": "boolean" }, "window_id": { "type": "string" } }, "required": [ "window_id", "enabled" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set synchronized panes" } ``` --- # show_environment Source: https://libtmux.org/en/java/latest/mcp/tools/show_environment/ > Reads the environment tmux passes to processes. Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Reads the environment tmux passes to processes. Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/show_environment.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L328) ## Arguments * `session_id` optional · string A session, such as $1; omit both for the global environment. * `session_name` optional · string A session's exact name, in place of session_id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session_id": { "description": "A session, such as $1; omit both for the global environment.", "type": "string" }, "session_name": { "description": "A session's exact name, in place of session_id.", "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "count": { "type": "integer" }, "session": { "type": "string" }, "unset": { "items": { "type": "string" }, "type": "array" }, "variables": { "additionalProperties": { "type": "string" }, "type": "object" } }, "required": [ "session", "count", "variables", "unset" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show tmux environment" } ``` --- # show_hooks Source: https://libtmux.org/en/java/latest/mcp/tools/show_hooks/ > Reads configured tmux hooks. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Reads configured tmux hooks. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/show_hooks.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L352) ## Arguments * `name` optional · string One hook name; omit to read all hooks in the scope. * `scope` optional · string global, server, session, window or pane. * `target` optional · string Required for session scope (an ID such as $1, or a name), window scope (@1) and pane scope (%1). ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "One hook name; omit to read all hooks in the scope.", "type": "string" }, "scope": { "description": "global, server, session, window or pane.", "type": "string" }, "target": { "description": "Required for session scope (an ID such as $1, or a name), window scope (@1) and pane scope (%1).", "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "count": { "type": "integer" }, "hooks": { "type": "object" }, "scope": { "type": "string" }, "target": { "type": "string" } }, "required": [ "scope", "target", "count", "hooks" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show hooks" } ``` --- # show_option Source: https://libtmux.org/en/java/latest/mcp/tools/show_option/ > Reads one named tmux option. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Reads one named tmux option. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/show_option.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L306) ## Arguments * `effective` optional · boolean Include an inherited value. Defaults to true. Default: `true`. * `name` required · string The exact option name. * `scope` optional · string global, server, session, window or pane. * `target` optional · string Required for session scope (an ID such as $1, or a name), window scope (@1) and pane scope (%1). ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "effective": { "default": true, "description": "Include an inherited value. Defaults to true.", "type": "boolean" }, "name": { "description": "The exact option name.", "type": "string" }, "scope": { "description": "global, server, session, window or pane.", "type": "string" }, "target": { "description": "Required for session scope (an ID such as $1, or a name), window scope (@1) and pane scope (%1).", "type": "string" } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "name": { "type": "string" }, "scope": { "type": "string" }, "target": { "type": "string" }, "value": { "type": "string" } }, "required": [ "scope", "target", "name", "value" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show one option" } ``` --- # signal_channel Source: https://libtmux.org/en/java/latest/mcp/tools/signal_channel/ > Signals one server-wide tmux channel. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Signals one server-wide tmux channel. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/signal_channel.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L180) ## Arguments * `channel` required · string The channel name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "The channel name.", "type": "string" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "channel": { "type": "string" }, "note": { "type": "string" } }, "required": [ "channel", "note" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Signal a channel" } ``` --- # snapshot_pane Source: https://libtmux.org/en/java/latest/mcp/tools/snapshot_pane/ > Returns what a pane shows and its metadata, as list_panes describes a pane, in one call. Use it when both are needed; capture_pane alone reads less. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Returns what a pane shows and its metadata, as [list_panes](https://libtmux.org/en/java/latest/mcp/tools/list_panes/) describes a pane, in one call. Use it when both are needed; [capture_pane](https://libtmux.org/en/java/latest/mcp/tools/capture_pane/) alone reads less. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/snapshot_pane.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L171) ## Arguments * `history` optional · boolean Include scrollback rather than only the visible screen. Defaults to false. Default: `false`. * `max_lines` optional · integer Maximum lines, keeping the newest. Defaults to 200. Default: `200`. * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "history": { "default": false, "description": "Include scrollback rather than only the visible screen. Defaults to false.", "type": "boolean" }, "max_lines": { "default": 200, "description": "Maximum lines, keeping the newest. Defaults to 200.", "type": "integer" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "content": { "items": { "type": "string" }, "type": "array" }, "cursor": { "type": "string" }, "lines_dropped": { "type": "integer" }, "pane": { "type": "object" }, "truncated": { "type": "boolean" } }, "required": [ "pane", "content", "cursor", "truncated", "lines_dropped" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Snapshot a pane" } ``` --- # split_window Source: https://libtmux.org/en/java/latest/mcp/tools/split_window/ > Creates a pane whose configured process starts after the split. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Creates a pane whose configured process starts after the split. Start a pane’s configured process; accepts no command payload. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/split_window.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ExecuteTools.java#L94) ## Arguments * `direction` optional · string below, above, left or right. * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. * `percent` optional · integer Share of the split occupied by the new pane. Defaults to 50. Default: `50`. * `start_directory` optional · string An absolute literal start directory. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "direction": { "description": "below, above, left or right.", "type": "string" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" }, "percent": { "default": 50, "description": "Share of the split occupied by the new pane. Defaults to 50.", "type": "integer" }, "start_directory": { "description": "An absolute literal start directory.", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "command": { "type": "string" }, "id": { "type": "string" }, "index": { "type": "integer" }, "path": { "type": "string" }, "session_id": { "type": "string" }, "size": { "type": "string" }, "title": { "type": "string" }, "window_id": { "type": "string" } }, "required": [ "id", "index", "window_id", "session_id", "active", "command", "path", "title", "size" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Split a window" } ``` --- # swap_pane Source: https://libtmux.org/en/java/latest/mcp/tools/swap_pane/ > Swaps the positions of two panes. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Swaps the positions of two panes. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/swap_pane.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L139) ## Arguments * `other_pane_id` required · string The other pane ID, such as %2. * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "other_pane_id": { "description": "The other pane ID, such as %2.", "type": "string" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" } }, "required": [ "pane_id", "other_pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "other_pane_id": { "type": "string" }, "pane_id": { "type": "string" } }, "required": [ "pane_id", "other_pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Swap panes" } ``` --- # wait_for_channel Source: https://libtmux.org/en/java/latest/mcp/tools/wait_for_channel/ > Waits on tmux's channel state with a bounded timeout. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Waits on tmux’s channel state with a bounded timeout. Change tmux state; no client-supplied executable input. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/wait_for_channel.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/ManageTools.java#L163) ## Arguments * `channel` required · string A server-wide tmux channel name. * `drain_first` optional · boolean Consume a pending signal before waiting. Defaults to false. Default: `false`. * `timeout` optional · number Seconds to wait before giving up. Defaults to 30.0. Default: `30`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "A server-wide tmux channel name.", "type": "string" }, "drain_first": { "default": false, "description": "Consume a pending signal before waiting. Defaults to false.", "type": "boolean" }, "timeout": { "default": 30, "description": "Seconds to wait before giving up. Defaults to 30.0.", "type": "number" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "channel": { "type": "string" }, "effective_timeout": { "type": "number" }, "note": { "type": "string" }, "outcome": { "type": "string" }, "seconds": { "type": "number" } }, "required": [ "channel", "outcome", "seconds", "effective_timeout" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Wait for a channel" } ``` --- # wait_for_text Source: https://libtmux.org/en/java/latest/mcp/tools/wait_for_text/ > Waits for new pane output without accepting executable input. Discounts recognized input from this server while pending and for ten seconds after submission. Output identical to that input and partially redrawn echoes are ambiguous; use run_shell_command for commands you start. Wait for the prompt before typing into a cold shell. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Waits for new pane output without accepting executable input. Discounts recognized input from this server while pending and for ten seconds after submission. Output identical to that input and partially redrawn echoes are ambiguous; use [run_shell_command](https://libtmux.org/en/java/latest/mcp/tools/run_shell_command/) for commands you start. Wait for the prompt before typing into a cold shell. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All Java tools](https://libtmux.org/en/java/latest/mcp/tools/) · [JSON](https://libtmux.org/en/java/latest/mcp/tools/wait_for_text.json) · [Source](https://github.com/libtmux/libtmux-java/blob/a0ecbc16da00140e2520462d478a2af470878272/libtmux-mcp/src/main/java/io/github/libtmux/mcp/InspectTools.java#L246) ## Arguments * `cursor` optional · string A cursor returned by an earlier capture. * `max_lines` optional · integer Maximum observed lines to return. Defaults to 200. Default: `200`. * `pane_id` required · string The pane to act on, such as %1. Every listing tool returns these. * `patterns` optional · array | string Text to wait for; any one ends the wait. One value may be sent on its own, without a list. * `regex` optional · boolean Treat patterns and stops as regular expressions. Defaults to false. Default: `false`. * `stop` optional · array | string Failure text; any one ends the wait. One value may be sent on its own, without a list. * `timeout` optional · number Seconds to wait before giving up. Defaults to 30.0. Default: `30`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "cursor": { "description": "A cursor returned by an earlier capture.", "type": "string" }, "max_lines": { "default": 200, "description": "Maximum observed lines to return. Defaults to 200.", "type": "integer" }, "pane_id": { "description": "The pane to act on, such as %1. Every listing tool returns these.", "type": "string" }, "patterns": { "description": "Text to wait for; any one ends the wait. One value may be sent on its own, without a list.", "items": { "maxLength": 4096, "type": "string" }, "maxItems": 32, "type": [ "array", "string" ] }, "regex": { "default": false, "description": "Treat patterns and stops as regular expressions. Defaults to false.", "type": "boolean" }, "stop": { "description": "Failure text; any one ends the wait. One value may be sent on its own, without a list.", "items": { "maxLength": 4096, "type": "string" }, "maxItems": 32, "type": [ "array", "string" ] }, "timeout": { "default": 30, "description": "Seconds to wait before giving up. Defaults to 30.0.", "type": "number" } }, "required": [ "pane_id" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "cursor": { "type": "string" }, "effective_timeout": { "type": "number" }, "lines_dropped": { "type": "integer" }, "matched": { "type": "string" }, "matched_line": { "type": "string" }, "note": { "type": "string" }, "outcome": { "type": "string" }, "output": { "items": { "type": "string" }, "type": "array" }, "pane_id": { "type": "string" }, "seconds": { "type": "number" }, "truncated": { "type": "boolean" } }, "required": [ "pane_id", "outcome", "output", "truncated", "lines_dropped", "cursor", "seconds", "effective_timeout" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Wait for pane text" } ``` --- # C# MCP tools Source: https://libtmux.org/en/csharp/latest/mcp/tools/ > Tools, resources, and prompts advertised by the C# MCP server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Use the wire name shown here when calling a tool. The C# server advertises 45 tools with the reference configuration below. Your client’s list follows the policy configured for its server. Read the [setup guide](https://libtmux.org/en/csharp/latest/mcp/guides/) before choosing tool access. The [language API reference](https://libtmux.org/en/csharp/latest/mcp/reference/) covers embedding and implementation types. [Download the protocol catalog as JSON](https://libtmux.org/en/csharp/latest/mcp/tools.json). Reference configuration * `LIBTMUX_TOOLSETS` `inspect,manage,execute,teardown` Protocol version: `2025-11-25`. ## Tools * [`call_read_tools_batch`](https://libtmux.org/en/csharp/latest/mcp/tools/call_read_tools_batch/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Execute up to 16 declared inspect operations serially; inner operations receive no separate approval. * [`capture_pane`](https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read the text a pane is showing, and optionally its scrollback. The newest lines are always kept; anything dropped to fit the budget is reported. To watch a pane across several turns, use capture_since instead — it returns only what is new. * [`capture_since`](https://libtmux.org/en/csharp/latest/mcp/tools/capture_since/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read only what a pane has printed since the last call. Pass back the cursor each time. Use this to watch a long-running process across turns: the tenth read costs what the first did, where re-capturing the pane would return everything again. Call with no cursor to start watching from now. * [`clear_pane_scrollback`](https://libtmux.org/en/csharp/latest/mcp/tools/clear_pane_scrollback/) Delete tmux state; accepts no command payload. Delete a pane's scrollback history, keeping what the screen shows. Deleted history cannot be read back. * [`create_session`](https://libtmux.org/en/csharp/latest/mcp/tools/create_session/) Start a pane's configured process; accepts no command payload. Create a detached tmux session and return its ids. Give a width and height when nothing will attach to it: a session with no client keeps tmux's default 80x24, which truncates wide output. * [`create_window`](https://libtmux.org/en/csharp/latest/mcp/tools/create_window/) Start a pane's configured process; accepts no command payload. Create a window in a tmux session and return its ids. * [`find_pane_by_position`](https://libtmux.org/en/csharp/latest/mcp/tools/find_pane_by_position/) Inspect tmux metadata; accepts no client-supplied executable input. Find the pane sitting at an index within a window. Answers nothing rather than failing when no pane is at that position. * [`get_pane_info`](https://libtmux.org/en/csharp/latest/mcp/tools/get_pane_info/) Inspect tmux metadata; accepts no client-supplied executable input. Read one pane's size, title, running command, working directory, process ID, history size and limit, and whether it is active, dead, zoomed, in a mode or the pane this server runs in. This is metadata only; to read what the pane shows, use capture_pane or snapshot_pane. * [`get_server_info`](https://libtmux.org/en/csharp/latest/mcp/tools/get_server_info/) Inspect tmux metadata; accepts no client-supplied executable input. Read the tmux server's version and how many sessions, windows and panes it holds. Use to confirm a socket is alive and which tmux is running it. * [`get_session_info`](https://libtmux.org/en/csharp/latest/mcp/tools/get_session_info/) Inspect tmux metadata; accepts no client-supplied executable input. Read one session's name, ID, window count and whether a client is attached, without listing every session. Give the session, or a window ID to read the session that holds it. * [`get_tmux_variables`](https://libtmux.org/en/csharp/latest/mcp/tools/get_tmux_variables/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Expand named tmux format variables for a pane, such as session_name or window_width. Use it for fields nothing else answers; get_pane_info already returns the common ones, and show_option reads configuration rather than live state. * [`get_window_info`](https://libtmux.org/en/csharp/latest/mcp/tools/get_window_info/) Inspect tmux metadata; accepts no client-supplied executable input. Read one window's name, index, size, layout, pane count and whether it is its session's current window, without listing every window. Give the window ID, or a pane ID to read the window that holds it. * [`kill_pane`](https://libtmux.org/en/csharp/latest/mcp/tools/kill_pane/) Delete tmux state; accepts no command payload. Close a pane and end its program. Refuses the pane this server runs in; to remove a whole window, use kill_window. * [`kill_session`](https://libtmux.org/en/csharp/latest/mcp/tools/kill_session/) Delete tmux state; accepts no command payload. Close a session with all its windows and panes. Refuses the session this server runs in. * [`kill_window`](https://libtmux.org/en/csharp/latest/mcp/tools/kill_window/) Delete tmux state; accepts no command payload. Close a window and every pane in it. Refuses the window this server runs in. * [`list_panes`](https://libtmux.org/en/csharp/latest/mcp/tools/list_panes/) Inspect tmux metadata; accepts no client-supplied executable input. List tmux panes, optionally within one session or window. Filter for isCaller=true to answer 'which pane am I in?', which finds one only when this server drives the caller's own socket — get_server_info says whose socket that is. This reads sizes and running commands, not terminal text — for that use search_panes. * [`list_sessions`](https://libtmux.org/en/csharp/latest/mcp/tools/list_sessions/) Inspect tmux metadata; accepts no client-supplied executable input. List the tmux sessions. This reads names and sizes, not terminal text — to find what a pane is showing, use search_panes. * [`list_windows`](https://libtmux.org/en/csharp/latest/mcp/tools/list_windows/) Inspect tmux metadata; accepts no client-supplied executable input. List tmux windows, optionally within one session. This reads names and layouts, not terminal text — to find what a pane is showing, use search_panes. * [`move_window`](https://libtmux.org/en/csharp/latest/mcp/tools/move_window/) Change tmux state; no client-supplied executable input. Move a window to another index, or into another session. With replaceExisting it takes an index that is already occupied by killing the window there, which needs the teardown toolset. * [`paste_text`](https://libtmux.org/en/csharp/latest/mcp/tools/paste_text/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Paste a block of text into exactly one pane through a tmux buffer. Use for multi-line text, or anything an editor would mangle if typed — bracketed paste stops auto-indent. Set enter to append a newline to that same private buffer. It refuses a target in a human-owned mode and never fans out to synchronized siblings. The temporary buffer is deleted afterwards; if cleanup fails, the result identifies what remains. * [`rename_session`](https://libtmux.org/en/csharp/latest/mcp/tools/rename_session/) Change tmux state; no client-supplied executable input. Rename a tmux session. Its id does not change, so anything holding one still works. * [`rename_window`](https://libtmux.org/en/csharp/latest/mcp/tools/rename_window/) Change tmux state; no client-supplied executable input. Rename a tmux window. Its id does not change. * [`resize_pane`](https://libtmux.org/en/csharp/latest/mcp/tools/resize_pane/) Change tmux state; no client-supplied executable input. Resize a pane, or zoom it to fill its window. Widening a pane before reading it is the fix for output that comes back wrapped across rows. * [`resize_window`](https://libtmux.org/en/csharp/latest/mcp/tools/resize_window/) Change tmux state; no client-supplied executable input. Resize a window to a width and height in cells; its panes resize with it. To resize one pane, use resize_pane. * [`respawn_pane`](https://libtmux.org/en/csharp/latest/mcp/tools/respawn_pane/) Start a pane's configured process; accepts no command payload. Only restarts a pane whose command has ALREADY EXITED. killExistingProcess overrides that and kills what is running first — an editor holding unsaved changes, a build part way through. It reruns the command the pane was created with rather than running something new. * [`run_shell_command`](https://libtmux.org/en/csharp/latest/mcp/tools/run_shell_command/) Run a shell command in a pane with your user's permissions. Run a shell command in one pane, wait for it to finish, and report its singular real exit status and output. This is the tool for 'run X and tell me if it worked'. It reaches only the pane you name: the command travels through a tmux buffer, which synchronize-panes does not fan out, so the exit status is one pane's. Use send_keys when you want a synchronized cohort to receive input. Do NOT send keys and then poll a capture in a loop — this waits deterministically and costs one call. The command runs in a subshell, so cd and export do not persist. It refuses the named pane in a human-owned mode. Check linesMissed and anchorLost. A timed-out command MAY STILL BE RUNNING; inspect it and do not retry it — unless started is false, which means it never ran because something other than an idle shell was reading that pane's input. * [`search_panes`](https://libtmux.org/en/csharp/latest/mcp/tools/search_panes/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Find which panes are showing text matching a regular expression. This is the tool for 'which pane has the error', 'where is the build running', or any question about what a pane CONTAINS — the list tools only see names and sizes. * [`select_layout`](https://libtmux.org/en/csharp/latest/mcp/tools/select_layout/) Change tmux state; no client-supplied executable input. Arrange a window's panes with a named layout — even-horizontal, even-vertical, main-horizontal, main-vertical, tiled — or a layout string read from list_windows. * [`select_pane`](https://libtmux.org/en/csharp/latest/mcp/tools/select_pane/) Change tmux state; no client-supplied executable input. Make a pane the active one in its window. This changes what a watching human sees; targeting a pane by id does not require selecting it first. * [`select_window`](https://libtmux.org/en/csharp/latest/mcp/tools/select_window/) Change tmux state; no client-supplied executable input. Make a window the current one in its session. * [`send_keys`](https://libtmux.org/en/csharp/latest/mcp/tools/send_keys/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send raw keystrokes to a pane and return immediately. Use for driving an interactive program — a key in vim, a menu choice, Ctrl-C. Set literal=false to send named keys such as C-c, Escape or F5. It refuses the named pane in a human-owned mode and, when source input expands, every synchronized input cohort peer. To run a shell command and learn whether it worked, use run_shell_command instead; this reports nothing about what happens next. Tracks what it sends — including edits such as backspace, Ctrl-U or Ctrl-C — so wait_for_text can tell this pane's echo apart from real output for a short time afterward. * [`send_keys_batch`](https://libtmux.org/en/csharp/latest/mcp/tools/send_keys_batch/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send several keystrokes to one pane in order, in a single call. Use for a short interactive sequence — open a file, move, type, save — instead of one call per key. Each operation refuses the named pane in a human-owned mode and, when source input expands, every synchronized input cohort peer. A batch has at most 64 steps and 64 KiB of UTF-8 text. Each delay is 0-2000 ms and all delays together must fit the server wait ceiling. * [`set_history_limit`](https://libtmux.org/en/csharp/latest/mcp/tools/set_history_limit/) Change tmux state; no client-supplied executable input. Set how many scrollback lines tmux keeps. This is a SESSION option, so it covers every window in the session rather than one pane, and the session must be named because the call can destroy data. Raise it before starting something that prints a lot: no capture can return lines tmux has already discarded. LOWERING it discards the excess from every pane immediately, and the result says how many lines went; raising the limit again does not bring them back. * [`set_mouse_enabled`](https://libtmux.org/en/csharp/latest/mcp/tools/set_mouse_enabled/) Change tmux state; no client-supplied executable input. Turn tmux mouse support on or off. This sets the global option, so it applies to every session on this server and changes what a human watching can do with their mouse. * [`set_pane_title`](https://libtmux.org/en/csharp/latest/mcp/tools/set_pane_title/) Change tmux state; no client-supplied executable input. Set a pane's title. Useful for labelling panes you created so a human watching can tell which is which. * [`set_synchronize_panes`](https://libtmux.org/en/csharp/latest/mcp/tools/set_synchronize_panes/) Change tmux state; no client-supplied executable input. Turn synchronize-panes on or off for a window. Input typed into one of its panes then reaches the synchronized input cohort: every pane whose effective synchronize-panes setting is on. A pane without a setting of its own follows the window; one with its own setting stays included or excluded either way. * [`show_environment`](https://libtmux.org/en/csharp/latest/mcp/tools/show_environment/) Read the tmux environment; accepts no client-supplied executable input. A listing answers names without values, and a named variable is still withheld when the name reads as a credential. Read what a NEW pane will inherit, at the server or session level — not what an already-running shell has. * [`show_hooks`](https://libtmux.org/en/csharp/latest/mcp/tools/show_hooks/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read the hooks tmux will run on its own events. Read-only on purpose: a hook written here would outlive this conversation and keep firing with nobody left who knows why. Put hooks you want to keep in your tmux config file. * [`show_option`](https://libtmux.org/en/csharp/latest/mcp/tools/show_option/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read tmux options at the server, session, window or pane level. Values set at a wider scope are included and marked inherited, because that is where nearly all tmux configuration lives. Omit the name to list them all. Reading history-limit before a long tail tells you how much output the pane can hold before it starts dropping lines. * [`signal_channel`](https://libtmux.org/en/csharp/latest/mcp/tools/signal_channel/) Change tmux state; no client-supplied executable input. Signal a tmux wait-for channel, releasing whatever waits on it. The channel latches: signalling before anyone waits still satisfies the next wait, so a handoff cannot be lost to a race. * [`snapshot_pane`](https://libtmux.org/en/csharp/latest/mcp/tools/snapshot_pane/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read a pane's visible content together with its cursor position, size and running command, in one call. Prefer this over capture_pane plus list_panes: it is one round trip and the cursor is guaranteed to describe the text returned with it. * [`split_window`](https://libtmux.org/en/csharp/latest/mcp/tools/split_window/) Start a pane's configured process; accepts no command payload. Split a pane and return the NEW pane's id. Use that id for what you put in it — pane ids stay valid across layout changes, where window names and indexes do not. * [`swap_pane`](https://libtmux.org/en/csharp/latest/mcp/tools/swap_pane/) Change tmux state; no client-supplied executable input. Swap two panes' positions; each keeps its program, its content and its ID. * [`wait_for_channel`](https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_channel/) Change tmux state; no client-supplied executable input. Block until something signals a tmux wait-for channel with 'tmux wait-for -S \'. Use when you composed a shell command that signals it. For an ordinary command whose completion you want, run_shell_command already does this and also reports the exit status. * [`wait_for_text`](https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_text/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Wait until a pane prints something matching one of these patterns, then return. Use for output you did NOT start — a server's ready line, another process's progress, a person typing. A matching pattern already on screen returns PresentAtEntry. For a command you are running yourself, run_shell_command is better: it reports the real exit status instead of guessing from text. Never poll capture_pane in a loop; this call does the waiting. Control observation is required by default; pollingFallback reports activation when the operator permits fallback. Text this server itself typed is discounted while deciding what is new, for a few seconds after it is sent or submitted, so its own echo cannot be the match — except on a pane whose program has not yet configured its terminal; wait for a first prompt before typing into a freshly created pane. ## Resources * `tmux://capabilities` The startup-frozen tmux connection and effective MCP tool capabilities. ## Resource templates This server does not advertise resource templates in this configuration. ## Prompts This server does not advertise prompts in this configuration. Source revision: [libtmux/libtmux-dotnet@ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc](https://github.com/libtmux/libtmux-dotnet/tree/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc). --- # call_read_tools_batch Source: https://libtmux.org/en/csharp/latest/mcp/tools/call_read_tools_batch/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Execute up to 16 declared inspect operations serially; inner operations receive no separate approval. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Execute up to 16 declared inspect operations serially; inner operations receive no separate approval. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/call_read_tools_batch.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L586) ## Arguments * `onError` optional · string Stop after the first failed operation, or continue serially. Default: `"stop"`. * `operations` required · array Between 1 and 16 declared inspect calls, executed serially without separate approval for each inner operation. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "onError": { "default": "stop", "description": "Stop after the first failed operation, or continue serially.", "enum": [ "continue", "stop" ], "type": "string" }, "operations": { "description": "Between 1 and 16 declared inspect calls, executed serially without separate approval for each inner operation.", "items": { "oneOf": [ { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "includeHistory": { "default": false, "description": "Include scrollback.", "type": "boolean" }, "joinWrappedLines": { "default": false, "description": "Rejoin tmux-wrapped lines.", "type": "boolean" }, "maxLines": { "default": null, "description": "Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] } }, "type": "object" }, "tool": { "const": "capture_pane" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "cursor": { "default": null, "description": "The opaque cursor returned by the previous call. Omit to start from what is on screen now.", "type": [ "string", "null" ] }, "maxLines": { "default": null, "description": "Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] } }, "type": "object" }, "tool": { "const": "capture_since" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "position": { "description": "The zero-based pane index.", "maximum": 2147483647, "minimum": -2147483648, "type": "integer" }, "windowId": { "description": "The window id.", "type": "string" } }, "required": [ "windowId", "position" ], "type": "object" }, "tool": { "const": "find_pane_by_position" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "paneId": { "description": "A pane id.", "type": "string" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "get_pane_info" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": {}, "type": "object" }, "tool": { "const": "get_server_info" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "description": "A session id or name.", "type": "string" } }, "required": [ "session" ], "type": "object" }, "tool": { "const": "get_session_info" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "names": { "description": "Variable names such as session_name, without #{...}. Between 1 and 64 names, each at most 64 letters, digits and underscores.", "items": { "type": "string" }, "type": "array" }, "paneId": { "default": null, "description": "A pane id used as the lookup context. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] } }, "required": [ "names" ], "type": "object" }, "tool": { "const": "get_tmux_variables" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "windowId": { "description": "A window id.", "type": "string" } }, "required": [ "windowId" ], "type": "object" }, "tool": { "const": "get_window_info" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "default": null, "description": "A session id or name. Omit for every session.", "type": [ "string", "null" ] }, "windowId": { "default": null, "description": "A window id. Omit for every window.", "type": [ "string", "null" ] } }, "type": "object" }, "tool": { "const": "list_panes" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": {}, "type": "object" }, "tool": { "const": "list_sessions" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "default": null, "description": "A session id or name. Omit for every session.", "type": [ "string", "null" ] } }, "type": "object" }, "tool": { "const": "list_windows" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "ignoreCase": { "default": true, "description": "Ignore case.", "type": "boolean" }, "includeHistory": { "default": false, "description": "Search scrollback too.", "type": "boolean" }, "maxMatchesPerPane": { "default": 20, "description": "Maximum matches per pane.", "maximum": 2147483647, "minimum": -2147483648, "type": "integer" }, "pattern": { "description": "A linear-time regular expression, at most 999 UTF-8 bytes. .NET syntax without lookarounds, backreferences or atomic groups.", "type": "string" }, "session": { "default": null, "description": "A session id or name. Omit for every session.", "type": [ "string", "null" ] } }, "required": [ "pattern" ], "type": "object" }, "tool": { "const": "search_panes" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "name": { "default": null, "description": "One variable name, which answers its value. Omit for every name with hasValue instead of values.", "type": [ "string", "null" ] }, "session": { "default": null, "description": "A session id or name. Omit for the server environment.", "type": [ "string", "null" ] } }, "type": "object" }, "tool": { "const": "show_environment" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "paneId": { "default": null, "description": "The pane whose scope is read. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "scope": { "default": "Session", "description": "Server, Session, Window, or Pane.", "enum": [ "Server", "Session", "Window", "Pane" ], "type": "string" } }, "type": "object" }, "tool": { "const": "show_hooks" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "name": { "description": "The option name.", "type": "string" }, "paneId": { "default": null, "description": "The pane whose scope is read. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "scope": { "default": "Pane", "description": "Server, Session, Window, or Pane.", "enum": [ "Server", "Session", "Window", "Pane" ], "type": "string" } }, "required": [ "name" ], "type": "object" }, "tool": { "const": "show_option" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "maxLines": { "default": null, "description": "Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] } }, "type": "object" }, "tool": { "const": "snapshot_pane" } }, "required": [ "tool" ], "type": "object" } ] }, "maxItems": 16, "minItems": 1, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "properties": { "failed": { "type": "integer" }, "onError": { "type": "string" }, "results": { "items": { "properties": { "error": { "type": [ "string", "null" ] }, "index": { "type": "integer" }, "result": true, "resultTruncated": { "type": "boolean" }, "success": { "type": "boolean" }, "tool": { "type": "string" } }, "required": [ "index", "tool", "success", "error", "result", "resultTruncated" ], "type": "object" }, "type": "array" }, "stoppedAt": { "type": [ "integer", "null" ] }, "succeeded": { "type": "integer" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "type": "integer" } }, "required": [ "results", "succeeded", "failed", "stoppedAt", "truncated", "truncatedBytes", "onError" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Call read tools batch" } ``` --- # capture_pane Source: https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read the text a pane is showing, and optionally its scrollback. The newest lines are always kept; anything dropped to fit the budget is reported. To watch a pane across several turns, use capture_since instead — it returns only what is new. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read the text a pane is showing, and optionally its scrollback. The newest lines are always kept; anything dropped to fit the budget is reported. To watch a pane across several turns, use [capture_since](https://libtmux.org/en/csharp/latest/mcp/tools/capture_since/) instead — it returns only what is new. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L576) ## Arguments * `includeHistory` optional · boolean Include scrollback. Default: `false`. * `joinWrappedLines` optional · boolean Rejoin tmux-wrapped lines. Default: `false`. * `maxLines` optional · integer | null Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another. Default: `null`. * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "includeHistory": { "default": false, "description": "Include scrollback.", "type": "boolean" }, "joinWrappedLines": { "default": false, "description": "Rejoin tmux-wrapped lines.", "type": "boolean" }, "maxLines": { "default": null, "description": "Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "content": { "properties": { "droppedBytes": { "type": "integer" }, "droppedLines": { "type": "integer" }, "lines": { "items": { "type": "string" }, "type": "array" }, "truncated": { "type": "boolean" } }, "required": [ "lines", "truncated", "droppedLines", "droppedBytes" ], "type": "object" }, "paneId": { "type": "string" } }, "required": [ "paneId", "content" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Capture pane" } ``` --- # capture_since Source: https://libtmux.org/en/csharp/latest/mcp/tools/capture_since/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read only what a pane has printed since the last call. Pass back the cursor each time. Use this to watch a long-running process across turns: the tenth read costs what the first did, where re-capturing the pane would return everything again. Call with no cursor to start watching from now. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read only what a pane has printed since the last call. Pass back the cursor each time. Use this to watch a long-running process across turns: the tenth read costs what the first did, where re-capturing the pane would return everything again. Call with no cursor to start watching from now. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/capture_since.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L577) ## Arguments * `cursor` optional · string | null The opaque cursor returned by the previous call. Omit to start from what is on screen now. Default: `null`. * `maxLines` optional · integer | null Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another. Default: `null`. * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "cursor": { "default": null, "description": "The opaque cursor returned by the previous call. Omit to start from what is on screen now.", "type": [ "string", "null" ] }, "maxLines": { "default": null, "description": "Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "anchorLost": { "type": "boolean" }, "content": { "properties": { "droppedBytes": { "type": "integer" }, "droppedLines": { "type": "integer" }, "lines": { "items": { "type": "string" }, "type": "array" }, "truncated": { "type": "boolean" } }, "required": [ "lines", "truncated", "droppedLines", "droppedBytes" ], "type": "object" }, "cursor": { "type": "string" }, "linesMissed": { "type": "boolean" }, "paneId": { "type": "string" } }, "required": [ "paneId", "content", "cursor", "linesMissed", "anchorLost" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Capture since" } ``` --- # clear_pane_scrollback Source: https://libtmux.org/en/csharp/latest/mcp/tools/clear_pane_scrollback/ > Delete tmux state; accepts no command payload. Delete a pane's scrollback history, keeping what the screen shows. Deleted history cannot be read back. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Delete a pane’s scrollback history, keeping what the screen shows. Deleted history cannot be read back. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/clear_pane_scrollback.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L613) ## Arguments * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Clear pane scrollback" } ``` --- # create_session Source: https://libtmux.org/en/csharp/latest/mcp/tools/create_session/ > Start a pane's configured process; accepts no command payload. Create a detached tmux session and return its ids. Give a width and height when nothing will attach to it: a session with no client keeps tmux's default 80x24, which truncates wide output. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Create a detached tmux session and return its ids. Give a width and height when nothing will attach to it: a session with no client keeps tmux’s default 80x24, which truncates wide output. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/create_session.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L603) ## Arguments * `height` optional · integer | null Rows. Omit for tmux's default of 24. Default: `null`. * `name` optional · string | null The session name. Omit and tmux names it with a number. Default: `null`. * `startDirectory` optional · string | null The literal starting directory. Omit for the MCP server's own working directory. Default: `null`. * `width` optional · integer | null Columns. Omit for tmux's default of 80. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "default": null, "description": "Rows. Omit for tmux's default of 24.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "name": { "default": null, "description": "The session name. Omit and tmux names it with a number.", "type": [ "string", "null" ] }, "startDirectory": { "default": null, "description": "The literal starting directory. Omit for the MCP server's own working directory.", "type": [ "string", "null" ] }, "width": { "default": null, "description": "Columns. Omit for tmux's default of 80.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Create session" } ``` --- # create_window Source: https://libtmux.org/en/csharp/latest/mcp/tools/create_window/ > Start a pane's configured process; accepts no command payload. Create a window in a tmux session and return its ids. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Create a window in a tmux session and return its ids. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/create_window.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L604) ## Arguments * `name` optional · string | null The window name. Omit and tmux names it after the program it runs. Default: `null`. * `session` optional · string | null A session id or name. Omit for the first session. Default: `null`. * `startDirectory` optional · string | null The literal starting directory. Omit for the MCP server's own working directory. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "default": null, "description": "The window name. Omit and tmux names it after the program it runs.", "type": [ "string", "null" ] }, "session": { "default": null, "description": "A session id or name. Omit for the first session.", "type": [ "string", "null" ] }, "startDirectory": { "default": null, "description": "The literal starting directory. Omit for the MCP server's own working directory.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Create window" } ``` --- # find_pane_by_position Source: https://libtmux.org/en/csharp/latest/mcp/tools/find_pane_by_position/ > Inspect tmux metadata; accepts no client-supplied executable input. Find the pane sitting at an index within a window. Answers nothing rather than failing when no pane is at that position. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Find the pane sitting at an index within a window. Answers nothing rather than failing when no pane is at that position. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/find_pane_by_position.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L580) ## Arguments * `position` required · integer The zero-based pane index. * `windowId` required · string The window id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "position": { "description": "The zero-based pane index.", "maximum": 2147483647, "minimum": -2147483648, "type": "integer" }, "windowId": { "description": "The window id.", "type": "string" } }, "required": [ "windowId", "position" ], "type": "object" } ``` Output schema ```json { "properties": { "active": { "type": "boolean" }, "currentCommand": { "type": [ "string", "null" ] }, "currentPath": { "type": [ "string", "null" ] }, "dead": { "type": "boolean" }, "height": { "type": "integer" }, "historyLimit": { "type": [ "integer", "null" ] }, "historySize": { "type": [ "integer", "null" ] }, "index": { "type": "integer" }, "inMode": { "type": "boolean" }, "isCaller": { "type": "boolean" }, "paneId": { "type": "string" }, "pid": { "type": [ "integer", "null" ] }, "sessionId": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "width": { "type": "integer" }, "windowId": { "type": "string" }, "zoomed": { "type": "boolean" } }, "required": [ "paneId", "windowId", "sessionId", "index", "width", "height", "title", "active", "dead", "zoomed", "inMode", "currentCommand", "currentPath", "pid", "historySize", "historyLimit", "isCaller" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Find pane by position" } ``` --- # get_pane_info Source: https://libtmux.org/en/csharp/latest/mcp/tools/get_pane_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Read one pane's size, title, running command, working directory, process ID, history size and limit, and whether it is active, dead, zoomed, in a mode or the pane this server runs in. This is metadata only; to read what the pane shows, use capture_pane or snapshot_pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Read one pane’s size, title, running command, working directory, process ID, history size and limit, and whether it is active, dead, zoomed, in a mode or the pane this server runs in. This is metadata only; to read what the pane shows, use [capture_pane](https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/) or [snapshot_pane](https://libtmux.org/en/csharp/latest/mcp/tools/snapshot_pane/). [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/get_pane_info.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L575) ## Arguments * `paneId` required · string A pane id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "A pane id.", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "properties": { "active": { "type": "boolean" }, "currentCommand": { "type": [ "string", "null" ] }, "currentPath": { "type": [ "string", "null" ] }, "dead": { "type": "boolean" }, "height": { "type": "integer" }, "historyLimit": { "type": [ "integer", "null" ] }, "historySize": { "type": [ "integer", "null" ] }, "index": { "type": "integer" }, "inMode": { "type": "boolean" }, "isCaller": { "type": "boolean" }, "paneId": { "type": "string" }, "pid": { "type": [ "integer", "null" ] }, "sessionId": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "width": { "type": "integer" }, "windowId": { "type": "string" }, "zoomed": { "type": "boolean" } }, "required": [ "paneId", "windowId", "sessionId", "index", "width", "height", "title", "active", "dead", "zoomed", "inMode", "currentCommand", "currentPath", "pid", "historySize", "historyLimit", "isCaller" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get pane info" } ``` --- # get_server_info Source: https://libtmux.org/en/csharp/latest/mcp/tools/get_server_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Read the tmux server's version and how many sessions, windows and panes it holds. Use to confirm a socket is alive and which tmux is running it. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Read the tmux server’s version and how many sessions, windows and panes it holds. Use to confirm a socket is alive and which tmux is running it. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/get_server_info.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L572) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "type": "object" } ``` Output schema ```json { "properties": { "callerPaneId": { "type": [ "string", "null" ] }, "callerPaneSocket": { "type": [ "string", "null" ] }, "paneCount": { "type": "integer" }, "sessionCount": { "type": "integer" }, "socketName": { "type": [ "string", "null" ] }, "socketPath": { "type": [ "string", "null" ] }, "version": { "type": [ "string", "null" ] }, "windowCount": { "type": "integer" } }, "required": [ "socketName", "socketPath", "version", "sessionCount", "windowCount", "paneCount", "callerPaneId", "callerPaneSocket" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get server info" } ``` --- # get_session_info Source: https://libtmux.org/en/csharp/latest/mcp/tools/get_session_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Read one session's name, ID, window count and whether a client is attached, without listing every session. Give the session, or a window ID to read the session that holds it. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Read one session’s name, ID, window count and whether a client is attached, without listing every session. Give the session, or a window ID to read the session that holds it. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/get_session_info.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L573) ## Arguments * `session` required · string A session id or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "A session id or name.", "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "properties": { "attached": { "type": "boolean" }, "name": { "type": "string" }, "sessionId": { "type": "string" }, "windowCount": { "type": [ "integer", "null" ] } }, "required": [ "sessionId", "name", "attached", "windowCount" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get session info" } ``` --- # get_tmux_variables Source: https://libtmux.org/en/csharp/latest/mcp/tools/get_tmux_variables/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Expand named tmux format variables for a pane, such as session_name or window_width. Use it for fields nothing else answers; get_pane_info already returns the common ones, and show_option reads configuration rather than live state. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Expand named tmux format variables for a pane, such as session_name or window_width. Use it for fields nothing else answers; [get_pane_info](https://libtmux.org/en/csharp/latest/mcp/tools/get_pane_info/) already returns the common ones, and [show_option](https://libtmux.org/en/csharp/latest/mcp/tools/show_option/) reads configuration rather than live state. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/get_tmux_variables.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L582) ## Arguments * `names` required · array Variable names such as session_name, without #{...}. Between 1 and 64 names, each at most 64 letters, digits and underscores. * `paneId` optional · string | null A pane id used as the lookup context. Omit for this server's own pane, or else the one the first session shows. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "names": { "description": "Variable names such as session_name, without #{...}. Between 1 and 64 names, each at most 64 letters, digits and underscores.", "items": { "type": "string" }, "type": "array" }, "paneId": { "default": null, "description": "A pane id used as the lookup context. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] } }, "required": [ "names" ], "type": "object" } ``` Output schema ```json { "additionalProperties": { "type": "string" }, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get tmux variables" } ``` --- # get_window_info Source: https://libtmux.org/en/csharp/latest/mcp/tools/get_window_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Read one window's name, index, size, layout, pane count and whether it is its session's current window, without listing every window. Give the window ID, or a pane ID to read the window that holds it. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Read one window’s name, index, size, layout, pane count and whether it is its session’s current window, without listing every window. Give the window ID, or a pane ID to read the window that holds it. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/get_window_info.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L574) ## Arguments * `windowId` required · string A window id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "windowId": { "description": "A window id.", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "properties": { "active": { "type": "boolean" }, "height": { "type": "integer" }, "index": { "type": "integer" }, "layout": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "paneCount": { "type": [ "integer", "null" ] }, "sessionId": { "type": "string" }, "width": { "type": "integer" }, "windowId": { "type": "string" } }, "required": [ "windowId", "sessionId", "index", "name", "width", "height", "active", "paneCount", "layout" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get window info" } ``` --- # kill_pane Source: https://libtmux.org/en/csharp/latest/mcp/tools/kill_pane/ > Delete tmux state; accepts no command payload. Close a pane and end its program. Refuses the pane this server runs in; to remove a whole window, use kill_window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Close a pane and end its program. Refuses the pane this server runs in; to remove a whole window, use [kill_window](https://libtmux.org/en/csharp/latest/mcp/tools/kill_window/). [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/kill_pane.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L614) ## Arguments * `paneId` required · string The pane id to kill. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "The pane id to kill.", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill pane" } ``` --- # kill_session Source: https://libtmux.org/en/csharp/latest/mcp/tools/kill_session/ > Delete tmux state; accepts no command payload. Close a session with all its windows and panes. Refuses the session this server runs in. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Close a session with all its windows and panes. Refuses the session this server runs in. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/kill_session.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L616) ## Arguments * `session` required · string The session id or name to kill. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "The session id or name to kill.", "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill session" } ``` --- # kill_window Source: https://libtmux.org/en/csharp/latest/mcp/tools/kill_window/ > Delete tmux state; accepts no command payload. Close a window and every pane in it. Refuses the window this server runs in. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Close a window and every pane in it. Refuses the window this server runs in. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/kill_window.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L615) ## Arguments * `windowId` required · string The window id to kill. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "windowId": { "description": "The window id to kill.", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill window" } ``` --- # list_panes Source: https://libtmux.org/en/csharp/latest/mcp/tools/list_panes/ > Inspect tmux metadata; accepts no client-supplied executable input. List tmux panes, optionally within one session or window. Filter for isCaller=true to answer 'which pane am I in?', which finds one only when this server drives the caller's own socket — get_server_info says whose socket that is. This reads sizes and running commands, not terminal text — for that use search_panes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. List tmux panes, optionally within one session or window. Filter for isCaller=true to answer ‘which pane am I in?’, which finds one only when this server drives the caller’s own socket — [get_server_info](https://libtmux.org/en/csharp/latest/mcp/tools/get_server_info/) says whose socket that is. This reads sizes and running commands, not terminal text — for that use [search_panes](https://libtmux.org/en/csharp/latest/mcp/tools/search_panes/). [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/list_panes.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L571) ## Arguments * `session` optional · string | null A session id or name. Omit for every session. Default: `null`. * `windowId` optional · string | null A window id. Omit for every window. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "default": null, "description": "A session id or name. Omit for every session.", "type": [ "string", "null" ] }, "windowId": { "default": null, "description": "A window id. Omit for every window.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "items": { "properties": { "active": { "type": "boolean" }, "currentCommand": { "type": [ "string", "null" ] }, "currentPath": { "type": [ "string", "null" ] }, "dead": { "type": "boolean" }, "height": { "type": "integer" }, "historyLimit": { "type": [ "integer", "null" ] }, "historySize": { "type": [ "integer", "null" ] }, "index": { "type": "integer" }, "inMode": { "type": "boolean" }, "isCaller": { "type": "boolean" }, "paneId": { "type": "string" }, "pid": { "type": [ "integer", "null" ] }, "sessionId": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "width": { "type": "integer" }, "windowId": { "type": "string" }, "zoomed": { "type": "boolean" } }, "required": [ "paneId", "windowId", "sessionId", "index", "width", "height", "title", "active", "dead", "zoomed", "inMode", "currentCommand", "currentPath", "pid", "historySize", "historyLimit", "isCaller" ], "type": "object" }, "type": "array" } }, "required": [ "result" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List panes" } ``` --- # list_sessions Source: https://libtmux.org/en/csharp/latest/mcp/tools/list_sessions/ > Inspect tmux metadata; accepts no client-supplied executable input. List the tmux sessions. This reads names and sizes, not terminal text — to find what a pane is showing, use search_panes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. List the tmux sessions. This reads names and sizes, not terminal text — to find what a pane is showing, use [search_panes](https://libtmux.org/en/csharp/latest/mcp/tools/search_panes/). [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/list_sessions.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L569) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "type": "object" } ``` Output schema ```json { "properties": { "result": { "items": { "properties": { "attached": { "type": "boolean" }, "name": { "type": "string" }, "sessionId": { "type": "string" }, "windowCount": { "type": [ "integer", "null" ] } }, "required": [ "sessionId", "name", "attached", "windowCount" ], "type": "object" }, "type": "array" } }, "required": [ "result" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List sessions" } ``` --- # list_windows Source: https://libtmux.org/en/csharp/latest/mcp/tools/list_windows/ > Inspect tmux metadata; accepts no client-supplied executable input. List tmux windows, optionally within one session. This reads names and layouts, not terminal text — to find what a pane is showing, use search_panes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. List tmux windows, optionally within one session. This reads names and layouts, not terminal text — to find what a pane is showing, use [search_panes](https://libtmux.org/en/csharp/latest/mcp/tools/search_panes/). [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/list_windows.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L570) ## Arguments * `session` optional · string | null A session id or name. Omit for every session. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "default": null, "description": "A session id or name. Omit for every session.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "items": { "properties": { "active": { "type": "boolean" }, "height": { "type": "integer" }, "index": { "type": "integer" }, "layout": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "paneCount": { "type": [ "integer", "null" ] }, "sessionId": { "type": "string" }, "width": { "type": "integer" }, "windowId": { "type": "string" } }, "required": [ "windowId", "sessionId", "index", "name", "width", "height", "active", "paneCount", "layout" ], "type": "object" }, "type": "array" } }, "required": [ "result" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List windows" } ``` --- # move_window Source: https://libtmux.org/en/csharp/latest/mcp/tools/move_window/ > Change tmux state; no client-supplied executable input. Move a window to another index, or into another session. With replaceExisting it takes an index that is already occupied by killing the window there, which needs the teardown toolset. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Move a window to another index, or into another session. With replaceExisting it takes an index that is already occupied by killing the window there, which needs the teardown toolset. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/move_window.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L595) ## Arguments * `destination` optional · string The destination window index. Omit for the next free index, as an empty one does. Default: `""`. * `replaceExisting` optional · boolean Kill the window already at that index and take its place. Needs the same authority as kill_window, because that is what it does to it. Default: `false`. * `session` optional · string | null The destination session id or name. Omit to stay in the window's session. Default: `null`. * `windowId` required · string The window id to move. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "destination": { "default": "", "description": "The destination window index. Omit for the next free index, as an empty one does.", "type": "string" }, "replaceExisting": { "default": false, "description": "Kill the window already at that index and take its place. Needs the same authority as kill_window, because that is what it does to it.", "type": "boolean" }, "session": { "default": null, "description": "The destination session id or name. Omit to stay in the window's session.", "type": [ "string", "null" ] }, "windowId": { "description": "The window id to move.", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Move window" } ``` --- # paste_text Source: https://libtmux.org/en/csharp/latest/mcp/tools/paste_text/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Paste a block of text into exactly one pane through a tmux buffer. Use for multi-line text, or anything an editor would mangle if typed — bracketed paste stops auto-indent. Set enter to append a newline to that same private buffer. It refuses a target in a human-owned mode and never fans out to synchronized siblings. The temporary buffer is deleted afterwards; if cleanup fails, the result identifies what remains. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Paste a block of text into exactly one pane through a tmux buffer. Use for multi-line text, or anything an editor would mangle if typed — bracketed paste stops auto-indent. Set enter to append a newline to that same private buffer. It refuses a target in a human-owned mode and never fans out to synchronized siblings. The temporary buffer is deleted afterwards; if cleanup fails, the result identifies what remains. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/paste_text.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L610) ## Arguments * `bracketed` optional · boolean Use bracketed paste. Default: `true`. * `enter` optional · boolean Append Enter to the same paste buffer. Default: `false`. * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. * `text` required · string The text to paste. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "bracketed": { "default": true, "description": "Use bracketed paste.", "type": "boolean" }, "enter": { "default": false, "description": "Append Enter to the same paste buffer.", "type": "boolean" }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "text": { "description": "The text to paste.", "type": "string" } }, "required": [ "text" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Paste text" } ``` --- # rename_session Source: https://libtmux.org/en/csharp/latest/mcp/tools/rename_session/ > Change tmux state; no client-supplied executable input. Rename a tmux session. Its id does not change, so anything holding one still works. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Rename a tmux session. Its id does not change, so anything holding one still works. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/rename_session.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L588) ## Arguments * `name` required · string The new session name. * `session` optional · string | null A session id or name. Omit for the first session. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "The new session name.", "type": "string" }, "session": { "default": null, "description": "A session id or name. Omit for the first session.", "type": [ "string", "null" ] } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Rename session" } ``` --- # rename_window Source: https://libtmux.org/en/csharp/latest/mcp/tools/rename_window/ > Change tmux state; no client-supplied executable input. Rename a tmux window. Its id does not change. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Rename a tmux window. Its id does not change. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/rename_window.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L589) ## Arguments * `name` required · string The new window name. * `windowId` optional · string | null A window id. Omit for this server's own window, or else the one the first session shows. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "The new window name.", "type": "string" }, "windowId": { "default": null, "description": "A window id. Omit for this server's own window, or else the one the first session shows.", "type": [ "string", "null" ] } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Rename window" } ``` --- # resize_pane Source: https://libtmux.org/en/csharp/latest/mcp/tools/resize_pane/ > Change tmux state; no client-supplied executable input. Resize a pane, or zoom it to fill its window. Widening a pane before reading it is the fix for output that comes back wrapped across rows. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Resize a pane, or zoom it to fill its window. Widening a pane before reading it is the fix for output that comes back wrapped across rows. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/resize_pane.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L594) ## Arguments * `height` optional · integer | null Rows. Omit to keep the current height. Default: `null`. * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. * `width` optional · integer | null Columns. Omit to keep the current width. Default: `null`. * `zoom` optional · boolean Zoom the pane. Default: `false`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "default": null, "description": "Rows. Omit to keep the current height.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "width": { "default": null, "description": "Columns. Omit to keep the current width.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "zoom": { "default": false, "description": "Zoom the pane.", "type": "boolean" } }, "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Resize pane" } ``` --- # resize_window Source: https://libtmux.org/en/csharp/latest/mcp/tools/resize_window/ > Change tmux state; no client-supplied executable input. Resize a window to a width and height in cells; its panes resize with it. To resize one pane, use resize_pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Resize a window to a width and height in cells; its panes resize with it. To resize one pane, use [resize_pane](https://libtmux.org/en/csharp/latest/mcp/tools/resize_pane/). [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/resize_window.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L593) ## Arguments * `height` optional · integer | null Rows. Omit to keep the current height. Default: `null`. * `width` optional · integer | null Columns. Omit to keep the current width. Default: `null`. * `windowId` optional · string | null A window id. Omit for this server's own window, or else the one the first session shows. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "default": null, "description": "Rows. Omit to keep the current height.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "width": { "default": null, "description": "Columns. Omit to keep the current width.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "windowId": { "default": null, "description": "A window id. Omit for this server's own window, or else the one the first session shows.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Resize window" } ``` --- # respawn_pane Source: https://libtmux.org/en/csharp/latest/mcp/tools/respawn_pane/ > Start a pane's configured process; accepts no command payload. Only restarts a pane whose command has ALREADY EXITED. killExistingProcess overrides that and kills what is running first — an editor holding unsaved changes, a build part way through. It reruns the command the pane was created with rather than running something new. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Only restarts a pane whose command has ALREADY EXITED. killExistingProcess overrides that and kills what is running first — an editor holding unsaved changes, a build part way through. It reruns the command the pane was created with rather than running something new. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/respawn_pane.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L606) ## Arguments * `killExistingProcess` optional · boolean Kill the existing pane process first. Default: `false`. * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. * `startDirectory` optional · string | null The literal starting directory. Omit for the directory the pane started in before. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "killExistingProcess": { "default": false, "description": "Kill the existing pane process first.", "type": "boolean" }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "startDirectory": { "default": null, "description": "The literal starting directory. Omit for the directory the pane started in before.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Respawn pane" } ``` --- # run_shell_command Source: https://libtmux.org/en/csharp/latest/mcp/tools/run_shell_command/ > Run a shell command in a pane with your user's permissions. Run a shell command in one pane, wait for it to finish, and report its singular real exit status and output. This is the tool for 'run X and tell me if it worked'. It reaches only the pane you name: the command travels through a tmux buffer, which synchronize-panes does not fan out, so the exit status is one pane's. Use send_keys when you want a synchronized cohort to receive input. Do NOT send keys and then poll a capture in a loop — this waits deterministically and costs one call. The command runs in a subshell, so cd and export do not persist. It refuses the named pane in a human-owned mode. Check linesMissed and anchorLost. A timed-out command MAY STILL BE RUNNING; inspect it and do not retry it — unless started is false, which means it never ran because something other than an idle shell was reading that pane's input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Run a shell command in a pane with your user’s permissions. Run a shell command in one pane, wait for it to finish, and report its singular real exit status and output. This is the tool for ‘run X and tell me if it worked’. It reaches only the pane you name: the command travels through a tmux buffer, which synchronize-panes does not fan out, so the exit status is one pane’s. Use [send_keys](https://libtmux.org/en/csharp/latest/mcp/tools/send_keys/) when you want a synchronized cohort to receive input. Do NOT send keys and then poll a capture in a loop — this waits deterministically and costs one call. The command runs in a subshell, so cd and export do not persist. It refuses the named pane in a human-owned mode. Check linesMissed and anchorLost. A timed-out command MAY STILL BE RUNNING; inspect it and do not retry it — unless started is false, which means it never ran because something other than an idle shell was reading that pane’s input. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/run_shell_command.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L607) ## Arguments * `command` required · string The shell command. * `maxLines` optional · integer | null Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another. Default: `null`. * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. * `suppressHistory` optional · boolean Keep the command out of shell history on a best-effort basis. Default: `false`. * `timeoutSeconds` optional · number | null Seconds to wait, lowered to the server's ceiling. Omit to wait the whole ceiling, 30 unless LIBTMUX_MCP_WAIT_MAX_SECONDS sets another. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "command": { "description": "The shell command.", "type": "string" }, "maxLines": { "default": null, "description": "Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "suppressHistory": { "default": false, "description": "Keep the command out of shell history on a best-effort basis.", "type": "boolean" }, "timeoutSeconds": { "default": null, "description": "Seconds to wait, lowered to the server's ceiling. Omit to wait the whole ceiling, 30 unless LIBTMUX_MCP_WAIT_MAX_SECONDS sets another.", "type": [ "number", "null" ] } }, "required": [ "command" ], "type": "object" } ``` Output schema ```json { "properties": { "anchorLost": { "default": false, "type": "boolean" }, "effectiveTimeoutSeconds": { "type": "number" }, "elapsedSeconds": { "type": "number" }, "exitStatus": { "type": [ "integer", "null" ] }, "linesMissed": { "default": false, "type": "boolean" }, "output": { "properties": { "droppedBytes": { "type": "integer" }, "droppedLines": { "type": "integer" }, "lines": { "items": { "type": "string" }, "type": "array" }, "truncated": { "type": "boolean" } }, "required": [ "lines", "truncated", "droppedLines", "droppedBytes" ], "type": "object" }, "paneExited": { "default": false, "type": "boolean" }, "paneId": { "type": "string" }, "started": { "default": true, "type": "boolean" }, "timedOut": { "type": "boolean" } }, "required": [ "paneId", "exitStatus", "timedOut", "output", "elapsedSeconds", "effectiveTimeoutSeconds" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Run shell command" } ``` --- # search_panes Source: https://libtmux.org/en/csharp/latest/mcp/tools/search_panes/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Find which panes are showing text matching a regular expression. This is the tool for 'which pane has the error', 'where is the build running', or any question about what a pane CONTAINS — the list tools only see names and sizes. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Find which panes are showing text matching a regular expression. This is the tool for ‘which pane has the error’, ‘where is the build running’, or any question about what a pane CONTAINS — the list tools only see names and sizes. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/search_panes.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L579) ## Arguments * `ignoreCase` optional · boolean Ignore case. Default: `true`. * `includeHistory` optional · boolean Search scrollback too. Default: `false`. * `maxMatchesPerPane` optional · integer Maximum matches per pane. Default: `20`. * `pattern` required · string A linear-time regular expression, at most 999 UTF-8 bytes. .NET syntax without lookarounds, backreferences or atomic groups. * `session` optional · string | null A session id or name. Omit for every session. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "ignoreCase": { "default": true, "description": "Ignore case.", "type": "boolean" }, "includeHistory": { "default": false, "description": "Search scrollback too.", "type": "boolean" }, "maxMatchesPerPane": { "default": 20, "description": "Maximum matches per pane.", "maximum": 2147483647, "minimum": -2147483648, "type": "integer" }, "pattern": { "description": "A linear-time regular expression, at most 999 UTF-8 bytes. .NET syntax without lookarounds, backreferences or atomic groups.", "type": "string" }, "session": { "default": null, "description": "A session id or name. Omit for every session.", "type": [ "string", "null" ] } }, "required": [ "pattern" ], "type": "object" } ``` Output schema ```json { "properties": { "panes": { "items": { "properties": { "matches": { "items": { "properties": { "row": { "type": "integer" }, "text": { "type": "string" } }, "required": [ "row", "text" ], "type": "object" }, "type": "array" }, "paneId": { "type": "string" }, "sessionId": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "paneId", "windowId", "sessionId", "matches" ], "type": "object" }, "type": "array" }, "panesSearched": { "type": "integer" }, "pattern": { "type": "string" }, "truncated": { "type": "boolean" } }, "required": [ "pattern", "panesSearched", "panes", "truncated" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Search panes" } ``` --- # select_layout Source: https://libtmux.org/en/csharp/latest/mcp/tools/select_layout/ > Change tmux state; no client-supplied executable input. Arrange a window's panes with a named layout — even-horizontal, even-vertical, main-horizontal, main-vertical, tiled — or a layout string read from list_windows. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Arrange a window’s panes with a named layout — even-horizontal, even-vertical, main-horizontal, main-vertical, tiled — or a layout string read from [list_windows](https://libtmux.org/en/csharp/latest/mcp/tools/list_windows/). [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/select_layout.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L592) ## Arguments * `layout` optional · string | null A supported layout name or layout string. Omit to reapply the window's last preset layout, if it has had one. Default: `null`. * `windowId` optional · string | null A window id. Omit for this server's own window, or else the one the first session shows. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "layout": { "default": null, "description": "A supported layout name or layout string. Omit to reapply the window's last preset layout, if it has had one.", "type": [ "string", "null" ] }, "windowId": { "default": null, "description": "A window id. Omit for this server's own window, or else the one the first session shows.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select layout" } ``` --- # select_pane Source: https://libtmux.org/en/csharp/latest/mcp/tools/select_pane/ > Change tmux state; no client-supplied executable input. Make a pane the active one in its window. This changes what a watching human sees; targeting a pane by id does not require selecting it first. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Make a pane the active one in its window. This changes what a watching human sees; targeting a pane by id does not require selecting it first. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/select_pane.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L591) ## Arguments * `paneId` required · string A pane id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "A pane id.", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select pane" } ``` --- # select_window Source: https://libtmux.org/en/csharp/latest/mcp/tools/select_window/ > Change tmux state; no client-supplied executable input. Make a window the current one in its session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Make a window the current one in its session. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/select_window.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L590) ## Arguments * `windowId` required · string A window id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "windowId": { "description": "A window id.", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select window" } ``` --- # send_keys Source: https://libtmux.org/en/csharp/latest/mcp/tools/send_keys/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send raw keystrokes to a pane and return immediately. Use for driving an interactive program — a key in vim, a menu choice, Ctrl-C. Set literal=false to send named keys such as C-c, Escape or F5. It refuses the named pane in a human-owned mode and, when source input expands, every synchronized input cohort peer. To run a shell command and learn whether it worked, use run_shell_command instead; this reports nothing about what happens next. Tracks what it sends — including edits such as backspace, Ctrl-U or Ctrl-C — so wait_for_text can tell this pane's echo apart from real output for a short time afterward. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Send raw keystrokes to a pane and return immediately. Use for driving an interactive program — a key in vim, a menu choice, Ctrl-C. Set literal=false to send named keys such as C-c, Escape or F5. It refuses the named pane in a human-owned mode and, when source input expands, every synchronized input cohort peer. To run a shell command and learn whether it worked, use [run_shell_command](https://libtmux.org/en/csharp/latest/mcp/tools/run_shell_command/) instead; this reports nothing about what happens next. Tracks what it sends — including edits such as backspace, Ctrl-U or Ctrl-C — so [wait_for_text](https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_text/) can tell this pane’s echo apart from real output for a short time afterward. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/send_keys.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L608) ## Arguments * `enter` optional · boolean Press Enter after the keys. Default: `false`. * `keys` required · string Text or a tmux key name. * `literal` optional · boolean Treat keys as literal text. Default: `true`. * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. * `suppressHistory` optional · boolean Keep text out of shell history on a best-effort basis. Default: `false`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enter": { "default": false, "description": "Press Enter after the keys.", "type": "boolean" }, "keys": { "description": "Text or a tmux key name.", "type": "string" }, "literal": { "default": true, "description": "Treat keys as literal text.", "type": "boolean" }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "suppressHistory": { "default": false, "description": "Keep text out of shell history on a best-effort basis.", "type": "boolean" } }, "required": [ "keys" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "type": "string" }, "targetPaneIds": { "items": { "type": "string" }, "type": "array" } }, "required": [ "changed", "paneId", "targetPaneIds" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Send keys" } ``` --- # send_keys_batch Source: https://libtmux.org/en/csharp/latest/mcp/tools/send_keys_batch/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send several keystrokes to one pane in order, in a single call. Use for a short interactive sequence — open a file, move, type, save — instead of one call per key. Each operation refuses the named pane in a human-owned mode and, when source input expands, every synchronized input cohort peer. A batch has at most 64 steps and 64 KiB of UTF-8 text. Each delay is 0-2000 ms and all delays together must fit the server wait ceiling. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Send several keystrokes to one pane in order, in a single call. Use for a short interactive sequence — open a file, move, type, save — instead of one call per key. Each operation refuses the named pane in a human-owned mode and, when source input expands, every synchronized input cohort peer. A batch has at most 64 steps and 64 KiB of UTF-8 text. Each delay is 0-2000 ms and all delays together must fit the server wait ceiling. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/send_keys_batch.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L609) ## Arguments * `onError` optional · string Stop after the first failed operation, or continue serially. Default: `"stop"`. * `operations` required · array Between 1 and 64 bounded pane-input operations, executed serially. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "onError": { "default": "stop", "description": "Stop after the first failed operation, or continue serially.", "enum": [ "continue", "stop" ], "type": "string" }, "operations": { "description": "Between 1 and 64 bounded pane-input operations, executed serially.", "items": { "additionalProperties": false, "properties": { "delayMilliseconds": { "default": null, "maximum": 2000, "minimum": 0, "type": [ "integer", "null" ] }, "enter": { "default": false, "type": "boolean" }, "keys": { "type": "string" }, "literal": { "default": true, "type": "boolean" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "suppressHistory": { "default": false, "type": "boolean" } }, "required": [ "keys" ], "type": "object" }, "maxItems": 64, "minItems": 1, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "properties": { "failed": { "type": "integer" }, "onError": { "type": "string" }, "results": { "items": { "properties": { "error": { "type": [ "string", "null" ] }, "index": { "type": "integer" }, "paneId": { "type": [ "string", "null" ] }, "success": { "type": "boolean" }, "targetPaneIds": { "items": { "type": "string" }, "type": "array" } }, "required": [ "index", "paneId", "success", "error", "targetPaneIds" ], "type": "object" }, "type": "array" }, "stoppedAt": { "type": [ "integer", "null" ] }, "succeeded": { "type": "integer" } }, "required": [ "results", "succeeded", "failed", "stoppedAt", "onError" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Send keys batch" } ``` --- # set_history_limit Source: https://libtmux.org/en/csharp/latest/mcp/tools/set_history_limit/ > Change tmux state; no client-supplied executable input. Set how many scrollback lines tmux keeps. This is a SESSION option, so it covers every window in the session rather than one pane, and the session must be named because the call can destroy data. Raise it before starting something that prints a lot: no capture can return lines tmux has already discarded. LOWERING it discards the excess from every pane immediately, and the result says how many lines went; raising the limit again does not bring them back. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set how many scrollback lines tmux keeps. This is a SESSION option, so it covers every window in the session rather than one pane, and the session must be named because the call can destroy data. Raise it before starting something that prints a lot: no capture can return lines tmux has already discarded. LOWERING it discards the excess from every pane immediately, and the result says how many lines went; raising the limit again does not bring them back. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/set_history_limit.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L601) ## Arguments * `lines` required · integer The scrollback line limit. * `session` required · string A session id such as $0, or its name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "lines": { "description": "The scrollback line limit.", "maximum": 2147483647, "minimum": -2147483648, "type": "integer" }, "session": { "description": "A session id such as $0, or its name.", "type": "string" } }, "required": [ "lines", "session" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set history limit" } ``` --- # set_mouse_enabled Source: https://libtmux.org/en/csharp/latest/mcp/tools/set_mouse_enabled/ > Change tmux state; no client-supplied executable input. Turn tmux mouse support on or off. This sets the global option, so it applies to every session on this server and changes what a human watching can do with their mouse. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Turn tmux mouse support on or off. This sets the global option, so it applies to every session on this server and changes what a human watching can do with their mouse. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/set_mouse_enabled.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L600) ## Arguments * `enabled` required · boolean Whether mouse support is enabled globally. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enabled": { "description": "Whether mouse support is enabled globally.", "type": "boolean" } }, "required": [ "enabled" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set mouse enabled" } ``` --- # set_pane_title Source: https://libtmux.org/en/csharp/latest/mcp/tools/set_pane_title/ > Change tmux state; no client-supplied executable input. Set a pane's title. Useful for labelling panes you created so a human watching can tell which is which. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set a pane’s title. Useful for labelling panes you created so a human watching can tell which is which. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/set_pane_title.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L597) ## Arguments * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. * `title` required · string The literal pane title. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "title": { "description": "The literal pane title.", "type": "string" } }, "required": [ "title" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set pane title" } ``` --- # set_synchronize_panes Source: https://libtmux.org/en/csharp/latest/mcp/tools/set_synchronize_panes/ > Change tmux state; no client-supplied executable input. Turn synchronize-panes on or off for a window. Input typed into one of its panes then reaches the synchronized input cohort: every pane whose effective synchronize-panes setting is on. A pane without a setting of its own follows the window; one with its own setting stays included or excluded either way. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Turn synchronize-panes on or off for a window. Input typed into one of its panes then reaches the synchronized input cohort: every pane whose effective synchronize-panes setting is on. A pane without a setting of its own follows the window; one with its own setting stays included or excluded either way. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/set_synchronize_panes.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L611) ## Arguments * `enabled` required · boolean Whether to set this window's inherited synchronize-panes default. Pane overrides can still include or exclude individual panes. * `windowId` optional · string | null A window id. Omit for this server's own window, or else the one the first session shows. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enabled": { "description": "Whether to set this window's inherited synchronize-panes default. Pane overrides can still include or exclude individual panes.", "type": "boolean" }, "windowId": { "default": null, "description": "A window id. Omit for this server's own window, or else the one the first session shows.", "type": [ "string", "null" ] } }, "required": [ "enabled" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set synchronize panes" } ``` --- # show_environment Source: https://libtmux.org/en/csharp/latest/mcp/tools/show_environment/ > Read the tmux environment; accepts no client-supplied executable input. A listing answers names without values, and a named variable is still withheld when the name reads as a credential. Read what a NEW pane will inherit, at the server or session level — not what an already-running shell has. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read the tmux environment; accepts no client-supplied executable input. A listing answers names without values, and a named variable is still withheld when the name reads as a credential. Read what a NEW pane will inherit, at the server or session level — not what an already-running shell has. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/show_environment.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L584) ## Arguments * `name` optional · string | null One variable name, which answers its value. Omit for every name with hasValue instead of values. Default: `null`. * `session` optional · string | null A session id or name. Omit for the server environment. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "default": null, "description": "One variable name, which answers its value. Omit for every name with hasValue instead of values.", "type": [ "string", "null" ] }, "session": { "default": null, "description": "A session id or name. Omit for the server environment.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "items": { "properties": { "hasValue": { "type": "boolean" }, "isRemoved": { "type": "boolean" }, "name": { "type": "string" }, "value": { "type": [ "string", "null" ] }, "withheld": { "type": "boolean" } }, "required": [ "name", "value", "isRemoved", "hasValue", "withheld" ], "type": "object" }, "type": "array" } }, "required": [ "result" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show environment" } ``` --- # show_hooks Source: https://libtmux.org/en/csharp/latest/mcp/tools/show_hooks/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read the hooks tmux will run on its own events. Read-only on purpose: a hook written here would outlive this conversation and keep firing with nobody left who knows why. Put hooks you want to keep in your tmux config file. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read the hooks tmux will run on its own events. Read-only on purpose: a hook written here would outlive this conversation and keep firing with nobody left who knows why. Put hooks you want to keep in your tmux config file. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/show_hooks.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L585) ## Arguments * `paneId` optional · string | null The pane whose scope is read. Omit for this server's own pane, or else the one the first session shows. Default: `null`. * `scope` optional · string Server, Session, Window, or Pane. Default: `"Session"`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "default": null, "description": "The pane whose scope is read. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "scope": { "default": "Session", "description": "Server, Session, Window, or Pane.", "enum": [ "Server", "Session", "Window", "Pane" ], "type": "string" } }, "type": "object" } ``` Output schema ```json { "properties": { "result": { "items": { "properties": { "command": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" }, "scope": { "enum": [ "Server", "Session", "Window", "Pane" ], "type": "string" } }, "required": [ "name", "index", "command", "scope" ], "type": "object" }, "type": "array" } }, "required": [ "result" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show hooks" } ``` --- # show_option Source: https://libtmux.org/en/csharp/latest/mcp/tools/show_option/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read tmux options at the server, session, window or pane level. Values set at a wider scope are included and marked inherited, because that is where nearly all tmux configuration lives. Omit the name to list them all. Reading history-limit before a long tail tells you how much output the pane can hold before it starts dropping lines. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read tmux options at the server, session, window or pane level. Values set at a wider scope are included and marked inherited, because that is where nearly all tmux configuration lives. Omit the name to list them all. Reading history-limit before a long tail tells you how much output the pane can hold before it starts dropping lines. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/show_option.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L583) ## Arguments * `name` required · string The option name. * `paneId` optional · string | null The pane whose scope is read. Omit for this server's own pane, or else the one the first session shows. Default: `null`. * `scope` optional · string Server, Session, Window, or Pane. Default: `"Pane"`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "The option name.", "type": "string" }, "paneId": { "default": null, "description": "The pane whose scope is read. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "scope": { "default": "Pane", "description": "Server, Session, Window, or Pane.", "enum": [ "Server", "Session", "Window", "Pane" ], "type": "string" } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "properties": { "result": { "items": { "properties": { "inherited": { "type": "boolean" }, "name": { "type": "string" }, "scope": { "enum": [ "Server", "Session", "Window", "Pane" ], "type": "string" }, "value": { "type": [ "string", "null" ] } }, "required": [ "name", "value", "scope", "inherited" ], "type": "object" }, "type": "array" } }, "required": [ "result" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show option" } ``` --- # signal_channel Source: https://libtmux.org/en/csharp/latest/mcp/tools/signal_channel/ > Change tmux state; no client-supplied executable input. Signal a tmux wait-for channel, releasing whatever waits on it. The channel latches: signalling before anyone waits still satisfies the next wait, so a handoff cannot be lost to a race. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Signal a tmux wait-for channel, releasing whatever waits on it. The channel latches: signalling before anyone waits still satisfies the next wait, so a handoff cannot be lost to a race. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/signal_channel.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L599) ## Arguments * `channel` required · string The tmux wait-for channel. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "The tmux wait-for channel.", "type": "string" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Signal channel" } ``` --- # snapshot_pane Source: https://libtmux.org/en/csharp/latest/mcp/tools/snapshot_pane/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read a pane's visible content together with its cursor position, size and running command, in one call. Prefer this over capture_pane plus list_panes: it is one round trip and the cursor is guaranteed to describe the text returned with it. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read a pane’s visible content together with its cursor position, size and running command, in one call. Prefer this over [capture_pane](https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/) plus [list_panes](https://libtmux.org/en/csharp/latest/mcp/tools/list_panes/): it is one round trip and the cursor is guaranteed to describe the text returned with it. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/snapshot_pane.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L578) ## Arguments * `maxLines` optional · integer | null Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another. Default: `null`. * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "maxLines": { "default": null, "description": "Maximum returned lines, newest kept. Omit for the server default, 500 unless LIBTMUX_MCP_MAX_LINES sets another.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "alternateScreen": { "type": "boolean" }, "content": { "properties": { "droppedBytes": { "type": "integer" }, "droppedLines": { "type": "integer" }, "lines": { "items": { "type": "string" }, "type": "array" }, "truncated": { "type": "boolean" } }, "required": [ "lines", "truncated", "droppedLines", "droppedBytes" ], "type": "object" }, "cursorX": { "type": [ "integer", "null" ] }, "cursorY": { "type": [ "integer", "null" ] }, "pane": { "properties": { "active": { "type": "boolean" }, "currentCommand": { "type": [ "string", "null" ] }, "currentPath": { "type": [ "string", "null" ] }, "dead": { "type": "boolean" }, "height": { "type": "integer" }, "historyLimit": { "type": [ "integer", "null" ] }, "historySize": { "type": [ "integer", "null" ] }, "index": { "type": "integer" }, "inMode": { "type": "boolean" }, "isCaller": { "type": "boolean" }, "paneId": { "type": "string" }, "pid": { "type": [ "integer", "null" ] }, "sessionId": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "width": { "type": "integer" }, "windowId": { "type": "string" }, "zoomed": { "type": "boolean" } }, "required": [ "paneId", "windowId", "sessionId", "index", "width", "height", "title", "active", "dead", "zoomed", "inMode", "currentCommand", "currentPath", "pid", "historySize", "historyLimit", "isCaller" ], "type": "object" } }, "required": [ "pane", "content", "cursorX", "cursorY", "alternateScreen" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Snapshot pane" } ``` --- # split_window Source: https://libtmux.org/en/csharp/latest/mcp/tools/split_window/ > Start a pane's configured process; accepts no command payload. Split a pane and return the NEW pane's id. Use that id for what you put in it — pane ids stay valid across layout changes, where window names and indexes do not. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Split a pane and return the NEW pane’s id. Use that id for what you put in it — pane ids stay valid across layout changes, where window names and indexes do not. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/split_window.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L605) ## Arguments * `direction` optional · string Below, Above, Left, or Right. Default: `"Below"`. * `paneId` optional · string | null The pane to split. Omit for this server's own pane, or else the one the first session shows. Default: `null`. * `percentage` optional · integer | null Percentage of the space for the new pane. Omit for half. Default: `null`. * `startDirectory` optional · string | null The literal starting directory. Omit for the MCP server's own working directory. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "direction": { "default": "Below", "description": "Below, Above, Left, or Right.", "enum": [ "Above", "Below", "Left", "Right" ], "type": "string" }, "paneId": { "default": null, "description": "The pane to split. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "percentage": { "default": null, "description": "Percentage of the space for the new pane. Omit for half.", "maximum": 2147483647, "minimum": -2147483648, "type": [ "integer", "null" ] }, "startDirectory": { "default": null, "description": "The literal starting directory. Omit for the MCP server's own working directory.", "type": [ "string", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Split window" } ``` --- # swap_pane Source: https://libtmux.org/en/csharp/latest/mcp/tools/swap_pane/ > Change tmux state; no client-supplied executable input. Swap two panes' positions; each keeps its program, its content and its ID. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Swap two panes’ positions; each keeps its program, its content and its ID. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/swap_pane.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L596) ## Arguments * `detach` optional · boolean Leave the swapped pane unselected. Default: `false`. * `keepZoom` optional · boolean Keep zoom state. Default: `false`. * `paneId` required · string The pane id to swap. * `targetPaneId` required · string The other pane id. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "detach": { "default": false, "description": "Leave the swapped pane unselected.", "type": "boolean" }, "keepZoom": { "default": false, "description": "Keep zoom state.", "type": "boolean" }, "paneId": { "description": "The pane id to swap.", "type": "string" }, "targetPaneId": { "description": "The other pane id.", "type": "string" } }, "required": [ "paneId", "targetPaneId" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "paneId": { "default": null, "type": [ "string", "null" ] }, "sessionId": { "default": null, "type": [ "string", "null" ] }, "windowId": { "default": null, "type": [ "string", "null" ] } }, "required": [ "changed" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Swap pane" } ``` --- # wait_for_channel Source: https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_channel/ > Change tmux state; no client-supplied executable input. Block until something signals a tmux wait-for channel with 'tmux wait-for -S '. Use when you composed a shell command that signals it. For an ordinary command whose completion you want, run_shell_command already does this and also reports the exit status. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Block until something signals a tmux wait-for channel with ‘tmux wait-for -S ’. Use when you composed a shell command that signals it. For an ordinary command whose completion you want, [run_shell_command](https://libtmux.org/en/csharp/latest/mcp/tools/run_shell_command/) already does this and also reports the exit status. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_channel.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L598) ## Arguments * `channel` required · string The tmux wait-for channel. * `timeoutSeconds` optional · number | null Seconds to wait, lowered to the server's ceiling. Omit to wait the whole ceiling, 30 unless LIBTMUX_MCP_WAIT_MAX_SECONDS sets another. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "The tmux wait-for channel.", "type": "string" }, "timeoutSeconds": { "default": null, "description": "Seconds to wait, lowered to the server's ceiling. Omit to wait the whole ceiling, 30 unless LIBTMUX_MCP_WAIT_MAX_SECONDS sets another.", "type": [ "number", "null" ] } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "properties": { "changed": { "type": "string" }, "channel": { "type": "string" }, "effectiveTimeoutSeconds": { "type": "number" }, "elapsedSeconds": { "type": "number" }, "signalled": { "type": "boolean" } }, "required": [ "changed", "channel", "signalled", "elapsedSeconds", "effectiveTimeoutSeconds" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Wait for channel" } ``` --- # wait_for_text Source: https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_text/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Wait until a pane prints something matching one of these patterns, then return. Use for output you did NOT start — a server's ready line, another process's progress, a person typing. A matching pattern already on screen returns PresentAtEntry. For a command you are running yourself, run_shell_command is better: it reports the real exit status instead of guessing from text. Never poll capture_pane in a loop; this call does the waiting. Control observation is required by default; pollingFallback reports activation when the operator permits fallback. Text this server itself typed is discounted while deciding what is new, for a few seconds after it is sent or submitted, so its own echo cannot be the match — except on a pane whose program has not yet configured its terminal; wait for a first prompt before typing into a freshly created pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Wait until a pane prints something matching one of these patterns, then return. Use for output you did NOT start — a server’s ready line, another process’s progress, a person typing. A matching pattern already on screen returns PresentAtEntry. For a command you are running yourself, [run_shell_command](https://libtmux.org/en/csharp/latest/mcp/tools/run_shell_command/) is better: it reports the real exit status instead of guessing from text. Never poll [capture_pane](https://libtmux.org/en/csharp/latest/mcp/tools/capture_pane/) in a loop; this call does the waiting. Control observation is required by default; pollingFallback reports activation when the operator permits fallback. Text this server itself typed is discounted while deciding what is new, for a few seconds after it is sent or submitted, so its own echo cannot be the match — except on a pane whose program has not yet configured its terminal; wait for a first prompt before typing into a freshly created pane. [All C# tools](https://libtmux.org/en/csharp/latest/mcp/tools/) · [JSON](https://libtmux.org/en/csharp/latest/mcp/tools/wait_for_text.json) · [Source](https://github.com/libtmux/libtmux-dotnet/blob/ec8b6ab2a4f65e23664f43fba538ba200d4ae8bc/src/LibTmux.Mcp/Policy/CapabilityModel.cs#L581) ## Arguments * `ignoreCase` optional · boolean Ignore case. Default: `true`. * `paneId` optional · string | null A pane id. Omit for this server's own pane, or else the one the first session shows. Default: `null`. * `patterns` optional · array | null Linear-time regular expressions that end the wait successfully: .NET syntax without lookarounds, backreferences or atomic groups. Output arriving after this call counts unless the pattern is already present, which returns PresentAtEntry. Omit to return on any new output. Across both pattern lists: at most 32 entries and 16384 UTF-8 bytes; each entry is at most 999 UTF-8 bytes. Default: `null`. * `stopPatterns` optional · array | null Linear-time regular expressions that stop the wait, in the same subset as patterns. Omit for none. Across both pattern lists: at most 32 entries and 16384 UTF-8 bytes; each entry is at most 999 UTF-8 bytes. Default: `null`. * `timeoutSeconds` optional · number | null Seconds to wait, lowered to the server's ceiling. Omit to wait the whole ceiling, 30 unless LIBTMUX_MCP_WAIT_MAX_SECONDS sets another. Default: `null`. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "ignoreCase": { "default": true, "description": "Ignore case.", "type": "boolean" }, "paneId": { "default": null, "description": "A pane id. Omit for this server's own pane, or else the one the first session shows.", "type": [ "string", "null" ] }, "patterns": { "default": null, "description": "Linear-time regular expressions that end the wait successfully: .NET syntax without lookarounds, backreferences or atomic groups. Output arriving after this call counts unless the pattern is already present, which returns PresentAtEntry. Omit to return on any new output. Across both pattern lists: at most 32 entries and 16384 UTF-8 bytes; each entry is at most 999 UTF-8 bytes.", "items": { "type": [ "string", "null" ] }, "type": [ "array", "null" ] }, "stopPatterns": { "default": null, "description": "Linear-time regular expressions that stop the wait, in the same subset as patterns. Omit for none. Across both pattern lists: at most 32 entries and 16384 UTF-8 bytes; each entry is at most 999 UTF-8 bytes.", "items": { "type": [ "string", "null" ] }, "type": [ "array", "null" ] }, "timeoutSeconds": { "default": null, "description": "Seconds to wait, lowered to the server's ceiling. Omit to wait the whole ceiling, 30 unless LIBTMUX_MCP_WAIT_MAX_SECONDS sets another.", "type": [ "number", "null" ] } }, "type": "object" } ``` Output schema ```json { "properties": { "anchorLost": { "type": "boolean" }, "effectiveTimeoutSeconds": { "type": "number" }, "elapsedSeconds": { "type": "number" }, "eventsDropped": { "type": "integer" }, "linesMissed": { "type": "boolean" }, "matchedPattern": { "type": [ "string", "null" ] }, "outcome": { "enum": [ "Matched", "AnyOutput", "Stopped", "Timeout", "PaneDied", "PresentAtEntry" ], "type": "string" }, "paneId": { "type": "string" }, "pollingFallback": { "type": "boolean" }, "tail": { "properties": { "droppedBytes": { "type": "integer" }, "droppedLines": { "type": "integer" }, "lines": { "items": { "type": "string" }, "type": "array" }, "truncated": { "type": "boolean" } }, "required": [ "lines", "truncated", "droppedLines", "droppedBytes" ], "type": "object" } }, "required": [ "paneId", "outcome", "matchedPattern", "tail", "elapsedSeconds", "effectiveTimeoutSeconds" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Wait for text" } ``` --- # C++ MCP tools Source: https://libtmux.org/en/cxx/latest/mcp/tools/ > Tools, resources, and prompts advertised by the C++ MCP server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Use the wire name shown here when calling a tool. The C++ server advertises 45 tools with the reference configuration below. Your client’s list follows the policy configured for its server. Read the [setup guide](https://libtmux.org/en/cxx/latest/mcp/guides/) before choosing tool access. The [language API reference](https://libtmux.org/en/cxx/latest/mcp/reference/) covers embedding and implementation types. This is the POSIX catalog. The Windows preview exposes a smaller read-only surface; see [platform limits](https://libtmux.org/en/cxx/latest/mcp/topics/). [Download the protocol catalog as JSON](https://libtmux.org/en/cxx/latest/mcp/tools.json). Reference configuration * `LIBTMUX_TOOLSETS` `inspect,manage,execute,teardown` Protocol version: `2025-11-25`. ## Tools * [`call_read_tools_batch`](https://libtmux.org/en/cxx/latest/mcp/tools/call_read_tools_batch/) Run up to sixteen declared inspect operations serially under this one call; inner operations receive no separate approval. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`capture_pane`](https://libtmux.org/en/cxx/latest/mcp/tools/capture_pane/) Return visible text, or retained history when requested. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`capture_since`](https://libtmux.org/en/cxx/latest/mcp/tools/capture_since/) Return bytes after a bounded client cursor and a replacement cursor. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`clear_pane_scrollback`](https://libtmux.org/en/cxx/latest/mcp/tools/clear_pane_scrollback/) Irreversibly discard retained scrollback for one pane. Delete tmux state; accepts no command payload. * [`create_session`](https://libtmux.org/en/cxx/latest/mcp/tools/create_session/) Create a detached session; names and path data are literalized before tmux expansion. Start a pane's configured process; accepts no command payload. * [`create_window`](https://libtmux.org/en/cxx/latest/mcp/tools/create_window/) Create a detached window; name and path data are literalized before tmux expansion. Start a pane's configured process; accepts no command payload. * [`find_pane_by_position`](https://libtmux.org/en/cxx/latest/mcp/tools/find_pane_by_position/) Resolve coordinates using fixed tmux layout fields. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_pane_info`](https://libtmux.org/en/cxx/latest/mcp/tools/get_pane_info/) Return one pane by stable ID. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_server_info`](https://libtmux.org/en/cxx/latest/mcp/tools/get_server_info/) Report liveness, tmux version, and the resolved socket when running. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_session_info`](https://libtmux.org/en/cxx/latest/mcp/tools/get_session_info/) Return one session by stable ID or name. Inspect tmux metadata; accepts no client-supplied executable input. * [`get_tmux_variables`](https://libtmux.org/en/cxx/latest/mcp/tools/get_tmux_variables/) Expand only validated variable identifiers, never a caller format. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. * [`get_window_info`](https://libtmux.org/en/cxx/latest/mcp/tools/get_window_info/) Return one window by stable ID. Inspect tmux metadata; accepts no client-supplied executable input. * [`kill_pane`](https://libtmux.org/en/cxx/latest/mcp/tools/kill_pane/) Delete one pane and its running process. Delete tmux state; accepts no command payload. * [`kill_session`](https://libtmux.org/en/cxx/latest/mcp/tools/kill_session/) Delete one session and every window it owns. Delete tmux state; accepts no command payload. * [`kill_window`](https://libtmux.org/en/cxx/latest/mcp/tools/kill_window/) Delete one window and every pane it owns. Delete tmux state; accepts no command payload. * [`list_panes`](https://libtmux.org/en/cxx/latest/mcp/tools/list_panes/) List every pane with stable pane, window, and session IDs. Inspect tmux metadata; accepts no client-supplied executable input. * [`list_sessions`](https://libtmux.org/en/cxx/latest/mcp/tools/list_sessions/) List stable session IDs, names, paths, and client counts. Inspect tmux metadata; accepts no client-supplied executable input. * [`list_windows`](https://libtmux.org/en/cxx/latest/mcp/tools/list_windows/) List windows through an exact owning session. Inspect tmux metadata; accepts no client-supplied executable input. * [`move_window`](https://libtmux.org/en/cxx/latest/mcp/tools/move_window/) Move a window to an exact index in its owning session. Change tmux state; no client-supplied executable input. * [`paste_text`](https://libtmux.org/en/cxx/latest/mcp/tools/paste_text/) Require the target pane to be live and outside human-owned mode, then stage a private target-only buffer, optionally append Enter, paste it once, and verify cleanup. Empty text without Enter is a guarded buffer-free no-op. Send input to a pane's program; a shell that receives it runs it with your user's permissions. * [`rename_session`](https://libtmux.org/en/cxx/latest/mcp/tools/rename_session/) Replace one session name. Change tmux state; no client-supplied executable input. * [`rename_window`](https://libtmux.org/en/cxx/latest/mcp/tools/rename_window/) Replace one window name. Change tmux state; no client-supplied executable input. * [`resize_pane`](https://libtmux.org/en/cxx/latest/mcp/tools/resize_pane/) Replace one or both pane dimensions. Change tmux state; no client-supplied executable input. * [`resize_window`](https://libtmux.org/en/cxx/latest/mcp/tools/resize_window/) Replace one window's dimensions. Change tmux state; no client-supplied executable input. * [`respawn_pane`](https://libtmux.org/en/cxx/latest/mcp/tools/respawn_pane/) Restart only the pane's configured process; no caller command is accepted. Start a pane's configured process; accepts no command payload. * [`run_shell_command`](https://libtmux.org/en/cxx/latest/mcp/tools/run_shell_command/) Require one live configured pane, outside human-owned mode and running a supported POSIX foreground shell, then send one command and return output after its private completion boundary. Run a shell command in a pane with your user's permissions. * [`search_panes`](https://libtmux.org/en/cxx/latest/mcp/tools/search_panes/) Search captured lines using a length-limited expression. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`select_layout`](https://libtmux.org/en/cxx/latest/mcp/tools/select_layout/) Replace the pane layout of one window. Names and mirrored layouts follow the selected daemon version. Saved layouts accept v1 checksums and v2 JSON; v2 requires tmux 3.8 (including 3.8-rc) or newer. Change tmux state; no client-supplied executable input. * [`select_pane`](https://libtmux.org/en/cxx/latest/mcp/tools/select_pane/) Make one pane active. Change tmux state; no client-supplied executable input. * [`select_window`](https://libtmux.org/en/cxx/latest/mcp/tools/select_window/) Make one window active. Change tmux state; no client-supplied executable input. * [`send_keys`](https://libtmux.org/en/cxx/latest/mcp/tools/send_keys/) Require every configured synchronized pane to be live and outside human-owned mode, then send one validated tmux key name. Send input to a pane's program; a shell that receives it runs it with your user's permissions. * [`send_keys_batch`](https://libtmux.org/en/cxx/latest/mcp/tools/send_keys_batch/) Preflight each row's configured synchronized pane cohort independently, requiring every pane to be live and outside human-owned mode before its text or key and optional Enter. Send input to a pane's program; a shell that receives it runs it with your user's permissions. * [`set_history_limit`](https://libtmux.org/en/cxx/latest/mcp/tools/set_history_limit/) Replace retained-history bounds with a non-negative integer. Change tmux state; no client-supplied executable input. * [`set_mouse_enabled`](https://libtmux.org/en/cxx/latest/mcp/tools/set_mouse_enabled/) Replace the global mouse option with a typed boolean. Change tmux state; no client-supplied executable input. * [`set_pane_title`](https://libtmux.org/en/cxx/latest/mcp/tools/set_pane_title/) Replace one pane title. Change tmux state; no client-supplied executable input. * [`set_synchronize_panes`](https://libtmux.org/en/cxx/latest/mcp/tools/set_synchronize_panes/) Set the inherited window synchronize-panes default; pane-level overrides determine effective synchronized input membership. Change tmux state; no client-supplied executable input. * [`show_environment`](https://libtmux.org/en/cxx/latest/mcp/tools/show_environment/) Read global or session environment values. Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. * [`show_hooks`](https://libtmux.org/en/cxx/latest/mcp/tools/show_hooks/) Read configured hooks, optionally filtered by exact name. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. * [`show_option`](https://libtmux.org/en/cxx/latest/mcp/tools/show_option/) Read one exact option without accepting an option value. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. * [`signal_channel`](https://libtmux.org/en/cxx/latest/mcp/tools/signal_channel/) Release or latch one named server-side channel. Change tmux state; no client-supplied executable input. * [`snapshot_pane`](https://libtmux.org/en/cxx/latest/mcp/tools/snapshot_pane/) Return pane metadata and visible terminal content from one call. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. * [`split_window`](https://libtmux.org/en/cxx/latest/mcp/tools/split_window/) Create a configured-process pane; path data is literalized before tmux expansion. Start a pane's configured process; accepts no command payload. * [`swap_pane`](https://libtmux.org/en/cxx/latest/mcp/tools/swap_pane/) Exchange two pane positions without changing their IDs. Change tmux state; no client-supplied executable input. * [`wait_for_channel`](https://libtmux.org/en/cxx/latest/mcp/tools/wait_for_channel/) Wait for a named server-side channel with an optional deadline. Change tmux state; no client-supplied executable input. * [`wait_for_text`](https://libtmux.org/en/cxx/latest/mcp/tools/wait_for_text/) Discount this server's pending input and recent submitted echoes; unmodelled keys stop tracking the current line. Wait for a new shell's prompt before typing. \`matched_at_entry\` reports visible text at entry; a mode ending in -unconfirmed identifies input that was still unconfirmed at the deadline. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. ## Resources * `tmux://capabilities` The startup-frozen effective tool capability manifest. ## Resource templates This server does not advertise resource templates in this configuration. ## Prompts This server does not advertise prompts in this configuration. Source revision: [libtmux/libtmux-cxx@3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f](https://github.com/libtmux/libtmux-cxx/tree/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f). --- # call_read_tools_batch Source: https://libtmux.org/en/cxx/latest/mcp/tools/call_read_tools_batch/ > Run up to sixteen declared inspect operations serially under this one call; inner operations receive no separate approval. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Run up to sixteen declared inspect operations serially under this one call; inner operations receive no separate approval. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/call_read_tools_batch.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2162) ## Arguments * `onError` optional · string Stop after the first failed operation or continue. * `operations` required · array One to sixteen typed inspect-tool operations. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "onError": { "description": "Stop after the first failed operation or continue.", "enum": [ "continue", "stop" ], "type": "string" }, "operations": { "description": "One to sixteen typed inspect-tool operations.", "items": { "oneOf": [ { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "history": { "description": "Capture retained history as well as the visible pane.", "type": "boolean" }, "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "capture_pane", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "cursor": { "description": "Previously returned byte cursor.", "minimum": 0, "type": "integer" }, "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "capture_since", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "column": { "description": "Zero-based terminal column.", "minimum": 0, "type": "integer" }, "row": { "description": "Zero-based terminal row.", "minimum": 0, "type": "integer" }, "windowId": { "description": "Optional stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "row", "column" ], "type": "object" }, "tool": { "const": "find_pane_by_position", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "get_pane_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": {}, "required": [], "type": "object" }, "tool": { "const": "get_server_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "description": "Stable session ID or name.", "maxLength": 512, "type": "string" } }, "required": [ "session" ], "type": "object" }, "tool": { "const": "get_session_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "names": { "description": "One to thirty-two validated tmux variable names.", "items": { "maxLength": 128, "type": "string" }, "maxItems": 32, "minItems": 1, "type": "array" }, "paneId": { "description": "Optional pane context.", "maxLength": 512, "type": "string" } }, "required": [ "names" ], "type": "object" }, "tool": { "const": "get_tmux_variables", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "windowId": { "description": "Stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "windowId" ], "type": "object" }, "tool": { "const": "get_window_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": {}, "required": [], "type": "object" }, "tool": { "const": "list_panes", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": {}, "required": [], "type": "object" }, "tool": { "const": "list_sessions", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "description": "Stable session ID or name.", "maxLength": 512, "type": "string" } }, "required": [ "session" ], "type": "object" }, "tool": { "const": "list_windows", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "pattern": { "description": "Bounded regular expression.", "maxLength": 256, "type": "string" } }, "required": [ "pattern" ], "type": "object" }, "tool": { "const": "search_panes", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "name": { "description": "Optional exact environment name.", "maxLength": 256, "type": "string" }, "session": { "description": "Optional session target.", "maxLength": 512, "type": "string" } }, "required": [], "type": "object" }, "tool": { "const": "show_environment", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "name": { "description": "Optional exact hook name.", "maxLength": 256, "type": "string" }, "target": { "description": "Optional tmux target.", "maxLength": 512, "type": "string" } }, "required": [], "type": "object" }, "tool": { "const": "show_hooks", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "name": { "description": "Exact option name.", "maxLength": 256, "type": "string" }, "target": { "description": "Optional session, window, or pane target.", "maxLength": 512, "type": "string" } }, "required": [ "name" ], "type": "object" }, "tool": { "const": "show_option", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "snapshot_pane", "type": "string" } }, "required": [ "tool" ], "type": "object" } ] }, "maxItems": 16, "minItems": 1, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Call read tools as a batch" } ``` --- # capture_pane Source: https://libtmux.org/en/cxx/latest/mcp/tools/capture_pane/ > Return visible text, or retained history when requested. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return visible text, or retained history when requested. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/capture_pane.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1836) ## Arguments * `history` optional · boolean Capture retained history as well as the visible pane. * `paneId` required · string Stable pane ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "history": { "description": "Capture retained history as well as the visible pane.", "type": "boolean" }, "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "pane_id": { "pattern": "^%[0-9]+$", "type": "string" }, "text": { "type": "string" } }, "required": [ "pane_id", "text" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Capture a tmux pane" } ``` --- # capture_since Source: https://libtmux.org/en/cxx/latest/mcp/tools/capture_since/ > Return bytes after a bounded client cursor and a replacement cursor. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return bytes after a bounded client cursor and a replacement cursor. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/capture_since.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1858) ## Arguments * `cursor` optional · integer Previously returned byte cursor. * `paneId` required · string Stable pane ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "cursor": { "description": "Previously returned byte cursor.", "minimum": 0, "type": "integer" }, "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Capture new pane output" } ``` --- # clear_pane_scrollback Source: https://libtmux.org/en/cxx/latest/mcp/tools/clear_pane_scrollback/ > Irreversibly discard retained scrollback for one pane. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Irreversibly discard retained scrollback for one pane. Delete tmux state; accepts no command payload. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/clear_pane_scrollback.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L3145) ## Arguments * `paneId` required · string Stable pane ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Clear tmux pane scrollback" } ``` --- # create_session Source: https://libtmux.org/en/cxx/latest/mcp/tools/create_session/ > Create a detached session; names and path data are literalized before tmux expansion. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Create a detached session; names and path data are literalized before tmux expansion. Start a pane’s configured process; accepts no command payload. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/create_session.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2543) ## Arguments * `height` optional · integer Optional detached height. * `name` optional · string Optional literal unique session name. * `startDirectory` optional · string Literal pane start directory. * `width` optional · integer Optional detached width. * `windowName` optional · string Optional literal first window name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "description": "Optional detached height.", "maximum": 100000, "minimum": 1, "type": "integer" }, "name": { "description": "Optional literal unique session name.", "maxLength": 512, "type": "string" }, "startDirectory": { "description": "Literal pane start directory.", "maxLength": 4096, "type": "string" }, "width": { "description": "Optional detached width.", "maximum": 100000, "minimum": 1, "type": "integer" }, "windowName": { "description": "Optional literal first window name.", "maxLength": 512, "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "name": { "type": "string" }, "session_id": { "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "name", "session_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Create a tmux session" } ``` --- # create_window Source: https://libtmux.org/en/cxx/latest/mcp/tools/create_window/ > Create a detached window; name and path data are literalized before tmux expansion. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Create a detached window; name and path data are literalized before tmux expansion. Start a pane’s configured process; accepts no command payload. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/create_window.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2587) ## Arguments * `name` optional · string Optional literal window name. * `session` required · string Stable owning session ID or name. * `startDirectory` optional · string Literal pane start directory. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Optional literal window name.", "maxLength": 512, "type": "string" }, "session": { "description": "Stable owning session ID or name.", "maxLength": 512, "type": "string" }, "startDirectory": { "description": "Literal pane start directory.", "maxLength": 4096, "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "session_id": { "pattern": "^\\$[0-9]+$", "type": "string" }, "window_id": { "pattern": "^@[0-9]+$", "type": "string" } }, "required": [ "session_id", "window_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Create a tmux window" } ``` --- # find_pane_by_position Source: https://libtmux.org/en/cxx/latest/mcp/tools/find_pane_by_position/ > Resolve coordinates using fixed tmux layout fields. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Resolve coordinates using fixed tmux layout fields. Inspect tmux metadata; accepts no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/find_pane_by_position.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1951) ## Arguments * `column` required · integer Zero-based terminal column. * `row` required · integer Zero-based terminal row. * `windowId` optional · string Optional stable window ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "column": { "description": "Zero-based terminal column.", "minimum": 0, "type": "integer" }, "row": { "description": "Zero-based terminal row.", "minimum": 0, "type": "integer" }, "windowId": { "description": "Optional stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "row", "column" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Find a pane by position" } ``` --- # get_pane_info Source: https://libtmux.org/en/cxx/latest/mcp/tools/get_pane_info/ > Return one pane by stable ID. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return one pane by stable ID. Inspect tmux metadata; accepts no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/get_pane_info.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1823) ## Arguments * `paneId` required · string Stable pane ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get tmux pane information" } ``` --- # get_server_info Source: https://libtmux.org/en/cxx/latest/mcp/tools/get_server_info/ > Report liveness, tmux version, and the resolved socket when running. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Report liveness, tmux version, and the resolved socket when running. Inspect tmux metadata; accepts no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/get_server_info.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1761) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get tmux server information" } ``` --- # get_session_info Source: https://libtmux.org/en/cxx/latest/mcp/tools/get_session_info/ > Return one session by stable ID or name. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return one session by stable ID or name. Inspect tmux metadata; accepts no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/get_session_info.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1794) ## Arguments * `session` required · string Stable session ID or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "Stable session ID or name.", "maxLength": 512, "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get tmux session information" } ``` --- # get_tmux_variables Source: https://libtmux.org/en/cxx/latest/mcp/tools/get_tmux_variables/ > Expand only validated variable identifiers, never a caller format. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Expand only validated variable identifiers, never a caller format. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/get_tmux_variables.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2023) ## Arguments * `names` required · array One to thirty-two validated tmux variable names. * `paneId` optional · string Optional pane context. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "names": { "description": "One to thirty-two validated tmux variable names.", "items": { "maxLength": 128, "type": "string" }, "maxItems": 32, "minItems": 1, "type": "array" }, "paneId": { "description": "Optional pane context.", "maxLength": 512, "type": "string" } }, "required": [ "names" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get tmux variables" } ``` --- # get_window_info Source: https://libtmux.org/en/cxx/latest/mcp/tools/get_window_info/ > Return one window by stable ID. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return one window by stable ID. Inspect tmux metadata; accepts no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/get_window_info.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1809) ## Arguments * `windowId` required · string Stable window ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "windowId": { "description": "Stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get tmux window information" } ``` --- # kill_pane Source: https://libtmux.org/en/cxx/latest/mcp/tools/kill_pane/ > Delete one pane and its running process. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete one pane and its running process. Delete tmux state; accepts no command payload. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/kill_pane.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L3161) ## Arguments * `paneId` required · string Stable pane ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill a tmux pane" } ``` --- # kill_session Source: https://libtmux.org/en/cxx/latest/mcp/tools/kill_session/ > Delete one session and every window it owns. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete one session and every window it owns. Delete tmux state; accepts no command payload. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/kill_session.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L3196) ## Arguments * `session` required · string Stable session ID or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "Stable session ID or name.", "maxLength": 512, "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill a tmux session" } ``` --- # kill_window Source: https://libtmux.org/en/cxx/latest/mcp/tools/kill_window/ > Delete one window and every pane it owns. Delete tmux state; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete one window and every pane it owns. Delete tmux state; accepts no command payload. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/kill_window.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L3178) ## Arguments * `windowId` required · string Stable window ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "windowId": { "description": "Stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill a tmux window" } ``` --- # list_panes Source: https://libtmux.org/en/cxx/latest/mcp/tools/list_panes/ > List every pane with stable pane, window, and session IDs. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List every pane with stable pane, window, and session IDs. Inspect tmux metadata; accepts no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/list_panes.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1733) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "panes": { "items": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "command": { "type": "string" }, "dead": { "type": "boolean" }, "height": { "minimum": 0, "type": "integer" }, "id": { "pattern": "^%[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "path": { "type": "string" }, "pid": { "minimum": 0, "type": "integer" }, "session_id": { "pattern": "^\\$[0-9]+$", "type": "string" }, "title": { "type": "string" }, "width": { "minimum": 0, "type": "integer" }, "window_id": { "pattern": "^@[0-9]+$", "type": "string" } }, "required": [ "active", "command", "dead", "height", "id", "index", "path", "pid", "session_id", "title", "width", "window_id" ], "type": "object" }, "type": "array" } }, "required": [ "panes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List tmux panes" } ``` --- # list_sessions Source: https://libtmux.org/en/cxx/latest/mcp/tools/list_sessions/ > List stable session IDs, names, paths, and client counts. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List stable session IDs, names, paths, and client counts. Inspect tmux metadata; accepts no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/list_sessions.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1699) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "sessions": { "items": { "additionalProperties": false, "properties": { "attached": { "type": "boolean" }, "client_count": { "minimum": 0, "type": "integer" }, "id": { "pattern": "^\\$[0-9]+$", "type": "string" }, "name": { "type": "string" }, "path": { "type": "string" }, "window_count": { "minimum": 0, "type": "integer" } }, "required": [ "attached", "client_count", "id", "name", "path", "window_count" ], "type": "object" }, "type": "array" } }, "required": [ "sessions" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List tmux sessions" } ``` --- # list_windows Source: https://libtmux.org/en/cxx/latest/mcp/tools/list_windows/ > List windows through an exact owning session. Inspect tmux metadata; accepts no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. List windows through an exact owning session. Inspect tmux metadata; accepts no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/list_windows.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1708) ## Arguments * `session` required · string Stable session ID or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "Stable session ID or name.", "maxLength": 512, "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "windows": { "items": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "height": { "minimum": 0, "type": "integer" }, "id": { "pattern": "^@[0-9]+$", "type": "string" }, "index": { "type": "integer" }, "layout": { "type": "string" }, "name": { "type": "string" }, "pane_count": { "minimum": 0, "type": "integer" }, "session_id": { "pattern": "^\\$[0-9]+$", "type": "string" }, "width": { "minimum": 0, "type": "integer" } }, "required": [ "active", "height", "id", "index", "layout", "name", "pane_count", "session_id", "width" ], "type": "object" }, "type": "array" } }, "required": [ "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List tmux windows" } ``` --- # move_window Source: https://libtmux.org/en/cxx/latest/mcp/tools/move_window/ > Move a window to an exact index in its owning session. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Move a window to an exact index in its owning session. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/move_window.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2417) ## Arguments * `index` required · integer Non-negative destination index. * `windowId` required · string Stable window ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "index": { "description": "Non-negative destination index.", "maximum": 100000, "minimum": 0, "type": "integer" }, "windowId": { "description": "Stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "windowId", "index" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Move a tmux window" } ``` --- # paste_text Source: https://libtmux.org/en/cxx/latest/mcp/tools/paste_text/ > Require the target pane to be live and outside human-owned mode, then stage a private target-only buffer, optionally append Enter, paste it once, and verify cleanup. Empty text without Enter is a guarded buffer-free no-op. Send input to a pane's program; a shell that receives it runs it with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Require the target pane to be live and outside human-owned mode, then stage a private target-only buffer, optionally append Enter, paste it once, and verify cleanup. Empty text without Enter is a guarded buffer-free no-op. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/paste_text.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L3008) ## Arguments * `enter` optional · boolean Append Enter to the same private paste buffer. * `paneId` required · string Stable pane ID. * `text` required · string Literal text to paste. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enter": { "description": "Append Enter to the same private paste buffer.", "type": "boolean" }, "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" }, "text": { "description": "Literal text to paste.", "maxLength": 1048576, "type": "string" } }, "required": [ "paneId", "text" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "changed": { "type": "boolean" }, "pane_id": { "pattern": "^%[0-9]+$", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Paste text into a tmux pane" } ``` --- # rename_session Source: https://libtmux.org/en/cxx/latest/mcp/tools/rename_session/ > Replace one session name. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replace one session name. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/rename_session.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2269) ## Arguments * `name` required · string Literal replacement session name. * `session` required · string Stable session ID or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Literal replacement session name.", "maxLength": 512, "type": "string" }, "session": { "description": "Stable session ID or name.", "maxLength": 512, "type": "string" } }, "required": [ "session", "name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Rename a tmux session" } ``` --- # rename_window Source: https://libtmux.org/en/cxx/latest/mcp/tools/rename_window/ > Replace one window name. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replace one window name. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/rename_window.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2288) ## Arguments * `name` required · string Literal replacement window name. * `windowId` required · string Stable window ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Literal replacement window name.", "maxLength": 512, "type": "string" }, "windowId": { "description": "Stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "windowId", "name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Rename a tmux window" } ``` --- # resize_pane Source: https://libtmux.org/en/cxx/latest/mcp/tools/resize_pane/ > Replace one or both pane dimensions. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replace one or both pane dimensions. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/resize_pane.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2383) ## Arguments * `height` optional · integer Optional positive pane height. * `paneId` required · string Stable pane ID. * `width` optional · integer Optional positive pane width. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "description": "Optional positive pane height.", "maximum": 100000, "minimum": 1, "type": "integer" }, "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" }, "width": { "description": "Optional positive pane width.", "maximum": 100000, "minimum": 1, "type": "integer" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Resize a tmux pane" } ``` --- # resize_window Source: https://libtmux.org/en/cxx/latest/mcp/tools/resize_window/ > Replace one window's dimensions. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replace one window’s dimensions. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/resize_window.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2362) ## Arguments * `height` required · integer Positive window height. * `width` required · integer Positive window width. * `windowId` required · string Stable window ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "description": "Positive window height.", "maximum": 100000, "minimum": 1, "type": "integer" }, "width": { "description": "Positive window width.", "maximum": 100000, "minimum": 1, "type": "integer" }, "windowId": { "description": "Stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "windowId", "width", "height" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Resize a tmux window" } ``` --- # respawn_pane Source: https://libtmux.org/en/cxx/latest/mcp/tools/respawn_pane/ > Restart only the pane's configured process; no caller command is accepted. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Restart only the pane’s configured process; no caller command is accepted. Start a pane’s configured process; accepts no command payload. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/respawn_pane.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2658) ## Arguments * `force` optional · boolean Permit replacing a running pane process. * `killFirst` optional · boolean Kill a running pane process before respawn. * `paneId` required · string Stable pane ID. * `startDirectory` optional · string Literal replacement start directory. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "force": { "description": "Permit replacing a running pane process.", "type": "boolean" }, "killFirst": { "description": "Kill a running pane process before respawn.", "type": "boolean" }, "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" }, "startDirectory": { "description": "Literal replacement start directory.", "maxLength": 4096, "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "changed": { "type": "boolean" }, "pane_id": { "pattern": "^%[0-9]+$", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Respawn a tmux pane" } ``` --- # run_shell_command Source: https://libtmux.org/en/cxx/latest/mcp/tools/run_shell_command/ > Require one live configured pane, outside human-owned mode and running a supported POSIX foreground shell, then send one command and return output after its private completion boundary. Run a shell command in a pane with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Require one live configured pane, outside human-owned mode and running a supported POSIX foreground shell, then send one command and return output after its private completion boundary. Run a shell command in a pane with your user’s permissions. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/run_shell_command.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2689) ## Arguments * `command` required · string Shell command sent to the pane. * `paneId` required · string Stable pane ID. * `timeoutMs` optional · integer Completion timeout in milliseconds. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "command": { "description": "Shell command sent to the pane.", "maxLength": 1048576, "type": "string" }, "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" }, "timeoutMs": { "description": "Completion timeout in milliseconds.", "maximum": 60000, "minimum": 1, "type": "integer" } }, "required": [ "paneId", "command" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Run a shell command in a tmux pane" } ``` --- # search_panes Source: https://libtmux.org/en/cxx/latest/mcp/tools/search_panes/ > Search captured lines using a length-limited expression. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Search captured lines using a length-limited expression. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/search_panes.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1906) ## Arguments * `pattern` required · string Bounded regular expression. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "pattern": { "description": "Bounded regular expression.", "maxLength": 256, "type": "string" } }, "required": [ "pattern" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "matches": { "items": { "additionalProperties": false, "properties": { "line": { "type": "string" }, "pane_id": { "pattern": "^%[0-9]+$", "type": "string" } }, "required": [ "line", "pane_id" ], "type": "object" }, "type": "array" } }, "required": [ "matches" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Search tmux panes" } ``` --- # select_layout Source: https://libtmux.org/en/cxx/latest/mcp/tools/select_layout/ > Replace the pane layout of one window. Names and mirrored layouts follow the selected daemon version. Saved layouts accept v1 checksums and v2 JSON; v2 requires tmux 3.8 (including 3.8-rc) or newer. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replace the pane layout of one window. Names and mirrored layouts follow the selected daemon version. Saved layouts accept v1 checksums and v2 JSON; v2 requires tmux 3.8 (including 3.8-rc) or newer. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/select_layout.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2339) ## Arguments * `layout` required · string Built-in name, unambiguous abbreviation or saved tmux layout. * `windowId` required · string Stable window ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "layout": { "description": "Built-in name, unambiguous abbreviation or saved tmux layout.", "maxLength": 4096, "type": "string" }, "windowId": { "description": "Stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "windowId", "layout" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select a tmux layout" } ``` --- # select_pane Source: https://libtmux.org/en/cxx/latest/mcp/tools/select_pane/ > Make one pane active. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Make one pane active. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/select_pane.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2323) ## Arguments * `paneId` required · string Stable pane ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select a tmux pane" } ``` --- # select_window Source: https://libtmux.org/en/cxx/latest/mcp/tools/select_window/ > Make one window active. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Make one window active. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/select_window.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2307) ## Arguments * `windowId` required · string Stable window ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "windowId": { "description": "Stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select a tmux window" } ``` --- # send_keys Source: https://libtmux.org/en/cxx/latest/mcp/tools/send_keys/ > Require every configured synchronized pane to be live and outside human-owned mode, then send one validated tmux key name. Send input to a pane's program; a shell that receives it runs it with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Require every configured synchronized pane to be live and outside human-owned mode, then send one validated tmux key name. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/send_keys.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2803) ## Arguments * `keys` required · string One tmux key name. * `paneId` required · string Stable pane ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "keys": { "description": "One tmux key name.", "maxLength": 256, "type": "string" }, "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId", "keys" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "pane_id": { "pattern": "^%[0-9]+$", "type": "string" }, "target_pane_ids": { "items": { "pattern": "^%[0-9]+$", "type": "string" }, "type": "array" } }, "required": [ "pane_id", "target_pane_ids" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Send keys to a tmux pane" } ``` --- # send_keys_batch Source: https://libtmux.org/en/cxx/latest/mcp/tools/send_keys_batch/ > Preflight each row's configured synchronized pane cohort independently, requiring every pane to be live and outside human-owned mode before its text or key and optional Enter. Send input to a pane's program; a shell that receives it runs it with your user's permissions. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Preflight each row’s configured synchronized pane cohort independently, requiring every pane to be live and outside human-owned mode before its text or key and optional Enter. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/send_keys_batch.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2876) ## Arguments * `onError` optional · string Stop after the first failed operation or continue. * `operations` required · array One to sixty-four ordered pane-input operations. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "onError": { "description": "Stop after the first failed operation or continue.", "enum": [ "continue", "stop" ], "type": "string" }, "operations": { "description": "One to sixty-four ordered pane-input operations.", "items": { "additionalProperties": false, "properties": { "enter": { "type": "boolean" }, "keys": { "maxLength": 4096, "type": "string" }, "literal": { "type": "boolean" }, "paneId": { "maxLength": 512, "type": "string" } }, "required": [ "paneId", "keys" ], "type": "object" }, "maxItems": 64, "minItems": 1, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Send a key sequence to a tmux pane" } ``` --- # set_history_limit Source: https://libtmux.org/en/cxx/latest/mcp/tools/set_history_limit/ > Replace retained-history bounds with a non-negative integer. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replace retained-history bounds with a non-negative integer. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/set_history_limit.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2523) ## Arguments * `limit` required · integer Retained history line limit. * `session` required · string Stable session ID or name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "limit": { "description": "Retained history line limit.", "maximum": 10000000, "minimum": 0, "type": "integer" }, "session": { "description": "Stable session ID or name.", "maxLength": 512, "type": "string" } }, "required": [ "session", "limit" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set tmux history limit" } ``` --- # set_mouse_enabled Source: https://libtmux.org/en/cxx/latest/mcp/tools/set_mouse_enabled/ > Replace the global mouse option with a typed boolean. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replace the global mouse option with a typed boolean. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/set_mouse_enabled.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2510) ## Arguments * `enabled` required · boolean Whether mouse handling is enabled. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enabled": { "description": "Whether mouse handling is enabled.", "type": "boolean" } }, "required": [ "enabled" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set tmux mouse handling" } ``` --- # set_pane_title Source: https://libtmux.org/en/cxx/latest/mcp/tools/set_pane_title/ > Replace one pane title. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Replace one pane title. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/set_pane_title.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2457) ## Arguments * `paneId` required · string Stable pane ID. * `title` required · string Literal replacement pane title. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" }, "title": { "description": "Literal replacement pane title.", "maxLength": 4096, "type": "string" } }, "required": [ "paneId", "title" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set a tmux pane title" } ``` --- # set_synchronize_panes Source: https://libtmux.org/en/cxx/latest/mcp/tools/set_synchronize_panes/ > Set the inherited window synchronize-panes default; pane-level overrides determine effective synchronized input membership. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Set the inherited window synchronize-panes default; pane-level overrides determine effective synchronized input membership. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/set_synchronize_panes.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L3106) ## Arguments * `enabled` required · boolean Whether later pane input is duplicated. * `windowId` required · string Stable window ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enabled": { "description": "Whether later pane input is duplicated.", "type": "boolean" }, "windowId": { "description": "Stable window ID.", "maxLength": 512, "type": "string" } }, "required": [ "windowId", "enabled" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set synchronized pane input" } ``` --- # show_environment Source: https://libtmux.org/en/cxx/latest/mcp/tools/show_environment/ > Read global or session environment values. Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read global or session environment values. Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/show_environment.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2097) ## Arguments * `name` optional · string Optional exact environment name. * `session` optional · string Optional session target. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Optional exact environment name.", "maxLength": 256, "type": "string" }, "session": { "description": "Optional session target.", "maxLength": 512, "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show the tmux environment" } ``` --- # show_hooks Source: https://libtmux.org/en/cxx/latest/mcp/tools/show_hooks/ > Read configured hooks, optionally filtered by exact name. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured hooks, optionally filtered by exact name. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/show_hooks.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2136) ## Arguments * `name` optional · string Optional exact hook name. * `target` optional · string Optional tmux target. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Optional exact hook name.", "maxLength": 256, "type": "string" }, "target": { "description": "Optional tmux target.", "maxLength": 512, "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show tmux hooks" } ``` --- # show_option Source: https://libtmux.org/en/cxx/latest/mcp/tools/show_option/ > Read one exact option without accepting an option value. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read one exact option without accepting an option value. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/show_option.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2072) ## Arguments * `name` required · string Exact option name. * `target` optional · string Optional session, window, or pane target. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Exact option name.", "maxLength": 256, "type": "string" }, "target": { "description": "Optional session, window, or pane target.", "maxLength": 512, "type": "string" } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show a tmux option" } ``` --- # signal_channel Source: https://libtmux.org/en/cxx/latest/mcp/tools/signal_channel/ > Release or latch one named server-side channel. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Release or latch one named server-side channel. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/signal_channel.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2496) ## Arguments * `channel` required · string Bounded channel name. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "Bounded channel name.", "maxLength": 256, "type": "string" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Signal a tmux channel" } ``` --- # snapshot_pane Source: https://libtmux.org/en/cxx/latest/mcp/tools/snapshot_pane/ > Return pane metadata and visible terminal content from one call. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Return pane metadata and visible terminal content from one call. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/snapshot_pane.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L1887) ## Arguments * `paneId` required · string Stable pane ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "Stable pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Snapshot a tmux pane" } ``` --- # split_window Source: https://libtmux.org/en/cxx/latest/mcp/tools/split_window/ > Create a configured-process pane; path data is literalized before tmux expansion. Start a pane's configured process; accepts no command payload. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Create a configured-process pane; path data is literalized before tmux expansion. Start a pane’s configured process; accepts no command payload. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/split_window.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2622) ## Arguments * `direction` optional · string vertical or horizontal. * `paneId` required · string Stable pane to split. * `startDirectory` optional · string Literal pane start directory. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "direction": { "description": "vertical or horizontal.", "maxLength": 16, "type": "string" }, "paneId": { "description": "Stable pane to split.", "maxLength": 512, "type": "string" }, "startDirectory": { "description": "Literal pane start directory.", "maxLength": 4096, "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "changed": { "type": "boolean" }, "pane_id": { "pattern": "^%[0-9]+$", "type": "string" } }, "required": [ "pane_id" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Split a tmux window" } ``` --- # swap_pane Source: https://libtmux.org/en/cxx/latest/mcp/tools/swap_pane/ > Exchange two pane positions without changing their IDs. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Exchange two pane positions without changing their IDs. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/swap_pane.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2435) ## Arguments * `sourcePaneId` required · string Stable source pane ID. * `targetPaneId` required · string Stable target pane ID. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "sourcePaneId": { "description": "Stable source pane ID.", "maxLength": 512, "type": "string" }, "targetPaneId": { "description": "Stable target pane ID.", "maxLength": 512, "type": "string" } }, "required": [ "sourcePaneId", "targetPaneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Swap two tmux panes" } ``` --- # wait_for_channel Source: https://libtmux.org/en/cxx/latest/mcp/tools/wait_for_channel/ > Wait for a named server-side channel with an optional deadline. Change tmux state; no client-supplied executable input. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Wait for a named server-side channel with an optional deadline. Change tmux state; no client-supplied executable input. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/wait_for_channel.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2476) ## Arguments * `channel` required · string Bounded channel name. * `timeoutMs` optional · integer Optional bounded wait in milliseconds. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "Bounded channel name.", "maxLength": 256, "type": "string" }, "timeoutMs": { "description": "Optional bounded wait in milliseconds.", "maximum": 60000, "minimum": 1, "type": "integer" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "additionalProperties": true, "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Wait for a tmux channel" } ``` --- # wait_for_text Source: https://libtmux.org/en/cxx/latest/mcp/tools/wait_for_text/ > Discount this server's pending input and recent submitted echoes; unmodelled keys stop tracking the current line. Wait for a new shell's prompt before typing. `matched_at_entry` reports visible text at entry; a mode ending in -unconfirmed identifies input that was still unconfirmed at the deadline. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Discount this server’s pending input and recent submitted echoes; unmodelled keys stop tracking the current line. Wait for a new shell’s prompt before typing. `matched_at_entry` reports visible text at entry; a mode ending in -unconfirmed identifies input that was still unconfirmed at the deadline. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. [All C++ tools](https://libtmux.org/en/cxx/latest/mcp/tools/) · [JSON](https://libtmux.org/en/cxx/latest/mcp/tools/wait_for_text.json) · [Source](https://github.com/libtmux/libtmux-cxx/blob/3f93b021cb51e8349bfb9cecc6fd4091f6e79a0f/apps/mcp/src/tool_catalog.cpp#L2006) ## Arguments * `target` required · string Pane ID or pane target. * `text` required · string Literal text to wait for. * `timeout_ms` optional · integer Bounded wait in milliseconds. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "target": { "description": "Pane ID or pane target.", "maxLength": 512, "type": "string" }, "text": { "description": "Literal text to wait for.", "maxLength": 4096, "type": "string" }, "timeout_ms": { "description": "Bounded wait in milliseconds.", "maximum": 60000, "minimum": 1, "type": "integer" } }, "required": [ "target", "text" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "elapsed_ms": { "minimum": 0, "type": "integer" }, "matched": { "type": "boolean" }, "matched_at_entry": { "type": "boolean" }, "mode": { "type": "string" }, "pane_id": { "pattern": "^%[0-9]+$", "type": "string" }, "text": { "type": "string" }, "timed_out": { "type": "boolean" } }, "required": [ "elapsed_ms", "matched", "matched_at_entry", "mode", "text", "timed_out" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Wait for pane text" } ``` --- # Swift MCP tools Source: https://libtmux.org/en/swift/latest/mcp/tools/ > Tools, resources, and prompts advertised by the Swift MCP server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Use the wire name shown here when calling a tool. The Swift server advertises 45 tools with the reference configuration below. Your client’s list follows the policy configured for its server. Read the [setup guide](https://libtmux.org/en/swift/latest/mcp/guides/) before choosing tool access. The [language API reference](https://libtmux.org/en/swift/latest/mcp/reference/) covers embedding and implementation types. [Download the protocol catalog as JSON](https://libtmux.org/en/swift/latest/mcp/tools.json). Reference configuration * `LIBTMUX_TOOLSETS` `inspect,manage,execute,teardown` Protocol version: `2025-11-25`. ## Tools * [`call_read_tools_batch`](https://libtmux.org/en/swift/latest/mcp/tools/call_read_tools_batch/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Invoke a serial batch of at most 16 inspect tools. One client approval covers every nested name; inner tools receive no separate approval. Retained rows contain full nested envelopes; oversized results are marked resultTruncated, and the response stays below the 1,000,000-byte wire cap. * [`capture_pane`](https://libtmux.org/en/swift/latest/mcp/tools/capture_pane/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return a bounded slice of rendered pane text. * [`capture_since`](https://libtmux.org/en/swift/latest/mcp/tools/capture_since/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return output after an opaque pane cursor. * [`clear_pane_scrollback`](https://libtmux.org/en/swift/latest/mcp/tools/clear_pane_scrollback/) Delete tmux state; accepts no command payload. Irreversibly discard retained scrollback for one pane. * [`create_session`](https://libtmux.org/en/swift/latest/mcp/tools/create_session/) Start a pane's configured process; accepts no command payload. Create a detached session with a configured pane process. * [`create_window`](https://libtmux.org/en/swift/latest/mcp/tools/create_window/) Start a pane's configured process; accepts no command payload. Create a window with a configured pane process. * [`find_pane_by_position`](https://libtmux.org/en/swift/latest/mcp/tools/find_pane_by_position/) Inspect tmux metadata; accepts no client-supplied executable input. Find a pane occupying a named window corner. * [`get_pane_info`](https://libtmux.org/en/swift/latest/mcp/tools/get_pane_info/) Inspect tmux metadata; accepts no client-supplied executable input. Return metadata for one pane. * [`get_server_info`](https://libtmux.org/en/swift/latest/mcp/tools/get_server_info/) Inspect tmux metadata; accepts no client-supplied executable input. Return liveness and identity metadata for the selected tmux server. * [`get_session_info`](https://libtmux.org/en/swift/latest/mcp/tools/get_session_info/) Inspect tmux metadata; accepts no client-supplied executable input. Return metadata for one session. * [`get_tmux_variables`](https://libtmux.org/en/swift/latest/mcp/tools/get_tmux_variables/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Resolve validated variable names without accepting raw format syntax. * [`get_window_info`](https://libtmux.org/en/swift/latest/mcp/tools/get_window_info/) Inspect tmux metadata; accepts no client-supplied executable input. Return metadata and placements for one window. * [`kill_pane`](https://libtmux.org/en/swift/latest/mcp/tools/kill_pane/) Delete tmux state; accepts no command payload. Delete one pane and its running process. * [`kill_session`](https://libtmux.org/en/swift/latest/mcp/tools/kill_session/) Delete tmux state; accepts no command payload. Delete one session and every window it owns. * [`kill_window`](https://libtmux.org/en/swift/latest/mcp/tools/kill_window/) Delete tmux state; accepts no command payload. Delete one window and every pane it owns. * [`list_panes`](https://libtmux.org/en/swift/latest/mcp/tools/list_panes/) Inspect tmux metadata; accepts no client-supplied executable input. List panes, optionally within a session or window. * [`list_sessions`](https://libtmux.org/en/swift/latest/mcp/tools/list_sessions/) Inspect tmux metadata; accepts no client-supplied executable input. List sessions on the selected server. * [`list_windows`](https://libtmux.org/en/swift/latest/mcp/tools/list_windows/) Inspect tmux metadata; accepts no client-supplied executable input. List windows, optionally within one session. * [`move_window`](https://libtmux.org/en/swift/latest/mcp/tools/move_window/) Change tmux state; no client-supplied executable input. Move one window appearance to another session. * [`paste_text`](https://libtmux.org/en/swift/latest/mcp/tools/paste_text/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Paste literal text and an optional newline target-only after two state checks. * [`rename_session`](https://libtmux.org/en/swift/latest/mcp/tools/rename_session/) Change tmux state; no client-supplied executable input. Set a literal-safe session name. * [`rename_window`](https://libtmux.org/en/swift/latest/mcp/tools/rename_window/) Change tmux state; no client-supplied executable input. Set a literal-safe window name. * [`resize_pane`](https://libtmux.org/en/swift/latest/mcp/tools/resize_pane/) Change tmux state; no client-supplied executable input. Resize one pane by dimensions or a directional amount. * [`resize_window`](https://libtmux.org/en/swift/latest/mcp/tools/resize_window/) Change tmux state; no client-supplied executable input. Resize the terminal dimensions reported for one window. * [`respawn_pane`](https://libtmux.org/en/swift/latest/mcp/tools/respawn_pane/) Start a pane's configured process; accepts no command payload. Restart only the pane's configured process; no caller command is accepted. * [`run_shell_command`](https://libtmux.org/en/swift/latest/mcp/tools/run_shell_command/) Run a shell command in a pane with your user's permissions. Run one command in a singular trusted POSIX shell and return bounded output. * [`search_panes`](https://libtmux.org/en/swift/latest/mcp/tools/search_panes/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Search bounded pane content for literal text or a regular expression. * [`select_layout`](https://libtmux.org/en/swift/latest/mcp/tools/select_layout/) Change tmux state; no client-supplied executable input. Apply a named layout, a unique abbreviation for the running tmux version, or a checksummed saved layout. Invalid syntax is refused before window lookup; tmux validates geometry when applying the layout. * [`select_pane`](https://libtmux.org/en/swift/latest/mcp/tools/select_pane/) Change tmux state; no client-supplied executable input. Select one pane as active. * [`select_window`](https://libtmux.org/en/swift/latest/mcp/tools/select_window/) Change tmux state; no client-supplied executable input. Select one exact window appearance. * [`send_keys`](https://libtmux.org/en/swift/latest/mcp/tools/send_keys/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send keys after checking the effective synchronized-pane cohort. * [`send_keys_batch`](https://libtmux.org/en/swift/latest/mcp/tools/send_keys_batch/) Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send an ordered bounded batch with a fresh check for every row. * [`set_history_limit`](https://libtmux.org/en/swift/latest/mcp/tools/set_history_limit/) Change tmux state; no client-supplied executable input. Set the default retained scrollback line limit. * [`set_mouse_enabled`](https://libtmux.org/en/swift/latest/mcp/tools/set_mouse_enabled/) Change tmux state; no client-supplied executable input. Set the global tmux mouse option through a boolean. * [`set_pane_title`](https://libtmux.org/en/swift/latest/mcp/tools/set_pane_title/) Change tmux state; no client-supplied executable input. Set one literal-safe pane title. * [`set_synchronize_panes`](https://libtmux.org/en/swift/latest/mcp/tools/set_synchronize_panes/) Change tmux state; no client-supplied executable input. Set the window input default; pane overrides determine effective synchronization. * [`show_environment`](https://libtmux.org/en/swift/latest/mcp/tools/show_environment/) Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. Read global or session tmux environment values. * [`show_hooks`](https://libtmux.org/en/swift/latest/mcp/tools/show_hooks/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read configured hooks, optionally for one session. * [`show_option`](https://libtmux.org/en/swift/latest/mcp/tools/show_option/) Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read one exact tmux option. * [`signal_channel`](https://libtmux.org/en/swift/latest/mcp/tools/signal_channel/) Change tmux state; no client-supplied executable input. Signal one tmux wait-for channel. * [`snapshot_pane`](https://libtmux.org/en/swift/latest/mcp/tools/snapshot_pane/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return pane metadata and bounded terminal content together. * [`split_window`](https://libtmux.org/en/swift/latest/mcp/tools/split_window/) Start a pane's configured process; accepts no command payload. Create a configured-process pane without accepting command or environment data. * [`swap_pane`](https://libtmux.org/en/swift/latest/mcp/tools/swap_pane/) Change tmux state; no client-supplied executable input. Swap two panes without changing their identities. * [`wait_for_channel`](https://libtmux.org/en/swift/latest/mcp/tools/wait_for_channel/) Change tmux state; no client-supplied executable input. Wait within one deadline for a tmux channel signal. * [`wait_for_text`](https://libtmux.org/en/swift/latest/mcp/tools/wait_for_text/) Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Wait within one deadline for pane text. ## Resources * `tmux://capabilities` The frozen tool surface, capability declarations, socket selection, and provenance. ## Resource templates This server does not advertise resource templates in this configuration. ## Prompts This server does not advertise prompts in this configuration. Source revision: [libtmux/libtmux-swift@7993e7044347629b08020e9b02ae8bcffa0e5898](https://github.com/libtmux/libtmux-swift/tree/7993e7044347629b08020e9b02ae8bcffa0e5898). --- # call_read_tools_batch Source: https://libtmux.org/en/swift/latest/mcp/tools/call_read_tools_batch/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Invoke a serial batch of at most 16 inspect tools. One client approval covers every nested name; inner tools receive no separate approval. Retained rows contain full nested envelopes; oversized results are marked resultTruncated, and the response stays below the 1,000,000-byte wire cap. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Invoke a serial batch of at most 16 inspect tools. One client approval covers every nested name; inner tools receive no separate approval. Retained rows contain full nested envelopes; oversized results are marked resultTruncated, and the response stays below the 1,000,000-byte wire cap. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/call_read_tools_batch.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L3) ## Arguments * `onError` optional · string Caller-controlled onError. * `operations` required · array Caller-controlled operations. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "onError": { "description": "Caller-controlled onError.", "enum": [ "stop", "continue" ], "type": "string" }, "operations": { "description": "Caller-controlled operations.", "items": { "oneOf": [ { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "end": { "description": "Caller-controlled end.", "maximum": 32767, "minimum": -2147483648, "type": "integer" }, "joinWrapped": { "description": "Caller-controlled joinWrapped.", "type": "boolean" }, "maxLines": { "description": "Caller-controlled maxLines.", "maximum": 2000, "minimum": 1, "type": "integer" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "start": { "description": "Caller-controlled start.", "maximum": 32767, "minimum": -2147483648, "type": "integer" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "capture_pane", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "cursor": { "description": "Caller-controlled cursor.", "maxLength": 16384, "type": "string" }, "maxLines": { "description": "Caller-controlled maxLines.", "maximum": 2000, "minimum": 1, "type": "integer" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "waitMs": { "description": "Caller-controlled waitMs.", "maximum": 10000, "minimum": 0, "type": "integer" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "capture_since", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "corner": { "description": "Caller-controlled corner.", "enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ], "type": "string" }, "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "corner", "windowId" ], "type": "object" }, "tool": { "const": "find_pane_by_position", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "get_pane_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": {}, "required": [], "type": "object" }, "tool": { "const": "get_server_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [ "session" ], "type": "object" }, "tool": { "const": "get_session_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "names": { "description": "Caller-controlled names.", "items": { "pattern": "^[A-Za-z][A-Za-z0-9_]*$", "type": "string" }, "maxItems": 32, "type": "array" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "names" ], "type": "object" }, "tool": { "const": "get_tmux_variables", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "windowId" ], "type": "object" }, "tool": { "const": "get_window_info", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "description": "Caller-controlled session.", "type": "string" }, "window": { "description": "Caller-controlled window.", "type": "string" } }, "required": [], "type": "object" }, "tool": { "const": "list_panes", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": {}, "required": [], "type": "object" }, "tool": { "const": "list_sessions", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [], "type": "object" }, "tool": { "const": "list_windows", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "maxMatchesPerPane": { "description": "Caller-controlled maxMatchesPerPane.", "maximum": 200, "minimum": 1, "type": "integer" }, "pattern": { "description": "Caller-controlled pattern.", "type": "string", "x-libtmux-max-utf8-bytes": 4096 }, "regex": { "description": "Caller-controlled regex.", "type": "boolean" }, "scrollbackLines": { "description": "Caller-controlled scrollbackLines.", "maximum": 2000, "minimum": 1, "type": "integer" }, "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [ "pattern" ], "type": "object" }, "tool": { "const": "search_panes", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [], "type": "object" }, "tool": { "const": "show_environment", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [], "type": "object" }, "tool": { "const": "show_hooks", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "name": { "description": "Caller-controlled name.", "type": "string" }, "scope": { "description": "Caller-controlled scope.", "enum": [ "server", "global_session", "global_window", "session", "window", "pane" ], "type": "string" }, "target": { "description": "Caller-controlled target.", "type": "string" } }, "required": [ "name" ], "type": "object" }, "tool": { "const": "show_option", "type": "string" } }, "required": [ "tool" ], "type": "object" }, { "additionalProperties": false, "properties": { "arguments": { "additionalProperties": false, "properties": { "maxLines": { "description": "Caller-controlled maxLines.", "maximum": 2000, "minimum": 1, "type": "integer" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "paneId" ], "type": "object" }, "tool": { "const": "snapshot_pane", "type": "string" } }, "required": [ "tool" ], "type": "object" } ] }, "maxItems": 16, "minItems": 1, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "failed": { "type": "integer" }, "onError": { "type": "string" }, "results": { "items": { "additionalProperties": false, "properties": { "error": { "type": [ "string", "null" ] }, "index": { "type": "integer" }, "result": { "additionalProperties": false, "properties": { "content": { "items": { "additionalProperties": false, "properties": { "text": { "type": "string" }, "type": { "type": "string" } }, "required": [ "text", "type" ], "type": "object" }, "type": "array" }, "isError": { "type": "boolean" }, "structuredContent": {} }, "required": [ "content", "structuredContent", "isError" ], "type": [ "object", "null" ] }, "resultTruncated": { "type": "boolean" }, "success": { "type": "boolean" }, "tool": { "type": "string" } }, "required": [ "error", "index", "result", "resultTruncated", "success", "tool" ], "type": "object" }, "type": "array" }, "stoppedAt": { "type": [ "integer", "null" ] }, "succeeded": { "type": "integer" }, "truncated": { "type": "boolean" }, "truncatedBytes": { "type": "integer" } }, "required": [ "failed", "onError", "results", "stoppedAt", "succeeded", "truncated", "truncatedBytes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Call read tools batch" } ``` --- # capture_pane Source: https://libtmux.org/en/swift/latest/mcp/tools/capture_pane/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return a bounded slice of rendered pane text. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return a bounded slice of rendered pane text. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/capture_pane.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L4) ## Arguments * `end` optional · integer Caller-controlled end. * `joinWrapped` optional · boolean Caller-controlled joinWrapped. * `maxLines` optional · integer Caller-controlled maxLines. * `paneId` required · string Caller-controlled paneId. * `start` optional · integer Caller-controlled start. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "end": { "description": "Caller-controlled end.", "maximum": 32767, "minimum": -2147483648, "type": "integer" }, "joinWrapped": { "description": "Caller-controlled joinWrapped.", "type": "boolean" }, "maxLines": { "description": "Caller-controlled maxLines.", "maximum": 2000, "minimum": 1, "type": "integer" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "start": { "description": "Caller-controlled start.", "maximum": 32767, "minimum": -2147483648, "type": "integer" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "droppedLines": { "type": "integer" }, "lines": { "items": { "type": "string" }, "type": "array" }, "paneId": { "type": "string" } }, "required": [ "droppedLines", "lines", "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Capture pane" } ``` --- # capture_since Source: https://libtmux.org/en/swift/latest/mcp/tools/capture_since/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return output after an opaque pane cursor. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return output after an opaque pane cursor. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/capture_since.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L5) ## Arguments * `cursor` optional · string Caller-controlled cursor. * `maxLines` optional · integer Caller-controlled maxLines. * `paneId` required · string Caller-controlled paneId. * `waitMs` optional · integer Caller-controlled waitMs. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "cursor": { "description": "Caller-controlled cursor.", "maxLength": 16384, "type": "string" }, "maxLines": { "description": "Caller-controlled maxLines.", "maximum": 2000, "minimum": 1, "type": "integer" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "waitMs": { "description": "Caller-controlled waitMs.", "maximum": 10000, "minimum": 0, "type": "integer" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "cursor": { "type": "string" }, "droppedLines": { "type": "integer" }, "lines": { "items": { "type": "string" }, "type": "array" }, "linesMissed": { "type": "boolean" }, "pane": { "type": "string" }, "paneRef": { "type": "string" }, "restarted": { "type": "boolean" } }, "required": [ "cursor", "droppedLines", "lines", "linesMissed", "pane", "paneRef", "restarted" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Capture since" } ``` --- # clear_pane_scrollback Source: https://libtmux.org/en/swift/latest/mcp/tools/clear_pane_scrollback/ > Delete tmux state; accepts no command payload. Irreversibly discard retained scrollback for one pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Irreversibly discard retained scrollback for one pane. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/clear_pane_scrollback.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L47) ## Arguments * `paneId` required · string Caller-controlled paneId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "deleted": { "type": "boolean" }, "paneId": { "type": "string" } }, "required": [ "deleted", "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Clear pane scrollback" } ``` --- # create_session Source: https://libtmux.org/en/swift/latest/mcp/tools/create_session/ > Start a pane's configured process; accepts no command payload. Create a detached session with a configured pane process. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Create a detached session with a configured pane process. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/create_session.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L37) ## Arguments * `height` optional · integer Caller-controlled height. * `name` required · string Caller-controlled name. * `startDirectory` optional · string Caller-controlled startDirectory. * `width` optional · integer Caller-controlled width. * `windowName` optional · string Caller-controlled windowName. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "description": "Caller-controlled height.", "minimum": 1, "type": "integer" }, "name": { "description": "Caller-controlled name.", "type": "string" }, "startDirectory": { "description": "Caller-controlled startDirectory.", "type": "string" }, "width": { "description": "Caller-controlled width.", "minimum": 1, "type": "integer" }, "windowName": { "description": "Caller-controlled windowName.", "type": "string" } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "createdAt": { "type": "integer" }, "id": { "type": "string" }, "isAttached": { "type": "boolean" }, "name": { "type": "string" }, "ref": { "type": "string" }, "windowCount": { "type": "integer" } }, "required": [ "createdAt", "id", "isAttached", "name", "ref", "windowCount" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Create session" } ``` --- # create_window Source: https://libtmux.org/en/swift/latest/mcp/tools/create_window/ > Start a pane's configured process; accepts no command payload. Create a window with a configured pane process. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Create a window with a configured pane process. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/create_window.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L38) ## Arguments * `name` optional · string Caller-controlled name. * `session` required · string Caller-controlled session. * `startDirectory` optional · string Caller-controlled startDirectory. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Caller-controlled name.", "type": "string" }, "session": { "description": "Caller-controlled session.", "type": "string" }, "startDirectory": { "description": "Caller-controlled startDirectory.", "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isActive": { "type": "boolean" }, "linkRef": { "type": "string" }, "name": { "type": "string" }, "paneCount": { "type": "integer" }, "sessionID": { "type": "string" }, "target": { "type": "string" }, "width": { "type": "integer" }, "windowRef": { "type": "string" } }, "required": [ "height", "id", "index", "isActive", "linkRef", "name", "paneCount", "sessionID", "target", "width", "windowRef" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Create window" } ``` --- # find_pane_by_position Source: https://libtmux.org/en/swift/latest/mcp/tools/find_pane_by_position/ > Inspect tmux metadata; accepts no client-supplied executable input. Find a pane occupying a named window corner. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Find a pane occupying a named window corner. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/find_pane_by_position.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L6) ## Arguments * `corner` required · string Caller-controlled corner. * `windowId` required · string Caller-controlled windowId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "corner": { "description": "Caller-controlled corner.", "enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ], "type": "string" }, "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "corner", "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "pane": { "additionalProperties": false, "properties": { "currentCommand": { "type": "string" }, "currentPath": { "type": "string" }, "height": { "type": "integer" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isActive": { "type": "boolean" }, "isAtBottom": { "type": "boolean" }, "isAtLeft": { "type": "boolean" }, "isAtRight": { "type": "boolean" }, "isAtTop": { "type": "boolean" }, "isDead": { "type": "boolean" }, "isSynchronized": { "type": "boolean" }, "modeCount": { "type": "integer" }, "ref": { "type": "string" }, "width": { "type": "integer" }, "windowID": { "type": "string" } }, "required": [ "currentCommand", "currentPath", "height", "id", "index", "isActive", "isAtBottom", "isAtLeft", "isAtRight", "isAtTop", "isDead", "isSynchronized", "modeCount", "ref", "width", "windowID" ], "type": "object" } }, "required": [ "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Find pane by position" } ``` --- # get_pane_info Source: https://libtmux.org/en/swift/latest/mcp/tools/get_pane_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Return metadata for one pane. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Return metadata for one pane. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/get_pane_info.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L7) ## Arguments * `paneId` required · string Caller-controlled paneId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "pane": { "additionalProperties": false, "properties": { "currentCommand": { "type": "string" }, "currentPath": { "type": "string" }, "height": { "type": "integer" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isActive": { "type": "boolean" }, "isAtBottom": { "type": "boolean" }, "isAtLeft": { "type": "boolean" }, "isAtRight": { "type": "boolean" }, "isAtTop": { "type": "boolean" }, "isDead": { "type": "boolean" }, "isSynchronized": { "type": "boolean" }, "modeCount": { "type": "integer" }, "ref": { "type": "string" }, "width": { "type": "integer" }, "windowID": { "type": "string" } }, "required": [ "currentCommand", "currentPath", "height", "id", "index", "isActive", "isAtBottom", "isAtLeft", "isAtRight", "isAtTop", "isDead", "isSynchronized", "modeCount", "ref", "width", "windowID" ], "type": "object" } }, "required": [ "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get pane info" } ``` --- # get_server_info Source: https://libtmux.org/en/swift/latest/mcp/tools/get_server_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Return liveness and identity metadata for the selected tmux server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Return liveness and identity metadata for the selected tmux server. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/get_server_info.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L8) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "running": { "type": "boolean" }, "socketPath": { "type": "string" }, "version": { "type": "string" } }, "required": [ "running" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get server info" } ``` --- # get_session_info Source: https://libtmux.org/en/swift/latest/mcp/tools/get_session_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Return metadata for one session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Return metadata for one session. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/get_session_info.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L9) ## Arguments * `session` required · string Caller-controlled session. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "session": { "additionalProperties": false, "properties": { "createdAt": { "type": "integer" }, "id": { "type": "string" }, "isAttached": { "type": "boolean" }, "name": { "type": "string" }, "ref": { "type": "string" }, "windowCount": { "type": "integer" } }, "required": [ "createdAt", "id", "isAttached", "name", "ref", "windowCount" ], "type": "object" } }, "required": [ "session" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get session info" } ``` --- # get_tmux_variables Source: https://libtmux.org/en/swift/latest/mcp/tools/get_tmux_variables/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Resolve validated variable names without accepting raw format syntax. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Resolve validated variable names without accepting raw format syntax. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/get_tmux_variables.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L10) ## Arguments * `names` required · array Caller-controlled names. * `paneId` optional · string Caller-controlled paneId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "names": { "description": "Caller-controlled names.", "items": { "pattern": "^[A-Za-z][A-Za-z0-9_]*$", "type": "string" }, "maxItems": 32, "type": "array" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "names" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "values": { "additionalProperties": { "type": [ "string", "null" ] }, "type": "object" } }, "required": [ "values" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get tmux variables" } ``` --- # get_window_info Source: https://libtmux.org/en/swift/latest/mcp/tools/get_window_info/ > Inspect tmux metadata; accepts no client-supplied executable input. Return metadata and placements for one window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. Return metadata and placements for one window. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/get_window_info.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L11) ## Arguments * `windowId` required · string Caller-controlled windowId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "placements": { "items": { "additionalProperties": false, "properties": { "index": { "type": "integer" }, "isActive": { "type": "boolean" }, "ref": { "type": "string" }, "sessionID": { "type": "string" }, "target": { "type": "string" }, "windowID": { "type": "string" } }, "required": [ "index", "isActive", "ref", "sessionID", "target", "windowID" ], "type": "object" }, "type": "array" }, "window": { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "id": { "type": "string" }, "name": { "type": "string" }, "paneCount": { "type": "integer" }, "ref": { "type": "string" }, "width": { "type": "integer" } }, "required": [ "height", "id", "name", "paneCount", "ref", "width" ], "type": "object" } }, "required": [ "placements", "window" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Get window info" } ``` --- # kill_pane Source: https://libtmux.org/en/swift/latest/mcp/tools/kill_pane/ > Delete tmux state; accepts no command payload. Delete one pane and its running process. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Delete one pane and its running process. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/kill_pane.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L48) ## Arguments * `force` optional · boolean Caller-controlled force. * `paneId` required · string Caller-controlled paneId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "force": { "description": "Caller-controlled force.", "type": "boolean" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "deleted": { "type": "boolean" }, "paneId": { "type": "string" } }, "required": [ "deleted", "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill pane" } ``` --- # kill_session Source: https://libtmux.org/en/swift/latest/mcp/tools/kill_session/ > Delete tmux state; accepts no command payload. Delete one session and every window it owns. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Delete one session and every window it owns. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/kill_session.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L49) ## Arguments * `force` optional · boolean Caller-controlled force. * `session` required · string Caller-controlled session. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "force": { "description": "Caller-controlled force.", "type": "boolean" }, "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [ "session" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "deleted": { "type": "boolean" }, "sessionId": { "type": "string" } }, "required": [ "deleted", "sessionId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill session" } ``` --- # kill_window Source: https://libtmux.org/en/swift/latest/mcp/tools/kill_window/ > Delete tmux state; accepts no command payload. Delete one window and every pane it owns. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Delete tmux state; accepts no command payload. Delete one window and every pane it owns. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/kill_window.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L50) ## Arguments * `force` optional · boolean Caller-controlled force. * `windowId` required · string Caller-controlled windowId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "force": { "description": "Caller-controlled force.", "type": "boolean" }, "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "deleted": { "type": "boolean" }, "windowId": { "type": "string" } }, "required": [ "deleted", "windowId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Kill window" } ``` --- # list_panes Source: https://libtmux.org/en/swift/latest/mcp/tools/list_panes/ > Inspect tmux metadata; accepts no client-supplied executable input. List panes, optionally within a session or window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. List panes, optionally within a session or window. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/list_panes.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L12) ## Arguments * `session` optional · string Caller-controlled session. * `window` optional · string Caller-controlled window. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "Caller-controlled session.", "type": "string" }, "window": { "description": "Caller-controlled window.", "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "panes": { "items": { "additionalProperties": false, "properties": { "currentCommand": { "type": "string" }, "currentPath": { "type": "string" }, "height": { "type": "integer" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isActive": { "type": "boolean" }, "isAtBottom": { "type": "boolean" }, "isAtLeft": { "type": "boolean" }, "isAtRight": { "type": "boolean" }, "isAtTop": { "type": "boolean" }, "isDead": { "type": "boolean" }, "isSynchronized": { "type": "boolean" }, "modeCount": { "type": "integer" }, "ref": { "type": "string" }, "width": { "type": "integer" }, "windowID": { "type": "string" } }, "required": [ "currentCommand", "currentPath", "height", "id", "index", "isActive", "isAtBottom", "isAtLeft", "isAtRight", "isAtTop", "isDead", "isSynchronized", "modeCount", "ref", "width", "windowID" ], "type": "object" }, "type": "array" } }, "required": [ "panes" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List panes" } ``` --- # list_sessions Source: https://libtmux.org/en/swift/latest/mcp/tools/list_sessions/ > Inspect tmux metadata; accepts no client-supplied executable input. List sessions on the selected server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. List sessions on the selected server. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/list_sessions.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L13) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": {}, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "sessions": { "items": { "additionalProperties": false, "properties": { "createdAt": { "type": "integer" }, "id": { "type": "string" }, "isAttached": { "type": "boolean" }, "name": { "type": "string" }, "ref": { "type": "string" }, "windowCount": { "type": "integer" } }, "required": [ "createdAt", "id", "isAttached", "name", "ref", "windowCount" ], "type": "object" }, "type": "array" } }, "required": [ "sessions" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List sessions" } ``` --- # list_windows Source: https://libtmux.org/en/swift/latest/mcp/tools/list_windows/ > Inspect tmux metadata; accepts no client-supplied executable input. List windows, optionally within one session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Inspect tmux metadata; accepts no client-supplied executable input. List windows, optionally within one session. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/list_windows.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L14) ## Arguments * `session` optional · string Caller-controlled session. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "windows": { "items": { "additionalProperties": false, "properties": { "height": { "type": "integer" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isActive": { "type": "boolean" }, "linkRef": { "type": "string" }, "name": { "type": "string" }, "paneCount": { "type": "integer" }, "sessionID": { "type": "string" }, "target": { "type": "string" }, "width": { "type": "integer" }, "windowRef": { "type": "string" } }, "required": [ "height", "id", "index", "isActive", "linkRef", "name", "paneCount", "sessionID", "target", "width", "windowRef" ], "type": "object" }, "type": "array" } }, "required": [ "windows" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "List windows" } ``` --- # move_window Source: https://libtmux.org/en/swift/latest/mcp/tools/move_window/ > Change tmux state; no client-supplied executable input. Move one window appearance to another session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Move one window appearance to another session. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/move_window.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L22) ## Arguments * `index` optional · integer Caller-controlled index. * `session` optional · string Caller-controlled session. * `sourceIndex` optional · integer Caller-controlled sourceIndex. * `sourceSession` optional · string Caller-controlled sourceSession. * `windowId` required · string Caller-controlled windowId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "index": { "description": "Caller-controlled index.", "minimum": 0, "type": "integer" }, "session": { "description": "Caller-controlled session.", "type": "string" }, "sourceIndex": { "description": "Caller-controlled sourceIndex.", "minimum": 0, "type": "integer" }, "sourceSession": { "description": "Caller-controlled sourceSession.", "type": "string" }, "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "target": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "target", "windowId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Move window" } ``` --- # paste_text Source: https://libtmux.org/en/swift/latest/mcp/tools/paste_text/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Paste literal text and an optional newline target-only after two state checks. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Paste literal text and an optional newline target-only after two state checks. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/paste_text.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L39) ## Arguments * `enter` optional · boolean Caller-controlled enter. * `force` optional · boolean Caller-controlled force. * `paneId` required · string Caller-controlled paneId. * `text` required · string Caller-controlled text. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enter": { "description": "Caller-controlled enter.", "type": "boolean" }, "force": { "description": "Caller-controlled force.", "type": "boolean" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "text": { "description": "Caller-controlled text.", "type": "string" } }, "required": [ "paneId", "text" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "characters": { "type": "integer" }, "pane": { "type": "string" }, "paneRef": { "type": "string" } }, "required": [ "characters", "pane", "paneRef" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Paste text" } ``` --- # rename_session Source: https://libtmux.org/en/swift/latest/mcp/tools/rename_session/ > Change tmux state; no client-supplied executable input. Set a literal-safe session name. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set a literal-safe session name. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/rename_session.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L23) ## Arguments * `name` required · string Caller-controlled name. * `session` required · string Caller-controlled session. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Caller-controlled name.", "type": "string" }, "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [ "name", "session" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "name": { "type": "string" }, "sessionId": { "type": "string" } }, "required": [ "name", "sessionId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Rename session" } ``` --- # rename_window Source: https://libtmux.org/en/swift/latest/mcp/tools/rename_window/ > Change tmux state; no client-supplied executable input. Set a literal-safe window name. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set a literal-safe window name. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/rename_window.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L24) ## Arguments * `name` required · string Caller-controlled name. * `windowId` required · string Caller-controlled windowId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Caller-controlled name.", "type": "string" }, "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "name", "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "name": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "name", "windowId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Rename window" } ``` --- # resize_pane Source: https://libtmux.org/en/swift/latest/mcp/tools/resize_pane/ > Change tmux state; no client-supplied executable input. Resize one pane by dimensions or a directional amount. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Resize one pane by dimensions or a directional amount. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/resize_pane.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L25) ## Arguments * `amount` optional · integer Caller-controlled amount. * `direction` optional · string Caller-controlled direction. * `height` optional · integer Caller-controlled height. * `paneId` required · string Caller-controlled paneId. * `width` optional · integer Caller-controlled width. * `zoom` optional · boolean Caller-controlled zoom. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "amount": { "description": "Caller-controlled amount.", "minimum": 1, "type": "integer" }, "direction": { "description": "Caller-controlled direction.", "enum": [ "up", "down", "left", "right" ], "type": "string" }, "height": { "description": "Caller-controlled height.", "minimum": 1, "type": "integer" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "width": { "description": "Caller-controlled width.", "minimum": 1, "type": "integer" }, "zoom": { "description": "Caller-controlled zoom.", "type": "boolean" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "paneId": { "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Resize pane" } ``` --- # resize_window Source: https://libtmux.org/en/swift/latest/mcp/tools/resize_window/ > Change tmux state; no client-supplied executable input. Resize the terminal dimensions reported for one window. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Resize the terminal dimensions reported for one window. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/resize_window.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L26) ## Arguments * `height` optional · integer Caller-controlled height. * `width` optional · integer Caller-controlled width. * `windowId` required · string Caller-controlled windowId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "height": { "description": "Caller-controlled height.", "minimum": 1, "type": "integer" }, "width": { "description": "Caller-controlled width.", "minimum": 1, "type": "integer" }, "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "windowId": { "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Resize window" } ``` --- # respawn_pane Source: https://libtmux.org/en/swift/latest/mcp/tools/respawn_pane/ > Start a pane's configured process; accepts no command payload. Restart only the pane's configured process; no caller command is accepted. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Restart only the pane’s configured process; no caller command is accepted. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/respawn_pane.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L40) ## Arguments * `force` optional · boolean Caller-controlled force. * `killFirst` optional · boolean Caller-controlled killFirst. * `paneId` required · string Caller-controlled paneId. * `startDirectory` optional · string Caller-controlled startDirectory. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "force": { "description": "Caller-controlled force.", "type": "boolean" }, "killFirst": { "description": "Caller-controlled killFirst.", "type": "boolean" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "startDirectory": { "description": "Caller-controlled startDirectory.", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "pane": { "type": "string" }, "paneRef": { "type": "string" } }, "required": [ "pane", "paneRef" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Respawn pane" } ``` --- # run_shell_command Source: https://libtmux.org/en/swift/latest/mcp/tools/run_shell_command/ > Run a shell command in a pane with your user's permissions. Run one command in a singular trusted POSIX shell and return bounded output. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Run a shell command in a pane with your user’s permissions. Run one command in a singular trusted POSIX shell and return bounded output. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/run_shell_command.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L41) ## Arguments * `command` required · string Caller-controlled command. * `force` optional · boolean Caller-controlled force. * `maxLines` optional · integer Caller-controlled maxLines. * `paneId` required · string Caller-controlled paneId. * `timeoutMs` optional · integer Caller-controlled timeoutMs. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "command": { "description": "Caller-controlled command.", "type": "string" }, "force": { "description": "Caller-controlled force.", "type": "boolean" }, "maxLines": { "description": "Caller-controlled maxLines.", "maximum": 2000, "minimum": 1, "type": "integer" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "timeoutMs": { "description": "Caller-controlled timeoutMs.", "maximum": 600000, "minimum": 100, "type": "integer" } }, "required": [ "command", "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "droppedLines": { "type": "integer" }, "effectiveTimeout": { "type": "number" }, "exitStatus": { "type": [ "integer", "null" ] }, "linesMissed": { "type": "boolean" }, "output": { "items": { "type": "string" }, "type": "array" }, "pane": { "type": "string" }, "paneRef": { "type": "string" }, "seconds": { "type": "number" }, "timedOut": { "type": "boolean" } }, "required": [ "droppedLines", "effectiveTimeout", "exitStatus", "linesMissed", "output", "pane", "paneRef", "seconds", "timedOut" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Run shell command" } ``` --- # search_panes Source: https://libtmux.org/en/swift/latest/mcp/tools/search_panes/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Search bounded pane content for literal text or a regular expression. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Search bounded pane content for literal text or a regular expression. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/search_panes.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L15) ## Arguments * `maxMatchesPerPane` optional · integer Caller-controlled maxMatchesPerPane. * `pattern` required · string Caller-controlled pattern. * `regex` optional · boolean Caller-controlled regex. * `scrollbackLines` optional · integer Caller-controlled scrollbackLines. * `session` optional · string Caller-controlled session. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "maxMatchesPerPane": { "description": "Caller-controlled maxMatchesPerPane.", "maximum": 200, "minimum": 1, "type": "integer" }, "pattern": { "description": "Caller-controlled pattern.", "type": "string", "x-libtmux-max-utf8-bytes": 4096 }, "regex": { "description": "Caller-controlled regex.", "type": "boolean" }, "scrollbackLines": { "description": "Caller-controlled scrollbackLines.", "maximum": 2000, "minimum": 1, "type": "integer" }, "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [ "pattern" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "matches": { "items": { "additionalProperties": false, "properties": { "line": { "type": "integer" }, "pane": { "type": "string" }, "paneRef": { "type": "string" }, "text": { "type": "string" } }, "required": [ "line", "pane", "paneRef", "text" ], "type": "object" }, "type": "array" }, "panesAvailable": { "type": "integer" }, "panesSearched": { "type": "integer" }, "truncated": { "type": "boolean" }, "truncatedBy": { "items": { "type": "string" }, "type": "array" } }, "required": [ "matches", "panesAvailable", "panesSearched", "truncated", "truncatedBy" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Search panes" } ``` --- # select_layout Source: https://libtmux.org/en/swift/latest/mcp/tools/select_layout/ > Change tmux state; no client-supplied executable input. Apply a named layout, a unique abbreviation for the running tmux version, or a checksummed saved layout. Invalid syntax is refused before window lookup; tmux validates geometry when applying the layout. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Apply a named layout, a unique abbreviation for the running tmux version, or a checksummed saved layout. Invalid syntax is refused before window lookup; tmux validates geometry when applying the layout. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/select_layout.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L27) ## Arguments * `layout` required · string Caller-controlled layout. * `windowId` required · string Caller-controlled windowId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "layout": { "description": "Caller-controlled layout.", "type": "string" }, "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "layout", "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "layout": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "layout", "windowId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select layout" } ``` --- # select_pane Source: https://libtmux.org/en/swift/latest/mcp/tools/select_pane/ > Change tmux state; no client-supplied executable input. Select one pane as active. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Select one pane as active. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/select_pane.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L28) ## Arguments * `paneId` required · string Caller-controlled paneId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "paneId": { "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select pane" } ``` --- # select_window Source: https://libtmux.org/en/swift/latest/mcp/tools/select_window/ > Change tmux state; no client-supplied executable input. Select one exact window appearance. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Select one exact window appearance. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/select_window.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L29) ## Arguments * `sourceIndex` optional · integer Caller-controlled sourceIndex. * `sourceSession` optional · string Caller-controlled sourceSession. * `windowId` required · string Caller-controlled windowId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "sourceIndex": { "description": "Caller-controlled sourceIndex.", "minimum": 0, "type": "integer" }, "sourceSession": { "description": "Caller-controlled sourceSession.", "type": "string" }, "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "target": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "target", "windowId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Select window" } ``` --- # send_keys Source: https://libtmux.org/en/swift/latest/mcp/tools/send_keys/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send keys after checking the effective synchronized-pane cohort. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Send keys after checking the effective synchronized-pane cohort. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/send_keys.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L42) ## Arguments * `enter` optional · boolean Caller-controlled enter. * `force` optional · boolean Caller-controlled force. * `keys` required · array Caller-controlled keys. * `literal` optional · boolean Caller-controlled literal. * `paneId` required · string Caller-controlled paneId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enter": { "description": "Caller-controlled enter.", "type": "boolean" }, "force": { "description": "Caller-controlled force.", "type": "boolean" }, "keys": { "description": "Caller-controlled keys.", "items": { "type": "string" }, "type": "array" }, "literal": { "description": "Caller-controlled literal.", "type": "boolean" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "keys", "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "keys": { "items": { "type": "string" }, "type": "array" }, "pane": { "type": "string" }, "paneRef": { "type": "string" }, "resolvedPaneIds": { "items": { "type": "string" }, "type": "array" } }, "required": [ "keys", "pane", "paneRef", "resolvedPaneIds" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Send keys" } ``` --- # send_keys_batch Source: https://libtmux.org/en/swift/latest/mcp/tools/send_keys_batch/ > Send input to a pane's program; a shell that receives it runs it with your user's permissions. Send an ordered bounded batch with a fresh check for every row. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send input to a pane’s program; a shell that receives it runs it with your user’s permissions. Send an ordered bounded batch with a fresh check for every row. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/send_keys_batch.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L43) ## Arguments * `onError` optional · string Caller-controlled onError. * `operations` required · array Caller-controlled operations. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "onError": { "description": "Caller-controlled onError.", "enum": [ "stop", "continue" ], "type": "string" }, "operations": { "description": "Caller-controlled operations.", "items": { "additionalProperties": false, "properties": { "enter": { "type": "boolean" }, "force": { "type": "boolean" }, "keys": { "items": { "type": "string" }, "type": "array" }, "literal": { "type": "boolean" }, "paneId": { "type": "string" } }, "required": [ "paneId", "keys" ], "type": "object" }, "maxItems": 64, "type": "array" } }, "required": [ "operations" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "completed": { "type": "integer" }, "failures": { "items": { "additionalProperties": false, "properties": { "index": { "type": "integer" }, "reason": { "type": "string" } }, "required": [ "index", "reason" ], "type": "object" }, "type": "array" }, "targets": { "items": { "additionalProperties": false, "properties": { "index": { "type": "integer" }, "resolvedPaneIds": { "items": { "type": "string" }, "type": "array" } }, "required": [ "index", "resolvedPaneIds" ], "type": "object" }, "type": "array" } }, "required": [ "completed", "failures", "targets" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Send keys batch" } ``` --- # set_history_limit Source: https://libtmux.org/en/swift/latest/mcp/tools/set_history_limit/ > Change tmux state; no client-supplied executable input. Set the default retained scrollback line limit. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set the default retained scrollback line limit. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/set_history_limit.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L30) ## Arguments * `lines` required · integer Caller-controlled lines. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "lines": { "description": "Caller-controlled lines.", "maximum": 2000000, "minimum": 0, "type": "integer" } }, "required": [ "lines" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "lines": { "type": "integer" } }, "required": [ "lines" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set history limit" } ``` --- # set_mouse_enabled Source: https://libtmux.org/en/swift/latest/mcp/tools/set_mouse_enabled/ > Change tmux state; no client-supplied executable input. Set the global tmux mouse option through a boolean. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set the global tmux mouse option through a boolean. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/set_mouse_enabled.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L31) ## Arguments * `enabled` required · boolean Caller-controlled enabled. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enabled": { "description": "Caller-controlled enabled.", "type": "boolean" } }, "required": [ "enabled" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "enabled": { "type": "boolean" } }, "required": [ "enabled" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set mouse enabled" } ``` --- # set_pane_title Source: https://libtmux.org/en/swift/latest/mcp/tools/set_pane_title/ > Change tmux state; no client-supplied executable input. Set one literal-safe pane title. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set one literal-safe pane title. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/set_pane_title.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L32) ## Arguments * `paneId` required · string Caller-controlled paneId. * `title` required · string Caller-controlled title. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "title": { "description": "Caller-controlled title.", "type": "string" } }, "required": [ "paneId", "title" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "paneId": { "type": "string" }, "title": { "type": "string" } }, "required": [ "paneId", "title" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set pane title" } ``` --- # set_synchronize_panes Source: https://libtmux.org/en/swift/latest/mcp/tools/set_synchronize_panes/ > Change tmux state; no client-supplied executable input. Set the window input default; pane overrides determine effective synchronization. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Set the window input default; pane overrides determine effective synchronization. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/set_synchronize_panes.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L44) ## Arguments * `enabled` required · boolean Caller-controlled enabled. * `windowId` required · string Caller-controlled windowId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "enabled": { "description": "Caller-controlled enabled.", "type": "boolean" }, "windowId": { "description": "Caller-controlled windowId.", "type": "string" } }, "required": [ "enabled", "windowId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "enabled": { "type": "boolean" }, "windowId": { "type": "string" } }, "required": [ "enabled", "windowId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Set synchronize panes" } ``` --- # show_environment Source: https://libtmux.org/en/swift/latest/mcp/tools/show_environment/ > Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. Read global or session tmux environment values. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read the tmux environment; accepts no client-supplied executable input. Returned values may contain secrets. Read global or session tmux environment values. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/show_environment.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L16) ## Arguments * `session` optional · string Caller-controlled session. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "environment": { "additionalProperties": { "type": [ "string", "null" ] }, "type": "object" } }, "required": [ "environment" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show environment" } ``` --- # show_hooks Source: https://libtmux.org/en/swift/latest/mcp/tools/show_hooks/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read configured hooks, optionally for one session. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read configured hooks, optionally for one session. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/show_hooks.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L17) ## Arguments * `session` optional · string Caller-controlled session. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "session": { "description": "Caller-controlled session.", "type": "string" } }, "required": [], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "hooks": { "items": { "additionalProperties": false, "properties": { "command": { "type": "string" }, "index": { "type": "integer" }, "name": { "type": "string" } }, "required": [ "command", "index", "name" ], "type": "object" }, "type": "array" } }, "required": [ "hooks" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show hooks" } ``` --- # show_option Source: https://libtmux.org/en/swift/latest/mcp/tools/show_option/ > Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read one exact tmux option. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read configured tmux commands; accepts no client-supplied executable input. Returned values may contain executable configuration. Read one exact tmux option. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/show_option.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L18) ## Arguments * `name` required · string Caller-controlled name. * `scope` optional · string Caller-controlled scope. * `target` optional · string Caller-controlled target. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "name": { "description": "Caller-controlled name.", "type": "string" }, "scope": { "description": "Caller-controlled scope.", "enum": [ "server", "global_session", "global_window", "session", "window", "pane" ], "type": "string" }, "target": { "description": "Caller-controlled target.", "type": "string" } }, "required": [ "name" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "options": { "items": { "additionalProperties": false, "properties": { "name": { "type": "string" }, "value": { "type": "string" } }, "required": [ "name", "value" ], "type": "object" }, "type": "array" } }, "required": [ "options" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Show option" } ``` --- # signal_channel Source: https://libtmux.org/en/swift/latest/mcp/tools/signal_channel/ > Change tmux state; no client-supplied executable input. Signal one tmux wait-for channel. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Signal one tmux wait-for channel. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/signal_channel.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L33) ## Arguments * `channel` required · string Caller-controlled channel. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "Caller-controlled channel.", "type": "string" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "channel": { "type": "string" }, "signalled": { "type": "boolean" } }, "required": [ "channel", "signalled" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Signal channel" } ``` --- # snapshot_pane Source: https://libtmux.org/en/swift/latest/mcp/tools/snapshot_pane/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return pane metadata and bounded terminal content together. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Return pane metadata and bounded terminal content together. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/snapshot_pane.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L19) ## Arguments * `maxLines` optional · integer Caller-controlled maxLines. * `paneId` required · string Caller-controlled paneId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "maxLines": { "description": "Caller-controlled maxLines.", "maximum": 2000, "minimum": 1, "type": "integer" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "capture": { "additionalProperties": false, "properties": { "droppedLines": { "type": "integer" }, "lines": { "items": { "type": "string" }, "type": "array" }, "paneId": { "type": "string" } }, "required": [ "droppedLines", "lines", "paneId" ], "type": "object" }, "pane": { "additionalProperties": false, "properties": { "currentCommand": { "type": "string" }, "currentPath": { "type": "string" }, "height": { "type": "integer" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isActive": { "type": "boolean" }, "isAtBottom": { "type": "boolean" }, "isAtLeft": { "type": "boolean" }, "isAtRight": { "type": "boolean" }, "isAtTop": { "type": "boolean" }, "isDead": { "type": "boolean" }, "isSynchronized": { "type": "boolean" }, "modeCount": { "type": "integer" }, "ref": { "type": "string" }, "width": { "type": "integer" }, "windowID": { "type": "string" } }, "required": [ "currentCommand", "currentPath", "height", "id", "index", "isActive", "isAtBottom", "isAtLeft", "isAtRight", "isAtTop", "isDead", "isSynchronized", "modeCount", "ref", "width", "windowID" ], "type": "object" } }, "required": [ "capture", "pane" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Snapshot pane" } ``` --- # split_window Source: https://libtmux.org/en/swift/latest/mcp/tools/split_window/ > Start a pane's configured process; accepts no command payload. Create a configured-process pane without accepting command or environment data. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Start a pane’s configured process; accepts no command payload. Create a configured-process pane without accepting command or environment data. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/split_window.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L45) ## Arguments * `direction` optional · string Caller-controlled direction. * `paneId` required · string Caller-controlled paneId. * `startDirectory` optional · string Caller-controlled startDirectory. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "direction": { "description": "Caller-controlled direction.", "enum": [ "right", "left", "above", "below" ], "type": "string" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "startDirectory": { "description": "Caller-controlled startDirectory.", "type": "string" } }, "required": [ "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "currentCommand": { "type": "string" }, "currentPath": { "type": "string" }, "height": { "type": "integer" }, "id": { "type": "string" }, "index": { "type": "integer" }, "isActive": { "type": "boolean" }, "isAtBottom": { "type": "boolean" }, "isAtLeft": { "type": "boolean" }, "isAtRight": { "type": "boolean" }, "isAtTop": { "type": "boolean" }, "isDead": { "type": "boolean" }, "isSynchronized": { "type": "boolean" }, "modeCount": { "type": "integer" }, "ref": { "type": "string" }, "width": { "type": "integer" }, "windowID": { "type": "string" } }, "required": [ "currentCommand", "currentPath", "height", "id", "index", "isActive", "isAtBottom", "isAtLeft", "isAtRight", "isAtTop", "isDead", "isSynchronized", "modeCount", "ref", "width", "windowID" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Split window" } ``` --- # swap_pane Source: https://libtmux.org/en/swift/latest/mcp/tools/swap_pane/ > Change tmux state; no client-supplied executable input. Swap two panes without changing their identities. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Swap two panes without changing their identities. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/swap_pane.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L34) ## Arguments * `otherPaneId` required · string Caller-controlled otherPaneId. * `paneId` required · string Caller-controlled paneId. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "otherPaneId": { "description": "Caller-controlled otherPaneId.", "type": "string" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" } }, "required": [ "otherPaneId", "paneId" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "otherPaneId": { "type": "string" }, "paneId": { "type": "string" } }, "required": [ "otherPaneId", "paneId" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Swap panes" } ``` --- # wait_for_channel Source: https://libtmux.org/en/swift/latest/mcp/tools/wait_for_channel/ > Change tmux state; no client-supplied executable input. Wait within one deadline for a tmux channel signal. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Change tmux state; no client-supplied executable input. Wait within one deadline for a tmux channel signal. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/wait_for_channel.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L35) ## Arguments * `channel` required · string Caller-controlled channel. * `timeoutMs` optional · integer Caller-controlled timeoutMs. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "channel": { "description": "Caller-controlled channel.", "maxLength": 1024, "type": "string" }, "timeoutMs": { "description": "Caller-controlled timeoutMs.", "maximum": 600000, "minimum": 100, "type": "integer" } }, "required": [ "channel" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "channel": { "type": "string" }, "effectiveTimeout": { "type": "number" }, "released": { "type": "boolean" }, "seconds": { "type": "number" } }, "required": [ "channel", "effectiveTimeout", "released", "seconds" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Wait for channel" } ``` --- # wait_for_text Source: https://libtmux.org/en/swift/latest/mcp/tools/wait_for_text/ > Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Wait within one deadline for pane text. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Wait within one deadline for pane text. [All Swift tools](https://libtmux.org/en/swift/latest/mcp/tools/) · [JSON](https://libtmux.org/en/swift/latest/mcp/tools/wait_for_text.json) · [Source](https://github.com/libtmux/libtmux-swift/blob/7993e7044347629b08020e9b02ae8bcffa0e5898/Sources/LibTmuxMCP/ToolOperation.swift#L20) ## Arguments * `cursor` optional · string Caller-controlled cursor. * `maxLines` optional · integer Caller-controlled maxLines. * `paneId` required · string Caller-controlled paneId. * `patterns` required · array Caller-controlled patterns. * `regex` optional · boolean Caller-controlled regex. * `stop` optional · array Caller-controlled stop. * `timeoutMs` optional · integer Caller-controlled timeoutMs. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "additionalProperties": false, "properties": { "cursor": { "description": "Caller-controlled cursor.", "maxLength": 16384, "type": "string" }, "maxLines": { "description": "Caller-controlled maxLines.", "maximum": 2000, "minimum": 1, "type": "integer" }, "paneId": { "description": "Caller-controlled paneId.", "type": "string" }, "patterns": { "description": "Caller-controlled patterns.", "items": { "type": "string", "x-libtmux-max-utf8-bytes": 4096 }, "maxItems": 32, "type": "array" }, "regex": { "description": "Caller-controlled regex.", "type": "boolean" }, "stop": { "description": "Caller-controlled stop.", "items": { "type": "string", "x-libtmux-max-utf8-bytes": 4096 }, "maxItems": 32, "type": "array" }, "timeoutMs": { "description": "Caller-controlled timeoutMs.", "maximum": 600000, "minimum": 100, "type": "integer" } }, "required": [ "paneId", "patterns" ], "type": "object" } ``` Output schema ```json { "additionalProperties": false, "properties": { "cursor": { "type": [ "string", "null" ] }, "effectiveTimeout": { "type": "number" }, "matched": { "type": [ "string", "null" ] }, "matchedAtEntry": { "type": "boolean" }, "matchedIndex": { "type": [ "integer", "null" ] }, "outcome": { "type": "string" }, "paneRef": { "type": "string" }, "sawNewOutput": { "type": "boolean" }, "seconds": { "type": "number" }, "tail": { "items": { "type": "string" }, "type": "array" } }, "required": [ "cursor", "effectiveTimeout", "matched", "matchedAtEntry", "matchedIndex", "outcome", "paneRef", "sawNewOutput", "seconds", "tail" ], "type": "object" } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": true, "readOnlyHint": false, "title": "Wait for text" } ``` --- # Ruby MCP tools Source: https://libtmux.org/en/ruby/latest/mcp/tools/ > Tools, resources, and prompts advertised by the Ruby MCP server. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Use the wire name shown here when calling a tool. The Ruby server advertises 8 tools with the reference configuration below. Your client’s list follows the policy configured for its server. Read the [setup guide](https://libtmux.org/en/ruby/latest/mcp/guides/) before choosing tool access. The [language API reference](https://libtmux.org/en/ruby/latest/mcp/reference/) covers embedding and implementation types. [Download the protocol catalog as JSON](https://libtmux.org/en/ruby/latest/mcp/tools.json). Reference configuration * `mode` `explicit CLI options` * `tools` `tmux_capabilities,tmux_snapshot,tmux_capture,tmux_wait,tmux_create,tmux_send,tmux_close,tmux_run` Protocol version: `2025-11-25`. ## Tools * [`tmux_capabilities`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_capabilities/) Discover the fixed endpoint, server binding, enabled tools, criteria schema and limits. Acquires metadata; starts no daemon.Default * [`tmux_capture`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_capture/) Read exact-pane screen/history rows preserving LF. Defaults: 200 lines, 65536 bytes, zero history lines, track=false. Limits: 1000 lines/history, 262144 bytes. UTF-8 or base64; truncation is separate from unknown history continuity. Tracked process cursors require tmux>=3.3 and a native process identity backend: Linux peer pidfds with matching PID namespaces, or Darwin kqueue process observation. Continuation returns an exact state row splice, not a live-output journal. Refuses capture after-hooks.Opt-in * [`tmux_close`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_close/) Destroy one exact session, window or pane. Opt-in destructive operation; closing a session or window also removes its contained topology. Never selects by name or closes the daemon directly. Returns the final tmux client outcome.Opt-in * [`tmux_create`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_create/) Create a session, window in an exact session, or split an exact pane using argv. Opt-in mutation; 64 KiB total string bytes and at most 256 argv entries. Window/pane focus defaults false. Cwd/environment are optional; size is cells or percent. Assigned refs prove creation, not program readiness or completion.Opt-in * [`tmux_run`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_run/) Run an authored POSIX script in an explicitly enrolled idle, empty zsh 5.9 editor. Opt-in; no terminal injection. Exact queue authorization binds the existing shell generation; execution may follow a later pane replacement without retargeting it. Inherits cwd/exported environment, closed stdin, separate bounded UTF-8/base64 outputs. Defaults: 65536 bytes per output, 65536 script bytes; overflow refuses completion. Reports native exit/signal only from the helper; cancellation never proves descendants stopped.Opt-in * [`tmux_send`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_send/) Send literal UTF-8 text or named keys to one exact pane. Opt-in mutation; 64 KiB total text bytes, at most 256 keys. Reports tmux client completion and input dispatch only; never shell completion.Opt-in * [`tmux_snapshot`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_snapshot/) Capture ordered metadata and evaluate Ruby criteria locally. Pages retain one immutable capture; expired cursors require a new query. Limit defaults to 50 records, maximum 200.Default * [`tmux_wait`](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_wait/) Wait for observed literal screen text or the initial pane process exit. Deadline in seconds is capped by the application limit. Uses control events/process descriptors; no polling. Requires tmux>=3.3 and Linux peer pidfds with matching PID namespaces or Darwin kqueue process observation. Reports observed evidence, never remote termination caused by cancellation or an inferred process exit status.Opt-in ## Resources This server does not advertise resources in this configuration. ## Resource templates * `tmux://{endpoint}/{generation}/snapshots/{entity}` Acquire metadata through tmux_snapshot with its default page limit. Encode every URI component; generation must match discovery. Reports capture interval and truncation. * `tmux://{endpoint}/{generation}/snapshots/{entity}/pages/{cursor}` Read a retained tmux_snapshot page without refreshing it. Encode the cursor component; endpoint, generation and entity must match its captured query. * `tmux://{endpoint}/{generation}/panes/{pane_id}/screen` Capture an exact pane through tmux_capture with its default byte/line bounds, without cursor tracking. Percent-encode pane IDs. Invalid UTF-8 is an application/octet-stream blob; \_meta includes capture interval, truncation and unknown history continuity. ## Prompts This server does not advertise prompts in this configuration. Source revision: [libtmux/libtmux-ruby@9b1545562a112353c2c893a1d3e8c0d9b4b51f8d](https://github.com/libtmux/libtmux-ruby/tree/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d). --- # tmux_capabilities Source: https://libtmux.org/en/ruby/latest/mcp/tools/tmux_capabilities/ > Discover the fixed endpoint, server binding, enabled tools, criteria schema and limits. Acquires metadata; starts no daemon. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Discover the fixed endpoint, server binding, enabled tools, criteria schema and limits. Acquires metadata; starts no daemon. **Policy:** enabled by default. [All Ruby tools](https://libtmux.org/en/ruby/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_capabilities.json) · [Source](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/catalog.rb#L249) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": {}, "required": [], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "data": { "additionalProperties": false, "properties": { "authored_run": { "additionalProperties": false, "properties": { "authorization": { "const": "exact_generation_at_queue_grant" }, "availability": { "enum": [ "conditional", "unsupported" ] }, "descendant_termination": { "const": "unobserved" }, "enrollment": { "const": "explicit_source" }, "persistent_shell_changes": { "const": false }, "requirements": { "items": { "type": "string" }, "type": "array" }, "shell_profile": { "const": "zsh-5.9-zle" }, "stdin": { "const": "closed" } }, "required": [ "availability", "shell_profile", "enrollment", "authorization", "stdin", "persistent_shell_changes", "descendant_termination", "requirements" ], "type": "object" }, "criteria_schema": { "type": "object" }, "enabled_tools": { "items": { "type": "string" }, "type": "array" }, "endpoint": { "type": "string" }, "limits": { "additionalProperties": { "type": "number" }, "type": "object" }, "observation": { "additionalProperties": false, "properties": { "history_continuity": { "const": "unknown" }, "process_cursor": { "enum": [ "conditional", "unsupported" ] }, "requirements": { "items": { "type": "string" }, "type": "array" }, "screen": { "const": "bounded_rows" }, "wait_conditions": { "items": { "enum": [ "screen_contains", "process_exit" ] }, "type": "array" } }, "required": [ "screen", "history_continuity", "process_cursor", "requirements", "wait_conditions" ], "type": "object" }, "owns_daemon": { "const": false }, "resource_subscriptions": { "const": false }, "server_identity": { "additionalProperties": false, "properties": { "generation": { "type": "string" }, "pid": { "type": "integer" }, "start_time": { "type": "integer" }, "tmux_version": { "type": "string" } }, "required": [ "generation", "pid", "start_time", "tmux_version" ], "type": "object" } }, "required": [ "endpoint", "server_identity", "enabled_tools", "criteria_schema", "limits", "owns_daemon", "resource_subscriptions", "authored_run", "observation" ], "type": "object" }, "ok": { "const": true } }, "required": [ "ok", "data" ], "type": "object" }, { "additionalProperties": false, "properties": { "error": { "additionalProperties": false, "properties": { "code": { "type": "string" }, "delivery": { "enum": [ "not_sent", "possibly_sent", "observed" ] }, "effects": { "additionalProperties": false, "properties": { "created": { "items": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] }, "maxItems": 3, "type": "array" }, "state": { "enum": [ "none", "known", "unknown" ] } }, "required": [ "state", "created" ], "type": "object" }, "message": { "type": "string" } }, "required": [ "code", "message", "delivery" ], "type": "object" }, "ok": { "const": false } }, "required": [ "ok", "error" ], "type": "object" } ] } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false } ``` --- # tmux_capture Source: https://libtmux.org/en/ruby/latest/mcp/tools/tmux_capture/ > Read exact-pane screen/history rows preserving LF. Defaults: 200 lines, 65536 bytes, zero history lines, track=false. Limits: 1000 lines/history, 262144 bytes. UTF-8 or base64; truncation is separate from unknown history continuity. Tracked process cursors require tmux>=3.3 and a native process identity backend: Linux peer pidfds with matching PID namespaces, or Darwin kqueue process observation. Continuation returns an exact state row splice, not a live-output journal. Refuses capture after-hooks. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Read exact-pane screen/history rows preserving LF. Defaults: 200 lines, 65536 bytes, zero history lines, track=false. Limits: 1000 lines/history, 262144 bytes. UTF-8 or base64; truncation is separate from unknown history continuity. Tracked process cursors require tmux>=3.3 and a native process identity backend: Linux peer pidfds with matching PID namespaces, or Darwin kqueue process observation. Continuation returns an exact state row splice, not a live-output journal. Refuses capture after-hooks. **Policy:** opt in with --enable-tool tmux_capture. [All Ruby tools](https://libtmux.org/en/ruby/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_capture.json) · [Source](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/catalog.rb#L239) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "history_lines": { "maximum": 1000, "minimum": 0, "type": "integer" }, "max_bytes": { "maximum": 262144, "minimum": 1, "type": "integer" }, "max_lines": { "maximum": 1000, "minimum": 1, "type": "integer" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] }, "track": { "type": "boolean" } }, "required": [ "target" ], "type": "object" }, { "additionalProperties": false, "properties": { "cursor": { "maxLength": 32, "pattern": "^[a-f0-9]{32}$", "type": "string" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "target", "cursor" ], "type": "object" } ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "data": { "oneOf": [ { "additionalProperties": false, "properties": { "bytes": { "maximum": 262144, "minimum": 0, "type": "integer" }, "capture_id": { "type": "string" }, "encoding": { "enum": [ "utf-8", "base64" ] }, "history_continuity": { "const": "unknown" }, "interval": { "additionalProperties": false, "properties": { "clock": { "const": "monotonic_seconds" }, "finished": { "type": "number" }, "started": { "type": "number" } }, "required": [ "clock", "started", "finished" ], "type": "object" }, "mode": { "const": "snapshot" }, "next_cursor": { "type": "string" }, "process_generation": { "type": [ "string", "null" ] }, "row_count": { "maximum": 1000, "minimum": 0, "type": "integer" }, "rows": { "items": { "type": "string" }, "maxItems": 1000, "type": "array" }, "scope": { "additionalProperties": false, "properties": { "history_lines": { "maximum": 1000, "minimum": 0, "type": "integer" }, "max_bytes": { "maximum": 262144, "minimum": 1, "type": "integer" }, "max_lines": { "maximum": 1000, "minimum": 1, "type": "integer" } }, "required": [ "max_lines", "max_bytes", "history_lines" ], "type": "object" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] }, "truncated": { "type": "boolean" } }, "required": [ "target", "capture_id", "process_generation", "encoding", "row_count", "bytes", "truncated", "history_continuity", "interval", "scope", "mode", "rows" ], "type": "object" }, { "additionalProperties": false, "properties": { "base_capture_id": { "type": "string" }, "bytes": { "maximum": 262144, "minimum": 0, "type": "integer" }, "capture_id": { "type": "string" }, "encoding": { "enum": [ "utf-8", "base64" ] }, "history_continuity": { "const": "unknown" }, "interval": { "additionalProperties": false, "properties": { "clock": { "const": "monotonic_seconds" }, "finished": { "type": "number" }, "started": { "type": "number" } }, "required": [ "clock", "started", "finished" ], "type": "object" }, "mode": { "const": "delta" }, "next_cursor": { "type": "string" }, "process_generation": { "type": [ "string", "null" ] }, "reset": { "type": "boolean" }, "row_count": { "maximum": 1000, "minimum": 0, "type": "integer" }, "scope": { "additionalProperties": false, "properties": { "history_lines": { "maximum": 1000, "minimum": 0, "type": "integer" }, "max_bytes": { "maximum": 262144, "minimum": 1, "type": "integer" }, "max_lines": { "maximum": 1000, "minimum": 1, "type": "integer" } }, "required": [ "max_lines", "max_bytes", "history_lines" ], "type": "object" }, "splice": { "additionalProperties": false, "properties": { "delete": { "minimum": 0, "type": "integer" }, "rows": { "items": { "type": "string" }, "maxItems": 1000, "type": "array" }, "start": { "minimum": 0, "type": "integer" } }, "required": [ "start", "delete", "rows" ], "type": "object" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] }, "truncated": { "type": "boolean" } }, "required": [ "target", "capture_id", "process_generation", "encoding", "row_count", "bytes", "truncated", "history_continuity", "interval", "scope", "mode", "base_capture_id", "reset", "splice", "next_cursor" ], "type": "object" } ] }, "ok": { "const": true } }, "required": [ "ok", "data" ], "type": "object" }, { "additionalProperties": false, "properties": { "error": { "additionalProperties": false, "properties": { "code": { "type": "string" }, "delivery": { "enum": [ "not_sent", "possibly_sent", "observed" ] }, "effects": { "additionalProperties": false, "properties": { "created": { "items": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] }, "maxItems": 3, "type": "array" }, "state": { "enum": [ "none", "known", "unknown" ] } }, "required": [ "state", "created" ], "type": "object" }, "message": { "type": "string" } }, "required": [ "code", "message", "delivery" ], "type": "object" }, "ok": { "const": false } }, "required": [ "ok", "error" ], "type": "object" } ] } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false } ``` --- # tmux_close Source: https://libtmux.org/en/ruby/latest/mcp/tools/tmux_close/ > Destroy one exact session, window or pane. Opt-in destructive operation; closing a session or window also removes its contained topology. Never selects by name or closes the daemon directly. Returns the final tmux client outcome. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Destroy one exact session, window or pane. Opt-in destructive operation; closing a session or window also removes its contained topology. Never selects by name or closes the daemon directly. Returns the final tmux client outcome. **Policy:** opt in with --enable-tool tmux_close. [All Ruby tools](https://libtmux.org/en/ruby/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_close.json) · [Source](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/catalog.rb#L247) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "target" ], "type": "object" } ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "data": { "additionalProperties": false, "properties": { "client_exit_status": { "const": 0 }, "delivery": { "const": "observed" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] } }, "required": [ "target", "delivery", "client_exit_status" ], "type": "object" }, "ok": { "const": true } }, "required": [ "ok", "data" ], "type": "object" }, { "additionalProperties": false, "properties": { "error": { "additionalProperties": false, "properties": { "code": { "type": "string" }, "delivery": { "enum": [ "not_sent", "possibly_sent", "observed" ] }, "effects": { "additionalProperties": false, "properties": { "created": { "items": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] }, "maxItems": 3, "type": "array" }, "state": { "enum": [ "none", "known", "unknown" ] } }, "required": [ "state", "created" ], "type": "object" }, "message": { "type": "string" } }, "required": [ "code", "message", "delivery" ], "type": "object" }, "ok": { "const": false } }, "required": [ "ok", "error" ], "type": "object" } ] } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false } ``` --- # tmux_create Source: https://libtmux.org/en/ruby/latest/mcp/tools/tmux_create/ > Create a session, window in an exact session, or split an exact pane using argv. Opt-in mutation; 64 KiB total string bytes and at most 256 argv entries. Window/pane focus defaults false. Cwd/environment are optional; size is cells or percent. Assigned refs prove creation, not program readiness or completion. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Create a session, window in an exact session, or split an exact pane using argv. Opt-in mutation; 64 KiB total string bytes and at most 256 argv entries. Window/pane focus defaults false. Cwd/environment are optional; size is cells or percent. Assigned refs prove creation, not program readiness or completion. **Policy:** opt in with --enable-tool tmux_create. [All Ruby tools](https://libtmux.org/en/ruby/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_create.json) · [Source](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/catalog.rb#L245) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "argv": { "items": { "maxLength": 65536, "pattern": "^[^\\u0000]*$", "type": "string" }, "maxItems": 256, "minItems": 1, "prefixItems": [ { "maxLength": 65536, "minLength": 1, "pattern": "^[^\\u0000]*$", "type": "string" } ], "type": "array" }, "cwd": { "maxLength": 65536, "minLength": 1, "pattern": "^[^\\u0000]*$", "type": "string" }, "environment": { "additionalProperties": { "maxLength": 65536, "pattern": "^[^\\u0000]*$", "type": "string" }, "maxProperties": 128, "propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" }, "height": { "maximum": 2147483647, "minimum": 1, "type": "integer" }, "kind": { "const": "session" }, "name": { "maxLength": 65536, "minLength": 1, "pattern": "^[^\\u0000]*$", "type": "string" }, "width": { "maximum": 2147483647, "minimum": 1, "type": "integer" }, "window_name": { "maxLength": 65536, "minLength": 1, "pattern": "^[^\\u0000]*$", "type": "string" } }, "required": [ "kind", "name", "argv" ], "type": "object" }, { "additionalProperties": false, "properties": { "argv": { "items": { "maxLength": 65536, "pattern": "^[^\\u0000]*$", "type": "string" }, "maxItems": 256, "minItems": 1, "prefixItems": [ { "maxLength": 65536, "minLength": 1, "pattern": "^[^\\u0000]*$", "type": "string" } ], "type": "array" }, "cwd": { "maxLength": 65536, "minLength": 1, "pattern": "^[^\\u0000]*$", "type": "string" }, "environment": { "additionalProperties": { "maxLength": 65536, "pattern": "^[^\\u0000]*$", "type": "string" }, "maxProperties": 128, "propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" }, "focus": { "type": "boolean" }, "index": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "kind": { "const": "window" }, "name": { "maxLength": 65536, "minLength": 1, "pattern": "^[^\\u0000]*$", "type": "string" }, "parent": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "kind", "parent", "name", "argv" ], "type": "object" }, { "additionalProperties": false, "properties": { "argv": { "items": { "maxLength": 65536, "pattern": "^[^\\u0000]*$", "type": "string" }, "maxItems": 256, "minItems": 1, "prefixItems": [ { "maxLength": 65536, "minLength": 1, "pattern": "^[^\\u0000]*$", "type": "string" } ], "type": "array" }, "cwd": { "maxLength": 65536, "minLength": 1, "pattern": "^[^\\u0000]*$", "type": "string" }, "direction": { "enum": [ "horizontal", "vertical" ] }, "environment": { "additionalProperties": { "maxLength": 65536, "pattern": "^[^\\u0000]*$", "type": "string" }, "maxProperties": 128, "propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" }, "focus": { "type": "boolean" }, "kind": { "const": "pane" }, "parent": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] }, "size": { "oneOf": [ { "maximum": 2147483647, "minimum": 1, "type": "integer" }, { "pattern": "^(?:[1-9][0-9]?|100)%$", "type": "string" } ] } }, "required": [ "kind", "parent", "direction", "argv" ], "type": "object" } ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "data": { "additionalProperties": false, "properties": { "created": { "items": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] }, "maxItems": 3, "minItems": 1, "type": "array" }, "delivery": { "const": "observed" }, "entity": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] }, "program_completion": { "const": "unobserved" } }, "required": [ "entity", "created", "delivery", "program_completion" ], "type": "object" }, "ok": { "const": true } }, "required": [ "ok", "data" ], "type": "object" }, { "additionalProperties": false, "properties": { "error": { "additionalProperties": false, "properties": { "code": { "type": "string" }, "delivery": { "enum": [ "not_sent", "possibly_sent", "observed" ] }, "effects": { "additionalProperties": false, "properties": { "created": { "items": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] }, "maxItems": 3, "type": "array" }, "state": { "enum": [ "none", "known", "unknown" ] } }, "required": [ "state", "created" ], "type": "object" }, "message": { "type": "string" } }, "required": [ "code", "message", "delivery" ], "type": "object" }, "ok": { "const": false } }, "required": [ "ok", "error" ], "type": "object" } ] } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false } ``` --- # tmux_run Source: https://libtmux.org/en/ruby/latest/mcp/tools/tmux_run/ > Run an authored POSIX script in an explicitly enrolled idle, empty zsh 5.9 editor. Opt-in; no terminal injection. Exact queue authorization binds the existing shell generation; execution may follow a later pane replacement without retargeting it. Inherits cwd/exported environment, closed stdin, separate bounded UTF-8/base64 outputs. Defaults: 65536 bytes per output, 65536 script bytes; overflow refuses completion. Reports native exit/signal only from the helper; cancellation never proves descendants stopped. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Run an authored POSIX script in an explicitly enrolled idle, empty zsh 5.9 editor. Opt-in; no terminal injection. Exact queue authorization binds the existing shell generation; execution may follow a later pane replacement without retargeting it. Inherits cwd/exported environment, closed stdin, separate bounded UTF-8/base64 outputs. Defaults: 65536 bytes per output, 65536 script bytes; overflow refuses completion. Reports native exit/signal only from the helper; cancellation never proves descendants stopped. **Policy:** opt in with --enable-tool tmux_run. [All Ruby tools](https://libtmux.org/en/ruby/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_run.json) · [Source](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/catalog.rb#L237) ## Arguments * `script` required · string See the schema for this argument’s constraints. * `stderr_limit` optional · integer See the schema for this argument’s constraints. * `stdout_limit` optional · integer See the schema for this argument’s constraints. * `target` required See the schema for this argument’s constraints. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "script": { "maxLength": 65536, "pattern": "^[^\\u0000]*$", "type": "string" }, "stderr_limit": { "maximum": 262144, "minimum": 0, "type": "integer" }, "stdout_limit": { "maximum": 262144, "minimum": 0, "type": "integer" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "target", "script" ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "data": { "additionalProperties": false, "properties": { "authorization": { "additionalProperties": false, "properties": { "enrollment_generation": { "maxLength": 32, "pattern": "^[a-f0-9]{32}$", "type": "string" }, "pane_id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "process_generation": { "maxLength": 32, "pattern": "^[a-f0-9]{32}$", "type": "string" }, "run_id": { "maxLength": 32, "pattern": "^[a-f0-9]{32}$", "type": "string" }, "script_digest": { "maxLength": 64, "pattern": "^[a-f0-9]{64}$", "type": "string" }, "server_generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "state": { "const": "authorized" } }, "required": [ "state", "run_id", "script_digest", "server_generation", "pane_id", "enrollment_generation", "process_generation" ], "type": "object" }, "completion": { "oneOf": [ { "additionalProperties": false, "properties": { "exit_status": { "maximum": 255, "minimum": 0, "type": "integer" }, "signal": { "type": "null" }, "state": { "const": "exited" } }, "required": [ "state", "exit_status", "signal" ], "type": "object" }, { "additionalProperties": false, "properties": { "exit_status": { "type": "null" }, "signal": { "maximum": 255, "minimum": 1, "type": "integer" }, "state": { "const": "signaled" } }, "required": [ "state", "exit_status", "signal" ], "type": "object" } ] }, "stderr": { "additionalProperties": false, "properties": { "bytes": { "maximum": 262144, "minimum": 0, "type": "integer" }, "data": { "maxLength": 349528, "type": "string" }, "encoding": { "enum": [ "utf-8", "base64" ] }, "truncated": { "const": false } }, "required": [ "encoding", "data", "bytes", "truncated" ], "type": "object" }, "stdout": { "additionalProperties": false, "properties": { "bytes": { "maximum": 262144, "minimum": 0, "type": "integer" }, "data": { "maxLength": 349528, "type": "string" }, "encoding": { "enum": [ "utf-8", "base64" ] }, "truncated": { "const": false } }, "required": [ "encoding", "data", "bytes", "truncated" ], "type": "object" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "target", "authorization", "completion", "stdout", "stderr" ], "type": "object" }, "ok": { "const": true } }, "required": [ "ok", "data" ], "type": "object" }, { "additionalProperties": false, "properties": { "error": { "additionalProperties": false, "properties": { "code": { "type": "string" }, "delivery": { "enum": [ "not_sent", "possibly_sent", "observed" ] }, "effects": { "additionalProperties": false, "properties": { "authorization": { "oneOf": [ { "additionalProperties": false, "properties": { "enrollment_generation": { "maxLength": 32, "pattern": "^[a-f0-9]{32}$", "type": "string" }, "pane_id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "process_generation": { "maxLength": 32, "pattern": "^[a-f0-9]{32}$", "type": "string" }, "run_id": { "maxLength": 32, "pattern": "^[a-f0-9]{32}$", "type": "string" }, "script_digest": { "maxLength": 64, "pattern": "^[a-f0-9]{64}$", "type": "string" }, "server_generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "state": { "const": "authorized" } }, "required": [ "state", "run_id", "script_digest", "server_generation", "pane_id", "enrollment_generation", "process_generation" ], "type": "object" }, { "type": "null" } ] }, "completion": { "oneOf": [ { "additionalProperties": false, "properties": { "state": { "const": "unobserved" } }, "required": [ "state" ], "type": "object" }, { "additionalProperties": false, "properties": { "exit_status": { "maximum": 255, "minimum": 0, "type": "integer" }, "signal": { "type": "null" }, "state": { "const": "exited" } }, "required": [ "state", "exit_status", "signal" ], "type": "object" }, { "additionalProperties": false, "properties": { "exit_status": { "type": "null" }, "signal": { "maximum": 255, "minimum": 1, "type": "integer" }, "state": { "const": "signaled" } }, "required": [ "state", "exit_status", "signal" ], "type": "object" } ] }, "state": { "enum": [ "none", "known", "unknown" ] } }, "required": [ "state", "authorization", "completion" ], "type": "object" }, "message": { "type": "string" } }, "required": [ "code", "message", "delivery" ], "type": "object" }, "ok": { "const": false } }, "required": [ "ok", "error" ], "type": "object" } ] } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false } ``` --- # tmux_send Source: https://libtmux.org/en/ruby/latest/mcp/tools/tmux_send/ > Send literal UTF-8 text or named keys to one exact pane. Opt-in mutation; 64 KiB total text bytes, at most 256 keys. Reports tmux client completion and input dispatch only; never shell completion. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Send literal UTF-8 text or named keys to one exact pane. Opt-in mutation; 64 KiB total text bytes, at most 256 keys. Reports tmux client completion and input dispatch only; never shell completion. **Policy:** opt in with --enable-tool tmux_send. [All Ruby tools](https://libtmux.org/en/ruby/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_send.json) · [Source](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/catalog.rb#L243) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "input": { "oneOf": [ { "additionalProperties": false, "properties": { "text": { "maxLength": 65536, "pattern": "^[^\\u0000]*$", "type": "string" }, "type": { "const": "text" } }, "required": [ "type", "text" ], "type": "object" }, { "additionalProperties": false, "properties": { "keys": { "items": { "maxLength": 65536, "minLength": 1, "pattern": "^[^\\u0000]*$", "type": "string" }, "maxItems": 256, "minItems": 1, "type": "array" }, "type": { "const": "keys" } }, "required": [ "type", "keys" ], "type": "object" } ] }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "target", "input" ], "type": "object" } ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "data": { "additionalProperties": false, "properties": { "client_exit_status": { "const": 0 }, "completion": { "const": "dispatch_only" }, "delivery": { "const": "observed" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] } }, "required": [ "target", "delivery", "client_exit_status", "completion" ], "type": "object" }, "ok": { "const": true } }, "required": [ "ok", "data" ], "type": "object" }, { "additionalProperties": false, "properties": { "error": { "additionalProperties": false, "properties": { "code": { "type": "string" }, "delivery": { "enum": [ "not_sent", "possibly_sent", "observed" ] }, "effects": { "additionalProperties": false, "properties": { "created": { "items": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] }, "maxItems": 3, "type": "array" }, "state": { "enum": [ "none", "known", "unknown" ] } }, "required": [ "state", "created" ], "type": "object" }, "message": { "type": "string" } }, "required": [ "code", "message", "delivery" ], "type": "object" }, "ok": { "const": false } }, "required": [ "ok", "error" ], "type": "object" } ] } ``` Tool annotations ```json { "destructiveHint": true, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false } ``` --- # tmux_snapshot Source: https://libtmux.org/en/ruby/latest/mcp/tools/tmux_snapshot/ > Capture ordered metadata and evaluate Ruby criteria locally. Pages retain one immutable capture; expired cursors require a new query. Limit defaults to 50 records, maximum 200. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Capture ordered metadata and evaluate Ruby criteria locally. Pages retain one immutable capture; expired cursors require a new query. Limit defaults to 50 records, maximum 200. **Policy:** enabled by default. [All Ruby tools](https://libtmux.org/en/ruby/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_snapshot.json) · [Source](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/catalog.rb#L6) ## Arguments * `criteria` optional See the schema for this argument’s constraints. * `cursor` optional · string See the schema for this argument’s constraints. * `entity` optional See the schema for this argument’s constraints. * `limit` optional · integer See the schema for this argument’s constraints. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$defs": { "client": { "additionalProperties": false, "properties": { "and": { "items": { "$ref": "#/$defs/client" }, "maxItems": 2048, "type": "array" }, "controlMode": { "$ref": "#/$defs/client.control_mode" }, "created": { "$ref": "#/$defs/client.created" }, "height": { "$ref": "#/$defs/client.height" }, "name": { "$ref": "#/$defs/client.name" }, "not": { "$ref": "#/$defs/client" }, "or": { "items": { "$ref": "#/$defs/client" }, "maxItems": 2048, "type": "array" }, "pid": { "$ref": "#/$defs/client.pid" }, "readOnly": { "$ref": "#/$defs/client.read_only" }, "session": { "additionalProperties": false, "minProperties": 1, "properties": { "is": { "anyOf": [ { "$ref": "#/$defs/session" }, { "type": "null" } ] }, "isNot": { "anyOf": [ { "$ref": "#/$defs/session" }, { "type": "null" } ] } }, "type": "object" }, "sessionId": { "$ref": "#/$defs/client.session_id" }, "tty": { "$ref": "#/$defs/client.tty" }, "utf8": { "$ref": "#/$defs/client.utf8" }, "width": { "$ref": "#/$defs/client.width" } }, "type": "object" }, "client.control_mode": { "anyOf": [ { "type": "boolean" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "type": "boolean" }, "in": { "items": { "type": "boolean" }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/client.control_mode" } }, "type": "object" } ] }, "client.created": { "anyOf": [ { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "gt": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "gte": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "in": { "items": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "lte": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "not": { "$ref": "#/$defs/client.created" } }, "type": "object" } ] }, "client.height": { "anyOf": [ { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "type": "null" } ] }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "type": "null" } ] }, "gt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "in": { "items": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "type": "null" } ] }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "lte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/client.height" } }, "type": "object" } ] }, "client.name": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "contains": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "endsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/client.name" }, "startsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 } }, "type": "object" } ] }, "client.pid": { "anyOf": [ { "maximum": 2147483647, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "gt": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "gte": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "lte": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/client.pid" } }, "type": "object" } ] }, "client.read_only": { "anyOf": [ { "type": "boolean" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "type": "boolean" }, "in": { "items": { "type": "boolean" }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/client.read_only" } }, "type": "object" } ] }, "client.session_id": { "anyOf": [ { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "type": "null" } ] }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "type": "null" } ] }, "in": { "items": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "type": "null" } ] }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/client.session_id" } }, "type": "object" } ] }, "client.tty": { "anyOf": [ { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "type": "null" } ] }, { "additionalProperties": false, "minProperties": 1, "properties": { "contains": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "endsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "equals": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "type": "null" } ] }, "in": { "items": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "type": "null" } ] }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/client.tty" }, "startsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 } }, "type": "object" } ] }, "client.utf8": { "anyOf": [ { "type": "boolean" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "type": "boolean" }, "in": { "items": { "type": "boolean" }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/client.utf8" } }, "type": "object" } ] }, "client.width": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "lte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/client.width" } }, "type": "object" } ] }, "pane": { "additionalProperties": false, "properties": { "active": { "$ref": "#/$defs/pane.active" }, "and": { "items": { "$ref": "#/$defs/pane" }, "maxItems": 2048, "type": "array" }, "currentCommand": { "$ref": "#/$defs/pane.current_command" }, "currentPath": { "$ref": "#/$defs/pane.current_path" }, "dead": { "$ref": "#/$defs/pane.dead" }, "deadStatus": { "$ref": "#/$defs/pane.dead_status" }, "height": { "$ref": "#/$defs/pane.height" }, "id": { "$ref": "#/$defs/pane.id" }, "index": { "$ref": "#/$defs/pane.index" }, "not": { "$ref": "#/$defs/pane" }, "or": { "items": { "$ref": "#/$defs/pane" }, "maxItems": 2048, "type": "array" }, "pid": { "$ref": "#/$defs/pane.pid" }, "title": { "$ref": "#/$defs/pane.title" }, "width": { "$ref": "#/$defs/pane.width" }, "window": { "additionalProperties": false, "minProperties": 1, "properties": { "is": { "$ref": "#/$defs/window" }, "isNot": { "$ref": "#/$defs/window" } }, "type": "object" }, "windowId": { "$ref": "#/$defs/pane.window_id" } }, "type": "object" }, "pane.active": { "anyOf": [ { "type": "boolean" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "type": "boolean" }, "in": { "items": { "type": "boolean" }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/pane.active" } }, "type": "object" } ] }, "pane.current_command": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "contains": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "endsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/pane.current_command" }, "startsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 } }, "type": "object" } ] }, "pane.current_path": { "anyOf": [ { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "type": "null" } ] }, { "additionalProperties": false, "minProperties": 1, "properties": { "contains": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "endsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "equals": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "type": "null" } ] }, "in": { "items": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "type": "null" } ] }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/pane.current_path" }, "startsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 } }, "type": "object" } ] }, "pane.dead": { "anyOf": [ { "type": "boolean" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "type": "boolean" }, "in": { "items": { "type": "boolean" }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/pane.dead" } }, "type": "object" } ] }, "pane.dead_status": { "anyOf": [ { "anyOf": [ { "maximum": 255, "minimum": 0, "type": "integer" }, { "type": "null" } ] }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "anyOf": [ { "maximum": 255, "minimum": 0, "type": "integer" }, { "type": "null" } ] }, "gt": { "maximum": 255, "minimum": 0, "type": "integer" }, "gte": { "maximum": 255, "minimum": 0, "type": "integer" }, "in": { "items": { "anyOf": [ { "maximum": 255, "minimum": 0, "type": "integer" }, { "type": "null" } ] }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 255, "minimum": 0, "type": "integer" }, "lte": { "maximum": 255, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/pane.dead_status" } }, "type": "object" } ] }, "pane.height": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "lte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/pane.height" } }, "type": "object" } ] }, "pane.id": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/pane.id" } }, "type": "object" } ] }, "pane.index": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "lte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/pane.index" } }, "type": "object" } ] }, "pane.pid": { "anyOf": [ { "maximum": 2147483647, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "gt": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "gte": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "lte": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/pane.pid" } }, "type": "object" } ] }, "pane.title": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "contains": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "endsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/pane.title" }, "startsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 } }, "type": "object" } ] }, "pane.width": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "lte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/pane.width" } }, "type": "object" } ] }, "pane.window_id": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/pane.window_id" } }, "type": "object" } ] }, "session": { "additionalProperties": false, "properties": { "and": { "items": { "$ref": "#/$defs/session" }, "maxItems": 2048, "type": "array" }, "attached": { "$ref": "#/$defs/session.attached" }, "created": { "$ref": "#/$defs/session.created" }, "currentWindow": { "additionalProperties": false, "minProperties": 1, "properties": { "is": { "anyOf": [ { "$ref": "#/$defs/window" }, { "type": "null" } ] }, "isNot": { "anyOf": [ { "$ref": "#/$defs/window" }, { "type": "null" } ] } }, "type": "object" }, "id": { "$ref": "#/$defs/session.id" }, "name": { "$ref": "#/$defs/session.name" }, "not": { "$ref": "#/$defs/session" }, "or": { "items": { "$ref": "#/$defs/session" }, "maxItems": 2048, "type": "array" }, "panes": { "additionalProperties": false, "minProperties": 1, "properties": { "every": { "$ref": "#/$defs/pane" }, "none": { "$ref": "#/$defs/pane" }, "some": { "$ref": "#/$defs/pane" } }, "type": "object" }, "windowCount": { "$ref": "#/$defs/session.window_count" }, "windowLinks": { "additionalProperties": false, "minProperties": 1, "properties": { "every": { "$ref": "#/$defs/window_link" }, "none": { "$ref": "#/$defs/window_link" }, "some": { "$ref": "#/$defs/window_link" } }, "type": "object" }, "windows": { "additionalProperties": false, "minProperties": 1, "properties": { "every": { "$ref": "#/$defs/window" }, "none": { "$ref": "#/$defs/window" }, "some": { "$ref": "#/$defs/window" } }, "type": "object" } }, "type": "object" }, "session.attached": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "lte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/session.attached" } }, "type": "object" } ] }, "session.created": { "anyOf": [ { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "gt": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "gte": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "in": { "items": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "lte": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "not": { "$ref": "#/$defs/session.created" } }, "type": "object" } ] }, "session.id": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/session.id" } }, "type": "object" } ] }, "session.name": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "contains": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "endsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/session.name" }, "startsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 } }, "type": "object" } ] }, "session.window_count": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "lte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/session.window_count" } }, "type": "object" } ] }, "window": { "additionalProperties": false, "properties": { "activePane": { "additionalProperties": false, "minProperties": 1, "properties": { "is": { "anyOf": [ { "$ref": "#/$defs/pane" }, { "type": "null" } ] }, "isNot": { "anyOf": [ { "$ref": "#/$defs/pane" }, { "type": "null" } ] } }, "type": "object" }, "and": { "items": { "$ref": "#/$defs/window" }, "maxItems": 2048, "type": "array" }, "height": { "$ref": "#/$defs/window.height" }, "id": { "$ref": "#/$defs/window.id" }, "layout": { "$ref": "#/$defs/window.layout" }, "name": { "$ref": "#/$defs/window.name" }, "not": { "$ref": "#/$defs/window" }, "or": { "items": { "$ref": "#/$defs/window" }, "maxItems": 2048, "type": "array" }, "paneCount": { "$ref": "#/$defs/window.pane_count" }, "panes": { "additionalProperties": false, "minProperties": 1, "properties": { "every": { "$ref": "#/$defs/pane" }, "none": { "$ref": "#/$defs/pane" }, "some": { "$ref": "#/$defs/pane" } }, "type": "object" }, "width": { "$ref": "#/$defs/window.width" }, "windowLinks": { "additionalProperties": false, "minProperties": 1, "properties": { "every": { "$ref": "#/$defs/window_link" }, "none": { "$ref": "#/$defs/window_link" }, "some": { "$ref": "#/$defs/window_link" } }, "type": "object" } }, "type": "object" }, "window_link": { "additionalProperties": false, "properties": { "active": { "$ref": "#/$defs/window_link.active" }, "and": { "items": { "$ref": "#/$defs/window_link" }, "maxItems": 2048, "type": "array" }, "index": { "$ref": "#/$defs/window_link.index" }, "not": { "$ref": "#/$defs/window_link" }, "or": { "items": { "$ref": "#/$defs/window_link" }, "maxItems": 2048, "type": "array" }, "session": { "additionalProperties": false, "minProperties": 1, "properties": { "is": { "$ref": "#/$defs/session" }, "isNot": { "$ref": "#/$defs/session" } }, "type": "object" }, "sessionId": { "$ref": "#/$defs/window_link.session_id" }, "window": { "additionalProperties": false, "minProperties": 1, "properties": { "is": { "$ref": "#/$defs/window" }, "isNot": { "$ref": "#/$defs/window" } }, "type": "object" }, "windowId": { "$ref": "#/$defs/window_link.window_id" } }, "type": "object" }, "window_link.active": { "anyOf": [ { "type": "boolean" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "type": "boolean" }, "in": { "items": { "type": "boolean" }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/window_link.active" } }, "type": "object" } ] }, "window_link.index": { "anyOf": [ { "maximum": 2147483647, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "gt": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "gte": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "lte": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/window_link.index" } }, "type": "object" } ] }, "window_link.session_id": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/window_link.session_id" } }, "type": "object" } ] }, "window_link.window_id": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/window_link.window_id" } }, "type": "object" } ] }, "window.height": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "lte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/window.height" } }, "type": "object" } ] }, "window.id": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/window.id" } }, "type": "object" } ] }, "window.layout": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "contains": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "endsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/window.layout" }, "startsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 } }, "type": "object" } ] }, "window.name": { "anyOf": [ { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, { "additionalProperties": false, "minProperties": 1, "properties": { "contains": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "endsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "equals": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "in": { "items": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 }, "maxItems": 1024, "type": "array" }, "not": { "$ref": "#/$defs/window.name" }, "startsWith": { "maxLength": 65536, "type": "string", "x-maxUtf8Bytes": 65536 } }, "type": "object" } ] }, "window.pane_count": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "lte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/window.pane_count" } }, "type": "object" } ] }, "window.width": { "anyOf": [ { "maximum": 4294967295, "minimum": 0, "type": "integer" }, { "additionalProperties": false, "minProperties": 1, "properties": { "equals": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "gte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "in": { "items": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "maxItems": 1024, "type": "array" }, "lt": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "lte": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "not": { "$ref": "#/$defs/window.width" } }, "type": "object" } ] } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "oneOf": [ { "not": { "required": [ "cursor" ] }, "required": [ "entity" ] }, { "not": { "anyOf": [ { "required": [ "entity" ] }, { "required": [ "criteria" ] }, { "required": [ "limit" ] } ] }, "required": [ "cursor" ] } ], "properties": { "criteria": { "oneOf": [ { "additionalProperties": false, "properties": { "entity": { "const": "session" }, "profile": { "const": "libtmux-ruby.where" }, "version": { "const": 1, "type": "integer" }, "where": { "$ref": "#/$defs/session" } }, "required": [ "profile", "version", "entity", "where" ], "type": "object" }, { "additionalProperties": false, "properties": { "entity": { "const": "window" }, "profile": { "const": "libtmux-ruby.where" }, "version": { "const": 1, "type": "integer" }, "where": { "$ref": "#/$defs/window" } }, "required": [ "profile", "version", "entity", "where" ], "type": "object" }, { "additionalProperties": false, "properties": { "entity": { "const": "pane" }, "profile": { "const": "libtmux-ruby.where" }, "version": { "const": 1, "type": "integer" }, "where": { "$ref": "#/$defs/pane" } }, "required": [ "profile", "version", "entity", "where" ], "type": "object" }, { "additionalProperties": false, "properties": { "entity": { "const": "window_link" }, "profile": { "const": "libtmux-ruby.where" }, "version": { "const": 1, "type": "integer" }, "where": { "$ref": "#/$defs/window_link" } }, "required": [ "profile", "version", "entity", "where" ], "type": "object" }, { "additionalProperties": false, "properties": { "entity": { "const": "client" }, "profile": { "const": "libtmux-ruby.where" }, "version": { "const": 1, "type": "integer" }, "where": { "$ref": "#/$defs/client" } }, "required": [ "profile", "version", "entity", "where" ], "type": "object" } ] }, "cursor": { "maxLength": 43, "pattern": "^[a-f0-9]{32}:[0-9]{1,10}$", "type": "string" }, "entity": { "enum": [ "session", "window", "pane", "window_link", "client" ] }, "limit": { "maximum": 200, "minimum": 1, "type": "integer" } }, "required": [], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "data": { "additionalProperties": false, "properties": { "capture_id": { "type": "string" }, "coverage": { "additionalProperties": { "enum": [ "complete", "unloaded" ] }, "type": "object" }, "entity": { "enum": [ "session", "window", "pane", "window_link", "client" ] }, "interval": { "additionalProperties": false, "properties": { "clock": { "const": "monotonic_seconds" }, "finished": { "type": "number" }, "reads": { "minimum": 0, "type": "integer" }, "started": { "type": "number" } }, "required": [ "clock", "started", "finished", "reads" ], "type": "object" }, "items": { "items": { "oneOf": [ { "additionalProperties": false, "properties": { "fields": { "additionalProperties": false, "properties": { "attached": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "created": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "id": { "type": "string" }, "name": { "type": "string" }, "windowCount": { "maximum": 4294967295, "minimum": 0, "type": "integer" } }, "required": [ "id", "name", "created", "attached", "windowCount" ], "type": "object" }, "kind": { "const": "session" }, "ref": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "kind", "fields", "ref" ], "type": "object" }, { "additionalProperties": false, "properties": { "fields": { "additionalProperties": false, "properties": { "height": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "id": { "type": "string" }, "layout": { "type": "string" }, "name": { "type": "string" }, "paneCount": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "width": { "maximum": 4294967295, "minimum": 0, "type": "integer" } }, "required": [ "id", "name", "width", "height", "paneCount", "layout" ], "type": "object" }, "kind": { "const": "window" }, "ref": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "kind", "fields", "ref" ], "type": "object" }, { "additionalProperties": false, "properties": { "fields": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "currentCommand": { "type": "string" }, "currentPath": { "type": [ "string", "null" ] }, "dead": { "type": "boolean" }, "deadStatus": { "maximum": 255, "minimum": 0, "type": [ "integer", "null" ] }, "height": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "id": { "type": "string" }, "index": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "pid": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "title": { "type": "string" }, "width": { "maximum": 4294967295, "minimum": 0, "type": "integer" }, "windowId": { "type": "string" } }, "required": [ "id", "windowId", "index", "pid", "currentCommand", "currentPath", "title", "active", "dead", "deadStatus", "width", "height" ], "type": "object" }, "kind": { "const": "pane" }, "ref": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "kind", "fields", "ref" ], "type": "object" }, { "additionalProperties": false, "properties": { "fields": { "additionalProperties": false, "properties": { "active": { "type": "boolean" }, "index": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "sessionId": { "type": "string" }, "windowId": { "type": "string" } }, "required": [ "sessionId", "windowId", "index", "active" ], "type": "object" }, "kind": { "const": "window_link" }, "ref": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] } }, "required": [ "kind", "fields", "ref" ], "type": "object" }, { "additionalProperties": false, "properties": { "fields": { "additionalProperties": false, "properties": { "controlMode": { "type": "boolean" }, "created": { "maximum": 9223372036854776000, "minimum": -9223372036854776000, "type": "integer" }, "height": { "maximum": 4294967295, "minimum": 0, "type": [ "integer", "null" ] }, "name": { "type": "string" }, "pid": { "maximum": 2147483647, "minimum": 0, "type": "integer" }, "readOnly": { "type": "boolean" }, "sessionId": { "type": [ "string", "null" ] }, "tty": { "type": [ "string", "null" ] }, "utf8": { "type": "boolean" }, "width": { "maximum": 4294967295, "minimum": 0, "type": "integer" } }, "required": [ "name", "pid", "created", "tty", "sessionId", "width", "height", "readOnly", "utf8", "controlMode" ], "type": "object" }, "kind": { "const": "client" }, "ref": { "type": "null" } }, "required": [ "kind", "fields", "ref" ], "type": "object" } ] }, "maxItems": 200, "type": "array" }, "next_cursor": { "type": "string" }, "server_identity": { "additionalProperties": false, "properties": { "generation": { "type": "string" }, "pid": { "type": "integer" }, "start_time": { "type": "integer" }, "tmux_version": { "type": "string" } }, "required": [ "generation", "pid", "start_time", "tmux_version" ], "type": "object" }, "truncated": { "type": "boolean" } }, "required": [ "capture_id", "server_identity", "entity", "items", "coverage", "interval", "truncated" ], "type": "object" }, "ok": { "const": true } }, "required": [ "ok", "data" ], "type": "object" }, { "additionalProperties": false, "properties": { "error": { "additionalProperties": false, "properties": { "code": { "type": "string" }, "delivery": { "enum": [ "not_sent", "possibly_sent", "observed" ] }, "effects": { "additionalProperties": false, "properties": { "created": { "items": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] }, "maxItems": 3, "type": "array" }, "state": { "enum": [ "none", "known", "unknown" ] } }, "required": [ "state", "created" ], "type": "object" }, "message": { "type": "string" } }, "required": [ "code", "message", "delivery" ], "type": "object" }, "ok": { "const": false } }, "required": [ "ok", "error" ], "type": "object" } ] } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false } ``` --- # tmux_wait Source: https://libtmux.org/en/ruby/latest/mcp/tools/tmux_wait/ > Wait for observed literal screen text or the initial pane process exit. Deadline in seconds is capped by the application limit. Uses control events/process descriptors; no polling. Requires tmux>=3.3 and Linux peer pidfds with matching PID namespaces or Darwin kqueue process observation. Reports observed evidence, never remote termination caused by cancellation or an inferred process exit status. MCP is in development Server behavior and tool contracts may change. Tool availability depends on the server configuration. Wait for observed literal screen text or the initial pane process exit. Deadline in seconds is capped by the application limit. Uses control events/process descriptors; no polling. Requires tmux>=3.3 and Linux peer pidfds with matching PID namespaces or Darwin kqueue process observation. Reports observed evidence, never remote termination caused by cancellation or an inferred process exit status. **Policy:** opt in with --enable-tool tmux_wait. [All Ruby tools](https://libtmux.org/en/ruby/latest/mcp/tools/) · [JSON](https://libtmux.org/en/ruby/latest/mcp/tools/tmux_wait.json) · [Source](https://github.com/libtmux/libtmux-ruby/blob/9b1545562a112353c2c893a1d3e8c0d9b4b51f8d/gems/libtmux-mcp/lib/libtmux/mcp/catalog.rb#L241) ## Arguments This tool has no top-level named arguments. Consult its schema below. ## Schemas The schema defines required fields, nested values, defaults, and validation constraints. Input schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "condition": { "oneOf": [ { "additionalProperties": false, "properties": { "text": { "maxLength": 4096, "minLength": 1, "type": "string" }, "type": { "const": "screen_contains" } }, "required": [ "type", "text" ], "type": "object" }, { "additionalProperties": false, "properties": { "type": { "const": "process_exit" } }, "required": [ "type" ], "type": "object" } ] }, "history_lines": { "maximum": 1000, "minimum": 0, "type": "integer" }, "max_bytes": { "maximum": 262144, "minimum": 1, "type": "integer" }, "max_lines": { "maximum": 1000, "minimum": 1, "type": "integer" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] }, "timeout": { "exclusiveMinimum": 0, "maximum": 60, "type": "number" } }, "required": [ "target", "condition" ], "type": "object" } ], "type": "object" } ``` Output schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "additionalProperties": false, "properties": { "data": { "oneOf": [ { "additionalProperties": false, "properties": { "capture": { "oneOf": [ { "additionalProperties": false, "properties": { "bytes": { "maximum": 262144, "minimum": 0, "type": "integer" }, "capture_id": { "type": "string" }, "encoding": { "enum": [ "utf-8", "base64" ] }, "history_continuity": { "const": "unknown" }, "interval": { "additionalProperties": false, "properties": { "clock": { "const": "monotonic_seconds" }, "finished": { "type": "number" }, "started": { "type": "number" } }, "required": [ "clock", "started", "finished" ], "type": "object" }, "mode": { "const": "snapshot" }, "next_cursor": { "type": "string" }, "process_generation": { "type": [ "string", "null" ] }, "row_count": { "maximum": 1000, "minimum": 0, "type": "integer" }, "rows": { "items": { "type": "string" }, "maxItems": 1000, "type": "array" }, "scope": { "additionalProperties": false, "properties": { "history_lines": { "maximum": 1000, "minimum": 0, "type": "integer" }, "max_bytes": { "maximum": 262144, "minimum": 1, "type": "integer" }, "max_lines": { "maximum": 1000, "minimum": 1, "type": "integer" } }, "required": [ "max_lines", "max_bytes", "history_lines" ], "type": "object" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] }, "truncated": { "type": "boolean" } }, "required": [ "target", "capture_id", "process_generation", "encoding", "row_count", "bytes", "truncated", "history_continuity", "interval", "scope", "mode", "rows" ], "type": "object" }, { "additionalProperties": false, "properties": { "base_capture_id": { "type": "string" }, "bytes": { "maximum": 262144, "minimum": 0, "type": "integer" }, "capture_id": { "type": "string" }, "encoding": { "enum": [ "utf-8", "base64" ] }, "history_continuity": { "const": "unknown" }, "interval": { "additionalProperties": false, "properties": { "clock": { "const": "monotonic_seconds" }, "finished": { "type": "number" }, "started": { "type": "number" } }, "required": [ "clock", "started", "finished" ], "type": "object" }, "mode": { "const": "delta" }, "next_cursor": { "type": "string" }, "process_generation": { "type": [ "string", "null" ] }, "reset": { "type": "boolean" }, "row_count": { "maximum": 1000, "minimum": 0, "type": "integer" }, "scope": { "additionalProperties": false, "properties": { "history_lines": { "maximum": 1000, "minimum": 0, "type": "integer" }, "max_bytes": { "maximum": 262144, "minimum": 1, "type": "integer" }, "max_lines": { "maximum": 1000, "minimum": 1, "type": "integer" } }, "required": [ "max_lines", "max_bytes", "history_lines" ], "type": "object" }, "splice": { "additionalProperties": false, "properties": { "delete": { "minimum": 0, "type": "integer" }, "rows": { "items": { "type": "string" }, "maxItems": 1000, "type": "array" }, "start": { "minimum": 0, "type": "integer" } }, "required": [ "start", "delete", "rows" ], "type": "object" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] }, "truncated": { "type": "boolean" } }, "required": [ "target", "capture_id", "process_generation", "encoding", "row_count", "bytes", "truncated", "history_continuity", "interval", "scope", "mode", "base_capture_id", "reset", "splice", "next_cursor" ], "type": "object" } ] }, "condition": { "const": "screen_contains" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "target", "condition", "capture" ], "type": "object" }, { "additionalProperties": false, "properties": { "condition": { "const": "process_exit" }, "exit_status": { "const": "unobserved" }, "observed_at": { "type": "number" }, "process_generation": { "type": "string" }, "target": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" } ] } }, "required": [ "target", "condition", "process_generation", "observed_at", "exit_status" ], "type": "object" } ] }, "ok": { "const": true } }, "required": [ "ok", "data" ], "type": "object" }, { "additionalProperties": false, "properties": { "error": { "additionalProperties": false, "properties": { "code": { "type": "string" }, "delivery": { "enum": [ "not_sent", "possibly_sent", "observed" ] }, "effects": { "additionalProperties": false, "properties": { "created": { "items": { "oneOf": [ { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" }, "kind": { "const": "session" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "kind": { "const": "window" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^%[0-9]+$", "type": "string" }, "kind": { "const": "pane" } }, "required": [ "generation", "kind", "id" ], "type": "object" }, { "additionalProperties": false, "properties": { "generation": { "maxLength": 128, "minLength": 1, "type": "string" }, "id": { "maxLength": 32, "pattern": "^@[0-9]+$", "type": "string" }, "index": { "minimum": 0, "type": "integer" }, "kind": { "const": "window_link" }, "session_id": { "maxLength": 32, "pattern": "^\\$[0-9]+$", "type": "string" } }, "required": [ "generation", "kind", "id", "session_id", "index" ], "type": "object" } ] }, "maxItems": 3, "type": "array" }, "state": { "enum": [ "none", "known", "unknown" ] } }, "required": [ "state", "created" ], "type": "object" }, "message": { "type": "string" } }, "required": [ "code", "message", "delivery" ], "type": "object" }, "ok": { "const": false } }, "required": [ "ok", "error" ], "type": "object" } ] } ``` Tool annotations ```json { "destructiveHint": false, "idempotentHint": false, "openWorldHint": false, "readOnlyHint": false } ```