Kiet Nguyen logo
NotesNotesResumeResume
© 2026 Kiet Nguyen
← All notes
Memphis-design close-up: a geometric viewfinder looking into a colorful engine that keeps running without the glass

How-to·May 14, 2026·10 min read

tmux: the viewfinder is not the engine

Linux · tmux · Shell · Terminal · Operations · SSH

tmux is a programmable session layer that decouples long-running work from the window you happen to be looking through. A how-to for junior engineers: four production situations, the expert mindset, and a complete script that builds a workspace without attaching too soon.

Begin with a distinction, not a feature list. tmux is a terminal multiplexer: a small server on the machine that owns sessions, windows, and panes, and a client that attaches your current terminal to that server. The window on your laptop is a viewfinder. The work lives in the engine.

If you have read Do you really understand the terminal?, you already know the injury that tmux exists to treat. Close a GUI emulator and the kernel sends SIGHUP down the PTY. Jobs die. tmux inserts its own PTY factory and keeps the session after hangup. That is not a convenience pane-splitter. That is a change of what is allowed to die.

This how-to is for a learner or junior engineer. We shall be rigorous: every scenario states a problem, a correct application, and a mistake that looks like competence. We end with a complete script—and we will correct two habits that tutorials still teach badly (chmod 777 on a socket; ~/ inside quoted strings).

Commands assume a POSIX shell and a typical Linux or macOS tmux (3.x). Pane numbers default to zero. If your ~/.tmux.conf sets base-index / pane-base-index to 1, adjust targets. Verify with tmux list-panes -a.

What you will learn

  1. What tmux is (one sentence you can defend).
  2. Four production-shaped uses: detach-safe work, one-screen workspace, shared incident session, scripted layout.
  3. How experts decide differently from beginners.
  4. A complete Bash script that builds a workspace detached, then attaches once.

One-sentence crystal

tmux is a headless session engine: processes keep a controlling TTY inside tmux after your SSH client and GUI window are gone; you attach a disposable viewfinder when you wish to look, and you script the layout because you refuse to treat a living session as irreplaceable furniture.


What tmux is

PhraseAccurate?
“A way to split the terminal”Incomplete. Splits are a view. The product is the server.
“A safety net if SSH drops”A use. The mechanism is: your job’s TTY is a tmux pane, not the SSH PTY.
“A replacement for the shell”No. Each pane runs a shell (or a program). tmux orchestrates them.
“A programmable session layer”Yes.

Three nouns, always:

NounMeaning
ServerOne process per user (typically), holds all sessions in memory.
SessionA named workspace (db-migration, api-backend).
Window / paneA screenful, possibly split; each pane has a PTY and a foreground program.

Client = tmux attach in this terminal. Close the client; the server remains.


Scenario 1 — Long work on the far side of an unreliable cable

The problem

You ssh to a host and start a four-hour migration, a large rsync, or an upgrade. Wi-Fi blinks. The laptop sleeps. The VPN dies. The SSH process dies. The remote shell is the session leader of that PTY. The kernel delivers SIGHUP. The job dies mid-write. Data may be inconsistent. “I will be careful” is not a control.

The correct application

Run the job inside a named session on the machine that owns the disks.

ssh admin@prod-db-01

# Named session: you can find it later without guessing
tmux new -s db-migration

python3 migrate_database.py --all

# Detach: prefix then d. Default prefix is Ctrl+b, then d.
# The GUI window may now close. The engine keeps the PTY.

Hours later, from this laptop or another:

ssh admin@prod-db-01
tmux attach -t db-migration

If you are unsure whether it exists:

tmux ls

How to apply it correctly

  1. Name the session after the operation, not after your mood (db-migration, not tmp).
  2. Start tmux before the dangerous command, not after you remember the lecture.
  3. Detach is optional for safety: even closing the SSH window should leave the tmux server holding the pane. Confirm you are inside tmux (echo $TMUX is non-empty).
  4. Logging: redirect the job as well (tee migrate.log) so you are not solely dependent on scrollback.

Scenario 2 — One screen, many processes

The problem

