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 at terminal column boundaries, and terminal dimensions with actual command output.
  4. No Command Completion or Busy-State Visibility: Standard tmux cannot distinguish a pane running a command from a pane sitting idle at a prompt without polling capture-pane or guessing via monitor-silence.

amux provides symmetric, full-duplex programmatic control:


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                   |   |
|   +-----------------------------------------------+   |
+-------------------------------------------------------+

Persistent Agent Environment & OSC 133 Shell Integration

When the agent session spawns, it automatically sources ~/.agent_profile:


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

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, flush the output buffer, and inject into the target window using write-pane -f:

    ax read-pane -C -t "mc-pokelovers-bluemap"
    ax write-pane -t "mc-pokelovers-bluemap" -e -f /dev/shm/task.sh
    rm -f /dev/shm/task.sh
    
  3. Synchronous Output Retrieval & Exit Verification: Wait for the command or multi-line script to finish, isolate the clean OSC 133 output, drain the queue, and propagate the exit code:

    ax read-pane -w -O -c -E -t "mc-pokelovers-bluemap"
    
  4. 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"
    
  5. 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, records the current stream buffer mark (wp->stream_mark), and immediately pre-marks the pane as running (PANE_CMDRUNNING) when newline execution (-e or trailing \n) is triggered.

tmux write-pane [-en] [-f file] [-b base64-data] [-t target-pane] [data ...]

Flags:


read-pane (alias: readp)

Reads raw or filtered output directly from the target pane's 16 MB in-memory stream buffer (wp->stream_buf), queries command execution state/exit status, or synchronously waits for command completion without screen scraping or polling.

tmux read-pane [-cCeElOprsSw] [-b buffer-name] [-f file] [-o file] [-T timeout] [-t target-pane]

Flags:


Format Variables & Status Bar Integration

amux exposes pane command state and buffer metrics as native tmux format variables usable in list-panes -F, display-message -p, and status lines:

Format Variable Description
#{pane_command_state} running, idle, dead, or unknown (combines OSC 133 and PTY tcgetpgrp tracking)
#{pane_last_exit_code} Exit code (0..255) of the last completed OSC 133 command (empty if none)
#{pane_stream_bytes} Unread byte count currently queued in wp->stream_buf
#{pane_command_running} 1 if an OSC 133 command is running, 0 otherwise
#{pane_command_status} Exit status from most recent OSC 133 command
#{pane_command_duration} Elapsed duration in seconds of the current or most recent OSC 133 command

Inspecting All Agent Panes at Once

ax list-panes -a -F '#{window_name} (#{pane_id}): state=#{pane_command_state} exit=#{pane_last_exit_code} duration=#{pane_command_duration}s unread=#{pane_stream_bytes}B'

In ~/.tmux.conf_agent, window titles in the orange [AGENT] status bar automatically display [RUN] while a command is executing and [ERR:<code>] if the last command exited with a non-zero code.


Standard Workflow: Synchronous Zero-Escape Bidirectional Automation

Step 1: Write Script to /dev/shm

cat > /dev/shm/job.sh << 'SCRIPT'
python3 - << 'PY'
import json, os
print(json.dumps({
    "user": os.getenv("USER"),
    "quote_test": 'Double "quotes" and single \'quotes\' work without escapes!'
}, indent=2))
PY
SCRIPT

Step 2: Flush, Inject, Wait, and Read Clean Output

ax read-pane -C -t mc-pokelovers-datapacks
ax write-pane -t mc-pokelovers-datapacks -e -f /dev/shm/job.sh
rm -f /dev/shm/job.sh

# Blocks until completion, extracts clean OSC 133 output, drains buffer, and propagates exit code
ax read-pane -w -O -c -E -t mc-pokelovers-datapacks

Structured Audit Logging

Both write-pane and read-pane integrate with systemd journal for structured security and execution logging:


Rebuilding & Updating amux

The source tree is maintained at /home/luke/git/amux (/home/luke/git/tmux):

cd /home/luke/git/amux
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.


Revision #9
Created 2026-09-27 22:10:33 UTC by luKe
Updated 2026-10-19 11:09:45 UTC by luKe