Core LibraryalphaGuides

Choose documentation 3

v0.1.0.alpha.3

Current version

v0.1.0.alpha.3
English

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

Getting started

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 · Find things · Packages · Guide · API reference · Recipes · API on libtmux.org

Alpha. APIs may change between releases. See the initial alpha notes and release guide.

It suits scripts, tests that need a real tmux, and tools that drive a terminal program. An MCP server, an Async adapter and a workspace loader ship beside the core, under Packages.

Contents — Quick start · Find things · Your own server · Packages · Build from source · Leaves out · Support · Documentation

Quick start

Install the core prerelease from RubyGems. It needs Ruby 3.3 or newer and tmux 3.3a or newer on PATH:

Terminal window
$ gem install libtmux --pre

This program creates a session, adds a window, splits it, and prints each window with its panes. Server.start closes its private tmux server when the block exits, and the snapshot stays readable afterward:

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

From a checkout, run the complete example:

Terminal window
$ mise exec -- bundle exec ruby examples/quickstart.rb

It prints:

main: %0
logs: %1, %2

Pane commands take argument arrays. Server.start gives its tmux server a socket and an empty configuration of its own, so it never touches a tmux you already use.

Find things in a snapshot

Server#snapshot: one read, many queries

Continue with the snapshot above. where accepts criteria as data, and select accepts a Ruby block. These queries make no tmux calls:

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.

A selection keeps the membership it captured. Call server.snapshot again while the server is open to read later changes.

The field catalog lists query fields and wire names, and the list/filter recipe covers exact matches and queries after close.

Use the tmux server you already run

Server.new: borrow a daemon

Server.open and Server.new bind an endpoint that already exists, such as Server.open(socket_path: ...). Closing the binding leaves the daemon running. The outer Server.start block here only supplies a daemon to borrow:

require "libtmux"
LibTmux::Server.start do |owner|
owner.new_session(name: "work", command: ["/bin/cat"])
server = LibTmux::Server.new(endpoint: owner.endpoint)
begin
puts "connected sessions: #{server.list_sessions.length}"
ensure
server.close
end
puts "sessions after client close: #{owner.list_sessions.length}"
end

It prints:

connected sessions: 1
sessions after client close: 1

See ownership and errors for what close and failure mean.

Packages

Start with libtmux. Add the companion for your caller:

GemRequireUse it for
libtmuxlibtmuxBlocking scripts, snapshots, and control connections
libtmux-asynclibtmux/asyncConcurrent commands and bounded streams in Async tasks
libtmux-mcplibtmux/mcpAn MCP server with explicit endpoints and tool policy
libtmux-workspacelibtmux/workspaceYAML/JSON workspace plans and a CLI to apply them

Requiring a gem starts no tmux process, scheduler, or protocol server. The companion gems install separately, and need --pre for their alpha versions too. Execution modes explains blocking calls, Async tasks, and control subscriptions.

libtmux: the core

Blocking server, session, window and pane handles, immutable snapshots, and control connections. Require libtmux.

API reference · Guides · RubyGems

Terminal window
$ gem install libtmux --pre

The quick start and snapshot queries above run against this gem.

libtmux-async: concurrent commands

Concurrent commands and bounded control streams inside an Async task that your application owns. Require libtmux/async, then open a scope with LibTmux::Async.open.

API reference · Guide · RubyGems

Terminal window
$ gem install libtmux-async --pre

Capture every pane concurrently with Scope#map. server is an open LibTmux::Server:

Async do |parent|
LibTmux::Async.open(parent: parent, server: server) do |scope|
refs = scope.server.list_panes.map(&:ref)
screens = scope.map(refs, concurrency: 2) { |ref| scope.server.pane(ref).capture }
Example.check(screens.length == refs.length && screens.all?(&:success?), "concurrent captures failed")
end
end.wait

libtmux-mcp: a tmux server for MCP clients

An MCP server over stdio for one tmux server, with an explicit tool policy. Installs libtmux-mcp; require libtmux/mcp to embed it through LibTmux::MCP::Application.

