Skip to content

Repository files navigation

libtmux for Ruby

libtmux for Ruby

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 · Queries · Gems · Guide · API reference · Recipes

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

Install

Install the core prerelease from RubyGems:

$ gem install libtmux --pre

The companion gems install separately; use --pre for their alpha versions too.

Install from source

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

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

The gemspecs declare Ruby 3.3+. The compatibility workflow 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.

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:

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

Output:

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.

Query a snapshot

Continue with the snapshot above. where accepts criteria as data; 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.

Selections retain captured membership. Call server.snapshot again while the server is open to read later changes. The field catalog lists query fields and wire names; the list/filter recipe also covers exact matches and queries after close.

Gems

Start with libtmux. Add the companion for your caller:

Gem Require Use it for
libtmux libtmux Blocking scripts, snapshots, and control connections
libtmux-async libtmux/async Concurrent commands and bounded streams in Async tasks
libtmux-mcp libtmux/mcp An MCP server with explicit endpoints and tool policy
libtmux-workspace 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 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. Workspace client-switching semantics are in the workspace guide.

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

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

$ gem install \
    --local \
    --no-document \
    pkg/libtmux-0.1.0.alpha.1.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.

More examples and reference

  • 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. MIT license.