Why tmux over WezTerm Lua, raw PTY, or X11/Wayland positioning
Each AI agent needs its own isolated terminal environment for executing commands, capturing output, and displaying real-time work. The substrate must allow the orchestrator to spawn sessions on demand, inject commands, read back output, split panes for side-by-side views, and tear down sessions cleanly — all from Go code without blocking the agent's own goroutine.
Every orchestrator operation maps to exactly one tmux subcommand. A single
execTmux helper wraps os/exec and surfaces errors; no
other abstraction is needed. The table below shows the full surface area.
tmux is the primary terminal substrate. A thin Go wrapper named execTmux shells out to the tmux binary for all session operations. WezTerm remains a named future alternative for cross-platform deployments where GPU rendering or Windows support becomes a requirement.
The orchestrator calls execTmux(args ...string) for every terminal operation.
The helper constructs the tmux subprocess, captures stdout/stderr, and returns
structured errors. No session state is held in memory — tmux owns the session tree.
This means the orchestrator can restart without killing any agent’s work-in-progress.
Session names follow the pattern agk-{agentID} to allow the orchestrator to
enumerate all live sessions via tmux list-sessions and reconcile against its
own registry on startup. Sessions that exist in tmux but not in the registry are treated
as orphans and killed after a grace period.
If the system expands to Windows or requires rich GPU-rendered agent UIs, WezTerm provides
a Lua scripting surface that exposes pane, tab, and window management. The Go orchestrator
would send JSON commands over a local socket to a WezTerm Lua listener, preserving the
same SpawnSession / SendCommand / CaptureOutput interface contract.
No WezTerm code is written today. The interface boundary is kept clean precisely so this swap is a single-file change in the terminal adapter layer.
execTmux wrapper is under 60 lines of Go; a raw PTY
equivalent would be several hundred with ongoing maintenance.
execTmux call forks
a process and parses output. At typical orchestration frequency (one command per agent task
step) the 5–15 ms overhead is acceptable. High-frequency polling patterns (e.g., streaming
output at <100 ms intervals) must batch capture-pane calls or use a polling
goroutine rather than issuing per-line subprocesses.
execTmux helper must pattern-match
known error strings (e.g., no server running, can't find session)
to surface typed Go errors. New tmux versions may change these strings; requires a test
fixture against the pinned tmux version.
send-keys
requires the Enter key literal as a final argument to submit a command. This
means every SendCommand call appends "Enter" after the command
string, which is invisible to callers but must be documented clearly to avoid double-Enter
bugs when callers pre-append newlines.