이 노트에 대하여

터미널에서도 GUI를 포기하지 않아도 되는 구성이 실제로 완성되었다는 선언이다. 한글 입력 5레이어 체인, OSC 52 클립보드, tmux truecolor, 독립 인스턴스와 세션 통신까지 삽질의 결론만 남겼다. 터미널 Emacs가 에이전트 협업의 보편 인터페이스가 되는 순간이다.

히스토리

  • [2026-06-15 Mon 11:39] @opus — zmx 라이브 세션을 Emacs로 끌어옴. term-sessions(zmx 백엔드) + ghostel 프론트엔드로 한글 입력이 살았고, zcc/zcx/zagy/zpi 셸 런처를 my/zmx-launch(SPC j a)로 이식. ghostel이 영속 라이브 세션의 정착지가 됨. 본문 “zmx 라이브 세션” 절 참고.
  • [2026-05-07 Thu 10:39] @junghan — ghostel 합류 — Emacs 안의 Ghostty (2026-05-07)
  • [2026-04-23 Thu 18:26] @junghan — WezTerm TTY minibuffer 공백 어긋남 원인을 한글 입력이 아니라 Consult prompt/path truncation의 hardcoded Unicode ellipsis(…)로 확인. tty-config.el에서 TTY 전용 advice로 ASCII … 치환.
  • [2026-04-19 Sun 19:38] @junghan — 성능 최적화 완료
  • [2026-04-17 Fri 17:30] @opus — 컬러 이모지 제거 작업 기록. 3레이어(NixOS fontconfig + WezTerm 내장 우회 + Emacs 방어층) 통합. VS-16 폭 미스매치는 별도 이슈로 남김.
  • [2026-04-17 Fri 16:11] @junghan#터미널 #이맥스: ¤Wezterm ¤Ghostty ¤kitty 이거 기억하자.
  • [2026-04-14 Tue 22:50] @gpt — 하네스 프론트엔드 관점으로 How to Read와 관련노트 보강. 이 글이 Emacs 일반 소개가 아니라, 거대한 라이브 그릇이 터미널 창 안에 들어와 에이전트 협업 인터페이스가 된 사건이라는 점을 더 분명히 남김.
  • [2026-04-13 Mon 14:34] @pi(분신) — 리뷰 완료. 퍼블리시 허가! 🫡 How to Read 섹션 추가, clipetty→xterm 전환 배경 보강
  • [2026-04-13 Mon 14:06] @pi — clipetty→xterm 내장 OSC 52 전환, WezTerm SSH OSC 52 제한사항 문서화, DECSCUSR 커서 추가
  • [2026-04-13 Mon 11:52] @junghan — 완성. 이전 로그 문서는 삭제한다.
  • [2026-04-13 Mon] @pi — 생성. 20251224T144906(llmlog)과 20260410T203723(llmlog)의 핵심을 합침. 2주간 삽질의 결론: 터미널 Emacs가 에이전트 하네스의 프론트엔드로 완성됨.

How to Read

이 글은 Emacs 입문서가 아니다. 거대한 라이브 그릇이 터미널 창 안에 들어왔고, 그 결과 인간과 에이전트가 같은 작업면에서 만날 수 있게 되었다는 기록이다.

  • 누구를 위한 글인가: 에이전트 협업의 프론트엔드를 GUI 앱이 아니라 터미널이라는 보편 인터페이스 위에 올리고 싶은 사람.
  • 무엇을 다루는가: 한글 입력 5레이어 체인, OSC 52 클립보드, 24bit truecolor, SSH 원격, 독립 인스턴스, 세션 간 통신.
  • 무엇을 일부러 다루지 않는가: Emacs의 수천 개 패키지, 키바인딩 문화, Org-mode 일반론. 여기서 중요한 것은 세부 기능 목록이 아니라, 그 거대한 그릇이 터미널 안에 담겼다 는 사실이다.
  • 어떻게 읽는가: 먼저 “이 문서의 존재이유”와 “해결된 것” 표를 본 뒤, 관심 있는 레이어만 상세 섹션으로 내려가라.
  • 왜 중요한가: 로컬이든 SSH 원격이든, 이 터미널 창 하나가 인간과 에이전트가 함께 만지고 스스로 eval하며 라이브로 개선할 수 있는 협업 인터페이스가 되기 때문이다.
  • 비유를 허용한다면: 냉장고에 코끼리를 넣은 것 같고, 보아뱀이 코끼리를 삼킨 그림을 터미널 안에 접어 넣은 것 같다. 핵심은 “작은 창”이 아니라, 그 안에 들어온 거대한 생태계 다.
  • 전제 조건: 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-directnixos shell.nix