A junior’s desktop becomes five GUI terminals: editor, tests, API logs, database logs. Focus dies. The arrangement cannot be rebuilt after a reboot.

The correct application

One client window. Several panes. Default prefix Ctrl+b:

Keys after prefixEffect
%Split vertically (left | right)
"Split horizontally (top / bottom)
arrow keys / oMove among panes
cNew window (another full screen in the same session)
n / p / 0–9Next / previous / numbered window
dDetach the client; engine stays

This is a valid use. It is not yet expertise. Expertise is Scenario 4: you refuse to recreate the layout by hand the third time.

How to apply it correctly

  • One window = one activity (edit vs watch logs), not one random split per impulse.
  • Put long-running servers in panes that you will not casually exit.
  • Learn to zoom a pane (Ctrl+b z) instead of opening another GUI window.

Scenario 3 — Shared session for an incident (“war room”)

The problem

Two operators must see the same bytes and type into the same shell. Video sharing adds latency and treats the terminal as a picture. Pairing needs a shared PTY, not a shared rectangle of pixels.

The correct application

tmux can use an explicit socket (-S) so two logins attach to one server.

# Engineer A — create a session on a dedicated socket
tmux -S /tmp/incident-war-room new -s war-room

# Restrict the socket to a shared UNIX group (example: ops).
# Do not chmod 777 on a production host: any local user could attach and type.
chgrp ops /tmp/incident-war-room
chmod 660 /tmp/incident-war-room

# Engineer B
tmux -S /tmp/incident-war-room attach -t war-room

Both clients see the same panes. Either may type. That is the point and the risk.

How to apply it correctly

  1. Socket permissions are the security boundary. chmod 777 is a tutorial vice. Use a group and 660, or tmux server-access where your version supports it.
  2. Announce who types. Two people in one shell is a shared stdin.
  3. When the incident ends: detach, kill-session if the socket was ad hoc, remove the socket file.
  4. This is not an audit log. If you need attribution, you need something else (shared script, ticket, pair protocol).

Scenario 4 — The layout is code

The problem

Every morning: four splits, three services, twenty minutes of cd and Ctrl+b. The session is left up for forty days because recreating it is painful. That is fear of setup, not operational maturity.

The expert rule

If you have built the same pane layout three times, you script it.

You create the session detached (-d), send keys into named targets, then attach. If you omit -d, new-session attaches immediately and the rest of the script never runs.

Target grammar:

session:window.pane
example:  my-project:infra.2

send-keys … C-m means: type this string, then Enter (carriage return).

Default pane index is 0 unless you set pane-base-index. The script below sets window and pane base index to 1 so infra.1 means the first pane—matching how humans count, and avoiding a class of off-by-one bugs.

Tilde in quotes: PROJECT_DIR="~/Projects/my-app" does not expand ~. Use "$HOME/Projects/my-app".


How experts think

Beginners use tmux as split screen plus SSH insurance. Experts use it as a programmable orchestrator that decouples computation from the glass.

1. Decouple the viewfinder from the engine

BeginnerExpert
The window is the server. Close it and the work should… well, tmux is a safety net.The window is a disposable lens. The session is the source of truth.

The expert SSHs in, attaches, starts or inspects, detaches, shuts the laptop. Connections are ephemeral. This is the same ontology as the PTY lecture: do not marry the job to the client.

2. Deterministic layout over precious furniture

BeginnerExpert
Spends five minutes splitting; leaves the session for forty daysAssumes crash, reboot, accidental kill-pane; rebuilds in milliseconds

Tools such as tmuxinator exist. A shell script is enough and is readable in an incident. The script below is that habit made concrete.

3. The buffer, not the picture

BeginnerExpert
Mouse to click panes, scroll, copyHands on the home row; scrollback is a text buffer

Copy-mode (often vi keys): prefix [, search with /, yank, prefix ]. The expert treats output as editable history, not as a screenshot. Configure this in ~/.tmux.conf when you are ready; do not postpone Scenario 1 until your config is pretty.

4. Sessions by context

BeginnerExpert
One session, fifteen windows, “what was window 7?”One session per mental context

