히스토리
- @pi(분신) — 리뷰 완료. 퍼블리시 허가! 🫡 How to Read 섹션 추가, clipetty→xterm 전환 배경 보강
- @pi — clipetty→xterm 내장 OSC 52 전환, WezTerm SSH OSC 52 제한사항 문서화, DECSCUSR 커서 추가
- @junghan — 완성. 이전 로그 문서는 삭제한다.
- @pi — 생성. 20251224T144906(llmlog)과 20260410T203723(llmlog)의 핵심을 합침. 2주간 삽질의 결론: 터미널 Emacs가 에이전트 하네스의 프론트엔드로 완성됨.
How to Read
터미널에서 GUI를 포기하지 않아도 되는 시대가 왔다. 한글 입력, 클립보드, truecolor, SSH 원격 — 전부 터미널 Emacs 안에서 동작한다. 이 문서는 그 구성의 완성 기록이다.
- 누구를 위한 글인가: 터미널 Emacs를 에이전트 하네스(pi, Claude Code 등)의 프론트엔드로 쓰려는 사람.
- 무엇을 다루는가: 한글 입력 5레이어 체인, OSC 52 클립보드, 24bit truecolor, SSH 원격, 독립 인스턴스, 세션 간 통신.
- 어떻게 읽는가: “해결된 것” 표를 먼저 보고, 관심 있는 항목의 상세 섹션으로 뛰어라.
- 전제 조건: WezTerm + tmux + Doom Emacs + NixOS. 다른 조합이라면 레이어별로 대응점을 찾아 읽어라.
이 문서의 존재이유
터미널 이맥스 하네스 프론트엔드 완성.
모든 삽질은 이걸 끌어내려고 했다. 터미널 Emacs에서 GUI와 동등한 환경 — 한글 입력, 클립보드, truecolor, SSH 원격, 독립 인스턴스 — 이 모두 동작하여 에이전트 협업의 보편 인터페이스가 된 시점의 기록.
해결된 것 (2026-04-12/13)
| 문제 | 해결 | 파일 |
|---|---|---|
| 한글 입력 (터미널) | term-keys + wezterm + fcitx5 기본그룹 | tty-config.el, korean-input-config.el |
| 클립보드 (로컬) | clipetty→xterm 내장 OSC 52 (send-string-to-terminal) | tty-config.el |
| 24bit truecolor (tmux) | e() wrapper TERM=tmux-direct | nixos shell.nix |
| 독립 인스턴스 (emacs -nw) | init.el 가드 daemon-only로 변경 | init.el |
| pi —session-control | extra-args :init setq (defer 타이밍) | ai-pi-agent.el |
| 세션 매니저 void 에러 | —last-usage → —state :stats :contextUsage | ai-pi-agent.el |
한글 입력: 5레이어 체인
물리 Right Alt
↓
① xkb (kr104): Alt_R keysym (fcitx5 기본그룹에서 통과)
↓
② wezterm: RightAlt → term-keys 바이트 시퀀스 \x1b\x1f\x50\x60\x1f
↓
③ SSH / tmux: 바이트 그대로 통과 (중간자가 가로챌 이유 없음)
↓
④ Emacs term-keys: input-decode-map → <Hangul>
↓
⑤ toggle-input-method → korean-hangul (Emacs 내장 입력기)핵심: OS 입력기를 안 쓴다. Emacs 내장 입력기만 쓴다. NFD 문제 자체가 발생하지 않는다.
왜 이렇게 삽질했나
kime가 X11 레벨에서 Hangul/S-Space를 Consume → KKP 도달 불가. fcitx5 복원 → TriggerKeys가 전역 Consume → 또 막힘. fcitx5 기본그룹(English)으로 고정 → Alt_R가 통과 → term-keys가 잡음. wezterm이 RightAlt를 인식 → 시퀀스 전송 → Emacs가 <Hangul>로 디코딩.
패턴: “왜 안 되는가”를 xev → 터미널 디버그 → C-h k 순으로 한 레이어씩 추적. 각 레이어의 “소비자”를 찾아서 제거.
undo-fu 충돌
term-keys 프리픽스 \x1b\x1f = ESC + C-_ = C-M-_. undo-fu-mode-map이 C-M-_ 바인딩 → 프리픽스 가로챔. 해결: undo-fu-mode-hook 에서 매번 unbind.
클립보드: OSC 52 전구간
Emacs kill → clipetty → OSC 52 → tmux allow-passthrough → SSH → WezTerm → 시스템 클립보드
시스템 클립보드 → Ctrl-Shift-V → WezTerm 터미널 페이스트 → Emacs insert- WezTerm: OSC 52 기본 지원 (설정 불필요)
- tmux:
set -g allow-passthrough on이 MVP — 없으면 중첩 터미널에서 차단 - Doom:
(tty)+(set-terminal-parameter nil 'xterm--set-selection t)한 줄 - clipetty 제거 이유: clipetty는
process-connection-type을nil로 설정한 뒤write-region으로 임시 파일을 거쳐 OSC 52를 보낸다. 이 과정에서terminal-name이/dev/tty일 때 시퀀스가 깨지는 문제가 있었다. Emacs 29+ 내장 xterm.el은send-string-to-terminal로 직접 전송하므로 이 문제가 원천 차단된다. 외부 패키지 의존 하나를 줄이고, 빌트인으로 통일. - xclip은 유지 (paste 방향 커버 — OSC 52는 copy 방향만 담당)
- ref: [emacs terminal-name /dev/tty 문제 조사]
WezTerm SSH OSC 52 제한사항
WezTerm은 SSH를 통해 들어오는 OSC 52를 처리하지 못함 (known issue: wezterm/wezterm#764, #1790). Ghostty에서는 동일 경로가 정상 동작.
| 시나리오 | 결과 |
|---|---|
| 로컬 → OSC 52 | ✅ |
| SSH Oracle → printf OSC 52 | ❌ |
| SSH Oracle → tmux copy-mode yank | ❌ |
| SSH Oracle → tmux → WezTerm copy mode | ✅ |
| Ghostty → SSH Oracle → tmux yank | ✅ |
대응: SSH+tmux에서는 WezTerm 자체 copy mode 사용.
truecolor: TERM=*-direct
tmux → TERM=tmux-256color → Emacs init_tty C레벨 → 256색 고정 → 테마 깨짐
해결: e() wrapper → tput colors < 257 → TERM=tmux-direct → colors#16777216 → 24bit OKEmacs 터미널 색상은 C 레벨 init_tty 에서 결정. Lisp로 사후 변경 불가. emacsclient 호출 시점에 TERM을 바꾸는 것이 유일한 방법.
독립 인스턴스: daemon-only 가드
init.el:
(when (and (daemonp) (server-running-p)) ; ← 비-daemon은 통과
(kill-emacs))doom run (GUI) → non-daemon → 가드 스킵 → 독립 실행. emacs -nw → non-daemon → 가드 스킵 → 서버 없는 독립 인스턴스.
메모리: TTY Emacs + pi RPC = ~530MB. 5개 = ~3.5GB. 27GB 시스템에서 여유.
에이전트 통합
Emacs에서 pi 시작 시 --session-control 플래그 포함 → send_to_session, list_sessions 사용 가능. :custom 은 defer 상태에서 적용 안 됨 → :init 의 setq 로 해결.
스크롤: pi-coding-agent--with-scroll-preservation 매크로가 자동 팔로잉. point가 버퍼 끝이면 따라가고, 위로 스크롤했으면 유지.
서버 소켓 정리
| 소켓 | 인스턴스 | 용도 |
|---|---|---|
user | Emacs 30.2 GUI | 힣의 메인 에디터 (doom run) |
server | Emacs 30.2 headless | 에이전트 데몬 (run.sh agent start) |
doom-igc | Emacs 31 IGC | MPS GC 실험 (bin/emacs-igc.sh) |
| (없음) | emacs -nw 독립 | 터미널 pi 세션들 |
관련 커밋
| 리포 | SHA | 내용 |
|---|---|---|
| doomemacs-config | ede202c | term-keys 항상 로드, NFC타이머 제거, undo-fu hook |
| doomemacs-config | 604a243 | tty-config 통합 (term-keys, kitty-graphics, clipboard) |
| doomemacs-config | 03fed55 | clipetty→xterm OSC 52 + DECSCUSR 커서 + keybindings |
| doomemacs-config | ce48767 | 문서 재작성 + 터미널 독립 실행 + IGC TTY |
| doomemacs-config | 0cabb89 | pi —session-control :init 타이밍 수정 |
| term-keys | 5ea6bfa | wezterm col: Hangul→RightAlt |
| nixos-config | e8eb520 | emacsclient 24bit truecolor wrapper |
관련노트
- §doomemacs-config 닷파일 이맥스 스타터키트
- [WezTerm SSH tmux Emacs 터미널 통합 — OSC 52 클립보드 한영키 truecolor]
- [터미널 이맥스 한글 입력 삽질기 — kime→fcitx5→term-keys→wezterm 해결]
- @힣: 이맥스 학습 의미 - 도구 효율성 가치
Comments