독립 인스턴스 (emacs -nw)init.el 가드 daemon-only로 변경init.el
pi —session-controlextra-args :init setq (defer 타이밍)ai-pi-agent.el
세션 매니저 void 에러—last-usage → —state :stats :contextUsageai-pi-agent.el
컬러 이모지 (터미널 fixed-pitch 깨짐)NixOS fontconfig 흑백 기본 + WezTerm 내장 우회 + Emacs doom-emoji-font 핀shared.nix, wezterm.lua, +user-info.el, ai-bot-config.el, korean-input-config.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-typenil 로 설정한 뒤 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

WezTerm TTY minibuffer 공백 어긋남 — Consult ellipsis

증상은 +default/search-cwd / consult-ripgrep 프롬프트에서 앞쪽에 입력하거나 백스페이스를 칠 때 공백이 어긋나 보이는 것이었다. 처음엔 한글 입력 문제처럼 보였지만, 실제 원인은 입력기가 아니라 Consult가 길어진 경로를 줄이면서 넣는 hardcoded Unicode ellipsis (U+2026) 였다.

예: Search (…/agent-config/pi-extensions)!

여기서 뒤의 ! / : 는 consult async indicator 상태 갱신이고, WezTerm TTY에서 앞의 가 폭 드리프트를 일으키면 indicator overlay가 갱신될 때 공백이 남거나 커서 위치가 틀어진 것처럼 보인다. 즉 한글 입력이 문제를 만든 것이 아니라, TTY 문자폭 드리프트를 consult redraw가 드러낸 것 이다.

핵심 포인트:

  • truncate-string-ellipsis 만 바꿔서는 해결되지 않음
  • consult 내부 함수가 를 직접 하드코딩하고 있었음
  • 문제 경로: consult--left-truncate-file, consult--directory-prompt
  • 해결: tty-config.el 에서 TTY일 때만 advice로 ... 치환

이 경로는 WezTerm + terminal Emacs + built-in Korean input 이 결합된 커스텀 경로다. 나중에 minibuffer/search prompt spacing이 다시 깨지면, 한글 입력기부터 의심하지 말고 먼저 Consult prompt/path truncation의 ellipsis와 TTY width drift 를 보라.

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 OK

Emacs 터미널 색상은 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 상태에서 적용 안 됨 → :initsetq 로 해결.

스크롤: pi-coding-agent--with-scroll-preservation 매크로가 자동 팔로잉. point가 버퍼 끝이면 따라가고, 위로 스크롤했으면 유지.

이모지: 흑백 통일 (2026-04-17)

터미널 fixed-pitch에 컬러 이모지가 섞이면 줄이 깨진다. Emacs에서 doom-emoji-fontNoto Emoji 로 핀했는데도 커서 hover에서 Noto Color Emoji 로 표시되는 현상. 원인이 한 곳이 아니라 3레이어에 동시 존재 해서, 한 군데만 막아서는 못 끈다.

3레이어 진단

  1. NixOS: fonts.packagesnoto-fonts-color-emoji 가 포함되고, fontconfig.defaultFonts.emoji 가 컬러로 잡혀 있었다. 시스템 차원에서 이미 컬러.
  2. WezTerm 내장: WezTerm이 Noto Color Emoji번들 폰트 로 들고 있다. 시스템에서 지워도 WezTerm 자체가 fallback으로 쏜다.
  3. Emacs 내부: Doom 기본 doom-emoji-fallback-font-families 는 컬러가 먼저. cl-find-if 가 컬러를 먼저 잡아 emoji fontset에 박히면, 뒤에 prepend로 흑백을 얹어도 VS-16 결합 이모지(✔️, ❤️)는 컬러로 폴백된다. telega의 telega-emoji-font-family defcustom 도 초기화 시 (font-family-list) 로 컬러를 적극 선택해 시스템 fontconfig를 캐싱시킨다.

