libtmux-ts

mcp
Security Audit
Warn
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Pass
  • Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Typed tmux library for Node.js, Bun, TypeScript. Alpha.

README.md
libtmux for TypeScript

libtmux for TypeScript

Typed control of tmux for Bun and TypeScript — immutable snapshots, declarative queries, and a library that ships zero runtime dependencies.

Quickstart •
Querying •
Packages •
API reference •
Hosted API reference •
Examples •
Changelog

typescript
libtmux
libtmux.org
license


[!WARNING]
Releases are numbered 0.1.N, and each release increments N. The API is not
settled: any release may change or remove exported identifiers, and the
changelog marks each break. Pin an exact version to avoid one.
Read the changelog before you upgrade.

Is this for you?

Yes, if you drive tmux from a program — an agent that runs commands and reads
what they printed, a workspace launcher, a test harness, a dashboard — and you
want the terminal's state as typed data rather than as parsed strings.

Probably not, if you want a .tmux.conf generator or a TUI. This library
controls a running server; it does not write your tmux configuration.

The idea in one line: read the whole server once into an immutable snapshot,
then query it like data.

Quickstart

$ bun add --exact [email protected]
npm, pnpm, yarn
$ npm i --save-exact [email protected]
$ pnpm add --save-exact [email protected]
$ yarn add --exact [email protected]

Requires Bun 1.3.14+ or Node 22+, and tmux 3.3a or newer.

  • The version that counts is the running daemon's.
  • An older daemon, or an executable that would start one, is refused with
    VersionTooLowError before any command takes effect.
  • A client reporting a newer release does not change that.

Runs on Linux, including WSL. macOS is supported on a best-effort basis,
and CI coverage for it is highly limited.

import { Server } from "libtmux";

const server = new Server();
const snapshot = await server.snapshot();

// No further tmux calls: everything below resolves against the snapshot.
const editors = snapshot.panes.where({ currentCommand: "vim" });
console.log(editors.count(), editors.at(0)?.session?.name);

Building something rather than reading it looks like this — and this block is a
literal excerpt of examples/quickstart/quickstart.ts, which the
integration suite runs against a real tmux server:

const session = await server.newSession({ name: "quickstart" });
const editor = await session.newWindow({ name: "editor" });
await editor.split();

const snapshot = await server.snapshot();

const found = snapshot.windows.where({ name: "editor" }).one();

const paneCount = found.panes.length;

What querying looks like

This is the part worth judging the library on. .where() takes declarative,
serializable criteria; .filter() takes an ordinary predicate. They are
never overloaded into each other.

// Equality, string operators, AND/OR/NOT, and regular expressions as data.
snapshot.sessions.where({
  AND: [
    { name: { startsWith: "prod" } },
    { windows: { some: { name: { regex: { pattern: "^log", flags: "" } } } } },
  ],
});

// Quantifiers over relations: some / every / none, and is / isNot.
snapshot.windows.where({ session: { is: { name: "work" } } });

// Case-insensitive when you ask for it.
snapshot.sessions.where({ name: { contains: "API", mode: "insensitive" } });

A Selection is immutable, ordered, replayable, and Iterable.
It is not an Array:

selection.length;
selection.at(-1);
selection.toArray();
[...selection];

selection.one({ name: "work" }); // throws NoMatchError / MultipleMatchesError
selection.oneOrUndefined({ name: "work" });
selection.exists({ name: "work" });

Criteria are data. encodeWhereDocument writes a model-tagged query;
decodeWhereDocument validates one read from a config file, MCP call, or CLI.

Packages

The library, MCP server, workspace builder, and workspace CLI share one release version.

Package What it is npm
libtmux The library. Server, session, window, pane and client handles over a snapshot. npm
@libtmux/mcp An MCP server exposing tmux to an AI agent. npm
@libtmux/workspace Declarative workspace builder, tmuxp-shaped config. npm
@libtmux/workspace-cli The native tmux-workspace command for Node and Bun. npm
examples Runnable examples, executed as tests. —

libtmux — the library

The library: Server, Session, Window, Pane and Client handles over an
immutable snapshot of tmux.

API reference ·
npm

$ bun add --exact [email protected]
import { Server } from "libtmux";

const server = new Server();
const session = await server.newSession({ name: "work" });
const editor = await session.newWindow({ name: "editor" });
await editor.split();

await editor.panes.at(0)?.sendKeys("echo hello");
const lines = await editor.panes.at(0)?.capture();

Read next: Snapshots ·
Querying ·
Operations ·
Watching ·
Recipes ·
Errors ·
API reference

@libtmux/mcp — tmux for an AI agent

