ZTMUX-CORE // NATIVE TMUX CLIENT ENGINE

// speaks tmux's wire protocol directly to the server socket — no tmux subprocess, not control mode

Engineering Report GitHub
Status: implemented engine. ztmux-core talks tmux's client/server protocol — OpenBSD imsg framing, protocol version 8 — straight to the server's Unix socket, the same protocol the tmux binary speaks, ported from tmux 3.6 sources. It is not control mode (tmux -CC); it is the raw binary client protocol. Built to be wired into GUI apps that render the returned JSON.

ztmux-core is the engine that lets a GUI drive tmux without shelling out. Instead of spawning the tmux binary and scraping its text, it implements the client side of tmux's wire protocol directly against the server's Unix socket (imsg framing, protocol v8, ported from tmux 3.6). Every operation returns a serde_json::Value, so each host renders sessions, windows, and panes in its own frontend. Created by MenkeTechnologies.

Wire protocol, not subprocess

Speaks imsg framing straight to the tmux server socket — no tmux child process, no text scraping, no control-mode parsing.

JSON out

Session tree, pane previews, search corpus, broadcast list, dashboard summary — all returned as serde_json::Value for the host to render.

Native process inspection

Reads the full command line running in each pane via libproc / /proc — again, no subprocess.

Snapshot save / restore

A native tmux-resurrect replacement: layout, cwd, full command line, active state, pane contents, and a process whitelist.

Owned on both ends

The same protocol version 8 is pinned by ztmux-core (client) and ztmux (the tmux server rewritten in Rust). Upstream tmux cannot break the pairing — both ends move together under one owner.

Capabilities

Layers

A thin module set; the host calls these and renders the JSON.

use ztmux_core::{transport, ops, snapshot};

// the wire client: run a tmux command over the server socket
let sock = transport::socket_path().unwrap();
let out  = transport::command(&sock, &["list-sessions"])?;

// high-level ops return serde_json::Value for the GUI to render
let tree = ops::tree();              // sessions → windows → panes (+ previews)
ops::send_keys(&panes, "echo hi", true);

Vertical integration — the wire protocol is owned end-to-end

ztmux-core is one half of a client/server pair MenkeTechnologies controls on both ends. The client pins PROTOCOL_VERSION = 8 (src/transport.rs); the server it talks to can be upstream tmux or ztmux — the from-source tmux rewrite in Rust — which pins the identical PROTOCOL_VERSION = 8. Upstream tmux is free to bump its protocol in a future release, which would break ztmux-core against a system tmux server; the ztmux-core ↔ ztmux pairing stays version-locked because both endpoints move together under one owner. The wire contract is fixed by this stack, not by upstream tmux's release cadence. The client leans into the owned server by default — socket_path() probes the ztmux-<uid> socket dir before tmux-<uid>, and ops::tmux_bin prefers the ztmux binary — so a running ztmux server is what gets driven when both are present.

Hosts

ztmux-core is consumed by the zterminal GUI and is built to drop into other MenkeTechnologies apps: each calls these functions and renders the JSON in its own frontend. See the engineering report for the module map.