3레이어 해결

레이어해결파일
NixOSnoto-fonts-color-emoji 제거, enableDefaultPackages = false, defaultFonts.emoji = [ "Noto Emoji" ]machines/shared.nix
WezTerm내장 폰트 fallback에 assume_emoji_presentation = true + Symbola 최종 fallbackusers/junghan/configs/wezterm.lua
Emacsdoom-emoji-fontNoto Emoji 로 pre-bind, telega emoji 변수 :init 에서 pre-bind, GUI에서 emoji fontset 전부 clear 후 흑백만 재등록+user-info.el, ai-bot-config.el, korean-input-config.el

핵심 교훈: 정말로 해결하려면 “제일 바깥에서 안 쓰게 만든다”. 시스템에서 빼고, 터미널에서 우회하고, 그래도 남은 가능성을 Emacs에서 방어. 한 층만 막으면 새어나온다.

남은 이슈: VS-16 폭 미스매치

wezterm ls-fonts --text "✔️"
  U+2714 U+FE0F  cells=0   # WezTerm: 결합해서 0셀로 처리
Emacs char-width-table       : 2   # Emacs: 2셀로 계산

✔️ (U+2714 + U+FE0F) 같은 VS-16 결합 이모지에서 WezTerm과 Emacs의 셀 폭 계산이 어긋난다. telega chat, org-mode 줄이 깨지는 원인.

후보 해결: WezTerm unicode_version = 14 (기본 9). 검증 필요. ref: https://wezterm.org/config/fonts.html#font-related-options

서버 소켓 정리

소켓인스턴스용도
userEmacs 30.2 GUI힣의 메인 에디터 (doom run)
serverEmacs 30.2 headless에이전트 데몬 (run.sh agent start)
doom-igcEmacs 31 IGCMPS GC 실험 (bin/emacs-igc.sh)
(없음)emacs -nw 독립터미널 pi 세션들

관련 커밋

리포SHA내용
doomemacs-configede202cterm-keys 항상 로드, NFC타이머 제거, undo-fu hook
doomemacs-config604a243tty-config 통합 (term-keys, kitty-graphics, clipboard)
doomemacs-config03fed55clipetty→xterm OSC 52 + DECSCUSR 커서 + keybindings
doomemacs-configce48767문서 재작성 + 터미널 독립 실행 + IGC TTY
doomemacs-config0cabb89pi —session-control :init 타이밍 수정
term-keys5ea6bfawezterm col: Hangul→RightAlt
nixos-confige8eb520emacsclient 24bit truecolor wrapper
nixos-config30acff6시스템 이모지 기본값 흑백 전환
nixos-config5a69c3d컬러 이모지 시스템/WezTerm에서 완전 배제
doomemacs-config8208441doom-emoji-font Noto Emoji 핀 (컬러 폴백 차단)
doomemacs-config2e03f4etelega emoji pre-bind + GUI fontset clear

관련노트

관련메타

BIBLIOGRAPHY

성능 경량화 — 타이머/훅 정리 (2026-04-19)

배경 — 프로파일이 말한 것

gg 로 대용량 저널 맨 위 이동 시 체감 지연. M-x profiler-report:

  • 57% Automatic GC
  • 13% timer-event-handler
  • 6% xterm-set-window-title
  • 1시간짜리 반복 타이머: org-persist--refresh-gc-lock, url-cookie-write-file, celestial-mode-line--update-handler, doom-modeline—github-fetch-notifications(30m)

TTY 에이전트 프론트엔드에 불필요하거나 비용 대비 이득 없는 것들을 걷어냈다.

제거한 것들

smooth-scroll 모듈

Doom ui/smooth-scroll +interpolateultra-scroll 은 GUI pixel-scroll 전용(pixel-scroll-precision-mode 전제), good-scrollscroll-up/down 에 advice + good-scroll--render 타이머. TTY 라인 렌더에서 픽셀 보간은 의미 없음. 통째 제거. GUI 에서 ultra-scroll 이 절실해지면 그때 다시.

