본문으로 건너뛰기

"터미널" 태그로 연결된 8개 게시물개의 게시물이 있습니다.

모든 태그 보기

AI 코딩 에이전트 도구 지도

· 약 7분

요즘 이런 도구가 쏟아진다

최근 몇 달 사이 herdr, Orca, cmux, Claude Squad 같은 이름을 부쩍 자주 봐요. 전부 "AI 코딩 에이전트 여러 개를 한 번에 굴리는 도구"라는 소개를 달고 나오는데, Claude Code나 Codex를 하나만 돌려도 벅찬 터라 여러 개를 동시에 관리한다니 눈길이 갈 만해요.

그런데 목록을 훑다 보면 이상한 질문이 머리에 떠오릅니다. "저는 Ghostty를 쓰는데, herdr로 갈아타야 하나?" "tmux를 버리고 cmux를 깔아야 하나?" 저도 처음엔 그렇게 물었습니다. 결론부터 말하면 이건 잘못 세운 질문입니다. Ghostty와 herdr는 애초에 경쟁 관계가 아니며, 서로 다른 층에서 다른 일을 합니다.

이 글은 그 착각을 푸는 지도입니다. 도구를 나열하기보다, 이 도구들이 각각 어느 층에 사는지를 먼저 나눕니다. 층을 나누고 나면 "뭘 써야 하나"라는 질문이 "지금 제 환경에서 어느 층이 비어 있나"로 바뀝니다. 그게 훨씬 답하기 쉬운 질문입니다.

왜 다들 같은 칸에 있는 것처럼 보이나

착각의 원인은 단순합니다. 이 도구들이 대부분 터미널에서 도는 CLI 형태라서, 겉보기에 다 비슷해 보입니다. 검은 화면에 글자가 흐르고, 키보드로 조작하고, 이름도 -mux로 끝나는 게 많습니다. 그래서 한 바구니에 담아 놓고 "이 중에 뭐가 제일 좋냐"를 따지게 됩니다.

하지만 실제로는 역할이 완전히 다릅니다. 어떤 건 화면을 그리는 일을 하고, 어떤 건 그 화면을 여러 칸으로 쪼개는 일을 하고, 어떤 건 그 칸 안에서 도는 에이전트들을 관리하는 일을 합니다. 모니터와 화면 분할기와 작업 반장을 놓고 "셋 중 뭐가 제일 좋냐"를 묻는 셈이라, 질문 자체가 성립하지 않습니다.

3개 층으로 나눈다

정리하면 층은 세 개입니다. 위에서 아래로 갈수록 더 안쪽에서 돕니다.

1층은 터미널 에뮬레이터입니다. 화면에 글자를 그리는 앱이고, 폰트와 색과 렌더링 속도가 승부처입니다. Ghostty, iTerm2, Alacritty가 여기 있습니다. 이 층은 에이전트를 "관리"하지 않습니다. 그냥 잘 보여줄 뿐입니다.

한 칸 아래가 멀티플렉서입니다. 터미널 하나 안을 여러 세션으로 쪼개고, 터미널을 닫아도 세션을 살려 둡니다. SSH가 끊겨도 작업이 죽지 않게 하는 게 이 층의 존재 이유입니다. tmux가 사실상 표준이고, Zellij가 Rust로 다시 쓴 현대판입니다. 다만 창을 나눠 줄 뿐, 그 창 속 에이전트가 일하는 중인지 끝났는지는 알지 못합니다.

가장 안쪽 3층이 이번 글의 주인공입니다. 에이전트마다 별도의 작업 공간을 만들어 서로 부딪치지 않게 격리하고, 각 에이전트의 상태를 추적하고, 결과 diff를 보여줍니다. herdr, cmux, Orca, Claude Squad가 여기 있습니다.

3층이 왜 필요한지는 한 문장으로 설명됩니다. 코딩 에이전트는 작업 디렉토리를 통째로 자기 것으로 쓸 때 가장 잘 동작합니다. 그런데 에이전트 둘이 같은 디렉토리를 동시에 만지면 서로의 편집을 뭉개고, 빌드가 깨지고, git 상태가 엉킵니다. 이런 충돌을 피하려고 3층 도구들은 하나같이 git worktree로 각 에이전트에게 독립된 체크아웃을 줍니다.

1층과 2층: 바탕이 되는 도구

3층 이야기로 넘어가기 전에, 바탕 두 층을 짧게 정리합니다. 이 층은 3층 도구와 경쟁하지 않고 함께 씁니다. 제가 즐겨 쓰는 Ghostty도 여기 있습니다.

도구플랫폼
Ghostty터미널 에뮬레이터macOS, Linux
iTerm2터미널 에뮬레이터macOS
Alacritty터미널 에뮬레이터전 플랫폼
tmux멀티플렉서전 플랫폼
Zellij멀티플렉서전 플랫폼

Ghostty는 GPU로 화면을 그려서 빠르고, 설정이 간결합니다. 요즘 새로 나오는 에이전트 도구 중 일부는 아예 이 Ghostty의 렌더링 엔진을 자기 기반으로 삼으며, 뒤에 나올 cmux가 그렇습니다. 이 사실 하나만 알아도 "Ghostty와 cmux 중 뭘 쓰지"라는 질문이 왜 이상한지 감이 옵니다. cmux가 Ghostty 위에 지어졌으니, 둘 중 하나를 고르는 문제가 애초에 성립하지 않습니다.

3층: 에이전트 오케스트레이터

이제 본론입니다. 3층 도구들을 순수 사양만 표로 정리했습니다. 어느 게 더 좋은지는 표 아래 산문으로 따로 풀었습니다. 도구마다 성격이 달라서 한 줄로 우열을 매기는 게 오히려 오해를 부릅니다.

도구유형플랫폼worktree 격리상태 인지라이선스
Claude Code Agent Teams빌트인Claude Code 환경지원지원무료
cmux (manaflow-ai)터미널 앱macOS지원지원OSS
cmux (craigsc)셸 스크립트macOS, Linux지원제한OSS
herdr멀티플렉서Linux, macOS, Win(beta)지원지원OSS
Claude SquadTUImacOS, Linux지원지원OSS
dmuxCLImacOS, Linux지원제한OSS
Orca데스크톱 GUImac, Win, Linux지원지원OSS(MIT)
Parallel Code데스크톱 GUImac, Win, Linux지원지원OSS
Emdash데스크톱 GUI전 플랫폼지원지원OSS

표의 "상태 인지"는 tmux처럼 창만 나누는 데서 그치지 않고, 각 에이전트가 지금 일하는 중인지 끝났는지 입력을 기다리는지까지 도구가 안다는 뜻입니다. 이게 3층을 2층과 갈라 놓는 결정적 차입니다. herdr가 멀티플렉서라고 소개되면 tmux 대체품처럼 들리지만, 실제로는 에이전트 상태를 아는 멀티플렉서라 2층과 3층에 걸쳐 있습니다.

크게 두 갈래로 나뉩니다. 터미널 안에서 도는 가벼운 쪽(herdr, Claude Squad, dmux, cmux)과, 자체 창을 띄우는 무거운 데스크톱 쪽(Orca, Parallel Code, Emdash)입니다. 데스크톱 쪽은 내장 브라우저로 에이전트가 만든 화면을 바로 확인하거나, diff에 코멘트를 달아 에이전트에게 되돌려 주는 기능을 얹습니다. 대신 앱이 무겁고, 원격 리눅스 서버에서는 쓰기 어렵습니다. 표에 다 넣지는 않았지만 wmux(cmux의 Windows 포팅), Termdock(세션별 CPU/메모리 모니터), amux 같은 것도 같은 계보에 있습니다.

착각하기 쉬운 세 지점

층을 나누고 나서도 개별 도구에서 헷갈리는 대목이 몇 개 남습니다.

첫째, cmux는 이름이 같은 도구가 둘입니다. 하나는 manaflow-ai가 만든 Ghostty 기반 macOS 앱이고, 다른 하나는 craigsc의 "tmux for Claude Code"라는 셸 스크립트입니다. 검색하면 둘이 섞여 나옵니다. 성격이 꽤 다르니 저장소 주소를 보고 구분하는 게 안전합니다.

둘째, Orca 같은 데스크톱 앱은 자체 터미널 렌더링을 내장합니다. 그래서 Orca를 쓰면 Ghostty를 거치지 않습니다. "Ghostty에서 Orca를 띄운다"기보다 "Orca가 Ghostty 자리를 대신한다"에 가깝습니다. 앞의 3층 도구들이 대부분 기존 터미널 위에 얹히는 것과 다른 지점입니다.

셋째, 가장 흔한 오해인데, 3층 도구가 없어도 병렬 작업은 이미 가능합니다. Claude Code에는 Agent Teams라는 기능이 내장되어 있어서, 서브에이전트를 병렬로 띄우고 각자 worktree에 격리합니다. 새 도구를 깔기 전에 이미 손에 있는 걸 먼저 써 보는 게 순서입니다.

제 환경이라면 이렇게 고릅니다

여기부터는 사양 비교를 넘어 선택의 문제로 들어갑니다. 제 작업 환경은 두 갈래입니다. 로컬은 macOS에 Ghostty, 원격은 리눅스 서버에 SSH로 붙습니다. 층으로 나눠 놓으니 각 환경에서 뭘 얹을지가 명확해집니다.

로컬 macOS에서는 cmux(manaflow-ai)가 가장 자연스러운 후보입니다. 이미 쓰는 Ghostty의 렌더링을 그대로 두고 그 위에 사이드바와 알림만 얹는 구조라, 기존 환경을 버릴 필요가 없습니다. 오케스트레이터라기보다 여러 에이전트를 나란히 두는 최소한의 장치라서, Claude Code를 쓰던 방식을 강제로 바꾸지 않는 점도 저는 마음에 들어요.

원격 서버에서는 사정이 다릅니다. macOS 앱은 당연히 못 씁니다. 여기서는 herdr나, 이미 쓰고 있는 tmux 위에 Claude Squad를 얹는 쪽이 맞습니다. herdr는 SSH로 붙어서 세션을 유지하고 휴대폰에서 재접속하는 시나리오에 강합니다. 다만 tmux를 이미 손에 익혔다면 Claude Squad로 넘어가는 이행 비용이 더 낮습니다. 익숙한 2층 위에 3층만 얹는 그림이기 때문입니다.

솔직히 덧붙이면, 저는 지금 당장 급하지는 않다고 봅니다. 제 작업은 대부분 글을 쓰거나 문서를 다듬는 일이라, 에이전트를 다섯 개씩 병렬로 굴려야 하는 순간이 매일 오지는 않습니다. worktree 격리가 절실해지는 건 서로 독립적인 작업을 진짜로 동시에 여러 개 돌릴 때입니다. 그 순간이 오기 전까지는 Claude Code의 Agent Teams로 충분하고, 필요가 분명해지면 그때 로컬은 cmux, 원격은 herdr로 넘어가면 됩니다.

도구를 고르기 전에 층을 묻는다

