# Getting started

Source: https://libtmux.org/en/ruby/v0.1.0.alpha.2/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`](<https://libtmux.org/en/ruby/v0.1.0.alpha.2/reference/libtmux-selection-where/>), `select`,
and the rest of `Enumerable`.

[Quick start](https://libtmux.org/en/ruby/v0.1.0.alpha.2/guides/getting-started/#quick-start) · [Queries](https://libtmux.org/en/ruby/v0.1.0.alpha.2/guides/getting-started/#query-a-snapshot) · [Gems](https://libtmux.org/en/ruby/v0.1.0.alpha.2/guides/getting-started/#gems) ·
[Guide](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/docs/index.md) · [API reference](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/docs/reference/api.md) ·
[Recipes](https://libtmux.org/en/ruby/v0.1.0.alpha.2/examples/recipes/)

**Alpha.** APIs may change between releases. See the
[initial alpha notes](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/CHANGELOG.md) and [release guide](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/docs/releasing.md).

## Install

Install the core prerelease from RubyGems:

```console
$ gem install libtmux --pre
```

The [companion gems](https://libtmux.org/en/ruby/v0.1.0.alpha.2/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/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/.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+ and the suite requires 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. 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.3a–3.8 on Linux and macOS, runs the
suite against a pinned tmux master build, and checks that tmux 3.0a, 3.1c,
3.2a and 3.3 daemons are refused. 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.

<!-- example: quickstart/main -->
```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
```
<!-- /example -->

Run the [complete example](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/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: ...)`](<https://libtmux.org/en/ruby/v0.1.0.alpha.2/reference/libtmux-server-open/>); closing that binding
leaves the daemon running. See [ownership and errors](https://libtmux.org/en/ruby/v0.1.0.alpha.2/topics/errors-and-exceptions/).

## Query a snapshot

Continue with the snapshot above. [`where`](<https://libtmux.org/en/ruby/v0.1.0.alpha.2/reference/libtmux-selection-where/>) accepts criteria as data; `select`
accepts a Ruby block. These queries make no tmux calls.

<!-- example: quickstart/queries -->
```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")
```
<!-- /example -->

[`one`](<https://libtmux.org/en/ruby/v0.1.0.alpha.2/reference/libtmux-selection-one/>) raises [`NoMatchError`](<https://libtmux.org/en/ruby/v0.1.0.alpha.2/reference/libtmux-nomatcherror/>) or [`MultipleMatchesError`](<https://libtmux.org/en/ruby/v0.1.0.alpha.2/reference/libtmux-multiplematcheserror/>) unless exactly one record
matches. [`one_or_nil`](<https://libtmux.org/en/ruby/v0.1.0.alpha.2/reference/libtmux-selection-one_or_nil/>) returns `nil` for no match and still rejects duplicates.
Both errors live under `LibTmux`.

Selections retain captured membership. Call [`server.snapshot`](<https://libtmux.org/en/ruby/v0.1.0.alpha.2/reference/libtmux-async-server-snapshot/>) again while the
server is open to read later changes. The [field catalog](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/docs/reference/fields.md)
lists query fields and wire names; the [list/filter recipe](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/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/v0.1.0.alpha.2/guides/core/) | `libtmux` | Blocking scripts, snapshots, and control connections |
| [libtmux-async](https://libtmux.org/en/ruby/v0.1.0.alpha.2/guides/async/) | `libtmux/async` | Concurrent commands and bounded streams in Async tasks |
| [libtmux-mcp](https://libtmux.org/en/ruby/v0.1.0.alpha.2/mcp/source-guide/) | `libtmux/mcp` | An MCP server with explicit endpoints and tool policy |
| [libtmux-workspace](https://libtmux.org/en/ruby/v0.1.0.alpha.2/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/v0.1.0.alpha.2/concepts/transports/) explains blocking calls, Async tasks, and
control subscriptions. Tracked MCP captures, waits, and authored runs require
tmux 3.3a+ and native process identity; see the
[MCP guide](https://libtmux.org/en/ruby/v0.1.0.alpha.2/mcp/source-guide/).
Workspace client-switching semantics are in the
[workspace guide](https://libtmux.org/en/ruby/v0.1.0.alpha.2/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.2.gem
```

Companion gems need their declared runtime dependencies too. The
[packaging check](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/.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/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/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/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/examples/window_links.rb): address one window at
  several session indexes.
- [Capture concurrently](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/examples/async_cancel.rb): read panes while another
  request waits, then cancel it.
- [Load a workspace](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/examples/workspace_apply.rb): parse a configuration, plan,
  and apply it.
- [All recipes](https://libtmux.org/en/ruby/v0.1.0.alpha.2/examples/recipes/): cancellation, control streams, command groups,
  and MCP.
- [API reference](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/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/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/docs/benchmark.md): workloads, measurements, and their limits.

See [Contributing](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/.github/CONTRIBUTING.md) for setup and checks.
[MIT license](https://github.com/libtmux/libtmux-ruby/blob/dcc9f8b5a6970144a9e7d80cd5f381d8f6198372/LICENSE).

## Attribution

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

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