Tmux Session Layout and Pane Management
Related source files:
src/agentmux/runtime/tmux_core.py(primitives),src/agentmux/runtime/content_zone.py(layout helpers +ContentZone),src/agentmux/runtime/pane_io.py(send/capture/trust),src/agentmux/runtime/tmux_control.py(session & pane factory)
Session naming
Tmux sessions are named from the feature directory:
agentmux-<feature_dir_name>
Example:
- Feature directory
.agentmux/.sessions/20260328-075309-enable-multiple-tmux-sessions - Tmux session
agentmux-20260328-075309-enable-multiple-tmux-sessions
When launching a new session, AgentMux also warns if other active agentmux-* sessions already exist.
Content zone
The tmux layout is split into two zones:
- Monitor zone on the left, fixed to 40 columns
- Content zone on the right, managed exclusively by
ContentZone
ContentZone owns the right-hand pane state. Its _visible list is the single source of truth for which agent panes are currently mounted in the main window. The placeholder pane is internal and never part of _visible.
Pane identity and pane display are separate:
@roleremains the stable logical role used for pane lookup and resume (coder,architect, etc.)@pane_labelis optional display metadata used for pane borders and visible pane titles- Pane borders are hidden (
pane-border-style none) while titles remain visible at the top of each pane viapane-border-status top - Coder panes use the structured plan name or fix iteration, reviewer panes use review iteration, and designer panes use the feature being designed
Invariant
- If
_visibleis empty, the placeholder pane occupies the content zone in the main window - If
_visibleis non-empty, the placeholder pane lives in_hidden - Every
show(),show_parallel(),hide(),hide_all(), andremove()mutation re-establishes that invariant immediately
This avoids reconstructing visibility from ad-hoc tmux queries and keeps placeholder handling confined to one abstraction.
Pane lifecycle
- Exclusive display:
ContentZone.show(pane_id)swaps a single agent into the content zone and parks any other visible agents - Parallel display:
ContentZone.show_parallel(pane_ids)shows the first pane exclusively, stacks the rest vertically withjoin-pane -v, then rebalances the visible content panes withselect-layout -E - Completed parallel coders: while the implementation phase is still waiting on other
done_Nmarkers, finished coder panes are parked in_hiddenso remaining active coders get the full visible content area - Parking: hidden agents are moved to the
_hiddenwindow withbreak-pane -d - Removal:
ContentZone.remove(pane_id)hides a visible pane if needed, kills it, and preserves an even split for any remaining visible content panes
The monitor/content split is only created once during session setup. Later mutations use swaps, vertical joins, and breaks so the horizontal divider stays stable.
Pane creation
create_agent_pane() always seeds new panes from _hidden if possible. If the placeholder is currently the only pane in the content zone, tmux may briefly split against it and immediately break the new pane back into _hidden; the steady-state result is still that background panes are parked and not left in the main layout.
tmux_new_session() returns both the initial pane registry and a ContentZone instance initialized with the primary role visible and the placeholder parked.
Runtime snapshot
runtime_state.json is version 2 and persists:
primary: primary pane IDs per roleparallel: worker/task pane IDsvisible: ordered pane IDs currently shown in the content zone
On resume, TmuxAgentRuntime.attach() rehydrates pane IDs, reconstructs ContentZone from visible, and reapplies the desired layout.
Missing panes
TmuxAgentRuntime also exposes a read-only view of the registered primary and parallel panes. The background InterruptionEventSource polls that registry and publishes an interruption event when any registered agent pane disappears, even if it was parked in _hidden.
Orchestrator-managed pane retirement is not an interruption. The runtime marks panes as intentionally retiring for the full remove/update/persist lifecycle, and interruption polling must treat those panes as internal cleanup rather than user-visible cancellation.
That is treated as a user-visible run cancellation rather than a silent pane recreation. The orchestrator persists the interruption to state.json, shows the cause in the monitor, and requires --resume to continue.
Prompt dispatch
send_prompt() no longer creates or reveals panes. It only sends a concise file reference message such as:
Read and follow the instructions in /path/to/prompt.mdVisibility is decided in TmuxAgentRuntime before prompt dispatch. Primary panes are auto-created only when no pane is registered for that role; if a registered pane vanished unexpectedly, the run is canceled instead.
Trust prompt handling
Trust or confirmation prompts from CLI tools are still answered automatically via accept_trust_prompt(), using the provider-specific trust_snippet on AgentConfig.