이 바닥은 변화가 빠릅니다. 이 글을 쓰는 지금(2026년 7월)에도 새 도구가 계속 나오고, 이름과 기능이 겹치고, 어제의 추천이 오늘 바뀝니다. 그러니 개별 도구 이름을 외우는 것보다, 새 도구를 만났을 때 "이건 몇 층 도구지"를 먼저 묻는 습관이 오래갑니다.

터미널을 바꾸고 싶은 건지, 세션 관리를 원하는 건지, 에이전트를 여러 개 굴리고 싶은 건지 생각해 봐야 해요. 이 세 가지는 서로 다른 문제이고 답도 다른 층에 있지만, 지도를 손에 쥐고 나면 쏟아지는 도구 목록이 위협이 아니라 그저 선택지로 보여요.

Claude Code Fullscreen

· 약 7분

입력창이 더는 안 흔들린다

Claude가 작업하는 동안 화면이 번쩍이고, 출력이 쏟아질 때 스크롤이 맨 위로 튀어 오르고, 긴 세션에서 메모리가 슬금슬금 차오르던 경험은 Claude Code를 오래 쓴 사람이면 익숙해요. Fullscreen 렌더링은 그 세 가지를 한 번에 잡으려고 나온 새 렌더링 경로로, 대화를 vim이나 htop처럼 터미널의 alternate screen buffer에 그려요.

/tui fullscreen 한 줄이면 켜집니다. 대화는 그대로 유지된 채 fullscreen으로 다시 뜹니다. 세션 중간에 켜도 맥락을 잃지 않습니다. Claude Code v2.1.89 이상에서 동작하는 리서치 프리뷰 기능입니다. (Fullscreen 렌더링 공식 문서)

주의: 이 글은 전부 리서치 프리뷰 기준입니다. 동작 방식, 키 바인딩, 설정 키 이름 모두 정식 출시 전에 바뀔 수 있습니다.

fullscreen은 창 최대화가 아닙니다

먼저 오해부터 풀고 갑니다. 여기서 fullscreen은 터미널 창을 최대화한다는 뜻이 아닙니다. Claude Code가 터미널의 그리는 표면(drawing surface)을 vim처럼 통째로 가져간다는 뜻입니다. 창 크기와 무관하게, 작은 창에서도 똑같이 동작합니다.

기존 렌더러(classic)는 대화를 터미널의 native scrollback에 차곡차곡 쌓습니다. 매 업데이트마다 화면을 다시 그리면서 터미널로 많은 데이터를 흘려보냅니다. Fullscreen은 다릅니다. 지금 화면에 보이는 메시지만 렌더 트리에 둡니다. 터미널로 보내는 데이터량이 확 줄어듭니다.

깜빡임, 메모리, 스크롤 점프를 줄입니다

세 가지 문제를 노립니다.

문제classic 렌더러fullscreen 렌더링
화면 깜빡임출력 스트리밍 중 번쩍임 발생alternate screen buffer로 제거
메모리대화가 길어질수록 증가보이는 메시지만 유지, 일정하게
스크롤 점프작업 중 맨 위로 튀어 오름입력창 하단 고정, 점프 없음

차이가 가장 크게 느껴지는 곳은 렌더링 처리량(throughput)이 병목인 터미널입니다. 공식 문서는 VS Code 통합 터미널, tmux, iTerm2를 콕 집습니다. 이런 환경에서 화면이 번쩍이거나 스크롤이 튀었다면 fullscreen이 정확히 그 증상을 겨냥합니다.

켜고 끄는 법

가장 쉬운 방법은 대화 안에서 슬래시 명령을 실행하는 것입니다.

/tui fullscreen # fullscreen 렌더링으로 전환 (대화 유지된 채 재시작)
/tui default # classic 렌더러로 복귀
/tui # 인자 없이 실행하면 현재 어떤 렌더러인지 출력

/tui 명령은 tui 설정을 ~/.claude/settings.json에 저장하고 그 값으로 다시 띄웁니다. 그래서 다음 세션에도 선택이 유지됩니다.

환경 변수로 켤 수도 있습니다. /tui 명령이 생긴 v2.1.110 이전 버전에서는 이쪽이 유일한 방법이었습니다.

CLAUDE_CODE_NO_FLICKER=1 claude

tui 설정과 CLAUDE_CODE_NO_FLICKER 환경 변수는 같은 의미입니다. /tui 명령은 재시작하는 프로세스에서 CLAUDE_CODE_NO_FLICKER를 지워, 새로 쓴 설정 값이 우선 적용되게 합니다.

fullscreen이 켜졌는지 확인하는 가장 직관적인 신호는 입력창입니다. 출력이 쏟아져도 입력창이 화면 하단에 고정돼 움직이지 않으면 fullscreen이 동작 중입니다. classic 렌더러에서는 입력창이 출력을 따라 위로 밀려 올라갑니다.

두 렌더러는 어디서 갈리나

대화가 어디에 저장되느냐가 갈림길입니다. 그 한 가지 차이에서 검색/복사 동작이 전부 달라집니다.

대화가 alternate screen buffer에 살기 때문에, 터미널의 native scrollback에 의존하던 동작이 달라집니다.

기존 (classic)fullscreen비고
Cmd+f/tmux 검색으로 텍스트 찾기Ctrl+o로 transcript 모드 진입 후 /로 검색검색 경로가 앱 안으로
터미널 native 드래그로 선택/복사앱 안에서 선택, 마우스 떼면 자동 복사클립보드는 앱이 채움
Cmd-클릭으로 URL 열기macOS는 Cmd-클릭, 그 외는 Ctrl-클릭OS별 키 차이

마우스가 붙는다

Fullscreen은 마우스 이벤트를 캡처해 Claude Code 안에서 처리합니다. classic 렌더러에는 없던 기능입니다.

입력창을 클릭하면 입력 중인 텍스트의 원하는 위치로 커서가 옮겨집니다. / 명령이나 @ 파일 목록에서는 제안 항목을 클릭으로 바로 고르고, 호버하면 해당 행이 강조됩니다. 권한 프롬프트나 /model//config 같은 select 메뉴도 클릭으로 선택할 수 있습니다(v2.1.187 이상). 접힌 tool 결과를 클릭하면 펼쳐서 전체 출력을 보고, 다시 클릭하면 접힙니다. URL이나 파일 경로는 Cmd(macOS)/Ctrl(Linux/Windows)를 누른 채 클릭하면 링크는 브라우저로, 파일 경로는 기본 앱으로 열립니다. v2.1.181부터는 키 없이 그냥 클릭해도 링크가 열리지 않는데, native 터미널 동작에 맞춘 변경입니다. 이 밖에 드래그로 선택하고 휠로 스크롤하며, 더블클릭은 단어, 트리플클릭은 줄 단위로 선택합니다.

선택한 텍스트는 마우스를 떼는 순간 클립보드에 자동 복사됩니다. 이 동작이 거슬리면 /config에서 Copy on select를 끕니다.

스크롤과 검색

스크롤도 앱 안에서 처리합니다. 주요 단축키는 다음과 같습니다.

단축키동작
PgUp / PgDn반 화면씩 위/아래
Ctrl+Home대화 맨 처음으로
Ctrl+End최신 메시지로 + auto-follow 재개
마우스 휠몇 줄씩 스크롤

MacBook처럼 PgUp/PgDn 전용 키가 없는 키보드는 Fn과 방향키를 조합합니다. Fn+↑PgUp, Fn+↓PgDn입니다.

위로 스크롤하면 auto-follow가 멈춰, 새 출력이 다시 맨 아래로 끌어내리지 않습니다. Ctrl+End를 누르거나 맨 아래로 내리면 다시 따라가기 시작합니다.

검색은 transcript 모드에서 합니다. Ctrl+o로 일반 프롬프트와 transcript 모드를 오갑니다. transcript 모드는 less 스타일 탐색을 지원합니다.

동작
/검색 시작
n / N다음/이전 매치로 이동
g / G맨 위/맨 아래로
Ctrl+o, Esc, qtranscript 모드 종료

