-
Notifications
You must be signed in to change notification settings - Fork 0
Why pytmux on Windows
이 문서는 "왜 굳이 또 하나의 터미널 멀티플렉서를 만들었나, 그것도 Windows를 1급 대상으로?"에 대한 솔직한 엔지니어링 근거입니다. 결론부터 말하면: tmux는 POSIX/PTY 가정 위에 세워져 있어 네이티브 Windows에서는 돌지 않고, WSL/Cygwin이라는 호환 레이어를 깔아야 합니다. pytmux는 그 레이어 없이 네이티브 Windows의 ConPTY를 직접 겨냥하는 단일 Python/Textual 코드베이스로 그 간극을 메웁니다.
tmux는 본질적으로 POSIX 프로그램입니다. 핵심 동작들이 다음 같은 Unix 전용 기능에 직접 묶여 있습니다.
-
PTY:
pty/forkpty로 의사 터미널을 만들고fcntl/termios의ioctl(예:TIOCSWINSZ)로 윈도우 크기를 조절합니다. -
프로세스 모델:
fork()+exec()로 셸을 띄우고,setsid로 데몬을 분리하며,killpg/프로세스 그룹/시그널(SIGHUP·SIGKILL 등)로 자식 트리를 다룹니다. -
IPC: 서버↔클라이언트를
AF_UNIX(유닉스 도메인 소켓)로 잇습니다. -
포그라운드 프로세스 그룹:
tcgetpgrp등으로 어떤 프로그램이 전경인지 파악합니다.
Windows에는 fork도, AF_UNIX 중심 모델도, 시그널의 같은 의미도 없습니다.
그래서 tmux를 Windows에서 쓰려면 거의 항상 WSL·Cygwin·MSYS2 같은 POSIX 호환
레이어 위에서 돌립니다. 이는 곧 별도 리눅스 배포판/런타임 설치, 파일시스템·
경로·줄바꿈 경계 문제, 네이티브 Windows 프로그램과의 통합 마찰을 떠안는다는
뜻입니다. "그냥 깔아서 바로"가 안 됩니다.
같은 벽은 pytmux 초기에도 그대로 나타났습니다. 네이티브 Windows Python에서 그냥 실행하면
wcwidth정도는 설치로 풀리지만, 곧바로ModuleNotFoundError: No module named 'fcntl'에서 막힙니다 — 여기서부터는 "패키지 설치"가 아니라 **포팅(부분 재작성)**의 영역입니다.
Windows 10(1809+)부터는 의사 콘솔 API인 ConPTY(Pseudo Console)가 표준으로 제공됩니다. 핵심 개념은 이렇습니다.
-
HPCON:
CreatePseudoConsole로 만드는 의사 콘솔 핸들. Unix의 PTY master에 대응하는 자리이며, 입력/출력 파이프 한 쌍과 묶입니다. - conhost 모델: 자식 프로그램(셸 등)은 conhost가 관리하는 콘솔에 붙고, VT 시퀀스로 출력합니다. 멀티플렉서는 그 출력 파이프를 읽어 자기 화면 모델로 렌더링하고, 입력 파이프로 키 입력을 흘려보냅니다.
- 윈도우 크기 조절은
ioctl대신ResizePseudoConsole로, 프로세스 종료는 시그널 대신TerminateProcess/Job 오브젝트(자식 트리 정리)로 합니다.
즉 Windows에는 터미널 멀티플렉싱에 필요한 1급 메커니즘이 이미 OS에 있습니다. 부족한 건 그걸 tmux 스타일로 엮어 주는 멀티플렉서일 뿐입니다.
pytmux는 WSL/Cygwin 없이 네이티브 Windows를 직접 지원합니다. 핵심 설계는 세 가지 플랫폼 추상 레이어로 압축됩니다.
- 단일 크로스플랫폼 코드베이스: 화면 모델·VT 파싱·레이아웃·UI(Textual)는 OS에 의존하지 않는 순수 로직이라 macOS·Linux·Windows에서 그대로 공유됩니다. OS 차이는 얇은 백엔드 레이어 뒤로 격리됩니다.
-
ConPTY 백엔드: PTY 계층을 백엔드로 분리해, POSIX에서는
pty.fork를, Windows에서는 ConPTY를 씁니다. Windows 추가 의존성은pywinpty하나 (pip install pywinpty)이며, 검증된 ConPTY 래퍼입니다. -
이벤트 루프 적응: Windows asyncio의 기본 Proactor 루프는 임의 파이프에
add_reader를 못 씁니다. 그래서 클라이언트 통신은 TCP 루프백으로, ConPTY 출력 읽기는 패널마다 리더 스레드가 블로킹 read 후 루프에 안전하게 넘기는 펌프 구조로 풀었습니다. -
IPC 적응:
AF_UNIX대신 TCP 루프백(127.0.0.1:랜덤포트) + 포트 번호를 사용자 로컬 데이터 경로의 작은 파일에 기록하는 방식으로 서버↔클라이언트를 잇습니다. -
데몬/프로세스 적응:
fork+setsid대신 분리 기동(콘솔 창 없이 백그라운드로 서버 실행),killpg대신TerminateProcess/Job 오브젝트로 자식 트리를 정리합니다.
pytmux의 강점 하나는 셸·실행 중 프로그램·스크롤백을 살린 채 서버 코드만 새 이미지로 교체하는 작업 보존 재시작입니다. POSIX에서는 제자리 re-exec로 충분하지만, Windows에서 ConPTY(HPCON)는 그걸 만든 프로세스가 사라지면 함께 무너집니다. 그래서 Windows에서는 별도 프로세스인 pty-host가 ConPTY를 영구 소유하도록 분리했습니다. 서버 프로세스가 재시작돼도 pty-host가 HPCON을 계속 쥐고 있어, 그 위의 셸/프로그램이 끊기지 않습니다. (롤백이 필요하면 환경 변수로 끌 수 있게 두었습니다.)
네이티브 Windows를 직접 겨냥한 대가로, POSIX에 직접 대응물이 없는 일부 기능은 크래시 없이 우아하게 폴백하되 약화됩니다.
- 패널 cwd 상속: 새 분할이 현재 디렉터리에서 시작하는 기능은 Windows에 간단한 per-process cwd 조회가 없어 폴백(서버 cwd에서 시작)합니다.
- fg 명령 기반 탭 자동이름·ssh 감지: ConPTY가 포그라운드 프로세스 그룹을 노출하지 않아 고정 탭 이름으로 폴백합니다.
-
시그널 의미: graceful 종료 동작이
TerminateProcess계열로 대체되며 미세하게 다릅니다. - 콘솔 코드페이지/UTF-8: 일부 콘솔 환경에서 출력 인코딩을 맞춰야 할 수 있습니다.
그리고 Windows 콘솔 특유의 입력 아티팩트(예: 수정자 단독 키다운에서 오는 널 문자)는 별도 가드로 흡수했습니다. 이런 항목들은 "기능이 빠질 뿐 서버는 정상 동작" 원칙으로 처리됩니다.
tmux를 어떤 식으로든 래핑하는 길도 생각할 수 있습니다. 하지만 그 길은 결국 Windows에 POSIX 호환 레이어를 다시 강제합니다(WSL/Cygwin). 그러면 "네이티브 Windows에서 의존성 추가만으로 바로"라는 목표가 무너지고, 두 세계(호환 레이어 안의 tmux와 바깥의 네이티브 프로그램) 사이의 경계 마찰을 항구적으로 떠안습니다.
대신 단일 Python/Textual 구현은 다음을 줍니다.
- 하나의 코드베이스, 세 OS: 렌더·UI·플러그인 로직이 OS 무관하게 공유되고, 차이는 얇은 백엔드 뒤로만 들어갑니다. 기능을 OS마다 따로 구현하지 않습니다.
- 마우스·메뉴 1급 UX: tmux 명령을 외우지 않아도 메뉴와 명령 프롬프트로 거의 모든 동작을 할 수 있게 처음부터 설계했습니다 — 이건 tmux를 래핑해선 못 얻습니다.
-
의존성 최소: Python + Textual + pyte + wcwidth, Windows에선
pywinpty하나 추가. POSIX 호환 레이어 설치가 필요 없습니다. -
검증 가능성: 헤드리스로 전 스위트를 돌려 회귀를 잡고, Windows ConPTY 경로는
클라우드 CI(
windows-latest)에서 자동 검증합니다 — 바이트 왕복(CJK 포함)과 자식 종료→EOF 감지까지 매 푸시마다 확인됩니다.
검토했지만, 불가능하고 동시에 불필요합니다. Windows 컨테이너는 Windows
커널을 공유해야 해서 비-Windows 호스트(특히 Apple Silicon arm64)에서는 원리적으로
못 돌고, Windows 호스트가 있어도 컨테이너는 헤드리스라 인터랙티브 콘솔 왕복을
보장하지 못합니다. 우리가 자동화하고 싶었던 ConPTY 검증은 이미 클라우드 CI의
windows-latest가 실측 PASS로 수행하고 있어, 컨테이너 경로는 이점이 없습니다.
실 Claude TUI 같은 "사람이 보는" 항목만 실 기기 라이브 검증으로 남깁니다.
소개 · 사용
- Project-Overview
- User-Manual
- Screenshots
- Settings-Popup
- Single-Session-Model
- Tmux-Feature-Comparison
플러그인
Claude Code 플러그인
- Claude-Code-Plugins
- Dev-Guide-claude-code
- Dev-Guide-claude-token-usage-view
- Dev-Guide-claude-prompt-history
- Dev-Guide-claude-resume
- Dev-Guide-claude-disable-feedback
플랫폼 · 성능
품질 · 보안
리뷰·분석 보고서
연혁
기여