Blocking tmux terminal control for AI agents, with captured logs and live human handoff
Project description
pairmux
Blocking, observable tmux terminals for AI agents — with live human handoff.
Documentation · CLI reference · Changelog · Source
pairmux is a small coordination layer over tmux with no separate pairmux service to supervise. Agents get actionable command outcomes and clean, bounded-by-default output; humans keep normal access to the same live terminal.
Why pairmux
- Actionable waits.
runblocks until a command completes, a recognized prompt appears, or its timeout expires. Completed runs include the exit code and duration; if no completion was observed by the deadline, the response reportsrunningand does not kill the command. - Captured history. Managed terminals write pane output to a per-terminal journal. Routine
reads stay bounded, while explicit
logselectors retrieve a captured command or selected journal history. Truncated replies point to the command that fetches the rest. - Shared control. Humans can
watch,attach, and leave anote. Read-only observation is lock-free; only onerunwriter is allowed per terminal, and a conflict returnsE_BUSY. - Agent-readable replies.
--jsonemits a versionedpairmux.v1envelope with status, shaped output, recovery hints, and ordered next steps.
Install
uv tool install pairmux
# or
pipx install pairmux
# or, inside a dedicated environment
python -m pip install pairmux
The wheel contains a prebuilt native Go binary, so installation needs no Go toolchain or source
build. Wheel installers must select Python 3.9 or newer; the installed pairmux executable itself
contains no Python code.
PyPI package requirements and wheel targets:
- tmux 3.2 or newer
- macOS 12+ or manylinux_2_17 (glibc 2.17+)
- x86-64 or ARM64 (aarch64)
- no native Windows wheel; use a compatible Linux distribution inside WSL
Check the local environment after installation:
pairmux doctor
60-second quickstart
Create one managed terminal, then run commands in it:
pairmux --json new --name demo
pairmux --json run demo "echo hello from pairmux"
# A timeout returns status=running; it does not kill the command.
pairmux --json run demo "sleep 2; echo finished" --timeout 1s
# When status is running, keep waiting without sleep-and-guess polling.
pairmux --json wait demo --idle 800
pairmux --json peek demo
wait --idle refreshes terminal state after output becomes quiet; silence alone is not treated as
completion. peek and log are read-only, so other agents can inspect the same terminal without
taking its writer lock.
Teach your agent
pairmux embeds its Agent Skill, including the new → run → wait/send/log loop and safe human
handoff guidance:
pairmux skill install --target codex --dry-run
pairmux skill install --target codex
Use --target all to update only the supported agent configuration directories that already
exist. See the Agent Skills guide for all
targets and install locations.
MCP clients can launch the built-in stdio server and use the core terminal operations as typed tools:
{
"command": "pairmux",
"args": ["mcp", "serve"]
}
Interactive work and human handoff
After 800 ms of output quiet, pairmux recognizes supported prompt patterns: confirmations,
password/passphrase/passcode prompts, pager markers, press-key messages, and Python's >>>. It
reports awaiting-input and never auto-answers. Replace the uppercase placeholders below before
sending ordinary input:
pairmux send NAME --text VALUE --enter
For a secret-shaped prompt, the response recommends pairmux wait NAME --human --notify. A human
can enter the same live pane with pairmux attach NAME, provide the input, and detach with
the configured tmux binding (default Ctrl-b d). Running pairmux note NAME "ready" afterward
records a message and releases an agent waiting with --human; it does not itself detach or enforce
control ownership. This avoids routing the input through the agent-facing send command. Prompt
recognition is heuristic, desktop notification is best-effort, and whether an application echoes or
records input remains application-dependent.
How it works
pairmux does not implement another PTY or add a background service of its own. tmux remains the
terminal-state engine; short-lived pairmux commands add completion detection, captured output,
model-friendly shaping, and coordination around the live pane. pairmux attach starts a native
tmux client against the correct managed session whenever a human needs to observe or take over.
pairmux is open source under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pairmux-0.1.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: pairmux-0.1.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.4 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
487c91f45909ce2bd129f9d3f2c910e7a252d4082dc37b5b9bc73a5b1c7d5a3a
|
|
| MD5 |
b26b31b080fed20558bdb8f2f4bf1f4b
|
|
| BLAKE2b-256 |
361e2e3e4c45585aedf37052db12d9182fd1a626d45ae836ef284a41707484de
|
File details
Details for the file pairmux-0.1.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: pairmux-0.1.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 1.3 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fc2049db340d8335fc5c8ba0853ed61277dcb2a57ab84e5c4ba5479ddae20e63
|
|
| MD5 |
a3b9ca24323ae73f7f16564bc6d8a7ed
|
|
| BLAKE2b-256 |
6da61fb4379fc4840fbb1295a28709e4a71d1e3d25873d68051198068f89e80c
|
File details
Details for the file pairmux-0.1.1-py3-none-macosx_12_0_x86_64.whl.
File metadata
- Download URL: pairmux-0.1.1-py3-none-macosx_12_0_x86_64.whl
- Upload date:
- Size: 1.4 MB
- Tags: Python 3, macOS 12.0+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
289d95080dce1f4a55f9cf3fcdad9556e2c59213651fc62c3a68c1f542fe045f
|
|
| MD5 |
1c417cb9436a82b69a0fe28fb40b94ad
|
|
| BLAKE2b-256 |
bfe39c385feb11eeef8325970b5ed2b8523f150f6e3d8a8319b661333dd57fe3
|
File details
Details for the file pairmux-0.1.1-py3-none-macosx_12_0_arm64.whl.
File metadata
- Download URL: pairmux-0.1.1-py3-none-macosx_12_0_arm64.whl
- Upload date:
- Size: 1.3 MB
- Tags: Python 3, macOS 12.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
423fedab111f1336fba6fc5008be62f94dd3234cbecd48d3e037aa553f3e3896
|
|
| MD5 |
0c320a3a64ede30600ec7b2026c04e25
|
|
| BLAKE2b-256 |
9b2e114fbedafe64fed8cad046758ad583e9df07bc7e01452fb2622ec0577e9f
|