kitty-graphics

kitty-graphics-mode 가 활성화되는 순간:

  • post-command-hook, window-scroll-functions, window-size-change-functions, window-buffer-change-functions 에 훅 추가
  • org-display-inline-images / org-link-preview / image-mode / doc-view-* / shr-put-image / markdown-overlays--fontify-image 등 11개 advice 설치

이미지가 한 번도 안 뜬 버퍼에서도 매 커맨드마다 호출이 돈다. gg 처럼 명령이 빠르게 반복되는 상황에서 누적된다. 에이전트 프론트엔드는 텍스트 중심이라 비용 대비 이득 없음 → tty-config 에서 제거. 필요 시 M-x kitty-graphics-mode 토글.

xterm-set-window-title

Emacs → 터미널 OSC 0/2 송출로 프레임 타이틀 동기화. tmux/WezTerm 이 이미 탭/윈도우 타이틀을 관리하므로 중복. (setq-default xterm-set-window-title nil) 로 6% 회수.

doom-modeline-github

30분 주기 GitHub 알림 fetch 타이머 + 네트워크 IO. 알림은 magit/ghcli 로 본다. (setq doom-modeline-github nil).

diff-hl-flydiff

after-change-functions 에 1초 debounced 타이머. diff-hl 자체는 유지하고 flydiff 만 off — save / vc-refresh 시 gutter 갱신은 여전히 동작.

auto-revert-check-vc-info

auto-revert-buffers 가 revert 시마다 git status 호출해 modeline VC 상태 갱신. 프로파일 auto-revert-buffers 6s 누적의 주원인. magit/diff-hl 이 대신하므로 off.

hook 타이밍 재정렬 — bonus

기존 tty-config.el 은 top-level 에서 (unless (display-graphic-p) ...) 여러 블록:

  • daemon 로드 시점엔 frame 이 없어 display-graphic-p 가 항상 t → 조건 통과 실패
  • non-daemon 에서도 Doom 이 tty-setup-hook / doom-first-buffer-hook 에서 xterm-mouse-mode, show-paren-mode나중에 켜서 우리가 끈 걸 덮어씀

해결: 모든 TTY 설정을 +tty-setup 단일 함수로 모아 Doom 의 같은 hook 에 :append 로 붙여 뒤에 돈다. OSC 52, display-table vertical-border, VS-16 FE0F 숨김도 같은 경로로 옮겨 daemon + GUI/TTY 혼합 frame 에서 정상.

구조 정리 — config.el 은 loader

config.el 에 섞여있던 better-default 뭉치(completion-at-point-functions, inhibit-compacting-font-caches, vc-follow-symlinks, auto-revert, kill-ring-max, create-lockfiles, xref-search-program) 를 lisp/defaults-config.el 로 추출. config.el 은 module loader 지향으로 정돈.

커밋

  • c52ad7b refactor: tty-config — Doom hook 이후로 TTY 설정 지연
  • f976d7d perf: TTY-first 경량화 + better defaults 모듈 분리

다음 라운드 후보 (today 는 여기까지)

  • celestial-mode-line — 달/해 표시 실사용 여부 확인 후 제거
  • display-time-event-handler — 모드라인 시계 주기 (현재 1m)
  • org-persist--refresh-gc-lock — org-persist 의존 기능 쓰는지 확인
  • url-cookie-write-file — eww 미사용이면 타이머 취소
  • IGC (MPS) 전환 — GC 57% 의 근본 처방

lockfiles 질문에 대한 결론

외부 에이전트가 Emacs 의 .#filename 규약을 따르지 않으므로 create-lockfiles 는 인간↔에이전트 충돌 보호에 무력. 진짜 안전장치는 이미 Emacs 내장:

  • basic-save-bufferverify-visited-file-modtime 체크 (y-or-n-p 경고)
  • inotify + global-auto-revert-mode 로 외부 write 시 즉시 revert (unsaved 아니면)

따라서 create-lockfiles nil 유지.

ghostel 합류 — Emacs 안의 Ghostty (2026-05-07)

