Skip to main content

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:

  1. Quoting and Escaping Hell: Nested quotes, shell variables, subshells, and escapes are easily mangled when passed across nested SSH sessions or bash wrappers.
  2. Terminal Echo & Input Race Conditions: Rapid key injection can race with shell readline redraws, bracketed paste triggers, or auto-suggestions.
  3. ANSI & Layout Pollution: Screen scraping mixes prompt redraws, color escape codes, truncated lines,lines at terminal column boundaries, and terminal dimensions with actual command output.

amux completelyprovides eliminatessymmetric, quotingfull-duplex andprogrammatic escapingcontrol:

issues
viaZero-Escape native file-streaming injectionWriting (write-pane -f): Direct PTY stream injection bypassing keystroke emulation and ashell dedicatedescaping. agentDirect sessionStream hierarchyReading (atx / axread-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 inside mtx. Styled with a high-visibility orange status bar (#ff8800), [AGENT] badge, and C-b prefix key (matching inner session convention without colliding with outer mtx C-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/tmux and 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=1
    • ROUTER=danknasty
    • ROUTER_REPO=/home/luke/git/router_config
    • MC_DIR=/data/minecraft
    • MC_ROUTER_V4=10.0.0.113
    • MC_ROUTER_V6=fd77:7777:5010::1337:f1ac:d00d:3c
    • MC_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 danknasty
    • rdo <cmd>: Direct non-interactive execution on router
    • mipctl: 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 pokelovers
  • mc-pokelovers-datapacks: Managing datapacks and gameplay tweaks
  • mc-pokelovers-console: Direct interactive Minecraft server console
  • rtr-dns-sync: Router DNS record and deSEC synchronization
  • rtr-pf-rules: Firewall rule adjustments and testing
  • bld-amux-stream: Compiling and patching tmux C source code
  • bkp-verify-daily: Backup execution and PAR2 verification

Window Lifecycle Protocol

  1. 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"
    
  2. 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\n linebreaks 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 133 C (output start) and D (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 FileBidirectional InjectionAutomation

    The golden rule for running multi-line commands, scripts, or nested shell invocations is: Write the code directly to a file, then inject it with write-pane -f.

    This completely eliminates worrying about single quotes, double quotes, subshells, or escaping.

    Step 1: Write theand Payload to FileFlush

    Write your exact code verbatim to /dev/shm (or /tmp):

    # 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 and Execute

    # 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/run.shscript.py
    rm -f /dev/shm/run.shscript.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.