Example segregation:

SessionTypical panes
api-backendeditor, tests, git
infra-deployTerraform, cloud CLI, bastion SSH
log-monitoringhtop, journalctl, tail

Jump with prefix s (session tree), or a fuzzy finder later. Windows are rooms in a house. Sessions are different houses.

Evolution matrix

ParadigmNoviceExpert
Primary useSplits + survive SSH dropHeadless orchestration + automation
NavigationMouse, arrows, default prefixKeys, later vi-copy and jumpers
WorkspaceAd hoc, preciousDeclarative script
CopyOS clipboard + mousetmux paste buffer (then OS clipboard if configured)

Level 5 — A workspace script

Target layout

  • Session: my-project
  • Window editor: one pane, editor
  • Window infra: left ~50% app server; top-right ~25% container logs; bottom-right ~25% free shell

Save as setup_project.sh (for example in the project or ~/bin).

#!/usr/bin/env bash
# Build (once) and attach a deterministic tmux workspace.
set -euo pipefail

SESSION_NAME="my-project"
PROJECT_DIR="${HOME}/Projects/my-app"

# Human-facing 1-based windows/panes for this session
tmux_index_opts=( -w pane-base-index 1 )

if ! tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
  echo "Building tmux workspace: $SESSION_NAME"

  # -d: stay detached so this script continues
  tmux new-session -d -s "$SESSION_NAME" -n editor -c "$PROJECT_DIR"
  tmux set-option -t "$SESSION_NAME" base-index 1
  tmux set-window-option -t "$SESSION_NAME:editor" pane-base-index 1

  tmux send-keys -t "$SESSION_NAME:editor.1" "nvim ." C-m

  tmux new-window -t "$SESSION_NAME" -n infra -c "$PROJECT_DIR"
  tmux set-window-option -t "$SESSION_NAME:infra" pane-base-index 1

  tmux send-keys -t "$SESSION_NAME:infra.1" "npm run dev" C-m

  # -h: left | right
  tmux split-window -h -t "$SESSION_NAME:infra.1" -c "$PROJECT_DIR"
  tmux send-keys -t "$SESSION_NAME:infra.2" "docker logs -f my-database" C-m

  # -v: split the right pane into top / bottom
  tmux split-window -v -t "$SESSION_NAME:infra.2" -c "$PROJECT_DIR"
  tmux send-keys -t "$SESSION_NAME:infra.3" "git status" C-m

  tmux select-layout -t "$SESSION_NAME:infra" main-vertical
  tmux select-window -t "$SESSION_NAME:editor"
fi

tmux attach-session -t "$SESSION_NAME"

How to run it

chmod +x setup_project.sh
./setup_project.sh

Second run: has-session succeeds, setup is skipped, you only attach. Your running editor is not rebuilt on top of itself.

Three facts the script depends on

  1. new-session -d — build in the dark; attach last.
  2. -t session:window.pane — name the room, do not hope the “current” pane is correct.
  3. send-keys … C-m — inject keystrokes; C-m is Enter.

Replace nvim ., npm run dev, and docker logs with your commands. The shape is the lesson: detached construct, named targets, attach once.


A short lab

  1. On a disposable host or your laptop: tmux new -s lab, run sleep 300, detach, exit the SSH or close the window, attach again. The sleep remains.
  2. Split twice. Name the feeling of getting lost. Create a second session (tmux new -s other). Prefix s. That is segregation.
  3. Run the script above against a throwaway directory. Kill the session (tmux kill-session -t my-project) and run the script again. Rebuild should be boring.
  4. Read man tmux section on sessions and windows only. Stop before customizing the prefix. Mechanism before cosmetics.

Closing

We have treated tmux as it is used when the network is rude, the desk is small, two people must share a PTY, and the morning layout must not be folklore. The expert shift is not more key bindings. It is this sentence, used as a policy:

The session is the engine. The terminal is a viewfinder. If the layout matters, it is code.

Return to the terminal fathom when you need to say why detach survives hangup. Then come back here and script the next layout you have now built twice.

Back to notes