A stdio MCP server. Point it at a socket and an agent can list sessions, read a
pane, send keys, and wait for output rather than polling for it.

API reference ·
Tools ·
npm

With no configuration it starts its own tmux server on the libtmux-mcp
socket:

$ npx -y @libtmux/[email protected]

Add it to any MCP client — this is the whole configuration:

{
  "mcpServers": {
    "tmux": {
      "command": "npx",
      "args": ["-y", "@libtmux/[email protected]"],
      "env": { "LIBTMUX_SOCKET": "agent" }
    }
  }
}
Claude Code, in one command
$ claude mcp add tmux --env LIBTMUX_SOCKET=agent -- \
    npx -y @libtmux/[email protected]

The tools an agent reaches for first:

Tool What it does
list_sessions Lists stable session identities and metadata
capture_since Returns only pane output after a cursor
wait_for_text Waits for bounded literal or regular-expression matches
run_shell_command Runs a command through a pane and reports output and exit status
create_session Creates a session without accepting a command or environment value

The tools are split into inspect, manage, execute, and teardown.
tmux://capabilities is the only resource; the server exposes no prompts,
resource templates, background jobs, or generic mutation tools.

Read next: Why it exists ·
Configuration ·
Toolsets and trust ·
Choosing the right tool

@libtmux/workspace — declarative sessions

Describe a session; apply it. Applying twice converges rather than duplicating.

API reference ·
npm

$ bun add --exact @libtmux/[email protected] [email protected]
import { Server } from "libtmux";
import { applyWorkspace } from "@libtmux/workspace";

const server = new Server();

await applyWorkspace(server, {
  session_name: "api",
  windows: [
    { window_name: "editor", panes: ["vim", "git status"] },
    { window_name: "server", panes: [{ shell_command: "bun dev", focus: true }] },
  ],
});

Read next: The config shape ·
Converging

@libtmux/workspace-cli — tmuxp workspaces from the shell

tmux-workspace loads, captures and converts tmuxp workspace files on Node or
Bun. Ordinary loads start no Python.

Command reference ·
npm

Save this document as workspace.yaml:

session_name: dev
windows:
  - window_name: editor
    layout: main-vertical
    panes:
      - vim
      - top

Load it detached, on a socket of its own:

$ npx -y @libtmux/[email protected] load ./workspace.yaml \
    -L workspace-cli-demo \
    -d

Read next: Install ·
Load and capture ·
Command reference

examples — runnable, and run

Four programs covering acquisition, control-mode watching, the act-then-wait
loop an agent needs, and building a workspace. Each is executed by the
integration suite, so the code there is the code that runs.

$ bun test examples

How work is arranged

Observation, planning and concurrency compose around the same command engine —
the full table is here.

Mode Turn it on When to use it
connected await server.connect() Pairing commands with a persistent event observer
watching server.watch() Reacting to a change rather than polling to find it
pipeline server.pipeline([…]) Ordered commands when printed output is enough
planned .plan + server.batch([…]) Ordered mutations that must return typed handles
concurrent Promise.all Independent work that may safely overlap

Creating twelve windows costs, each figure including the one query that reads
the result back:

  • 25 tmux invocations one at a time, 13 through
    pipeline, and 14 through
    batch, whose extra is the snapshot that turns printed ids
    into typed handles.
  • A snapshot is one invocation whatever the server's size, and querying it is
    none.
  • The wall-clock beside those counts, and why Promise.all buys nothing over
    doing the same work in order, are in
    the benchmarks.
$ bun packages/libtmux/scripts/bench-modes.ts

What this project promises

  • The library ships zero runtime dependencies. A test holds it. @libtmux/mcp and @libtmux/workspace declare their own.
  • Real tmux, every commit. CI runs the suite against every tmux release from 3.3a to 3.8a — no mocks stand in for a server.
  • Documentation is a gate. Every public symbol carries a compiled example, the API reference is generated from the source that implements it, and every link, install command and recipe on this page is checked on each run.
  • Softly tracks Python libtmux. Names and shapes follow 0.62.0 where TypeScript agrees with them; each departure is a decision a gate holds to the code.

Repository

packages/libtmux     the library
packages/mcp         the MCP server
packages/workspace   the workspace builder
packages/workspace-cli the tmux-workspace command
examples             runnable examples, used as tests
attic                reference notes

Working here: AGENTS.md routes to the policy that governs a
change. The layout and the change discipline live there; how we write is in
.github/WRITING.md, and the gates, real tmux, and
releases are in .github/CONTRIBUTING.md.

Attribution

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

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

License

MIT — a port of
tmux-python/libtmux.

Reviews (0)

No results found