vterm 옆에 ghostel 을 실험적 옵션으로 붙였다. ghostel은 libghostty 기반 — 즉 Mitchell Hashimoto의 Ghostty 터미널 코어를 Emacs 안으로 임베딩한 것이다. src/Zig 로 작성됐고, Kitty graphics, OSC 8 hyperlink, OSC 133 prompt navigation 같은 modern terminal 기능을 기본 으로 들고 있다.

vterm은 안정적이지만 정체된 libvterm에 묶여 있다. ghostel은 터미널 에뮬레이터의 미래(Ghostty) 가 Emacs 안에서 돌아가는 첫 순간 이다. 에이전트 하네스 프론트엔드 입장에서 vterm의 정착지가 될 수 있는 후보이므로, 지금부터 길들인다. Doom 기본은 vterm을 baseline으로 두고, ghostel은 M-x ghostel 로 호출.

한글 입력 — 우리가 직접 고쳤다

ghostel 키맵은 [remap self-insert-command] 로 영문 입력을 잡는데, hangul-input-method(self-insert-command 1)함수로 직접 호출 해서 이 remap을 우회한다. 한글이 buffer에는 들어가지만 PTY로는 안 가서, 다음 redraw에 글자가 사라진다 — RET, SPC, Backspace에서 모두.

vterm/eat 등 PTY-mirror 계열 터미널 패키지 공통의 사각지대 였다. vterm은 input-method-function 이 이벤트 리스트를 반환한다는 전제로 돌아가는데, hangul은 buffer를 직접 만지고 nil을 반환한다.

해결: input-method-function 을 ghostel buffer 한정으로 wrap. 원래 IME 호출 전후(point) 위치를 비교해, IME가 buffer에 commit한 텍스트를 잡아 buffer에서 지우고 PTY로 UTF-8 전송. shell echo가 정상 redraw 경로로 다시 채운다. 이벤트를 반환하는 일반 quail 패키지는 point가 안 움직이므로 그대로 통과. +72 lines, 기존 코드 무수정.

junghan0611/ghostel fix/korean-ime-commit 에 푸시. packages.el 은 그동안 fork branch를 가리킴. 2주 실사용 후 upstream PR 예정 — 단순 코드 제안이 아니라 검증 히스토리가 붙은 fix로 가져가려는 것.

상세 분석/디자인은 별도 llmlog: [ghostel 한글 IME commit 경로 fix 디자인]

pi 데몬 개방

config.el 의 터미널 모듈 게이트를 풀었다.

