# ╔═══════════════════════════════════════════════════════════════════════════╗ # ║ SHIPWRIGHT — TMUX OVERLAY CONFIGURATION ║ # ║ ║ # ║ This overlay adds agent-aware pane styling and team keybindings to ║ # ║ your existing tmux config. It is sourced automatically by tmux.conf ║ # ║ but can also be used independently: ║ # ║ ║ # ║ tmux source-file ~/.tmux/shipwright-overlay.conf ║ # ║ ║ # ║ What this overlay does: ║ # ║ - Shows agent names in pane borders (pane_title) ║ # ║ - Enables aggressive resize for better multi-agent layouts ║ # ║ - Adds safety bindings to prevent accidentally killing agent panes ║ # ║ - Provides team-specific keybindings for navigation and management ║ # ║ - Fixes known Claude Code + tmux compatibility issues ║ # ║ ║ # ║ Convention: Each Claude agent pane should set its title on startup via: ║ # ║ printf '\033]2;agent-name\033\\' ║ # ║ The shipwright CLI does this automatically when spawning agent panes. ║ # ╚═══════════════════════════════════════════════════════════════════════════╝ # ═══════════════════════════════════════════════════════════════════════════ # PANE TITLES — Show agent names in borders # ═══════════════════════════════════════════════════════════════════════════ # Display pane titles at the top of each pane border set -g pane-border-status top # Format: pane index, agent name, running command, zoom indicator # Active pane: bold + bright │ Inactive: muted, recessed # Uses #{pane_title} which each agent sets via OSC 2 escape sequence # The ● dot gives a visual "alive" indicator on the active pane set -g pane-border-format "#{?pane_active,#[fg=#00d4ff]#[bold] ● #P │ #{pane_title} #[fg=#52525b]│#[fg=#a1a1aa] #{pane_current_command}#{?window_zoomed_flag, #[fg=#facc15]#[bold]⊞ FOCUS,},#[fg=#52525b] #P │ #[fg=#71717a]#{pane_title} #[fg=#333355]│ #[fg=#52525b]#{pane_current_command}}" # ═══════════════════════════════════════════════════════════════════════════ # LAYOUT — Optimize for multi-agent pane layouts # ═══════════════════════════════════════════════════════════════════════════ # Aggressive resize: let panes resize independently per client # This prevents smaller terminal clients from constraining team pane sizes setw -g aggressive-resize on # ═══════════════════════════════════════════════════════════════════════════ # DARK THEME — Active pane gets a subtle background lift # ═══════════════════════════════════════════════════════════════════════════ # Inactive panes: deep navy, dimmed text — recedes visually # Active pane: subtle bg lift, softer warm gray text — easy on the eyes # NOTE: Claude Code renders its own colors for TUI elements. These fg values # only affect plain terminal output (shell prompts, command output, etc.) # The bg lift (#1a1a2e → #1e1e36) gives the active pane a "floating" feel. set -g window-style 'bg=#1a1a2e,fg=#8888a0' set -g window-active-style 'bg=#1e1e36,fg=#b4b4c8' # Hooks: set pane colors on creation to prevent white flash. # New panes start with inactive colors; active pane lift applies automatically. set-hook -g after-split-window "select-pane -P 'bg=#1a1a2e,fg=#8888a0'" set-hook -g after-new-window "select-pane -P 'bg=#1a1a2e,fg=#8888a0'" set-hook -g after-new-session "select-pane -P 'bg=#1a1a2e,fg=#8888a0'" # ═══════════════════════════════════════════════════════════════════════════ # ROLE-COLORED BORDERS — Active pane border reflects agent role # ═══════════════════════════════════════════════════════════════════════════ # When you switch panes, a hook reads the pane title and sets the active # border color to match the agent's role: # leader/pm → cyan (#00d4ff) builder/dev → blue (#0066ff) # reviewer → orange (#f97316) tester → yellow (#facc15) # security → red (#ef4444) docs → violet (#a78bfa) # optimizer → green (#4ade80) researcher → purple (#7c3aed) # # The hook script must exist; -q makes source-file silent if missing. # Falls back to cyan for non-agent panes (plain shell, vim, etc.) set-hook -g pane-focus-in "run-shell -b 'bash ~/.shipwright/scripts/sw-tmux-role-color.sh 2>/dev/null || true'" # ═══════════════════════════════════════════════════════════════════════════ # SAFETY — Confirm before killing agent panes # ═══════════════════════════════════════════════════════════════════════════ # Override default kill-pane to require confirmation in team windows # This prevents accidentally terminating a running Claude agent bind x confirm-before -p "Kill pane #{pane_title}? (y/n)" kill-pane bind X confirm-before -p "Kill ALL panes in window #W? (y/n)" kill-window # ═══════════════════════════════════════════════════════════════════════════ # TEAM NAVIGATION # ═══════════════════════════════════════════════════════════════════════════ # prefix + g → display pane numbers for 5 seconds (type number to select) bind g display-panes -d 5000 # prefix + G → toggle zoom on current agent pane (focus on one agent's output) bind G resize-pane -Z # prefix + w → choose window/pane from a tree (visual picker) bind w choose-tree -Zw # ═══════════════════════════════════════════════════════════════════════════ # TEAM MANAGEMENT # ═══════════════════════════════════════════════════════════════════════════ # prefix + M-t → send the same command to all panes (synchronized input) # Useful for stopping all agents at once, etc. bind M-t setw synchronize-panes \; display-message "Team sync #{?synchronize-panes,ON,OFF}" # prefix + M-l → rotate through even-horizontal, even-vertical, tiled layouts bind M-l next-layout # prefix + M-s → capture current pane's full scrollback to file bind M-s run-shell "tmux capture-pane -pS - > /tmp/claude-pane-#{pane_title}-\$(date +%%s).txt && tmux display-message 'Captured #{pane_title} to /tmp/'" # prefix + M-a → capture ALL panes in current window (full scrollback each) # NOTE: All $() must be escaped as \$() so they run at keypress time, not config load bind M-a run-shell "\ for pane_id in \$(tmux list-panes -F '#{pane_id}'); do \ title=\$(tmux display-message -t \$pane_id -p '#{pane_title}'); \ tmux capture-pane -t \$pane_id -pS - > /tmp/claude-pane-\${title:-\$pane_id}-\$(date +%%s).txt; \ done && tmux display-message 'Captured all panes to /tmp/'" # ═══════════════════════════════════════════════════════════════════════════ # LAYOUT PRESETS — Quick-switch pane arrangements # ═══════════════════════════════════════════════════════════════════════════ # prefix + M-1 → main-horizontal: leader (left 65%) | agents stacked (right 35%) # prefix + M-2 → main-vertical: leader (top 60%) | agents tiled (bottom 40%) # prefix + M-3 → tiled (equal sizes) bind M-1 select-layout main-horizontal \; resize-pane -t 0 -x 65% bind M-2 select-layout main-vertical \; resize-pane -t 0 -y 60% bind M-3 select-layout tiled # ═══════════════════════════════════════════════════════════════════════════ # SHIPWRIGHT POPUPS — Quick access to tools # ═══════════════════════════════════════════════════════════════════════════ # prefix + M-d → Shipwright dashboard in floating popup bind M-d display-popup -w 85% -h 80% -E "shipwright status 2>/dev/null; echo ''; shipwright ps 2>/dev/null; echo ''; echo 'Press ENTER to close'; read" # prefix + M-m → Memory system in floating popup bind M-m display-popup -w 80% -h 70% -E "shipwright memory show 2>/dev/null || echo 'No memories found'; echo ''; echo 'Press ENTER to close'; read" # prefix + M-h → Heartbeat status in floating popup bind M-h display-popup -w 70% -h 50% -E "shipwright heartbeat list 2>/dev/null || echo 'No active heartbeats'; echo ''; echo 'Press ENTER to close'; read" # ═══════════════════════════════════════════════════════════════════════════ # PANE REAPER — Quick cleanup of dead agent panes # ═══════════════════════════════════════════════════════════════════════════ # prefix + R — Run one-shot reaper (clean dead agent panes) bind R run-shell "shipwright reaper 2>/dev/null; tmux display-message 'Reaper: cleaned dead agent panes'"