터미널의 Cmd+f나 tmux 검색은 대화를 보지 못합니다. 대화가 native scrollback이 아니라 alternate screen buffer에 있기 때문입니다. 내용을 터미널로 다시 넘기려면 Ctrl+o로 transcript 모드에 들어간 뒤 [를 누릅니다. 전체 대화가 native scrollback에 평범한 텍스트로 다시 쓰이고, 그때부터 Cmd+f/tmux copy mode가 다시 통합니다.

tmux와 함께 쓸 때

Fullscreen은 tmux 안에서도 동작합니다. 세 가지만 주의합니다.

첫째, 마우스 휠 스크롤은 tmux의 mouse mode가 필요합니다. ~/.tmux.conf에 아래 한 줄을 넣고 설정을 다시 읽습니다. 없으면 휠 이벤트가 Claude Code 대신 tmux로 갑니다.

set -g mouse on

둘째, iTerm2의 tmux 통합 모드(tmux -CC)와는 호환되지 않습니다. 이 모드에서는 alternate screen buffer와 마우스 추적이 제대로 동작하지 않고, 더블클릭이 터미널 상태를 깨뜨릴 수 있습니다. tmux -CC 세션에서는 fullscreen을 켜지 않는 편이 좋습니다. -CC 없는 일반 tmux는 문제없습니다.

셋째, tmux는 synchronized output을 지원하지 않아, Claude Code를 터미널에서 바로 실행할 때보다 redraw 중 깜빡임이 더 보일 수 있습니다. SSH 환경에서 특히 거슬리면 tmux 밖 별도 탭에서 실행하는 편이 낫습니다.

native 선택을 그대로 두고 싶다면

마우스 캡처는 가장 흔한 마찰 지점입니다. SSH나 tmux 안에서 특히 그렇습니다. Claude Code가 마우스 이벤트를 가져가면 터미널의 native copy-on-select가 멈춥니다. 드래그로 만든 선택은 Claude Code 안에만 있고, 터미널의 선택 버퍼에는 없습니다.

한 번만 native 선택을 쓰고 싶으면 터미널별 지정 키를 누른 채 드래그합니다. Terminal.app은 Fn, iTerm2는 Option, VS Code/Cursor는 Shift입니다.

마우스 캡처 자체가 늘 거슬린다면, 깜빡임 제거와 일정한 메모리는 유지하면서 마우스 캡처만 끌 수 있습니다.

CLAUDE_CODE_NO_FLICKER=1 CLAUDE_CODE_DISABLE_MOUSE=1 claude

이렇게 하면 PgUp, PgDn, Ctrl+Home, Ctrl+End 키보드 스크롤은 그대로 살고, 선택은 터미널이 native로 처리합니다. 대신 클릭으로 커서 옮기기, tool 결과 펼치기, URL 클릭, 앱 안 휠 스크롤은 포기해야 합니다.

DBA/개발자가 지금 해 볼 것

긴 작업을 자주 돌리는 사람일수록 효과가 큽니다. 대형 리팩터링이나 수십 개 파일을 훑는 세션에서 classic 렌더러는 출력이 쌓이며 메모리가 늘고 스크롤이 튀지만, fullscreen은 일정하게 버팁니다.

일단 /tui fullscreen을 실행하고, 출력이 쏟아질 때 입력창이 고정되는지 봅니다. 안 맞으면 /tui default로 즉시 돌아오면 됩니다. VS Code, tmux, iTerm2 사용자라면 우선순위를 높게 둘 만한데, 깜빡임/스크롤 점프가 가장 심하던 환경이라 체감 차이가 큽니다. tmux를 쓴다면 set -g mouse on을 먼저 넣어야 휠 스크롤이 tmux로 새어 나가지 않습니다. 마지막으로 검색 습관을 바꿔야 합니다. Cmd+f 대신 Ctrl+o로 transcript 모드에 들어가 /로 찾고, 내용을 터미널로 넘기려면 그 안에서 [를 누릅니다.

복귀 경로가 명확한 것도 저는 안심돼요. /tui default로 돌아가거나, 저장된 설정과 무관하게 classic 렌더러를 강제하려면 CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1을 둡니다. agent view나 claude attach로 여는 백그라운드 세션은 항상 fullscreen으로 뜬다는 점만 기억하면 됩니다.

정리

Fullscreen 렌더링은 Claude Code의 TUI를 vim/htop 계열로 한 단계 올립니다. alternate screen buffer를 써서 깜빡임이 사라지고 메모리가 일정해지며 마우스가 붙는 대신, 검색/복사는 앱 안 동작으로 바뀝니다. 손에 익히는 데 며칠 걸리지만, 긴 세션을 자주 돌리는 사람에게는 그만한 값을 합니다.

아직 리서치 프리뷰라서 흔치 않은 터미널이나 특이한 설정에서는 렌더링 문제가 생길 수 있고, 그럴 땐 /feedback이나 claude-code GitHub 저장소로 터미널 이름/버전과 함께 알리면 돼요. 동작이 바뀔 여지도 남아 있지만, 한 줄(/tui fullscreen)로 켜고 한 줄(/tui default)로 끄는 비용이면 한 번 켜 보고 판단하기에 충분히 싸요.

agnoster와 Starship

· 약 7분

어느 날 Enter가 느려졌다

터미널에서 Enter를 눌렀는데 다음 프롬프트가 뜰 때까지 300ms 넘게 비는 느낌이 왔어요. 큰 레포일 때는 그러려니 했지만 작은 디렉토리에서도 똑같이 굼떴고, "디렉토리 크기와 무관하게 느리다" — 이 사실이 첫 번째 단서였어요.

이 글은 그 지연의 정체를 찾아가서, 얕은 수정으로 안 됐고, 결국 프롬프트 테마를 갈아엎고 Starship으로 넘어온 여정의 기록입니다.

첫 시도: status를 빠르게 한다

처음에는 단순하게 접근했습니다. "Enter 뒤 지연 = git status가 느림"이라고 가정하고, 속도를 높이는 옵션부터 모두 켰습니다.

# ~/.zshrc
DISABLE_UNTRACKED_FILES_DIRTY="true"
# git 전역
git config --global core.fsmonitor true
git config --global core.untrackedCache true
git config --global feature.manyFiles true

fsmonitor는 파일 시스템 이벤트를 상주 데몬이 추적해 git status의 내부 스캔 비용을 사실상 0에 가깝게 만듭니다. 실제로 git status --porcelain 자체의 시간은 크게 짧아졌습니다.

레포.git 크기fsmonitor 적용 후 status
small-repo작음즉시
mid-repo-A30 MB0.025 s
mid-repo-B51 MB0.041 s
big-repo246 MB0.042 s

그런데 Enter 지연은 거의 그대로였습니다. git status가 10배 빨라졌는데도 체감이 달라지지 않았으니, 제가 엉뚱한 부분을 최적화했다는 뜻이었습니다.

측정을 다시 할 때 만난 세 가지 함정

문제를 다시 풀어헤치려면 먼저 제대로 측정해야 했습니다. 여기서 쉽게 빠지는 함정이 세 개 있었습니다.

함정 1. zsh -i -c exit는 per-Enter 지연이 아니다

흔히 쓰는 "쉘 벤치마크"인 time zsh -i -c exit는 전혀 다른 대상을 측정합니다. 쉘이 시작할 때 한 번만 드는 비용입니다. compinit, plugin 로딩 같은 일회성 작업을 포함합니다. 매번 Enter를 칠 때 드는 비용과는 다른 층이라, 이 값을 아무리 줄여도 프롬프트 재평가 비용은 그대로입니다.

함정 2. precmd를 직접 호출해도 안 된다

일반적인 zsh 테마는 precmd_functions에 훅을 걸어 매 프롬프트 직전에 준비 작업을 합니다. 그러나 agnoster는 다릅니다.

PROMPT='%{%f%b%k%}$(build_prompt) '

PROMPT 변수 안에 명령 치환 $(build_prompt)를 끼워 둔 구조라, 프롬프트 문자열이 expansion될 때 비로소 git 호출이 일어납니다. 그래서 precmd를 수동으로 실행해 재면 거의 0ms가 찍힙니다. 실제 Enter 경로와 다른 곳에서 측정하는 셈입니다.

함정 3. 반복마다 새 zsh를 띄우면 측정이 오염된다

# 나쁜 예
for i in {1..10}; do
time zsh -ic 'print -P "$PROMPT" >/dev/null'
done

이렇게 측정하면 매 반복이 zsh 시작 비용(~200ms)에 묻힙니다. 같은 zsh 프로세스 안에서 루프를 돌려야 순수 프롬프트 렌더 비용만 남습니다.

올바른 one-liner

결국 큰 레포로 cd 한 상태에서 다음과 같이 측정해야 했습니다.

zsh -ic '
print -P "$PROMPT" >/dev/null # 웜업
{ time (for i in {1..10}; do print -P "$PROMPT" >/dev/null; done) } 2>&1
'

print -P "$PROMPT"는 PROMPT 문자열을 강제로 expand시키기 때문에 내부의 $(build_prompt)가 실제로 실행되고, 진짜 비용이 드러납니다.

진짜 범인: agnoster의 7× git spawn

측정을 제대로 돌리자 범인이 또렷이 보였습니다. ~/.oh-my-zsh/themes/agnoster.zsh-themeprompt_git()은 매 프롬프트 렌더마다 git 서브프로세스를 일곱 번 띄웁니다.

1. git config --get oh-my-zsh.hide-status
2. git rev-parse --is-inside-work-tree
3. git rev-parse --git-dir
4. git status --porcelain (parse_git_dirty)
5. git symbolic-ref HEAD
6. git log --oneline @{upstream}.. (ahead)
7. git log --oneline ..@{upstream} (behind)

그리고 macOS의 기본 git 바이너리는 Apple wrapper입니다.

/Library/Developer/CommandLineTools/usr/libexec/git-core/git

호출 한 번당 fork → exec → wrapper → core 체인에 고정적으로 40~50ms가 듭니다. 이 오버헤드는 git이 아무리 빨라도 줄어들지 않습니다.

산수가 맞아떨어집니다.

7 × 50ms ≈ 350ms

그래서 .git이 수십 MB든 수백 MB든 바닥값은 비슷하게 나옵니다. 이게 Enter 지연의 정체였습니다.

측정 결과 (10회 평균)

상태big-repo (246MB .git)small-repo
agnoster 원본 (prompt_git 포함)~427 ms~335 ms
prompt_git를 빈 함수로 대체~14.7 ms~13.6 ms

프롬프트 지연의 95% 이상이 prompt_git의 spawn 오버헤드였습니다. git status 자체는 fsmonitor 덕분에 이미 충분히 빨랐습니다. 제가 status 내부를 최적화하느라 헛돈 까닭은 줄일 수 있는 구간만 보고 줄이려 했기 때문입니다. spawn 횟수는 그대로 7이었으니 체감이 달라지지 않은 게 당연했습니다.

세 가지 선택지

구조적 한계가 확인되자 길이 명확해졌습니다.

A. agnoster의 git 세그먼트를 끈다

git config --global oh-my-zsh.hide-status 1

혹은 zshrc 마지막에:

prompt_git() { : }

프롬프트 렌더 비용이 15ms로 떨어집니다. 대신 브랜치/dirty 표시가 사라집니다. 저는 브랜치를 프롬프트에서 보는 편이 좋아서 이 선택지는 제외했습니다.

B. powerlevel10k로 간다

gitstatusd라는 상주 데몬이 변경을 감시하며 결과를 파이프로 돌려줍니다. git 바이너리를 띄우지 않으므로 spawn은 0회입니다. instant prompt를 사용해 초기 표시도 빠릅니다.

괜찮은 옵션이지만, 설정을 직접 다듬기엔 .p10k.zsh 포맷이 다소 난잡해 보였습니다.

C. Starship으로 간다

Rust로 작성한 단일 바이너리입니다. zsh 프롬프트 훅에서 starship 바이너리를 한 번만 fork하고, 그 안에서 libgit2를 라이브러리로 링크해 호출합니다. 외부 git 프로세스는 띄우지 않습니다. 즉 spawn 1회로 끝납니다.

  • 설정은 ~/.config/starship.toml 한 파일 (TOML)
  • git diff로 리뷰/롤백이 쉬움
  • 프리셋 갤러리가 존재해 시작점 제공

풍부한 정보와 속도, 설정 가독성을 모두 고려해 Starship으로 결정했습니다.

Starship 전환 작업

설치

brew install starship
# 1.25.0

~/.zshrc 두 군데 수정

agnoster를 끄고:

- ZSH_THEME="agnoster"
+ # ZSH_THEME="agnoster" # 비활성, Starship 사용
+ ZSH_THEME=""

파일 끝에 초기화 추가:

# Starship prompt. agnoster 대신. 없으면 graceful skip.
if command -v starship >/dev/null 2>&1; then
eval "$(starship init zsh)"
fi

바이너리가 없으면 조용히 건너뛰도록 command -v 체크를 넣었습니다. 새 머신 셋업할 때 zshrc를 그대로 복사해도 안전합니다.

프리셋 적용

starship preset pastel-powerline -o ~/.config/starship.toml

pastel-powerline의 정보 밀도가 가장 괜찮아 선택했습니다. 이대로 써도 되지만 두 가지가 걸렸습니다.

  1. 한 줄 프롬프트라 긴 디렉토리/브랜치명이 나오면 명령 입력 공간이 좁아집니다.
  2. 다크 터미널에서 일부 세그먼트의 글자가 묻힙니다.

튜닝 1: 두 줄 프롬프트

format 문자열 끝(마지막 """ 직전)에 줄바꿈과 character 모듈을 추가합니다.

$line_break\
$character

파일 끝에는 [character] 섹션을 추가합니다.

[character]
success_symbol = "[❯](bold #FCA17D)"
error_symbol = "[❯](bold red)"
vimcmd_symbol = "[❮](bold green)"

이제 첫 줄에는 정보(유저/경로/git/언어/시간)를 표시하고, 두 번째 줄에는 하나만 둡니다. 명령 입력이 세그먼트에 영향받지 않습니다.

튜닝 2: 다크 터미널 가독성

기본 pastel-powerline은 각 세그먼트 배경색만 지정하고 글자색은 터미널 기본을 씁니다. 어두운 터미널(제 환경은 거의 검정 배경)에서는 짙은 배경 세그먼트 안의 글자가 잘 보이지 않았습니다.

각 세그먼트에 명시적 글자색과 bold를 지정했습니다.

세그먼트배경글자색
username#9A348E (보라)#ffffff bold
directory#DA627D (분홍)#1a1a2e bold
git_branch / git_status#FCA17D (피치)#1a1a2e bold
언어 버전 (golang 등)#86BBD8 (연파랑)#1a1a2e bold
docker_context#06969A (청록)#ffffff bold
time#33658A#4A86C5#ffffff bold

time 세그먼트의 원래 배경 #33658A는 너무 어두워서 거의 터미널 배경과 합쳐져 보였습니다. 더 밝은 파랑 #4A86C5로 바꾸고, format 문자열 안의 배경/전경 치환자 두 군데도 같이 교체했습니다.

bg:#33658A) → bg:#4A86C5)
fg:#33658A) → fg:#4A86C5)

Nerd Font 글리프가 많은 파일이라 직접 편집하면 글자가 깨지기 쉽습니다. 수정은 Python 스크립트로 바이트 안전하게 적용했습니다.

결과

속도 (20회 평균, 같은 zsh 내 print -P "$PROMPT")

상태big-repo (246MB .git)small-repo
agnoster 원본427 ms335 ms
Starship (pastel-powerline)~70 ms~60 ms

약 6배입니다. 인간 지각 한계(~100ms) 안쪽이라 체감상 즉시 반응합니다. Enter가 걸리던 감각이 완전히 사라졌습니다.

시각

실제 화면입니다(일부 모자이크).

Starship 프롬프트 실제 렌더링

표시 요소:

  • 사용자명 (흰 bold, 보라 배경)
  • 디렉토리 (3계층 축약)
  • git 브랜치 + 상태 (stashed $ / untracked ? / modified ! / renamed / ahead/behind 등)
  • 감지된 언어 버전 (위 예시엔 Go v7.3.2, Java v25.0.1)
  • 시간 (♥ HH:MM)
  • 두 번째 줄: 입력 커서

이 과정에서 배운 것

  1. 느린 걸 고치려면 먼저 제대로 재야 합니다. 제가 잰 zsh -i -c exit는 Enter 지연이 아니라 쉘 시작 시간이었습니다. 엉뚱한 걸 최적화하느라 며칠 돌아갔습니다.

  2. spawn 횟수는 내부 로직 속도와 독립입니다. git이 1ms에 끝나도 7번 띄우면 350ms가 듭니다. 개선 가능한 구간이 보여도, 그 부분이 병목인지부터 확인해야 합니다.

  3. 도구의 구조를 모르면 설정도 고치기 어렵습니다. agnoster가 PROMPT 변수 안에 명령 치환을 넣는 구조라는 걸 몰랐다면 precmd 벤치마크만 반복하며 "왜 안 느리지?"라고 했을 겁니다.

  4. 근본 전환이 결국 싸게 먹힐 때가 있어요. 보조 옵션을 쌓아도 못 넘는 한계가 있을 때는 테마 자체를 갈아치우는 편이 빨라요. agnoster → Starship은 설정 파일 두 개 수정 + brew install 한 번이었어요.

참고 자료

Vi/Vim 단축키 가이드

· 약 15분

이 글은 Vim 단축키 시리즈의 첫 번째 글이에요.

  1. Vi/Vim 단축키 종합 가이드: 기본부터 실전까지 ← 현재 글
  2. Neovim 단축키 가이드: Vim을 넘어서는 기능들

Vim의 언어: 동사 + 명사

Vim 단축키는 외워야 하는 목록보다 문법에 가깝습니다.

동사(operator)는 "무엇을 할 것인가":

동사의미
d삭제 (delete)
c변경 (change) — 삭제 후 Insert
y복사 (yank)
>들여쓰기
<내어쓰기
gU대문자로
gu소문자로
=자동 정렬

명사(motion/text object)는 "어디까지":

명사의미
w다음 단어까지
$줄 끝까지
gg파일 처음까지
%매칭 괄호까지
iw단어 안쪽 (inner word)
i"따옴표 안쪽
a(괄호 포함 전체

동사와 명사는 다음처럼 조합합니다.

d + iw = diw → 단어 삭제
c + i" = ci" → 따옴표 안 내용 변경
y + $ = y$ → 줄 끝까지 복사
> + ap = >ap → 문단 들여쓰기
gU + iw = gUiw → 단어 대문자로

이 문법을 이해하면 수백 개의 조합을 일일이 외우지 않고 만들어낼 수 있습니다.

모드

Vim은 모드 기반 에디터입니다. 같은 키도 모드에 따라 다르게 동작합니다.

모드진입역할
NormalEsc이동, 편집 명령 실행
Inserti, a, o텍스트 입력
Visualv, V, Ctrl-v영역 선택
Command-line:, /, ?명령 실행, 검색
ReplaceR덮어쓰기 입력

Insert 모드 내 단축키

Insert 모드에서도 몇 가지 유용한 키가 있습니다.

동작
Ctrl-w커서 앞 단어 삭제
Ctrl-u커서 앞 줄 전체 삭제
Ctrl-r "레지스터 내용 붙여넣기
Ctrl-oNormal 모드 명령 1회 실행 후 Insert 복귀
Ctrl-t들여쓰기
Ctrl-d내어쓰기

기본 이동

k

h ← → l

j

숫자를 앞에 붙이면 반복합니다. 5j는 5줄 아래, 10k는 10줄 위로 이동합니다.

단어 단위 이동

동작
w다음 단어 시작
b이전 단어 시작
e현재/다음 단어 끝
ge이전 단어 끝
W/B/EWORD 단위 (공백 기준으로만 구분)

wW의 차이: hello-world에서 w-에서 멈추지만, W는 공백까지 건너뜁니다.

줄 안에서 이동

위치
0줄 맨 처음 (0번째 열)
^줄 첫 번째 글자 (공백 제외)
$줄 끝
g_줄 마지막 글자 (공백 제외)
+다음 줄 첫 글자
-이전 줄 첫 글자

문자 찾기로 이동

줄 안에서 특정 문자로 이동하는 기능입니다. 이동뿐 아니라 동사와 조합하면 강력해집니다.

동작
f{char}오른쪽으로 {char} 위치로 이동
F{char}왼쪽으로 {char} 위치로 이동
t{char}오른쪽으로 {char} 앞까지 이동
T{char}왼쪽으로 {char} 뒤까지 이동
;같은 방향으로 반복
,반대 방향으로 반복

실전에서 자주 쓰는 조합:

dt) → 닫는 괄호 앞까지 삭제
cf, → 쉼표까지 변경 (쉼표 포함)
yt; → 세미콜론 앞까지 복사
vf" → 따옴표까지 선택

괄호와 블록 사이 이동

동작
%매칭 괄호로 점프 — (↔), {↔}, [↔]
[{현재 블록의 여는 {
]}현재 블록의 닫는 }
[(현재 블록의 여는 (
])현재 블록의 닫는 )

%는 코드 읽을 때 특히 유용합니다. 긴 함수의 시작 {에서 %를 누르면 닫는 }로 바로 이동합니다.

화면과 파일 안에서 이동

스크롤

동작
Ctrl-d반 페이지 아래
Ctrl-u반 페이지 위
Ctrl-f한 페이지 아래
Ctrl-b한 페이지 위

화면 내 이동

동작
H화면 상단 (High)
M화면 중단 (Middle)
L화면 하단 (Low)

화면 정렬

동작
zz현재 줄을 화면 가운데로
zt현재 줄을 화면 상단으로
zb현재 줄을 화면 하단으로

파일 내 이동

동작
gg파일 처음
G파일 끝
{n}Gn번째 줄로 (:42와 동일)

검색으로 이동

동작
/pattern아래로 검색
?pattern위로 검색
n다음 결과
N이전 결과
*커서 아래 단어를 아래로 검색
#커서 아래 단어를 위로 검색
gn다음 검색 결과를 Visual 선택
gd현재 파일에서 변수 선언으로

*#은 변수명 위에서 누르면 같은 이름을 바로 찾아줍니다. 검색어를 타이핑할 필요가 없습니다.

텍스트 삽입

위치
i커서 앞
a커서 뒤
I줄 첫 글자 앞
A줄 끝
o아래에 새 줄
O위에 새 줄
gi마지막 Insert 위치로 돌아가서 입력

gi는 편집 중 Normal로 돌아가서 다른 작업을 하다가, 다시 이전 편집 위치로 돌아갈 때 씁니다.

텍스트 삭제

삭제(d)는 동사입니다. 명사와 조합합니다.

동작
x커서 아래 문자
X커서 앞 문자
dw다음 단어까지
de단어 끝까지
db이전 단어까지
dd줄 전체
D = d$줄 끝까지
d0줄 처음까지
d^첫 글자까지
dG파일 끝까지
dgg파일 처음까지
diw단어 (inner)
daw단어 + 주변 공백 (around)
di"따옴표 안
di(괄호 안

텍스트 변경

변경(c)은 삭제 후 Insert 모드로 진입합니다. d와 같은 문법을 따르며 곧바로 입력할 수 있습니다.

동작
cw단어 끝까지 변경
ciw단어 전체 변경
ci"따옴표 안 변경
ci(괄호 안 변경
cc줄 전체 변경
C = c$줄 끝까지 변경
s문자 하나 변경 (= cl)
S줄 전체 변경 (= cc)
r{char}커서 문자를 {char}로 교체 (Normal 유지)
RReplace 모드 진입 (타이핑이 기존 텍스트를 덮어씀)

ci"는 아마 Vim에서 가장 많이 쓰는 조합 중 하나입니다. 따옴표 안에 커서를 놓고 ci"를 누르면 안의 내용이 지워지고 바로 새 내용을 입력하게 됩니다.

복사와 붙여넣기

동작
yy줄 복사
yw단어 복사
y$줄 끝까지 복사
yi"따옴표 안 복사
ya(괄호 포함 전체 복사
p커서 뒤에 붙여넣기
P커서 앞에 붙여넣기
]p들여쓰기 맞춰서 붙여넣기
[p위에 들여쓰기 맞춰서 붙여넣기

자주 쓰는 조합:

조합결과
yyp현재 줄 복제
ddp현재 줄과 아래 줄 교환
xp커서 아래 두 문자 교환

줄 조작

동작
J현재 줄과 아래 줄 합치기 (공백 추가)
gJ줄 합치기 (공백 없이)
>>현재 줄 들여쓰기
<<현재 줄 내어쓰기
5>>5줄 들여쓰기
==현재 줄 자동 정렬
=G현재 줄부터 파일 끝까지 자동 정렬
:m+1현재 줄을 한 줄 아래로 이동
:m-2현재 줄을 한 줄 위로 이동

>> 후에 .을 누르면 한 단계씩 더 들여씁니다. 들여쓰기 레벨을 조절할 때 편리합니다.

대소문자와 숫자 편집

동작
~커서 아래 문자 대소문자 토글
gUiw단어 대문자로
guiw단어 소문자로
gU$줄 끝까지 대문자로
gUU줄 전체 대문자로
guu줄 전체 소문자로
Ctrl-a커서 아래(또는 뒤) 숫자 +1
Ctrl-x커서 아래(또는 뒤) 숫자 -1
5Ctrl-a숫자 +5

Ctrl-a/Ctrl-x는 코드에서 인덱스나 포트 번호를 바꿀 때 유용합니다. 커서가 숫자 위에 없어도, 같은 줄의 다음 숫자를 찾아서 변경합니다.

반복의 힘: . 명령어

.마지막 편집 동작을 반복합니다. Vim에서 가장 강력한 키 중 하나입니다.

패턴 1: 검색 + 반복 치환

1. * → 커서 아래 단어 검색
2. ciw → 단어 변경
3. 새 단어 → 입력
4. Esc → Normal 복귀
5. n → 다음 결과
6. . → 같은 변경 반복

n.n.를 반복하면 원하는 것만 골라서 치환할 수 있습니다. :%s와 달리 하나씩 확인하면서 바꿀 수 있습니다.

패턴 2: 여러 줄에 같은 편집

1. A; → 줄 끝에 세미콜론 추가
2. Esc
3. j → 다음 줄
4. . → 같은 동작 반복

패턴 3: 점진적 들여쓰기

1. >> → 들여쓰기
2. . → 한 레벨 더
3. . → 한 레벨 더

.과 잘 어울리는 명령어

명령어.으로 반복하면
ciw + 입력다른 단어를 같은 내용으로 변경
A;줄 끝에 세미콜론 추가
I// 줄 앞에 주석 추가
dd줄 삭제
>>들여쓰기
r{char}문자 교체

텍스트 오브젝트

i(inner)는 안쪽만, a(around)는 주변 공백이나 구분자를 포함합니다.

오브젝트inner (i)around (a)대상
단어iwawword
WORDiWaWWORD (공백 구분)
문장isassentence
문단ipapparagraph
"i"a""큰따옴표"
'i'a''작은따옴표'
`i`a``백틱`
( / )i(a((소괄호)
{ / }i{a{{중괄호}
[ / ]i[a[[대괄호]
< / >i<a<<꺾쇠>
태그itatHTML 태그

실전 조합:

ciw → 단어 내용 변경
da" → 따옴표 포함 삭제
vi( → 괄호 안 Visual 선택
yat → HTML 태그 전체 복사
>ip → 현재 문단 들여쓰기
gUiw → 단어 대문자로

Visual 모드 기본

세 가지 Visual 모드

모드선택 단위
vVisual문자 단위
VVisual Line줄 단위
Ctrl-vVisual Block사각형 블록

선택 확장

동작
o선택 영역의 양 끝을 토글 (시작↔끝 커서 이동)
OVisual Block에서 같은 줄의 반대쪽 모서리로

o는 선택을 시작한 후 반대 방향으로도 확장하고 싶을 때 씁니다.

모드 전환

선택을 유지한 채 모드를 바꿀 수 있습니다. vV로 문자에서 줄로, VCtrl-v로 줄에서 블록으로 바꿀 수 있습니다.

재선택

동작
gv마지막 Visual 선택 영역을 다시 선택

>로 들여쓰기 후 gv로 재선택하면 한 번 더 들여쓸 수 있습니다. gv>gv> 순서입니다.

선택 + 모션

조합결과
v2w2단어 선택
vit태그 안 선택
vi{중괄호 안 선택
vap문단 선택
v$줄 끝까지 선택

Visual 모드에서 선택 영역 조작

영역을 선택한 후 다음 명령을 사용합니다.

기본 조작

동작
d삭제
c변경 (삭제 후 Insert)
y복사

들여쓰기

동작
>한 레벨 들여쓰기
<한 레벨 내어쓰기
3>3레벨 들여쓰기

V로 여러 줄을 선택하고 >를 누르면 한꺼번에 들여쓸 수 있습니다. .으로 반복할 수 있습니다.

대소문자

동작
~대소문자 토글
U전부 대문자
u전부 소문자

정렬과 외부 명령

동작
=자동 정렬 (indentation)
J선택한 줄 합치기
!sort선택 영역을 알파벳 정렬
!sort -n숫자 정렬
!column -t컬럼 정렬 (표 형태)

ex 명령

선택 후 :를 누르면 :'<,'>가 자동 입력됩니다. 선택 범위에 ex 명령을 적용할 수 있습니다.

:'<,'>s/old/new/g " 선택 영역에서 치환
:'<,'>normal A; " 선택한 모든 줄 끝에 ; 추가
:'<,'>normal I// " 선택한 모든 줄 앞에 // 추가

컬럼 편집 심화 (Visual Block)

Ctrl-v로 진입하는 Visual Block 모드는 사각형 영역을 선택합니다. 일반 에디터의 "멀티 커서"와 비슷한 결과를 만들 수 있습니다.

컬럼 선택

Ctrl-v → Visual Block 진입
j/k → 위아래 행 확장
l/h → 좌우 열 확장
$ → 각 줄 끝까지 (줄 길이 달라도 OK)

다중 행 앞에 삽입

여러 줄 앞에 동시에 텍스트를 넣습니다.

1. Ctrl-v → Visual Block 진입
2. jjj → 4줄 선택
3. I → 맨 앞에 Insert
4. // (스페이스) → 입력
5. Esc → 모든 줄에 적용

예: 주석 추가

실행 전: 실행 후:
let a = 1 // let a = 1
let b = 2 // let b = 2
let c = 3 // let c = 3
let d = 4 // let d = 4

다중 행 끝에 추가

1. Ctrl-v → Visual Block 진입
2. jjj → 4줄 선택
3. $ → 각 줄 끝까지 (길이 달라도 OK)
4. A → 끝에 Append
5. ; → 입력
6. Esc → 모든 줄에 적용

컬럼 삭제

선택한 사각형 영역을 통째로 삭제합니다.

1. Ctrl-v → Visual Block 진입
2. jjj → 행 선택
3. ll → 열 확장
4. d → 삭제

예: 들여쓰기 일괄 제거

실행 전: 실행 후:
line 1 line 1
line 2 line 2
line 3 line 3

4칸 공백 위치에 Ctrl-vjjllld.

예: 주석 일괄 제거

실행 전: 실행 후:
// let a = 1 let a = 1
// let b = 2 let b = 2
// let c = 3 let c = 3

// 위에 Ctrl-vjjlld.

컬럼 치환

선택한 사각형 영역을 새로운 텍스트로 교체합니다.

1. Ctrl-v → Visual Block 진입
2. jjj → 행 선택
3. e → 단어 끝까지 열 확장
4. c → 변경
5. newText → 새 텍스트 입력
6. Esc → 모든 줄에 적용

컬럼 문자 교체

선택 영역의 모든 문자를 같은 문자로 바꿉니다.

1. Ctrl-v → 블록 선택
2. r- → 모든 문자를 -로 교체

구분선을 만들거나, 공백을 특정 문자로 채울 때 유용합니다.

컬럼 들여쓰기

1. Ctrl-v → Visual Block 진입
2. jjj → 행 선택
3. > → 들여쓰기
4. gv → 재선택
5. > → 한 레벨 더

또는 Vjjj3>로 3레벨 한 번에 들여쓰기.

컬럼 대소문자

Ctrl-v → 영역 선택 → ~ (토글)
Ctrl-v → 영역 선택 → U (대문자)
Ctrl-v → 영역 선택 → u (소문자)

순차 번호 매기기

g Ctrl-a는 Visual Block으로 선택한 숫자들을 순차적으로 증가시킵니다.

실행 전 (모두 0): 실행 후:
0. item 1. item
0. item 2. item
0. item 3. item
0. item 4. item

방법: Ctrl-vjjj (0들을 선택) → g Ctrl-a.

실전 예제 모음

상황방법
여러 줄 앞에 // 주석Ctrl-vjjjI// Esc
여러 줄 // 주석 제거Ctrl-vjjjlld
여러 줄 끝에 ; 추가Ctrl-vjjj$A;Esc
CSV 특정 컬럼 삭제해당 열에 Ctrl-vGd
변수명 일괄 교체해당 열에 Ctrl-vjjjec → 새 이름 → Esc
여러 줄 들여쓰기Ctrl-vjjj> (또는 Vjjj>)
0부터 순차 번호0을 입력 → 복사해서 여러 줄 → Ctrl-v로 선택 → g Ctrl-a
HTML 속성 일괄 추가태그 뒤에 Ctrl-vjjjA class="new"Esc

검색과 치환

검색

동작
/pattern아래 방향 검색
?pattern위 방향 검색
n다음 결과
N이전 결과
*커서 아래 단어 검색 (아래로)
#커서 아래 단어 검색 (위로)

치환

:s/old/new/ " 현재 줄, 첫 번째만
:s/old/new/g " 현재 줄, 전체
:%s/old/new/g " 파일 전체
:%s/old/new/gc " 파일 전체, 하나씩 확인
:'<,'>s/old/new/g " Visual 선택 영역
:5,20s/old/new/g " 5~20번째 줄

정규식 기초

패턴의미
.아무 문자 1개
.*아무 문자 0개 이상
\d숫자
\w영문/숫자/밑줄
\s공백
^줄 시작
$줄 끝
\(\)캡처 그룹
\1첫 번째 캡처 역참조

예: 순서 뒤집기

:%s/\(\w\+\), \(\w\+\)/\2, \1/g
" "Kim, John" → "John, Kim"

다중 줄 일괄 편집 (ex 명령)

특정 줄 범위나 패턴에 매칭되는 줄에 일괄 명령을 적용합니다.

줄 범위 조작

명령동작
:5,20d5~20줄 삭제
:5,20y5~20줄 복사
:10,20m3010~20줄을 30줄 뒤로 이동
:10,20co3010~20줄을 30줄 뒤에 복사

:g (global)로 패턴 매칭 일괄 실행

:g/pattern/d " pattern 포함 줄 전부 삭제
:v/pattern/d " pattern 미포함 줄 전부 삭제 (v = inverse)
:g/TODO/normal A; " TODO 포함 줄 끝에 ; 추가
:g/^$/d " 빈 줄 전부 삭제
:g/console.log/d " console.log 줄 전부 삭제

:normal로 줄 범위에 Normal 명령 적용

:5,20normal >> " 5~20줄 들여쓰기
:5,20normal I// " 5~20줄 앞에 // 추가
:5,20normal A; " 5~20줄 끝에 ; 추가
:5,20normal dd " 5~20줄 삭제

:g:normal을 조합하면 Vim 안에서 거의 모든 일괄 편집이 가능합니다.

매크로

매크로는 키 입력을 녹화하고 재생하는 기능입니다.

기본 사용법

1. qa → a 레지스터에 녹화 시작
2. (편집 동작) → 원하는 작업 수행
3. q → 녹화 종료
4. @a → 매크로 실행
5. @@ → 마지막 매크로 반복
6. 10@a → 10회 반복 실행

실전 예제: CSV를 SQL INSERT로 변환

원본:

John,30,Seoul
Jane,25,Busan

변환 결과:

INSERT INTO users VALUES ('John', 30, 'Seoul');
INSERT INTO users VALUES ('Jane', 25, 'Busan');

첫 줄에서 매크로를 녹화하고, 나머지 줄에 @a로 적용하면 됩니다.

재귀 매크로

매크로 안에서 자기 자신을 호출할 수도 있습니다.

qaq → a 레지스터 초기화
qa → 녹화 시작
(편집 동작)
j → 다음 줄
@a → 자기 자신 호출
q → 녹화 종료
@a → 실행 (파일 끝까지 반복)

파일 끝에 도달하면 j가 실패해서 자동으로 멈춥니다.

레지스터

Vim은 삭제하거나 복사한 텍스트를 여러 레지스터에 저장합니다.

레지스터이름용도
""무명마지막 d/c/y 결과
"0yank마지막 y 결과만 (d/c 제외)
"1~"9숫자최근 삭제 이력
"+시스템 클립보드OS 복사/붙여넣기
"a~"z이름 지정사용자 지정 저장
"A~"Z이름 추가기존 레지스터에 추가(append)
"_블랙홀삭제해도 어디에도 저장 안 됨
"/검색마지막 검색 패턴
":명령마지막 ex 명령
".입력마지막 Insert 입력

사용법

"ay → a 레지스터에 복사
"ap → a 레지스터에서 붙여넣기
"+y → 시스템 클립보드에 복사
"+p → 시스템 클립보드에서 붙여넣기
"_dd → 줄 삭제하되 레지스터 건드리지 않기
:reg → 모든 레지스터 확인

"0이 유용한 상황: yy로 복사한 후 dd로 다른 줄을 삭제하면, p는 삭제한 줄을 붙여넣습니다. 원래 복사한 줄을 붙여넣으려면 "0p.

마크

파일 내 위치를 북마크처럼 저장합니다.

동작
m{a-z}현재 위치를 로컬 마크로 저장
m{A-Z}현재 위치를 글로벌 마크로 저장 (파일 간 이동 가능)
`a마크 a의 정확한 위치로 이동
'a마크 a가 있는 줄의 처음으로 이동
:marks마크 목록 보기

자동 마크

Vim이 자동으로 설정하는 마크:

마크위치
`.마지막 편집 위치
`"마지막으로 파일을 닫았던 위치
`[마지막 변경/붙여넣기 시작
`]마지막 변경/붙여넣기 끝
''마지막 점프 이전 위치

''(작은따옴표 두 번)는 "아까 있던 곳으로 돌아가기"입니다. 검색이나 G로 이동한 후 원래 위치로 돌아갈 때 씁니다.

윈도우/버퍼/탭

버퍼

열려 있는 파일 목록입니다.

명령동작
:e file파일 열기
:ls열린 버퍼 목록
:bn / :bp다음 / 이전 버퍼
:bd현재 버퍼 닫기
:b{n}n번 버퍼로 이동
:b name이름으로 버퍼 이동 (탭 자동완성)

윈도우

화면을 분할해서 여러 파일을 동시에 봅니다.

명령동작
:split / :sp가로 분할
:vsplit / :vs세로 분할
Ctrl-w h/j/k/l윈도우 간 이동
Ctrl-w =크기 동일하게
Ctrl-w o현재 윈도우만 남기고 닫기
Ctrl-w > / <너비 조절
Ctrl-w + / -높이 조절
Ctrl-w r윈도우 위치 회전

명령동작
:tabnew새 탭
gt / gT다음 / 이전 탭
:tabclose탭 닫기
{n}gtn번 탭으로 이동

접기 (Folding)

코드의 일부를 접어서 숨길 수 있습니다.

동작
zf{motion}접기 생성 (예: zfap 문단 접기)
za접기 토글
zo접기 열기
zc접기 닫기
zR전체 열기
zM전체 닫기
zj다음 접기로 이동
zk이전 접기로 이동

실전 편집 레시피

"이걸 하고 싶은데 어떻게 하지?"라는 상황에 맞춘 단축키 조합입니다.

하고 싶은 것방법
이 단어를 전부 바꾸고 싶다*ciw → 새 단어 → Esc → n. 반복
여러 줄 앞에 주석 추가Ctrl-vjjjI// → Esc
여러 줄 주석 제거Ctrl-vjjjlld
괄호 안 내용만 교체ci(
따옴표 안 내용 복사yi"
태그 안 내용 삭제dit
현재 줄 복제yyp
두 줄 순서 바꾸기ddp
여러 줄 들여쓰기Vjjj> (반복: .)
여러 줄 내어쓰기Vjjj<
선택 영역 정렬V → 선택 → !sort
단어를 대문자로gUiw
줄 전체 대문자로gUU
0~N 순차 번호 매기기0 여러 줄 → Ctrl-v로 선택 → g Ctrl-a
함수 블록 전체 복사여는 {에서 V%y
빈 줄 전부 삭제:g/^$/d
TODO 줄만 남기기:v/TODO/d
console.log 전부 삭제:g/console.log/d
5~20줄에 주석 추가:5,20normal I//

마치며

이 글에서 다룬 것은 모두 Vi/Vim에서 동작하는 보편적인 단축키라서 Neovim, Vim, Vi 어디서든 쓸 수 있어요.

기억할 것은 세 가지예요.

  1. 문법 이해 — 동사 + 명사 조합으로 암기량 줄이기
  2. . 습관화 — 반복 가능한 편집으로 생산성 높이기
  3. Visual Block 익히기 — 멀티 커서 없이 다중 행 편집하기

다음 글에서는 LSP, 터미널, 플러그인, 마우스 활용까지 Neovim만의 단축키를 다뤄요.

Claude HUD 상태 표시줄

· 약 3분

Claude Code를 쓸 때 궁금한 것들

Claude Code로 작업하다 보면 이런 생각이 들어요:

  • 컨텍스트를 얼마나 썼지? 곧 한계에 도달하나?
  • 지금 무슨 도구를 실행 중이지? 파일을 읽고 있나, 편집 중인가?
  • 서브에이전트가 돌고 있는데 얼마나 걸리고 있지?
  • 할 일 목록에서 몇 번째까지 끝났지?

이 정보들을 터미널 하단에 항상 보여주는 플러그인이 Claude HUD예요. GitHub Stars 18.7k로 Claude Code 플러그인 중 가장 인기가 많아요.

뭘 보여주는가

Claude HUD는 터미널 입력창 바로 아래에 상태 표시줄을 추가합니다.

[Opus] │ my-project git:(main*)
Context █████░░░░░ 45% │ Usage ██░░░░░░░░ 25% (1h 30m / 5h)

기본 표시 항목

항목설명
모델명현재 사용 중인 모델 (Opus, Sonnet 등)
프로젝트 경로작업 디렉토리 (depth 조절 가능)
Git 브랜치현재 브랜치 + dirty 상태(*), ahead/behind 표시
Context 바컨텍스트 윈도우 사용률 (1M 토큰 기준)
Usage 바구독 사용량 (주간 한도 대비)

선택 표시 항목

설정으로 다음 정보를 추가할 수 있습니다.

도구 활동

◐ Edit: auth.ts | ✓ Read ×3 | ✓ Grep ×2

지금 Claude가 어떤 파일을 편집 중인지, 몇 번 읽기/검색을 했는지 실시간으로 보입니다.

에이전트 상태

◐ explore [haiku]: Finding auth code (2m 15s)

서브에이전트가 돌고 있을 때 어떤 에이전트가 뭘 하고 있는지, 얼마나 걸렸는지 표시합니다.

할 일 진행률

▸ Fix authentication bug (2/5)

TaskCreate로 만든 할 일 목록의 진행 상황을 보여줍니다.

왜 유용한가

1. 컨텍스트 관리

Claude Code는 대화가 길어지면 컨텍스트 윈도우가 차오릅니다. 가득 차면 이전 내용이 압축되면서 맥락을 잃을 수 있습니다. Context 바를 보면서 적절한 시점에 새 대화를 시작할 수 있습니다.

2. 대기 시간 활용

Claude가 뭘 하고 있는지 보이면, 기다릴지 다른 일을 할지 판단할 수 있습니다. "에이전트가 탐색 중이니 2분은 걸리겠군" 같은 판단이 가능해집니다.

3. 사용량 추적

구독 사용자라면 주간 사용량 한도가 있습니다. Usage 바를 보면서 속도를 조절할 수 있습니다. 80% 이상이면 경고 표시도 됩니다.

설치

Claude Code 안에서 3줄이면 됩니다.

/plugin marketplace add jarrodwatts/claude-hud
/plugin install claude-hud
/claude-hud:setup

setup에서 프리셋을 선택할 수 있습니다.

프리셋표시 내용
Full도구, 에이전트, 할 일, Git, 사용량 전부 표시
Essential활동 상태 + Git, 적당한 밀도
Minimal모델명 + 컨텍스트 바만

설치 후 Claude Code를 재시작하면 적용됩니다.

설정 커스터마이징

~/.claude/plugins/claude-hud/config.json에서 세부 설정을 조정할 수 있습니다.

{
"language": "en",
"lineLayout": "expanded",
"pathLevels": 1,
"gitStatus": { "enabled": true },
"display": {
"showTools": true,
"showAgents": true,
"showTodos": true,
"showDuration": false,
"showMemoryUsage": false,
"showCost": false
}
}

레이아웃

  • expanded: 여러 줄로 펼쳐서 표시 (정보 밀도 높음)
  • compact: 한 줄로 압축 (화면 절약)

경로 깊이

pathLevels: 1 → my-project
pathLevels: 2 → apps/my-project
pathLevels: 3 → dev/apps/my-project

색상

named color(dim, red, green 등), 256-color 번호(0-255), hex 값(#rrggbb) 모두 지원합니다.

동작 원리

Claude HUD는 Claude Code의 statusline API를 사용합니다.

  • Claude Code가 약 300ms 간격으로 세션 데이터를 JSON으로 전달
  • HUD가 이를 파싱해서 컨텍스트 사용량, 토큰 속도 등을 계산
  • transcript JSONL 파일을 읽어 도구 사용, 에이전트, 할 일 상태를 추출
  • 포맷팅된 텍스트를 터미널 하단에 출력

별도 창이나 tmux 없이, Claude Code 터미널 자체에 통합됩니다.

요구사항

  • Claude Code v1.0.80 이상
  • Node.js 18+ 또는 Bun

마치며

Claude Code를 많이 쓸수록 "지금 뭘 하고 있는지"가 중요해집니다. 특히 서브에이전트를 여러 개 띄우거나, 긴 작업을 시킬 때 HUD가 있으면 체감이 크게 다릅니다.

설치에 1분, 설정에 1분이면 되니까 한번 써보는 걸 추천해요.

GitHub: jarrodwatts/claude-hud

Obsidian CLI 입문

· 약 5분

이 글은 Obsidian CLI 시리즈의 첫 번째 글이에요.

  1. Obsidian CLI 입문: 터미널에서 노트를 다루는 새로운 방법 ← 현재 글
  2. Obsidian CLI 비교: 공식 CLI vs URI vs 직접 파일 조작
  3. Obsidian CLI 자동화: 스크립트와 워크플로우 실전 가이드

문제: 노트 하나 쓰려고 GUI를 열어야 하는가

터미널에서 코드를 쓰다가 떠오른 생각을 메모하고 싶을 때가 있습니다.

  1. ⌘+Tab으로 Obsidian 창을 찾습니다
  2. 데일리 노트를 엽니다
  3. 적당한 위치에 커서를 놓고 입력합니다
  4. 다시 ⌘+Tab으로 터미널로 돌아옵니다

한 줄 메모에 4단계. 이런 상황이 반복되면 점점 메모를 안 하게 됩니다.

자동화도 마찬가지입니다. 매일 데일리 노트를 만들고, 커밋 로그를 기록하고, 태그를 정리하고 싶은데, GUI에서는 이걸 스크립트로 만들 수가 없습니다.

2026년 2월, Obsidian v1.12에서 공식 CLI가 추가됐습니다.

Obsidian CLI란

Obsidian CLI는 Obsidian v1.12.0에서 Early Access로 출시되고, v1.12.4부터 모든 사용자에게 무료로 공개된 공식 커맨드라인 인터페이스입니다.

100개 이상의 명령어를 제공하며, 데일리 노트 작성부터 검색, 태그 관리, 노트 생성, 파일 비교까지 Obsidian의 핵심 기능을 터미널에서 사용할 수 있습니다.

동작 구조는 다음과 같습니다:

터미널 명령어 → CLI → 로컬 소켓 → Obsidian 프로세스 → 볼트 조작

CLI가 Obsidian 내부 API를 통해 작동하기 때문에, 파일을 이동하면 위키링크가 자동으로 업데이트되고, 속성을 변경하면 인덱스에 즉시 반영됩니다. 단, Obsidian 데스크톱 앱이 실행 중이어야 합니다 — 헤드리스 도구가 아닙니다.

활성화

1. CLI 활성화

Obsidian을 열고 Settings → General → Command line interface를 켭니다.

화면의 안내에 따라 시스템 PATH에 CLI를 추가하고, 터미널을 재시작합니다.

2. 설치 확인

obsidian --version

정상이면 버전 번호가 출력됩니다.

3. 볼트 확인

# 등록된 볼트 목록
obsidian vault list

여러 볼트를 사용한다면 기본 볼트를 지정해두면 편리합니다:

# 기본 볼트 설정
obsidian vault set-default "MyVault"

이후 명령어에서 vault= 옵션을 생략할 수 있습니다.

데일리 노트

CLI의 킬러 피처입니다. 터미널에서 데일리 노트를 열고, 내용을 추가하고, 태스크를 확인할 수 있습니다.

기본 사용

# 오늘의 데일리 노트 열기 (없으면 자동 생성)
obsidian daily

# 어제 데일리 노트 열기
obsidian daily --offset=-1

# 특정 날짜
obsidian daily --offset=-7

내용 추가

# 데일리 노트에 텍스트 추가
obsidian daily:append content="## 오후 회의 메모
- 배포 일정 확인
- 버그 #234 논의"

태스크 확인

# 오늘 데일리 노트의 태스크 목록
obsidian tasks daily

실전 예제: git 커밋 로그를 데일리 노트에 기록

터미널에서 하루 작업을 마치고, 오늘의 커밋을 데일리 노트에 자동으로 기록할 수 있습니다:

obsidian daily:append content="## Git 커밋 요약
$(git log --oneline --since='08:00' --until='now')"

이 한 줄이면 됩니다. GUI를 열 필요도, 복사-붙여넣기를 할 필요도 없습니다.

검색과 읽기

볼트 검색

# 키워드로 볼트 전체 검색
obsidian search query="프로젝트 일정"

# 특정 경로 안에서만 검색
obsidian search query="배포" path="Work/"

검색 옵션:

옵션설명예시
query키워드 검색obsidian search query="TODO"
tag태그로 필터링obsidian search tag="#project"
path경로 제한obsidian search query="회의" path="Daily/"

노트 읽기

# 노트 내용을 터미널에 출력
obsidian read path="Projects/blog-migration.md"

# 활성 파일 읽기
obsidian read

터미널에서 노트를 읽을 수 있다는 건, grep이나 fzf와 조합할 수 있다는 뜻입니다.

파일 비교

# 노트의 변경 이력 확인
obsidian diff path="Projects/blog-migration.md"

노트 생성

# 새 노트 생성
obsidian create name="Meeting/2026-04-14-standup"

# 템플릿을 적용해서 생성
obsidian create name="Projects/new-feature" template="Templates/project"

# 내용과 함께 생성
obsidian create name="TIL/obsidian-cli" content="# Obsidian CLI
오늘 배운 것: 터미널에서 노트를 다루는 방법"

GUI에서 템플릿을 쓰는 것과 동일하게, template 옵션으로 지정한 템플릿이 적용됩니다. Obsidian 내부 API를 통해 생성되므로 플러그인(Templater 등)도 정상 작동합니다.

태그 관리

# 볼트의 모든 태그와 사용 횟수
obsidian tags counts

출력 예시:

태그노트 수
#project23
#til45
#meeting12
#blog8

특정 태그가 달린 노트를 찾으려면:

# 태그로 노트 목록 조회
obsidian tags list tag="#project"

태그 사용 현황을 한눈에 파악하고, 정리가 필요한 태그를 빠르게 찾을 수 있습니다.

주요 명령어 정리

명령어설명
obsidian daily오늘의 데일리 노트 열기/생성
obsidian daily:append content="..."데일리 노트에 내용 추가
obsidian daily --offset=-1어제 데일리 노트 열기
obsidian tasks daily데일리 노트의 태스크 목록
obsidian search query="..."볼트 전체 검색
obsidian read path="..."노트 내용을 터미널에 출력
obsidian diff path="..."노트 변경 이력 확인
obsidian create name="..."새 노트 생성
obsidian create ... template=...템플릿으로 노트 생성
obsidian tags counts태그별 사용 횟수
obsidian tags list tag="..."태그로 노트 필터링
obsidian vault list볼트 목록
obsidian vault set-default "..."기본 볼트 설정

마치며

Obsidian CLI는 Obsidian을 터미널 시민으로 만들어줍니다. 생각이 떠오른 순간에서 기록까지의 거리가 짧아집니다.

설정에 1분, 첫 명령어 실행에 10초예요. 이미 Obsidian을 쓰고 있다면 한번 켜보세요.

다음 글에서는 공식 CLI 외에 URI scheme과 직접 파일 조작까지 포함해서, Obsidian을 터미널에서 제어하는 세 가지 방법을 비교해요.

참고 자료

나의 tmux 설정

· 약 7분

tmux란?

tmux(Terminal Multiplexer)는 하나의 터미널 안에서 여러 셸 세션을 관리할 수 있는 도구예요.

왜 쓰는가?

화면 분할은 하나의 터미널을 여러 패널로 나눠서 동시에 작업합니다. 세션 유지는 SSH 연결이 끊어져도 작업이 계속 유지됩니다. 원격 작업은 서버에서 tmux를 띄워두면 언제든 다시 붙을 수 있습니다 (detach/attach). 자동화는 스크립트로 복잡한 윈도우/패널 레이아웃을 한 번에 구성합니다.

설치

# macOS
brew install tmux

# Rocky Linux / CentOS
dnf install -y tmux

# Ubuntu / Debian
apt install -y tmux

기본 개념

tmux
├── Session (세션)
│ ├── Window 1 (윈도우 = 탭)
│ │ ├── Pane 1 (패널 = 분할 영역)
│ │ └── Pane 2
│ └── Window 2
│ └── Pane 1
└── Session 2
└── ...

Session은 독립적인 작업 단위입니다. 프로젝트별로 세션을 만들면 좋습니다. Window는 세션 안의 탭으로, 화면 전체를 차지합니다. Pane은 윈도우를 분할한 패널입니다. 여러 셸을 동시에 볼 수 있습니다.

필수 단축키

tmux의 모든 단축키는 Prefix 키를 먼저 누른 뒤 명령키를 누릅니다.

저는 Prefix를 Ctrl+Space로 설정했어요 (기본값 Ctrl+b도 유지).

세션

동작
tmux new -s 이름새 세션 생성
Prefix d세션에서 분리 (detach)
tmux attach -t 이름세션에 다시 붙기
tmux ls세션 목록
tmux kill-session -t 이름세션 삭제

윈도우

동작
Prefix c새 윈도우
Prefix n / Prefix p다음/이전 윈도우
Prefix 숫자해당 번호 윈도우로 이동
Prefix ,윈도우 이름 변경
Prefix &윈도우 닫기

패널

동작
Prefix %세로 분할
Prefix "가로 분할
Prefix h/j/k/l패널 이동 (내 설정)
Prefix x패널 닫기
Prefix z패널 풀스크린 토글 (zoom)
Prefix Space레이아웃 순환

Prefix z는 유용합니다. 패널 하나를 전체화면으로 확대했다가 다시 원래 크기로 되돌릴 수 있습니다.

저의 tmux.conf 전체 설정

Prefix 키

# Ctrl+Space를 메인 Prefix로, Ctrl+b도 유지
set -g prefix C-Space
set -g prefix2 C-b
bind C-Space send-prefix

기본 Ctrl+b는 손이 불편해요. Ctrl+Space가 훨씬 자연스럽습니다.

기본 옵션

# 히스토리 50000줄 유지
set-option -g history-limit 50000

# 분할 시 현재 경로 유지
bind % split-window -h -c "#{pane_current_path}"
bind '"' split-window -v -c "#{pane_current_path}"

# 트루컬러 지원
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",xterm-256color:RGB"

# 윈도우 이름 자동 변경 끄기
set -g automatic-rename off

# 마우스 지원
set -g mouse on

# 스크롤 여유
set -g allow-passthrough on

패널 테두리 커스터마이징

# 패널 상단에 인덱스와 명령어 표시
set -g pane-border-format " #{pane_index} #{pane_current_command} "
set -g pane-border-status top
set -g pane-border-lines double

# 활성 패널 강조 (파란색)
set -g pane-active-border-style "fg=#89b4fa"
set -g pane-border-style "fg=#585b70"

# 활성/비활성 윈도우 배경색 차이
set -g window-active-style "bg=#1e1e2e"
set -g window-style "bg=#11111b"

비활성 패널의 배경을 약간 어둡게 하면 현재 작업 중인 패널이 바로 눈에 들어옵니다.

vi 복사 모드

setw -g mode-keys vi

# v로 선택 시작, y로 복사 (시스템 클립보드에)
bind-key -T copy-mode-vi v send-keys -X begin-selection
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "pbcopy"

# 마우스 드래그로 선택 시 클립보드에 복사
bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-no-clear "pbcopy"

Prefix [로 복사 모드에 진입하면 Vim처럼 v로 선택, y로 복사할 수 있습니다. pbcopy로 macOS 클립보드에 바로 들어갑니다.

마우스 더블클릭으로 단어 선택

# 단어 구분자에서 -./?를 제외 (URL, 경로를 한 덩어리로 선택)
set -g word-separators " =()[]{};,!@#$%^&*+|<>\"'"

# 더블클릭으로 단어 선택
bind -T copy-mode-vi DoubleClick1Pane select-pane \; send-keys -X select-word
bind -n DoubleClick1Pane select-pane \; copy-mode -M \; send-keys -X select-word

마우스 스크롤 속도

# 기본 3줄 → 5줄씩 스크롤
bind-key -T copy-mode-vi WheelUpPane send-keys -X -N 5 scroll-up
bind-key -T copy-mode-vi WheelDownPane send-keys -X -N 5 scroll-down

패널 이동 (hjkl)

bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
bind L last-window # 마지막 윈도우로 이동
bind r source-file ~/.tmux.conf \; display "Reloaded!"

Neovim과 동일한 hjkl 방향키를 사용합니다. Prefix r로 설정을 다시 불러옵니다.

yazi 파일 탐색기 연동

# Prefix + Tab: 오른쪽 50% 분할에서 yazi 실행
bind Tab split-window -h -l 50% -c "#{pane_current_path}" "yazi"

yazi는 터미널 파일 관리자입니다. Prefix Tab으로 현재 디렉토리에서 바로 열 수 있습니다.

플러그인

TPM (Tmux Plugin Manager)

# 설치
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

tmux 실행 후 Prefix + I(대문자)로 플러그인을 설치합니다.

사용 중인 플러그인

set -g @plugin 'tmux-plugins/tpm' # 플러그인 매니저
set -g @plugin 'catppuccin/tmux' # 테마
set -g @plugin 'tmux-plugins/tmux-cpu' # CPU 사용률
set -g @plugin 'tmux-plugins/tmux-battery' # 배터리 표시
set -g @plugin 'tmux-plugins/tmux-resurrect' # 세션 저장/복원
set -g @plugin 'tmux-plugins/tmux-continuum' # 자동 저장/복원
플러그인역할
catppuccin/tmuxCatppuccin Mocha 테마
tmux-cpu상태바에 CPU/메모리 사용률 표시
tmux-battery상태바에 배터리 잔량 표시
tmux-resurrectPrefix Ctrl-s로 세션 저장, Prefix Ctrl-r로 복원
tmux-continuum15분마다 자동 저장, tmux 시작 시 자동 복원

tmux-resurrect + continuum

set -g @continuum-restore 'on' # tmux 시작 시 자동 복원
set -g @continuum-save-interval '15' # 15분마다 자동 저장

이 조합 덕분에 시스템을 재시작해도 tmux 세션이 그대로 살아납니다. 윈도우 레이아웃, 패널 구성, 작업 디렉토리까지 복원됩니다.

Catppuccin 테마 + 상태바

set -g @catppuccin_flavor 'mocha'
set -g @catppuccin_window_status_style 'rounded'

상태바 구성

왼쪽: 세션 이름

set -g status-left "#{E:@catppuccin_status_session}"

오른쪽: 디렉토리 → Git 브랜치 → CPU → 메모리 → 배터리 → 시간

set -g status-right "#{E:@catppuccin_status_directory}"
set -ag status-right " #(cd #{pane_current_path}; git rev-parse --abbrev-ref HEAD 2>/dev/null || echo '-') "
set -ag status-right " #{cpu_percentage} "
set -ag status-right " #{ram_percentage} "
set -ag status-right " #{battery_icon} #{battery_percentage} "
set -ag status-right "#{E:@catppuccin_status_date_time}"

상태바에 Git 브랜치가 표시되어서 어떤 브랜치에서 작업 중인지 바로 알 수 있습니다.

실전 활용: 다중 서버 접속 자동화

tmux의 진짜 힘은 스크립트로 레이아웃을 자동 구성할 수 있다는 점입니다.

예를 들어 운영 서버 여러 대에 동시에 접속하는 스크립트를 만들 수 있습니다:

#!/bin/bash
SESSION="my-servers"

# 이미 세션이 있으면 재사용
tmux has-session -t $SESSION 2>/dev/null && {
tmux attach -t $SESSION
exit 0
}

# 윈도우 1: 전체 서버 모니터링 (tiled 레이아웃)
tmux new-session -d -s $SESSION -n "all" "ssh server1"
tmux split-window -t $SESSION:1 "ssh server2"
tmux split-window -t $SESSION:1 "ssh server3"
tmux split-window -t $SESSION:1 "ssh server4"
tmux select-layout -t $SESSION:1 tiled

# 윈도우 2: DB 서버만
tmux new-window -t $SESSION -n "db" "ssh db-primary"
tmux split-window -t $SESSION:2 -h "ssh db-replica"

tmux select-window -t $SESSION:1
tmux attach -t $SESSION

이 스크립트를 실행하면:

┌─────────────┬─────────────┐
│ server1 │ server2 │
├─────────────┼─────────────┤
│ server3 │ server4 │
└─────────────┴─────────────┘

이런 레이아웃이 한 번에 만들어집니다. 저는 이 방식으로 환경별(beta/prod) x 리전별 서버 접속 스크립트를 만들어서 사용하고 있어요.

synchronize-panes

모든 패널에 동일한 명령을 동시에 입력할 수도 있습니다:

# 동기화 모드 토글
Prefix :setw synchronize-panes on

이 상태에서 타이핑하면 모든 패널에 같은 명령이 입력됩니다. 여러 서버에 동시에 같은 작업을 할 때 유용합니다.

설정 적용 방법

1. TPM 설치

git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

2. tmux.conf 저장

위 설정 내용을 ~/.tmux.conf에 저장합니다.

3. 플러그인 설치

tmux # tmux 실행
# Prefix + I (Shift+i) # 플러그인 설치

4. 설정 리로드

# tmux 안에서
Prefix r

# 또는 터미널에서
tmux source-file ~/.tmux.conf

5. yazi 설치 (선택)

# macOS
brew install yazi

# 기타: https://yazi-rs.github.io/docs/installation

정리

기능설정
PrefixCtrl+Space (+ Ctrl+b)
패널 이동Prefix h/j/k/l
복사 모드vi 스타일 (v 선택, y 복사)
테마Catppuccin Mocha
상태바세션, 디렉토리, Git, CPU, RAM, 배터리, 시간
세션 복원resurrect + continuum (자동)
파일 탐색Prefix Tab (yazi)
설정 리로드Prefix r

tmux는 터미널에서 작업하는 시간이 길수록 효과가 큽니다. 특히 원격 서버 작업이 많다면 세션 유지와 다중 접속 자동화만으로도 생산성이 크게 올라갑니다.

부록: tmux 단축키 & 플러그인 학습 페이지

별도로 정리한 인터랙티브 학습 페이지도 있어요. 단축키를 카테고리별로 정리해두었으니 참고하면 좋습니다.

tmux 단축키 & 플러그인 학습

참고 자료

Neovim 입문

· 약 4분

이 글은 Neovim 시리즈의 첫 번째 글이에요.

  1. Neovim 입문: Vim을 넘어서는 첫걸음 ← 현재 글
  2. Neovim 중급: 생산성을 높이는 기능들
  3. Neovim 고급: 플러그인과 LSP로 IDE처럼 쓰기
  4. 저의 Neovim 설정 전체 공개

Neovim이란?

Neovim은 Vim의 모던 포크(fork)입니다. Vim의 철학(모달 편집, 키보드 중심)을 유지하면서 내부를 현대적으로 재구성했습니다.

Vim과 뭐가 다른가?

VimNeovim
설정 언어VimScriptLua (VimScript도 지원)
비동기 처리제한적내장
내장 LSP없음있음
내장 터미널기본적완전한 터미널 에뮬레이터
플러그인 생태계성숙빠르게 성장 중
설정 파일~/.vimrc~/.config/nvim/init.lua

한 줄로 요약하면 Vim의 편집 철학 + 현대적인 확장성입니다.

설치

macOS

brew install neovim

Rocky Linux / CentOS

# EPEL에서 설치
dnf install -y epel-release
dnf install -y neovim

Ubuntu / Debian

apt install -y neovim

설치 확인:

nvim --version

4가지 모드

Neovim(Vim)이 다른 에디터와 결정적으로 다른 점은 모드가 있다는 것입니다.

Normal 모드

Neovim을 열면 이 모드입니다. 글을 쓰는 게 아니라 글을 조작하는 모드입니다.

  • 커서 이동, 삭제, 복사, 붙여넣기 등
  • 다른 모드에서 Esc를 누르면 항상 Normal로 돌아옵니다

Insert 모드

실제로 글을 타이핑하는 모드입니다.

동작
i커서 앞에 입력
a커서 뒤에 입력
I줄 맨 앞에 입력
A줄 맨 뒤에 입력
o아래에 새 줄 만들고 입력
O위에 새 줄 만들고 입력

Visual 모드

텍스트를 선택하는 모드입니다.

동작
v문자 단위 선택
V줄 단위 선택
Ctrl-v블록(사각형) 선택

Command 모드

:를 누르면 하단에 명령줄이 나타납니다.

:w 저장
:q 종료
:wq 저장 후 종료
:q! 저장하지 않고 종료

커서 이동

Normal 모드에서의 이동이 Vim의 핵심입니다. 처음에는 어색하지만 손에 익으면 마우스보다 빠릅니다.

기본 이동

k
h l
j
방향
h← 왼쪽
j↓ 아래
k↑ 위
l→ 오른쪽

: j의 아래쪽 꼬리를 생각하면 기억하기 쉽습니다.

단어 단위 이동

동작
w다음 단어 시작
b이전 단어 시작
e단어 끝

줄 이동

동작
0줄 맨 앞
$줄 맨 끝
^줄의 첫 글자 (공백 제외)

화면/파일 이동

동작
gg파일 맨 위
G파일 맨 아래
Ctrl-d반 페이지 아래
Ctrl-u반 페이지 위
{숫자}G해당 줄로 이동 (예: 42G)

기본 편집

삭제

동작
x커서 위 문자 삭제
dd줄 삭제
dw단어 삭제
d$ 또는 D커서부터 줄 끝까지 삭제

복사 & 붙여넣기

동작
yy줄 복사 (yank)
yw단어 복사
p커서 뒤에 붙여넣기
P커서 앞에 붙여넣기

실행 취소 & 다시 실행

동작
u실행 취소 (Undo)
Ctrl-r다시 실행 (Redo)

검색과 치환

검색

/검색어 아래 방향으로 검색
?검색어 위 방향으로 검색
n 다음 결과
N 이전 결과

치환

:s/old/new/ 현재 줄에서 첫 번째만
:s/old/new/g 현재 줄에서 모두
:%s/old/new/g 파일 전체에서 모두
:%s/old/new/gc 파일 전체, 하나씩 확인하며

파일 열기

# 터미널에서
nvim filename.txt

# Neovim 안에서
:e filename.txt
:e . 현재 디렉토리 탐색

숫자 + 명령 조합

Vim의 강력한 문법: 숫자 + 동작으로 반복할 수 있습니다.

5j 5줄 아래로
3dd 3줄 삭제
4w 4단어 앞으로
10G 10번째 줄로
2yy 2줄 복사

vimtutor로 연습하기

Neovim에는 대화형 튜토리얼이 내장되어 있습니다.

nvim +Tutor

30분 정도 따라 하면 기본 조작이 손에 익습니다. 처음 Neovim을 설치했다면 반드시 한 번은 해보세요.

다음 글

기본 조작이 익숙해졌다면 텍스트 오브젝트, 매크로, 레지스터 등 생산성을 끌어올리는 기능을 알아봐요.

Neovim 중급: 생산성을 높이는 기능들

참고 자료