BeforeAfter
(equal server-name "user")(member server-name '("user" "pi"))

agent-server/server 같은 가벼운 보조 데몬은 그대로 제외. pi(분신)와 user GUI에서는 ghostel/vterm 모두 사용 가능.

관련 커밋

리포SHA내용
junghan0611/ghostela3a0511Forward IME-committed text to PTY for Emacs input methods
doomemacs-configad39610feat(term): add ghostel with Korean IME fix, allow user/pi daemons

zmx 라이브 세션 — Emacs가 영속 세션의 클라이언트 (2026-06-15)

ghostel이 “Emacs 안의 터미널”이었다면, zmx는 그 한 칸 위 — 세션을 소유하는 백엔드 다. 노트북을 닫고 SSH가 끊겨도 세션은 살아 있고, Emacs는 그 세션의 클라이언트 로만 붙는다. tmux를 버리고 zmx(neurosnap, libghostty-vt)를 주력 substrate로 옮기면서, 터미널 하네스 프론트엔드 서사의 다음 장이 열렸다.

zmx 철학은 반-tmux다: 윈도우  스플릿은 OS WM이 할 일이고, 터미널 안에 또 다른 WM을 두지 않는다. zmx는 세션 영속성 하나 만 한다 — 평평한(flat) 네임스페이스, session→window→pane 트리 없음. 이 평평함이 설계의 출발점이다.

term-sessions.el — Emacs는 client, zmx가 owner

ArthurHeymans/emacs-term-sessions 를 붙였다. 세션 lifecycle/PTY/history는 전부 zmx 소유, Emacs는 control 동사(list/history/send/run/kill)를 shell-out 하고 attach만 프론트엔드로 연다.

동사의미
term-sessions-consult-sessionconsult 멀티소스 피커 — bashrc zx fzf 피커의 Emacs 판 (SPC j z)
term-sessions-open이름으로 create-or-attach (zmx attach)
term-sessions-listtabulated 세션 목록 UI

핵심은 term-sessions-run아니라는 것이다 — 그건 세션 안에서 일회성 job을 돌려 출력을 잡는 detached.el 스타일이다. 우리가 원한 건 TUI에 인터랙티브 attach 라, term-sessions-open 의 command 인자(zmx attach NAME COMMAND)가 맞다.

ghostel 프론트엔드 — 한글 IME가 여기서 빛난다

frontend를 ghostel 로 고정했다(term-sessions-preferred-frontend 'ghostel). vterm/term은 한글 입력 경로가 없어 처음엔 글자가 안 들어갔다. ghostel은 ghostel-exec 가 버퍼를 ghostel-mode 로 전환 → 우리가 위에서 직접 고친 ghostel-ime-mode 훅이 발동 → 한글 입력이 그대로 산다. 위 “ghostel 합류” 절의 IME commit fix가 정확히 이 자리에서 결실을 본다. evil-ghostel-mode 가 ESC를 PTY로 보내줘서 claude/pi 같은 라이브 TUI에 붙을 때 궁합도 맞다.

zcc/zcx/zagy/zpi → my/zmx-launch (SPC j a)

bashrc의 셸 런처(zmx attach "<prefix>.<basename PWD>" <command>)를 Emacs로 이식했다. 데이터 주도 alist 하나 + 런처 하나:

keyzmx attach모델/하네스
claudecc.<proj> claudeClaude Code
codexcx.<proj> codexCodex
agyagy.<proj> agyAntigravity
pipi.<proj> bash -lc "source $HOME/.bashrc.local; pit5"pi garden gpt-5.5

세션명은 PWD가 아니라 project root basename 기준 — 파일 위치 무관하게 프로젝트당 세션 1개로 안정화된다. SPC j a → harness 고르면 ghostel로 attach.

삽질 결론 — 세 개의 함정

  1. :config 는 늦다. term-sessions-open 은 open 시점에 term-sessions-preferred-frontend 를 읽는데, defcustom 기본값이 term 이다. :config 의 setq는 패키지 로드 라 레이스 → 첫 open이 term으로 떨어진다. :init 으로 옮겨 로드 전 에 박아야 결정적이다.
  2. 기존 버퍼 재사용. term-sessions-open 은 같은 세션 버퍼가 이미 있으면 frontend 무시하고 그걸 재사용한다. 한 번 term으로 뜬 버퍼가 남아 있으면 preferred를 바꿔도 term이 다시 뜬다 → stale 버퍼 kill 필요.
  3. single quote는 안 먹는다. command는 split-string-and-unquote 로 분해되는데 이건 Lisp read 방식이라 큰따옴표만 인식한다. pit5 셸 함수 래퍼를 bash -lc 'source …; pit5' (single)로 썼더니 ' source / pit5' 로 쪼개져 깨졌다. bash -lc "source $HOME/.bashrc.local; pit5" (double)로 고쳐서 통과. $HOME 은 백슬래시 이스케이프되어 내부 bash가 확장한다.

설계 정렬 — fact layer vs flat substrate

[zmx 라이브 세션 활용 방안] 의 결론과 정확히 맞물린다: 계층은 fact layer(entwurf_peers)가 알고, zmx는 평평한 라이브 substrate만 제공한다. zmx 세션 이름 ≡ garden-id 로 두면 분신 제어가 mapping 테이블 없이 원커맨드(attach/history/send/tail)로 떨어진다. 이 Emacs 클라이언트는 그 인간축 — “라이브 세션을 한번에 둘러보고 이동” — 의 GUI 구현이다. 에이전트축 (entwurf-v2 zmx-live transport)은 같은 평평한 zmx 핸들 위에서 다음 차례다.

관련 커밋

리포SHA내용
doomemacs-config83ea3c3feat(term): term-sessions + ghostel frontend + zmx 하네스 런처