| 1 | # tmux configuration for anvil agent sessions. |
| 2 | # |
| 3 | # The browser terminal is the only client, so the usual interactive niceties |
| 4 | # (status bar, prefix gymnastics) are noise. What matters is that the pane |
| 5 | # behaves like a real terminal for a TUI and that scrollback is deep enough to |
| 6 | # replay on reconnect. |
| 7 | |
| 8 | # Status bar at the top. Note: `capture-pane` (the reconnect snapshot) only |
| 9 | # ever sees pane content, never this bar — it's client chrome — so a browser |
| 10 | # that reconnects gets a one-row jump versus the live view until the next |
| 11 | # repaint. Cosmetic, not a correctness issue. |
| 12 | set -g status on |
| 13 | set -g status-position top |
| 14 | |
| 15 | # Mouse reporting through to the application, so a TUI's click targets and |
| 16 | # scroll work in the browser. |
| 17 | set -g mouse on |
| 18 | |
| 19 | # Forward focus in/out (DECSET 1004) to the pane. Without it Claude Code warns |
| 20 | # on startup and can't tell when the browser tab is focused — wterm's input |
| 21 | # layer already tracks real DOM focus/blur on the terminal element and turns |
| 22 | # it into the same escape sequences, this is what lets tmux pass them through. |
| 23 | set -g focus-events on |
| 24 | |
| 25 | # Deep scrollback — `capture-pane -S -` replays this on reconnect, and an agent |
| 26 | # session produces a lot of output before anyone looks at it. |
| 27 | set -g history-limit 50000 |
| 28 | |
| 29 | # 256-colour + true-colour advertisement. wterm's core resolves 24-bit SGR, so |
| 30 | # there is no reason to let tmux downsample. |
| 31 | set -g default-terminal "tmux-256color" |
| 32 | set -ga terminal-overrides ",*256col*:Tc" |
| 33 | |
| 34 | # The attached client is always anvil's own websocket bridge (see |
| 35 | # container.rs's `attach`), never a real terminal tmux can query — so rather |
| 36 | # than rely on tmux's built-in detection for the client's TERM (xterm-256color, |
| 37 | # set in `attach`'s exec env), say explicitly that it understands OSC 8. wterm |
| 38 | # already parses OSC 8 (docs/agent-sessions.md); this is what lets those |
| 39 | # sequences reach it instead of being dropped in tmux. |
| 40 | set -ga terminal-features ",*:hyperlinks" |
| 41 | |
| 42 | # Keep the pane after its command exits, so the browser can still read the last |
| 43 | # screen; the entrypoint decides when the container is actually done. |
| 44 | set -g remain-on-exit on |
| 45 | |
| 46 | # With remain-on-exit on, a dead pane never actually closes — it just stops |
| 47 | # accepting input — so tmux never re-selects for it the way it would if the |
| 48 | # pane were destroyed. `pane-died` is the hook that fires for exactly that |
| 49 | # case (see tmux.1: "the program running in a pane exits, but remain-on-exit |
| 50 | # is on so the pane has not closed"). Only matters once something splits the |
| 51 | # window — a single-pane session has nowhere else to go — which is what a |
| 52 | # Claude Code teammate spawned with `teammateMode: tmux` would do. |
| 53 | set-hook -g pane-died 'select-pane -t :.+' |
| 54 | |
| 55 | # Do not renumber or rename out from under the supervisor, which addresses the |
| 56 | # session by name. |
| 57 | set -g allow-rename off |
| 58 | |
| 59 | # With several browsers attached, size the window to the most recently active |
| 60 | # client rather than the smallest. The default ("smallest") means one phone |
| 61 | # viewer squeezes everyone else's terminal down to its width for as long as it |
| 62 | # stays connected. |
| 63 | set -g window-size latest |