amux - Agent modified tmux
Overview
amux (Agent-Modified tmux) is a custom build of tmux designed to provide clean, robust bidirectional programmatic control for AI CLI agents and automated scripting.
Standard tmux requires emulating physical keystrokes (send-keys) and screen-scraping the visual terminal grid (capture-pane). This introduces significant failure modes:
- Quoting and Escaping Hell: Nested quotes, shell variables, subshells, and escapes are easily mangled when passed across nested SSH sessions or bash wrappers.
- Terminal Echo & Input Race Conditions: Rapid key injection can race with shell readline redraws, bracketed paste triggers, or auto-suggestions.
- ANSI & Layout Pollution: Screen scraping mixes prompt redraws, color escape codes, truncated lines at terminal column boundaries, and terminal dimensions with actual command output.
amux provides symmetric, full-duplex programmatic control:
- Zero-Escape Writing (
write-pane -f): Direct PTY stream injection bypassing keystroke emulation and shell escaping. - Direct Stream Reading (
read-pane): Direct PTY output buffer capture bypassing 2D screen grid layout truncation and ANSI pollution.
Architecture & Session Hierarchy
The tmux sessions on the host are organized into clean layers managed by /home/luke/bin/tmux_control:
+-------------------------------------------------------+
| mtx / mx: Outer Master Session |
| Socket: /tmp/tmux-1000/tmux_luke_mtx |
| Config: ~/.tmux.conf_outer |
| |
| +-----------------------------------------------+ |
| | stx / sx: User Interactive Session | |
| | Socket: /tmp/tmux-1000/tmux_luke_stx | |
| | Config: ~/.tmux.conf_inner | |
| +-----------------------------------------------+ |
| |
| +-----------------------------------------------+ |
| | atx / ax: Agent Session (amux) | |
| | Socket: /tmp/tmux-1000/tmux_luke_atx | |
| | Config: ~/.tmux.conf_agent | |
| +-----------------------------------------------+ |
+-------------------------------------------------------+
atx [session]: Attaches to or creates the agent session insidemtx. Styled with a high-visibility orange status bar (#ff8800),[AGENT]badge, andC-bprefix key (matching inner session convention without colliding with outermtxC-a).ax <command>: Runs commands directly on the agent socket (e.g.ax list-panes,ax write-pane ...,ax read-pane ...).- Binary: The custom binary is built from
/home/luke/git/tmuxand installed at/usr/local/bin/tmux-custom. The system tmux (/usr/bin/tmux) remains unmodified as a fallback.
Persistent Agent Environment
When the agent session spawns, it automatically sources ~/.agent_profile:
- Persistent Environment Variables:
AGENT_SESSION=1ROUTER=danknastyROUTER_REPO=/home/luke/git/router_configMC_DIR=/data/minecraftMC_ROUTER_V4=10.0.0.113MC_ROUTER_V6=fd77:7777:5010::1337:f1ac:d00d:3cMC_BACKEND_PREFIX=fd77:7777:5010::1337:3c:d00d:
- Persistent Helper Functions:
rcfg: Git wrapper for router config (git -C $ROUTER_REPO)rssh: Direct SSH to danknastyrdo <cmd>: Direct non-interactive execution on routermipctl: Shortcut for/data/minecraft/ipctl
Window Naming & Task Lifecycle Methodology
To maintain strict isolation between tasks, prevent command collisions, and keep workspaces clean, windows in atx follow a structured naming convention:
<project_or_domain>-<target>-<task_suffix>
Naming Pattern Examples
mc-pokelovers-bluemap: BlueMap setup or rendering for pokeloversmc-pokelovers-datapacks: Managing datapacks and gameplay tweaksmc-pokelovers-console: Direct interactive Minecraft server consolertr-dns-sync: Router DNS record and deSEC synchronizationrtr-pf-rules: Firewall rule adjustments and testingbld-amux-stream: Compiling and patching tmux C source codebkp-verify-daily: Backup execution and PAR2 verification
Window Lifecycle Protocol
-
Window Creation (Task Start): Before running multi-step commands for a task, verify if the dedicated window exists; if not, spawn it:
ax list-windows -F '#{window_name}' | grep -q '^mc-pokelovers-bluemap$' || \ ax new-window -n "mc-pokelovers-bluemap" "bash --rcfile ~/.agent_profile" -
Scoped Execution via File Injection: Write the script or commands to a file on
/dev/shm, clear any lingering buffer, inject it, and delete the temporary file:ax read-pane -C -t "mc-pokelovers-bluemap" ax write-pane -t "mc-pokelovers-bluemap" -e -f /dev/shm/task_payload.sh rm -f /dev/shm/task_payload.sh -
Clean Output Reading: Read or stream the exact output directly from the queue without screen scraping:
# Read clean output and drain the queue ax read-pane -c -t "mc-pokelovers-bluemap" -
Status Renaming: If a task transitions to a persistent state (e.g. watching logs, running tests), update the title:
ax rename-window -t "mc-pokelovers-bluemap" "mc-pokelovers-watch" -
Task Completion Confirmation & Cleanup Rule:
- When a task or subtask is complete, the outcome must be explicitly verified (service status, connectivity, file state).
- Once verified, promptly close the dedicated task window:
ax kill-window -t "mc-pokelovers-bluemap" - No completed task windows are left lingering in the agent session. Confirm to the user that the task is finished and that its task window has been torn down.
Built-In Commands
write-pane (alias: writep)
Injects raw binary data, files, or Base64 payloads directly into the target pane's PTY input buffer. It completely bypasses terminal keystroke decoding and shell quoting.
tmux write-pane [-en] [-f file] [-b base64-data] [-t target-pane] [data ...]
Flags:
-f <file>: Reads the given file from disk and streams its raw bytes directly into the pane's input buffer. (Recommended Standard)-e: Automatically appends a newline (\n/ Enter) to trigger immediate execution.-b <base64-data>: Decodes a base64 payload in C (b64_pton) and writes raw bytes to the PTY.-n: Do not separate multiple positional arguments with spaces.-t <target-pane>: Specifies the target session, window, or pane (e.g.-t mc-pokelovers-bluemap).
read-pane (alias: readp)
Reads raw or filtered output directly from the target pane's in-memory stream buffer (wp->stream_buf), bypassing 2D screen grid scraping entirely. Output is unaffected by terminal column width, pane geometry, or scrollback limits.
tmux read-pane [-cClOprs] [-b buffer-name] [-f file] [-o file] [-t target-pane]
Flags:
- Default (Clean Mode): Automatically strips ANSI / VT100 escape sequences, removes bracketed paste triggers (
\033[?2004h/l), and normalizes\r\nlinebreaks to standard\n. -c(consume): Drains read bytes from the pane buffer (FIFO behavior). Repeated calls return only new output produced since the last read.-C(clear/flush): Immediately flushes the pane output buffer without reading (ideal before running a new command).-l(length): Returns the current number of queued bytes in the pane buffer without draining.-r(raw): Bypasses ANSI stripping and outputs the raw, unmodified PTY byte stream.-s(strip): Explicitly strip ANSI escape codes (default behavior).-O(OSC 133 isolation): Semantically isolates command output between the last OSC 133C(output start) andD(output end) markers, completely eliminating prompt redraws and command echo.-o <file>/-f <file>: Streams buffer content directly to a file on disk.-b <buffer-name>: Stores captured content into a tmux paste buffer.-t <target-pane>: Target pane specification.
Standard Workflow: Zero-Escape Bidirectional Automation
Step 1: Write and Flush
# File: /dev/shm/script.py
import json
import os
data = {
"user": os.getenv("USER"),
"paths": ["/data/minecraft", "/home/luke/git"],
"quote_test": 'Double "quotes" and single \'quotes\' work without escapes!'
}
print(json.dumps(data, indent=2))
Step 2: Flush Buffer & Inject
# Flush previous output from buffer
ax read-pane -C -t mc-pokelovers-datapacks
# Inject script
ax write-pane -t mc-pokelovers-datapacks -e -f /dev/shm/script.py
rm -f /dev/shm/script.py
Step 3: Read Clean Queued Output
# Read output cleanly without screen scraping or line-wrapping distortion:
ax read-pane -c -t mc-pokelovers-datapacks
Structured Audit Logging
Both write-pane and read-pane integrate with systemd journal for structured security and execution logging:
- Injected scripts are archived to
/data/amux/scripts/<timestamp>_<window>.sh. - Audit events are sent to the systemd journal under identifier
amux:journalctl -t amux -n 20 --no-pager
Rebuilding & Updating amux
The source tree is maintained at /home/luke/git/tmux:
cd /home/luke/git/tmux
make -j$(nproc)
sudo install -m 755 tmux /usr/local/bin/tmux-custom
Existing sessions can continue running undisturbed; new sessions or restarts of tmux_control (atx, stx, mtx) automatically pick up the updated binary.