# ╔═══════════════════════════════════════════════════════════════════════════╗ # ║ TMUX CONFIGURATION ║ # ║ Shipwright — Optimized for Claude Code ║ # ╚═══════════════════════════════════════════════════════════════════════════╝ # ═══════════════════════════════════════════════════════════════════════════ # GENERAL SETTINGS # ═══════════════════════════════════════════════════════════════════════════ set -g default-terminal "tmux-256color" # ─── Terminal-specific overrides ──────────────────────────────────────── # True color + italics for modern terminals set -ag terminal-overrides ",xterm-256color:RGB" set -ag terminal-overrides ",xterm-256color:Tc" set -ag terminal-overrides ",iTerm2*:RGB:Tc" # Ghostty, kitty, WezTerm, Alacritty true color set -ag terminal-overrides ",xterm-ghostty:RGB:Tc" set -ag terminal-overrides ",xterm-kitty:RGB:Tc" set -ag terminal-overrides ",wezterm:RGB:Tc" set -ag terminal-overrides ",alacritty:RGB:Tc" # Styled underline (curly, dotted, dashed) set -ag terminal-overrides ",*:Smulx=\\E[4::%p1%dm" set -ag terminal-overrides ",*:Setulc=\\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m" # Terminal.app: 256 color only, basic mouse set -ag terminal-overrides ",Apple_Terminal*:colors=256" # ─── Claude Code TUI Compatibility ──────────────────────────────────── # Passthrough: enables DEC 2026 synchronized output (eliminates flicker), # OSC 52 clipboard, OSC notifications, and image protocols. # Critical for Claude Code's rapid TUI updates inside tmux. set -g allow-passthrough on # Extended keys: lets TUI apps (Claude Code, vim, etc.) receive modifier # key combos that plain terminals would swallow (Ctrl+Shift+key, etc.) set -g extended-keys on set -as terminal-features 'xterm*:extkeys' # Signal true color support to apps inside tmux. # Without this, Claude Code falls back to 256-color ANSI palette (washed-out). set-environment -g COLORTERM truecolor # Ensure TERM is correct in the global environment. # Prevents inherited TERM=dumb (from launchers/IDEs) from disabling colors. set-environment -g TERM tmux-256color # ─── Mouse ────────────────────────────────────────────────────────────── set -g mouse on # Fix: tmux 3.4+ defaults MouseDown1Status to switch-client (sessions), # but we want select-window so clicking status bar windows actually works bind -T root MouseDown1Status select-window -t = # Double-click on status bar word to rename window bind -T root DoubleClick1Status command-prompt -I "#W" "rename-window -- '%%'" # ─── Core Behavior ───────────────────────────────────────────────────── set -g base-index 1 # Claude Code expects 0-based pane indexing for agent team pane routing setw -g pane-base-index 0 set -g renumber-windows on set -sg escape-time 0 set -g focus-events on setw -g monitor-activity on set -g visual-activity off # Display messages for 3 seconds (default 750ms is too fast) set -g display-time 3000 # Display pane indicators for 2 seconds set -g display-panes-time 2000 # Smoother repeated key operations (600ms window) set -g repeat-time 600 # Clipboard: native OSC 52 — copies work across SSH + tmux nesting set -g set-clipboard on # ─── History ─────────────────────────────────────────────────────────── # Claude Code generates 4,000-6,700 scroll events/sec during streaming. # 250k lines prevents buffer exhaustion during long agent runs. set -g history-limit 250000 # ═══════════════════════════════════════════════════════════════════════════ # STATUS BAR CONFIGURATION # ═══════════════════════════════════════════════════════════════════════════ set -g status-position bottom set -g status-interval 3 set -g status-justify left set -g status-style "bg=#1a1a2e,fg=#a1a1aa" set -g status-left-length 100 set -g status-right-length 150 # Left: session name, prefix indicator, zoom warning set -g status-left "#[fg=#1e1e32,bg=#00d4ff,bold] #S #[fg=#00d4ff,bg=#0066ff]#[fg=#1e1e32,bg=#0066ff,bold] #{?client_prefix,⌨ ,λ }#[fg=#0066ff,bg=#1a1a2e]#{?window_zoomed_flag, #[fg=#facc15]#[bold]🔍 ZOOM ,} " setw -g window-status-separator " " # Inactive windows; team windows (claude-*) get a λ icon setw -g window-status-format "#{?#{m:claude-*,#W},#[fg=#7c3aed]#[bg=#252538] λ #I:#W ,#[fg=#71717a]#[bg=#252538] #I:#W }#[fg=#252538]#[bg=#1a1a2e]" # Active window; team windows get λ icon in cyan setw -g window-status-current-format "#{?#{m:claude-*,#W},#[fg=#1e1e32]#[bg=#00d4ff]#[bold] λ #I:#W ,#[fg=#1e1e32]#[bg=#00d4ff]#[bold] #I:#W }#[fg=#00d4ff]#[bg=#1a1a2e]" # Right side: key hints when prefix is active, otherwise pipeline + agents + clock # Pipeline widget: shows current stage (BUILD, TEST, etc.) with stage-colored badge # Agent widget: shows active agent count as λN in purple # Rule: dark text (#1e1e32) on bright backgrounds, muted text on dark backgrounds set -g status-right-length 200 set -g status-right "#{?client_prefix,#[fg=#1e1e32]#[bg=#0066ff]#[bold] T team | split - split hjkl nav G zoom S sync x kill F fzf #[fg=#1e1e32]#[bg=#00d4ff]#[bold] ^a ,#(~/.shipwright/scripts/sw-tmux-status.sh agents 2>/dev/null)#(~/.shipwright/scripts/sw-tmux-status.sh pipeline 2>/dev/null)#[fg=#71717a]#[bg=#252538] #(whoami)@#h #[fg=#1e1e32]#[bg=#7c3aed]#[bold] %H:%M #[fg=#1e1e32]#[bg=#0066ff]#[bold] %b %d #[fg=#1e1e32]#[bg=#00d4ff]#[bold] %a }" # ═══════════════════════════════════════════════════════════════════════════ # PANE STYLING # ═══════════════════════════════════════════════════════════════════════════ # window-style/window-active-style defined in shipwright-overlay.conf (with hooks) set -g pane-border-style "fg=#333355,bg=#1a1a2e" set -g pane-active-border-style "fg=#00d4ff,bg=#1a1a2e" # Heavy pane border lines for better visibility (tmux 3.2+) set -g pane-border-lines heavy set -g display-panes-colour "#333355" set -g display-panes-active-colour "#00d4ff" # ─── Popup Styling (tmux 3.3+) ───────────────────────────────────────── set -gq popup-style 'bg=#252538' set -gq popup-border-style 'fg=#00d4ff' set -gq popup-border-lines rounded # ═══════════════════════════════════════════════════════════════════════════ # MESSAGE STYLING # ═══════════════════════════════════════════════════════════════════════════ set -g message-style "bg=#00d4ff,fg=#1e1e32,bold" set -g message-command-style "bg=#7c3aed,fg=#1e1e32,bold" # ═══════════════════════════════════════════════════════════════════════════ # MODE STYLING (copy mode, etc.) # ═══════════════════════════════════════════════════════════════════════════ setw -g mode-style "bg=#0066ff,fg=#1e1e32,bold" setw -g clock-mode-colour "#00d4ff" setw -g clock-mode-style 24 # ═══════════════════════════════════════════════════════════════════════════ # KEY BINDINGS # ═══════════════════════════════════════════════════════════════════════════ unbind C-b set -g prefix C-a bind C-a send-prefix bind r source-file ~/.tmux.conf \; source-file -q ~/.tmux/shipwright-overlay.conf \; display-message "Config reloaded!" bind | split-window -h -c "#{pane_current_path}" bind - split-window -v -c "#{pane_current_path}" unbind '"' unbind % bind h select-pane -L bind j select-pane -D bind k select-pane -U bind l select-pane -R bind -r H resize-pane -L 5 bind -r J resize-pane -D 5 bind -r K resize-pane -U 5 bind -r L resize-pane -R 5 bind -r C-h select-window -t :- bind -r C-l select-window -t :+ bind c new-window -c "#{pane_current_path}" # x/X bindings defined in shipwright-overlay.conf with confirm-before safety # bind x → confirm-before kill-pane # bind X → confirm-before kill-window setw -g mode-keys vi bind -T copy-mode-vi v send-keys -X begin-selection bind -T copy-mode-vi r send-keys -X rectangle-toggle bind p paste-buffer # Clipboard handled by tmux-yank plugin (loaded via TPM below) # tmux-yank uses OSC 52 + pbcopy/xclip automatically bind S setw synchronize-panes \; display-message "Sync #{?synchronize-panes,ON,OFF}" # ═══════════════════════════════════════════════════════════════════════════ # SMART PANE SWITCHING (vim-tmux-navigator style) # ═══════════════════════════════════════════════════════════════════════════ is_vim="ps -o state= -o comm= -t '#{pane_tty}' \ | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?|fzf)(diff)?$'" bind -n 'C-h' if-shell "$is_vim" 'send-keys C-h' 'select-pane -L' bind -n 'C-j' if-shell "$is_vim" 'send-keys C-j' 'select-pane -D' bind -n 'C-k' if-shell "$is_vim" 'send-keys C-k' 'select-pane -U' bind -n 'C-l' if-shell "$is_vim" 'send-keys C-l' 'select-pane -R' # ═══════════════════════════════════════════════════════════════════════════ # SESSION MANAGEMENT # ═══════════════════════════════════════════════════════════════════════════ bind s choose-tree -sZ -O name bind N new-session # ═══════════════════════════════════════════════════════════════════════════ # FLOATING POPUP TERMINALS (tmux 3.2+) # ═══════════════════════════════════════════════════════════════════════════ # prefix + F → floating popup terminal in current directory bind F display-popup -E -w 80% -h 75% -d "#{pane_current_path}" # prefix + C-f → FZF session/window switcher in a popup bind C-f display-popup -E -w 60% -h 50% "\ tmux list-sessions -F '#{session_name}' | \ fzf --reverse --header='Switch session' | \ xargs -I{} tmux switch-client -t {}" # ═══════════════════════════════════════════════════════════════════════════ # PLUGINS (via TPM) # ═══════════════════════════════════════════════════════════════════════════ set -g @plugin 'tmux-plugins/tpm' set -g @plugin 'tmux-plugins/tmux-sensible' set -g @plugin 'tmux-plugins/tmux-resurrect' set -g @plugin 'tmux-plugins/tmux-continuum' set -g @plugin 'tmux-plugins/tmux-yank' set -g @plugin 'sainnhe/tmux-fzf' # ─── Plugin Configuration ────────────────────────────────────────────── # Resurrect: persist full pane content + programs set -g @resurrect-capture-pane-contents 'on' set -g @resurrect-strategy-nvim 'session' # Continuum: auto-save every 15 min, auto-restore on tmux start set -g @continuum-restore 'on' set -g @continuum-save-interval '15' # Yank: use system clipboard, stay in copy mode after yanking set -g @yank_selection_mouse 'clipboard' set -g @yank_action 'copy-pipe' # FZF: use popup window (tmux 3.2+), Shipwright color scheme set -g @tmux-fzf-launch-key 'C-f' TMUX_FZF_OPTIONS="-p -w 60% -h 50%" TMUX_FZF_PREVIEW=0 # ═══════════════════════════════════════════════════════════════════════════ # SHIPWRIGHT INTEGRATION # ═══════════════════════════════════════════════════════════════════════════ # Source teams overlay (agent pane styling, keybindings) source-file -q ~/.tmux/shipwright-overlay.conf # Quick launch: prefix + T → start a Claude team session bind T run-shell "shipwright session" # Quick status: prefix + C-t → show team dashboard in floating popup bind C-t display-popup -w 80% -h 70% -E "shipwright status; echo ''; echo 'Press ENTER to close'; read" # Quick logs: prefix + C-l → tail agent logs in popup bind M-L display-popup -w 85% -h 80% -E "shipwright logs --follow 2>/dev/null || echo 'No active logs'; echo ''; echo 'Press ENTER to close'; read" # Quick cost: prefix + C-c → cost dashboard in popup bind M-C display-popup -w 70% -h 60% -E "shipwright cost show 2>/dev/null || echo 'Cost tracking not configured'; echo ''; echo 'Press ENTER to close'; read" # Initialize TPM (keep at very bottom) run-shell '~/.tmux/plugins/tpm/tpm'