The problem
If you run Claude Code in a browser-based terminal — like Cockpit — your session lives inside a WebSocket connection. When that connection drops, everything dies.
Close the browser tab. Lock your phone. Let your laptop sleep. Lose wifi for 30 seconds. Claude stops mid-task. Your context is gone. You start over.
Cockpit terminates idle web sessions after 15 minutes by default. If Claude is quietly running tools and you're not clicking in the UI, the session gets killed automatically.
Without tmux, Claude is a child process of the browser terminal. Connection drops → shell dies → Claude dies. No recovery. No way to reconnect to the same session.
The solution: tmux
tmux is a terminal multiplexer that runs on the server, not in your browser. Your Claude session lives inside tmux. The browser terminal is just a viewport — a window into a room that exists whether or not you're looking at it.
You can attach to the same tmux session from desktop, laptop, and phone simultaneously. All see the same terminal, live.
Setup
Configure tmux
Create ~/.tmux.conf on your server. Enables mouse support, readable status bar, 10k-line scrollback, and a built-in help popup at Ctrl+B H.
# True color + mouse support
set -g default-terminal "screen-256color"
set -g mouse on
# Window numbering from 1, auto-renumber
set -g base-index 1
set -g pane-base-index 1
set-option -g renumber-windows on
# More scrollback
set -g history-limit 10000
# Status bar
set -g status-style "bg=#0d1117,fg=#8b949e"
set -g status-left "#[fg=#3fb950,bold] [#S] "
set -g status-right "#[fg=#484f58]Ctrl+B H for help #[fg=#3fb950]%H:%M #[fg=#484f58]%b %d"
set -g window-status-current-style "fg=#3fb950,bold"
set -g pane-active-border-style "fg=#3fb950"
# Ctrl+B H — quick reference popup (requires tmux 3.2+)
bind H display-popup -E -w 62 -h 26 "cat << 'EOF'
tmux quick reference
Ctrl+B C new window
Ctrl+B , rename window
Ctrl+B W list all windows
Ctrl+B 1-9 switch to window
Ctrl+B N / P next / previous window
Ctrl+B % split left/right
Ctrl+B \" split top/bottom
Ctrl+B arrows move between panes
Ctrl+B Z zoom pane (toggle)
Ctrl+B [ scroll mode (Q to exit)
Ctrl+B D detach (session keeps running)
Ctrl+B H this help
EOF
read -n1 -s -r -p ' press any key to close'"
Requires tmux 3.2+ for the popup. Check with tmux -V. Remove the bind H block for older versions.
Auto-attach on terminal open
Add this to ~/.bashrc. It detects the Cockpit environment via XDG_SESSION_TYPE=web and attaches to (or creates) a tmux session named main.
# Auto-attach to persistent tmux session in cockpit terminals.
# XDG_SESSION_TYPE=web is set by cockpit, not SSH or a physical console.
# new-session -A creates 'main' or attaches if it already exists.
if [ -z "$TMUX" ] && [ "$XDG_SESSION_TYPE" = "web" ]; then
exec tmux new-session -A -s main
fi
Replace the condition with [ -n "$SSH_TTY" ]. This fires only for interactive SSH logins — not for automated ssh host "command" calls that don't allocate a TTY.
Disable the Cockpit idle timeout
Cockpit kills idle web sessions after 15 minutes — exactly long enough to time out while Claude is working quietly. Disable it:
[Session]
IdleTimeout=0
sudo systemctl restart cockpit.service
Key bindings
All tmux commands use a prefix: press Ctrl+B, release it, then press the next key. It's a sequence, not a chord. Ctrl+B H shows a popup cheatsheet in your terminal.
| Ctrl+B C | New window |
| Ctrl+B , | Rename current window |
| Ctrl+B W | List all windows (interactive picker) |
| Ctrl+B 1–9 | Switch to window by number |
| Ctrl+B N / P | Next / previous window |
| Ctrl+B % | Split left/right |
| Ctrl+B " | Split top/bottom |
| Ctrl+B ↑↓←→ | Move between panes |
| Ctrl+B Z | Zoom pane to full screen (toggle) |
| Ctrl+B [ | Scroll mode — arrows or PgUp, press Q to exit |
| Ctrl+B D | Detach — session keeps running on the server |
| Ctrl+B H | Help popup (from this config) |
| Ctrl+B ? | Full built-in keybinding list |
Suggested window layout
Name your windows with Ctrl+B , so the status bar tells you what's running at a glance.
1: claude
Your active Claude Code session. This is where you work.
2: logs
journalctl -f or tail -f on scheduler or app logs.
3: shell
Free shell for quick commands, file checks, or builds.
Coexisting with scheduled sessions
If you run automated Claude sessions on a cron schedule, they can conflict with your interactive session — competing for CPU and processing the same data. Add a guard to skip automated wakes when you're actively working:
def is_interactive_session_active():
"""Skip automated wakes when the user has an active Claude session."""
result = subprocess.run(
['tmux', 'has-session', '-t', 'main'], capture_output=True
)
if result.returncode != 0:
return False # 'main' session doesn't exist
result = subprocess.run(
['tmux', 'list-panes', '-t', 'main', '-F', '#{pane_current_command}'],
capture_output=True, text=True
)
return 'claude' in result.stdout.lower()
# In your run_task() function, before spawning:
if is_interactive_session_active():
print("Skipping: interactive Claude session is active")
return False
Getting notified when input is needed
tmux can highlight a tab when the process in it goes quiet — a reliable signal that something finished and is waiting for you. This uses monitor-silence, which fires after a window produces no output for a set number of seconds.
Add to ~/.tmux.conf:
# Light up tabs that have gone quiet (waiting for input)
set-window-option -g monitor-silence 20
set -g visual-silence on
# Also pass terminal bell alerts through
set -g monitor-bell on
set -g visual-bell on
set -g bell-action any
# Show ~ in tab name when silent, ! on bell
set -g window-status-format " #I:#W#{?window_silence_flag, ~,}#{?window_bell_flag, !,} "
How the indicators work
2:claude ~
Window 2 has been silent for 20+ seconds — likely at a prompt or waiting for input
2:claude !
Window 2 rang the terminal bell — explicit program-triggered alert
Why silence, not activity? monitor-activity fires on every byte of output — too noisy when Claude is actively streaming. monitor-silence fires only when output stops. While a session runs it produces continuous output; when it finishes or hits a prompt, it goes quiet. That's the signal you actually want.
Common pitfalls
The first session after setup won't be in tmux
The .bashrc change only applies to new terminals. Close your current terminal and open a fresh one to get the auto-attach behavior.
display-popup requires tmux 3.2+
Check with tmux -V. Remove the bind H display-popup ... block for older versions and use Ctrl+B ? instead.
Name your windows
Use Ctrl+B , to name each window. Without names, the status bar shows a row of identical bash entries.
tmux survives disconnects, not reboots
Sessions persist across browser drops and network hiccups — not server reboots. A Raspberry Pi or always-on VPS is ideal. A laptop you shut down is not.