tmux, 터미널을 닫아도 남는 작업
이 글은 Claude Opus 5.5 를 이용해 초안이 작성되었으며, 이후 퇴고를 거쳤습니다.
엉클 밥 시리즈 2편을 쓰면서 swarm-forge 의 설치 조건을 옮겨 적었습니다. zsh, git, tmux, Babashka. 이 가운데 tmux 는 써 본 적이 없었습니다. swarm-forge 는 에이전트 역할마다 tmux 세션을 하나씩 띄우고, 일을 넘길 때마다 tmux 로 그 에이전트의 화면에 문장을 타이핑해 넣습니다. 에이전트 여러 개를 사람 대신 부리는 최신 도구가 기대는 바탕이 오래된 터미널 도구라는 점이 묘하게 걸렸습니다.
tmux 는 “terminal multiplexer” 를 줄인 이름입니다. 터미널 하나 안에서 여러 개의 셸을 띄우고 나누고 오가게 해 주는데, 그보다 중요한 성질이 하나 있습니다. 그 셸들이 터미널 창보다 오래 삽니다. 창을 닫아도, SSH 연결이 끊겨도, 안에서 돌던 프로그램은 그대로 돌고 있다가 다시 붙으면 그 자리를 보여 줍니다. 이 글은 tmux 를 처음 쓰는 사람의 눈으로 그 개념을 정리하고, 가끔 vim 을 쓰고 평소에는 Warp 를 쓰는 사람이 업무에서 바로 쓸 만한 레시피를 모읍니다. 레시피는 모두 Homebrew 로 설치한 tmux 3.8 에서 직접 돌려 확인했습니다.
서버, 세션, 창, 패널#
tmux 를 이해하는 열쇠는 화면이 아니라 프로세스 구조입니다. tmux 를 처음 실행하면 백그라운드에 tmux 서버가 하나 뜨고, 지금 보고 있는 터미널은 그 서버에 붙은 클라이언트가 됩니다. 셸과 그 안의 프로그램은 서버가 들고 있습니다. 둘은 /tmp 아래의 소켓 파일로 이야기합니다. 그래서 클라이언트(터미널 창)가 사라져도 서버와 그 안의 프로그램은 남습니다.
서버 안의 구조는 세 단계입니다. 세션(session)은 작업 묶음이고 이름이 있습니다. 세션 안에 창(window)이 있고, 창은 브라우저의 탭처럼 한 번에 하나만 보입니다. 창은 다시 패널(pane)로 나뉘고, 패널 하나가 셸 하나입니다.
flowchart TD
T1[터미널 창 1: 클라이언트] --> S[tmux 서버]
T2[터미널 창 2 또는 SSH: 클라이언트] --> S
S --> W[세션 work]
S --> D[세션 dev]
W --> W1[창 1: editor]
W --> W2[창 2: build]
W2 --> P1[패널 1: make test]
W2 --> P2[패널 2: tail -f log]
style S fill:#FFD700,color:#000000
style W fill:#87CEEB,color:#000000
style D fill:#87CEEB,color:#000000
클라이언트를 세션에서 떼어 내는 걸 detach, 다시 붙이는 걸 attach 라고 합니다. 한 세션에 클라이언트 여러 개가 동시에 붙을 수도 있어서, 사무실에서 띄운 세션을 집에서 SSH 로 이어 볼 수 있습니다. tmux 공식 위키의 입문 문서가 tmux 를 쓰는 이유로 맨 먼저 드는 것도 이 장면입니다.
tmux 안에서 tmux 자신에게 명령을 내릴 때는 먼저 prefix 키를 누릅니다. 기본값은 Ctrl+b 이고, 이 글에서는 C-b 로 적습니다. C-b 를 눌렀다 떼고 그다음 키를 누르는 방식입니다. 처음 며칠은 이 정도만 손에 익히면 됩니다.
| 하고 싶은 일 | 키 또는 명령 |
|---|---|
| 이름 붙여 세션 시작 / 있으면 붙기 | tmux new -A -s work |
| 세션 목록 / 다시 붙기 | tmux ls / tmux attach -t work |
| 세션에서 빠져나오기 (프로그램은 계속 돎) | C-b d |
| 새 창 / 다음·이전 창 / 창 목록에서 고르기 | C-b c / C-b n·C-b p / C-b w |
| 좌우 분할 / 상하 분할 / 패널 이동 | C-b % / C-b " / C-b 방향키 |
| 패널 하나를 잠깐 크게 보기 | C-b z |
| 스크롤하고 복사하기 (복사 모드) | C-b [ |
| 패널 닫기 / 세션 통째로 끝내기 | C-b x / tmux kill-session -t work |
| 키 목록 보기 | C-b ? |
Warp 를 쓰고 있다면#
Warp 에도 분할 화면이 있습니다. ⌘D 로 좌우, ⌘⇧D 로 상하를 나누고, 앱을 다시 켜면 창과 탭과 패널 배치, 그리고 최근 블록(명령과 출력 기록)을 되살려 줍니다. 화면을 나눠 보는 것만이 목적이라면 Warp 로 충분합니다.
차이는 프로세스에 있습니다. Warp 문서가 되살린다고 적은 건 배치와 기록이고, 여느 터미널 앱처럼 Warp 를 끄면 그 안에서 돌던 셸과 프로그램은 함께 끝납니다. tmux 의 패널은 tmux 서버가 들고 있으니 터미널 앱을 꺼도 살아 있습니다. SSH 너머의 서버에서는 더 분명합니다. 연결이 끊기면 Warp 의 분할 화면은 빈 화면이 되지만, 서버의 tmux 세션은 그대로 남습니다. 그리고 tmux 는 모든 동작을 명령으로도 할 수 있어서 스크립트로 화면을 짜고 조작할 수 있습니다. swarm-forge 가 tmux 를 고른 이유도 이것입니다.
Warp 안에서 tmux 를 쓸 때 알아 둘 것이 있습니다. Warp 문서는 tmux 를 vim·Emacs 와 함께 키 입력을 확장 방식으로 주고받는 전체 화면 앱으로 다룹니다. tmux 3.8 은 마우스가 기본으로 켜져 있지만, Warp 쪽에서 Settings > Features > Terminal 의 Enable Mouse Reporting 을 켜야 클릭으로 패널을 고르거나 휠로 스크롤하는 동작이 tmux 에 전달됩니다. 예전에는 Warp 가 SSH 세션의 기능을 tmux 로 구현하던 시기도 있었는데, 지금은 SSH extension 으로 바뀌어 그 방식은 제거됐습니다.
vim 과 겹치는 곳, 다른 곳#
vim 을 가끔 쓰는 사람에게 tmux 의 용어는 익숙하게 들립니다. vim 에도 창(window)과 탭(tab)이 있고 화면을 나눌 수 있습니다. 하지만 나누는 대상이 다릅니다. vim 은 편집기 하나 안에서 버퍼를 여러 개 보여 주는 것이고, tmux 는 터미널 자체를 나눠 각 칸에서 아무 프로그램이나 돌리게 합니다. vim 을 끄면 vim 의 분할도 사라지지만, tmux 의 패널은 그 안의 vim 이 꺼져도 셸로 남습니다. 그래서 둘은 경쟁하지 않고 겹쳐 씁니다. tmux 패널 하나에서 vim 을 열고, 옆 패널에서 테스트를 돌리는 식입니다.
vim 을 쓰는 사람이 tmux 에서 가장 먼저 만나는 건 복사 모드입니다. C-b [ 로 들어가면 화면이 멈추고 스크롤과 검색과 선택을 할 수 있습니다. 키 배치는 mode-keys 옵션이 정하는데, 기본값은 emacs 식이고 VISUAL 이나 EDITOR 환경 변수에 vi 가 들어 있을 때만 vi 식이 됩니다. vi 식으로 바꿔도 vim 과 완전히 같지는 않습니다. 3.8 의 기본 배치에서 선택 시작은 Space, 복사는 Enter 이고, v 는 선택 시작이 아니라 사각형 선택 전환입니다. vim 처럼 v 로 선택하고 y 로 복사하고 싶다면 설정을 두 줄 더하면 됩니다(아래 설정 파일에 넣었습니다). / 와 ? 로 검색하고 n·N 으로 다음 결과로 가는 건 vim 과 같습니다.
또 하나는 Esc 입니다. 터미널에서 Esc 는 다른 키의 시작이기도 해서, tmux 는 Esc 가 들어오면 뒤에 무엇이 이어지는지 잠깐 기다립니다. 그 시간이 escape-time 이고, tmux 3.5(2024년 9월)부터 기본값이 10밀리초입니다. 그보다 오래된 tmux 는 기본값이 훨씬 길어서 vim 에서 Esc 로 일반 모드로 나올 때 굼뜨게 느껴집니다. 회사 서버처럼 배포판 패키지로 깔린 오래된 tmux 를 쓴다면 설정 파일에 set -sg escape-time 10 을 넣어 두는 게 좋습니다.
vim 을 주로 쓰는 사람들은 vim 의 창 이동과 tmux 의 패널 이동을 같은 키로 묶는 플러그인(vim-tmux-navigator 같은 것)을 쓰기도 합니다. 가끔 쓰는 정도라면 거기까지는 필요 없다고 봅니다.
설정 파일 하나#
tmux 는 홈 디렉터리의 .tmux.conf 를 읽습니다. 3.8 은 기본값이 꽤 좋아져서 손댈 것이 적습니다. 마우스는 기본으로 켜져 있고, 터미널 종류도 tmux-256color 로 잡혀 있습니다. 제가 출발점으로 고른 건 이 정도입니다.
set -g history-limit 50000 # 스크롤백을 넉넉하게 (기본 2000줄)
set -g base-index 1 # 창 번호를 1부터
setw -g pane-base-index 1 # 패널 번호도 1부터
set -g renumber-windows on # 창을 닫으면 번호를 다시 매김
set -sg escape-time 10 # 오래된 tmux 에서 vim 의 Esc 가 굼뜨지 않게
setw -g mode-keys vi # 복사 모드에서 vi 식 키
bind -T copy-mode-vi v send -X begin-selection # vim 처럼 v 로 선택
bind -T copy-mode-vi y send -X copy-pipe-and-cancel # vim 처럼 y 로 복사 (copy-command 로 넘김)
set -s copy-command 'pbcopy' # 복사한 내용을 macOS 클립보드로
bind | split-window -h -c "#{pane_current_path}" # 지금 디렉터리에서 좌우 분할
bind - split-window -v -c "#{pane_current_path}" # 지금 디렉터리에서 상하 분할
bind r source-file ~/.tmux.conf \; display-message "config reloaded"
split-window 에 -c "#{pane_current_path}" 를 붙이면 새 패널이 홈 디렉터리가 아니라 지금 보던 디렉터리에서 열립니다. 작은 차이인데 하루에 수십 번 체감됩니다. 설정을 고친 뒤에는 C-b r 로 바로 다시 읽습니다. copy-command 는 복사 모드의 copy-pipe 계열 명령(기본 Enter 와 위에서 묶은 y)이 복사한 내용을 넘길 명령이라, 리눅스 서버라면 pbcopy 대신 그 환경의 클립보드 명령을 넣습니다. 실험할 때는 클립보드를 건드리지 않으려고 파일에 쓰는 명령을 넣어 봤고, 선택한 줄이 그대로 넘어가는 것을 확인했습니다.
레시피 1: SSH 가 끊겨도 작업은 남는다#
원격 서버에서 오래 걸리는 일을 하다가 노트북을 덮거나 와이파이가 끊기면, 보통은 그 셸과 함께 작업도 끝납니다. 서버에 tmux 가 있다면 접속하자마자 세션 안으로 들어가는 습관 하나로 이걸 막을 수 있습니다.
ssh -t build-server 'tmux new -A -s work'
-A 는 work 세션이 이미 있으면 새로 만들지 않고 거기에 붙으라는 뜻이라, 이 한 줄을 접속할 때마다 그대로 쓰면 됩니다. 처음이면 세션이 생기고, 끊겼다가 다시 들어오면 하던 화면으로 돌아갑니다. 로컬에서 이 상황을 흉내 내 봤습니다. 1초마다 줄을 쌓는 작업을 세션 안에서 돌리고, 가짜 터미널로 tmux new -A -s work 를 실행해 붙은 다음, 그 클라이언트 프로세스를 강제로 죽였습니다. 연결이 갑자기 끊긴 상황입니다. 클라이언트 목록은 비었지만 세션은 그대로 있었고, 작업은 그사이에도 줄을 계속 쌓고 있었습니다.
주의할 점은 서버의 tmux 버전입니다. 배포판 패키지로 깔린 tmux 는 노트북의 3.8 보다 오래된 경우가 많고, 그러면 마우스가 기본으로 꺼져 있고(3.8 부터 기본 켜짐) 앞에서 말한 escape-time 도 길 수 있습니다. 서버에도 같은 .tmux.conf 를 두면 차이가 줄어듭니다.
레시피 2: 오래 걸리는 작업을 지켜보기#
빌드나 마이그레이션처럼 몇십 분 걸리는 일은 창 하나에 띄워 두고 다른 일을 하는 경우가 많습니다. 이때 쓸 만한 장치가 넷 있습니다.
실패한 작업의 화면을 남기려면 remain-on-exit 을 씁니다. 보통 패널은 그 안의 명령이 끝나면 닫히는데, failed 로 두면 실패했을 때만 패널이 남습니다. 성공하는 명령과 종료 코드 3으로 실패하는 명령을 창 두 개에 띄워 보니, 성공한 창은 사라지고 실패한 창만 “Pane is dead (status 3, …)” 라는 표시와 함께 남았습니다.
tmux set -g remain-on-exit failed
tmux new-window -n migrate 'bin/migrate --all'
작업이 끝나기를 스크립트에서 기다리려면 wait-for 를 씁니다. 패널에 보낸 명령 끝에 신호를 걸어 두면, 바깥의 tmux wait-for 가 그 신호가 올 때까지 멈춰 있다가 이어서 진행합니다. 3초 걸리는 명령으로 해 보니 정확히 3초 뒤에 돌아왔습니다.
tmux send-keys -t build:job 'make test; tmux wait-for -S tests-done' Enter
tmux wait-for tests-done && echo "테스트가 끝났습니다"
출력을 파일로 남기는 방법은 둘입니다. pipe-pane -o 'cat >> job.log' 은 그 패널에 나오는 모든 것을 실시간으로 파일에 이어 씁니다. 다만 터미널에 나가는 그대로라 프롬프트와 색상 제어 문자까지 섞입니다. 깔끔한 텍스트가 필요하면 끝난 뒤에 capture-pane -p -S - 로 스크롤백 전체를 뽑는 편이 낫습니다.
마지막은 알림입니다. monitor-silence 30 을 걸어 두면 그 창에 30초 동안 출력이 없을 때 상태 줄에 표시가 뜨고, monitor-activity on 은 반대로 조용하던 창에 출력이 생길 때 표시합니다. 로그를 쏟아내던 작업이 멈췄다는 건 끝났거나 멈췄다는 뜻이라, 다른 창에서 일하다가도 알아챌 수 있습니다.
레시피 3: 에이전트 CLI 여러 개#
Claude Code 와 Codex 를 같이 쓰다 보면 터미널 탭이 금세 늘어납니다. tmux 세션 하나에 에이전트마다 창을 하나씩 두고, 창마다 다른 git worktree 에서 띄우면 서로의 변경이 섞이지 않습니다. 이런 스크립트를 하나 만들어 두면 됩니다.
#!/bin/sh
# agents.sh [repo] : 에이전트 CLI 마다 창 하나, 각자 자기 git worktree 에서 띄운다
repo=${1:-$PWD}; s=agents
tmux has-session -t "$s" 2>/dev/null && exec tmux attach -t "$s"
tmux new-session -d -s "$s" -n claude -c "$repo/.worktrees/claude"
tmux send-keys -t "$s:claude" "claude" Enter
tmux new-window -t "$s" -n codex -c "$repo/.worktrees/codex"
tmux send-keys -t "$s:codex" "codex" Enter
tmux new-window -t "$s" -n shell -c "$repo"
tmux select-window -t "$s:claude"
exec tmux attach -t "$s"
두 번째 실행부터는 이미 있는 세션에 붙기만 합니다. 실제 에이전트 대신 메시지를 출력하는 명령으로 돌려 보니, 창 셋이 각자의 디렉터리에서 떴습니다. 에이전트가 일을 마치고 입력을 기다리는지 알고 싶을 때는 레시피 2의 monitor-silence 가 그대로 쓰입니다. 출력이 멈춘 창에 표시가 뜨면 그 에이전트가 끝났거나 내 답을 기다린다는 뜻입니다. 3초로 걸어 두고 기다려 보니 해당 창에만 표시가 켜졌습니다.
창을 바꾸지 않고 바깥에서 에이전트의 화면을 훑을 수도 있습니다. tmux capture-pane -p -t agents:codex | tail -20 은 그 창의 마지막 스무 줄을 출력합니다. swarm-forge 가 에이전트들을 지켜보고 깨우는 방식도 결국 capture-pane 과 send-keys 입니다. 다만 send-keys 는 그 창에 키를 그대로 쳐 넣는 것이라, 에이전트가 확인을 기다리는 화면에 엉뚱한 문장이 들어가면 그대로 답이 됩니다. 여러 패널에 같은 입력을 보내는 synchronize-panes 도 에이전트 창에서는 켜지 않는 편이 안전합니다.
3.7 부터는 레이아웃 위에 뜨는 floating pane 도 생겼습니다. tmux new-pane 'git status; read' 를 실행하면 지금 창 위에 작은 패널이 떠서, 에이전트 화면을 가리지 않고 잠깐 셸 일을 보고 닫을 수 있습니다. 3.8 에서 실행해 보니 기본 크기는 창 너비의 절반, 높이의 4분의 1이었습니다.
레시피 4: 로컬 프로세스 여러 개#
개발 서버, DB, 로그 감시처럼 매일 같은 조합을 띄운다면 화면 배치까지 스크립트로 고정해 둡니다.
#!/bin/sh
# dev.sh [dir] : 개발 서버·DB·로그를 한 창에 띄운다. 끝낼 때는 tmux kill-session -t dev
dir=${1:-$PWD}; s=dev
tmux has-session -t "$s" 2>/dev/null && exec tmux attach -t "$s"
tmux new-session -d -s "$s" -n app -c "$dir" -x "$(tput cols)" -y "$(tput lines)"
tmux send-keys -t "$s:app.1" "make serve" Enter
tmux split-window -h -t "$s:app" -c "$dir"
tmux send-keys -t "$s:app.2" "docker compose up db" Enter
tmux split-window -v -t "$s:app.2" -c "$dir"
tmux send-keys -t "$s:app.3" "tail -f log/development.log" Enter
tmux set -w -t "$s:app" main-pane-width 60%
tmux select-layout -t "$s:app" main-vertical
tmux select-pane -t "$s:app.1"
exec tmux attach -t "$s"
왼쪽 60% 에 개발 서버, 오른쪽 위아래에 DB 와 로그가 뜹니다. 패널 번호가 1부터인 건 앞의 설정 파일 덕분입니다. -x·-y 로 세션 크기를 지금 터미널에 맞춰 두지 않으면, 붙기 전에 나눈 패널이 기본 크기(80×24) 기준으로 잘게 쪼개져 이상한 모양이 됩니다. 실험에서 실제로 그런 모양이 나와서 이 두 옵션을 넣었습니다. 하루 일을 마칠 때는 tmux kill-session -t dev 한 줄이면 세 프로세스가 함께 정리됩니다. 오래 도는 가짜 프로세스 셋을 띄워 놓고 이 명령을 실행해 보니, 1초 뒤 셋 모두 사라졌습니다.
2025~2026 년의 tmux#
tmux 는 GNU Screen 의 뒤를 잇는 오래된 도구지만 지금도 빠르게 바뀌고 있습니다. 2025년 11월의 3.6 에서 패널 스크롤바가 생겼고, 2026년 6월의 3.7 에서 floating pane 이 들어왔습니다. 9월의 3.8 은 마우스를 기본으로 켜고, 밝은·어두운 테마를 터미널에 맞춰 고르고, 다른 패널과의 상호작용을 막는 모달 패널과 형식(format)이 바뀔 때 훅을 실행하는 감시 기능을 더했습니다. 셸이 OSC 133 이라는 신호로 명령의 시작과 끝을 알려 주면 tmux 가 그걸 이벤트로 받는 기능도 3.8 에 들어갔습니다. 레시피 2의 wait-for 를 쓰지 않아도 “명령이 끝나면” 을 직접 잡을 수 있게 된 셈인데, 이 부분은 셸 쪽 설정이 필요해 이번에는 돌려 보지 않았습니다.
정리하면, 화면을 나눠 보는 것만이라면 Warp 로 충분하고, 터미널보다 오래 살아야 하는 작업이 있거나 화면을 스크립트로 다루고 싶을 때 tmux 를 꺼내면 됩니다. SSH 로 서버에 들어가는 날이 잦다면 tmux new -A -s work 한 줄부터 손에 익혀 두는 것을 권합니다.
자료에 대해#
개념과 기본값은 tmux 3.8 의 man 페이지와 저장소의 CHANGES 파일, 공식 위키의 Getting Started 문서로 확인했습니다. 기본값은 설정 파일 없이 띄운 tmux 3.8 에서 직접 조회한 값이고, 오래된 버전의 escape-time 은 CHANGES 의 3.5 항목만 확인해 구체적인 이전 값은 적지 않았습니다. 레시피는 모두 macOS 에서 별도 소켓(tmux -L)으로 띄운 tmux 3.8 에서 돌렸습니다. SSH 끊김은 실제 원격 서버가 아니라 가짜 터미널로 붙인 클라이언트를 강제로 죽여 흉내 낸 것이고, 에이전트와 개발 서버는 메시지를 출력하거나 잠만 자는 대체 명령으로 돌렸습니다. Warp 에 관한 내용은 Warp 문서로 확인했고 Warp 안에서 tmux 를 직접 돌려 보지는 않았습니다. 마우스 설정, 클립보드, floating pane 의 동작은 터미널과 tmux 버전에 따라 다를 수 있습니다.
References#
최신 자료 (2026)
- tmux, CHANGES (3.6 2025-11-26, 3.7 2026-06-26, 3.8 2026-09-09) · Getting Started, tmux 위키 (조회 2026-10-24) [문서]
- tmux 3.8 man 페이지
tmux(1)(Homebrew 설치본, 조회 2026-10-24) [문서] - Warp, 「Split panes」 · 「Session Restoration」 · 「Full-screen apps」 · 「SSH」, Warp 문서 (조회 2026-10-24) [문서]
- 직접 실행: tmux 3.8 에서 레시피 1~4, 설정 파일, vi 복사 모드, floating pane 확인 (2026-10-24)
비교·배경 자료
- Robert C. Martin, unclebob/swarm-forge (tmux 세션과
send-keys로 에이전트를 운영) [저장소]