API reference · Tools · Guides · RubyGems

Terminal window
$ gem install libtmux-mcp --pre

The server borrows a tmux server that is already running. Start one on a socket of its own:

Terminal window
$ tmux -L agent new-session -d -s work

Add the server to Claude Code. Until you enable more tools, it serves tmux_capabilities and tmux_snapshot:

Terminal window
$ claude mcp add tmux -- libtmux-mcp --socket-name agent --endpoint dev

The MCP README covers other clients, every tool and authored shell commands. Tracked captures, waits and authored runs need tmux 3.3a or newer and native process identity.

libtmux-workspace: YAML workspaces

YAML or JSON workspaces, validated, planned offline and applied to an open server. Installs libtmux-workspace; require libtmux/workspace to use it from Ruby through LibTmux::Workspace.

API reference · Command reference · Guides · RubyGems

Terminal window
$ gem install libtmux-workspace --pre

Save this workspace as workspace.yaml:

session_name: work
environment:
PROJECT_MODE: development
windows:
- window_name: editor
window_index: 1
layout: tiled
panes:
- shell_command: printf 'editor ready\n'
- {}

Check it without contacting tmux:

Terminal window
$ libtmux-workspace validate workspace.yaml
Workspace configuration is valid.

The workspace README loads it into a running server and lists every option, including how --switch moves a client.

Build from source

Use the Ruby pinned in .tool-versions and have tmux on your PATH. From this checkout, install the development bundle:

Terminal window
$ mise install
Terminal window
$ mise exec -- bundle config set --local path vendor/bundle
Terminal window
$ mise exec -- bundle install

To use the core outside this checkout, build the artifacts:

Terminal window
$ 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:

Terminal window
$ gem install \
--local \
--no-document \
pkg/libtmux-0.1.0.alpha.3.gem

Companion gems need their declared runtime dependencies too. The packaging check verifies each gem in an isolated installation and runs the recipes outside the checkout.

What it leaves out

  • Live objects. A snapshot record is what tmux said when you read it, and a selection keeps the membership it captured. Read again to see a change.
  • A terminal emulator. Pane#capture returns what tmux’s capture-pane prints for the pane.
  • An implied server. Endpoint.new needs an explicit socket, and no API in the recipes uses the default server.
  • Whole-program typing. RBS declarations ship with each gem, and selected installed calls are checked. See the public methods.
  • Throughput claims. The benchmarks list their workloads, measurements and limits.

Support and status

Alpha. APIs may change between releases.

  • Ruby 3.3 or newer and tmux 3.3a or newer. Unpatched 3.3 is below the minimum. A server handle checks the connected daemon’s release, not the client’s, and refuses an older daemon before any requested command runs.
  • Linux, including WSL, and macOS. The compatibility workflow runs Ruby 3.3, 3.4 and 4.0 with tmux 3.3a through 3.8 on Ubuntu 24.04. macOS is supported on a best-effort basis, and CI coverage for it is highly limited.
  • tmux master and old daemons. On Ubuntu the workflow also runs the suite against a pinned tmux master, and checks that tmux 3.0a, 3.1c, 3.2a and 3.3 daemons are refused.
  • Per-revision results. Check the workflow’s results for your revision before relying on one combination.

Documentation

  • Send text and capture output: split panes, wait for output events, and round-trip binary buffers.
  • Work with linked windows: address one window at several session indexes.
  • Capture concurrently: read panes while another request waits, then cancel it.
  • Load a workspace: parse a configuration, plan, and apply it.
  • All recipes: cancellation, control streams, command groups, and MCP.
  • API reference: 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: workloads, measurements, and their limits.

See Contributing for setup and checks.

Attribution

Please use the following BibTeX template to cite libtmux-ruby in scientific discourse:

@misc{libtmux-ruby,
author = {Tony Narlock},
year = {2026},
note = {https://libtmux.org/en/ruby/},
title = {libtmux-ruby: Ruby wrapper for tmux}
}

License

MIT. See LICENSE.

Esc

Type to search.

Reference preview Open reference