Ghostty 기반 GPU 가속 렌더링 + Swift/AppKit 네이티브 + 사이드바 알림. Claude Code·Codex·OpenCode 여러 세션을 동시에 굴리는 개발자가 "지금 어느 에이전트가 내 답을 기다리는지" 한눈에 알기 위해 만들어진 도구.
"여러 AI 에이전트를 병렬로 굴릴 때 한 명도 놓치지 않는 터미널"
cmux는 Ghostty의 터미널 렌더링 엔진(libghostty)을 그대로 가져다 쓴, Swift/AppKit 기반의 네이티브 macOS 터미널이다. 보통 터미널과 비슷하게 생겼지만 결정적인 차이가 있다 — "AI 에이전트가 내 입력을 기다리고 있을 때 사이드바 탭이 빛난다"는 점.
창업자 본인이 Claude Code·Codex 세션을 너무 많이 열어놓고 일하다가 "지금 누가 나를 부르는지 모르겠다"는 고통을 겪고 직접 만들었다. 그래서 tab(탭)·split(분할)·notification(알림)이라는 평범한 기능들이, AI 에이전트 워크플로에 맞게 다시 설계됐다.
트렌딩 #16 · "에이전트 오케스트레이터" 시장의 네이티브 답안
2026년 들어 Claude Code·Codex·OpenCode·Gemini CLI 같은 coding agent(코딩 에이전트)가 폭발적으로 늘었다. 사용자들은 한 화면에 여러 에이전트를 동시에 띄워놓고, 각각 다른 브랜치·다른 작업을 병렬로 굴린다.
이 시장의 빈 자리에 들어가려는 시도가 여럿 있었다. 대부분 Electron이나 Tauri로 만들어진 GUI 오케스트레이터였는데, 성능이 거슬렸고 워크플로를 강제로 제품 흐름에 맞춰야 했다. cmux는 정반대 길을 택한다.
대부분의 "AI 코딩 워크스페이스" 앱은 Electron(웹 기술을 데스크톱으로 감싼 것)으로 만들어져 시작 속도가 느리고 메모리를 많이 먹는다. cmux는 macOS 전용으로 좁히는 대신 네이티브 Swift + AppKit + Metal GPU 렌더링으로 빠른 시작과 낮은 메모리를 가져간다.
Ghostty는 Mitchell Hashimoto(HashiCorp 창업자)가 만든 GPU 가속 터미널로, 2025년 오픈소스 공개 후 가장 빠르게 성장한 터미널이다. cmux는 Ghostty를 fork해 libghostty를 라이브러리로 임베드한다. 사용자 입장에선 기존 ~/.config/ghostty/config(폰트·테마·색상)를 그대로 읽어 쓰므로, Ghostty 사용자라면 마이그레이션 비용이 거의 0이다.
코딩 에이전트가 권한 요청·계획 확인·질문을 하면 해당 탭에 파란 링이 뜨고 사이드바 탭이 빛난다. Cmd+Shift+U로 "가장 최근에 대기 중인 에이전트"로 점프. 사이드바엔 git 브랜치·연결된 PR 상태·작업 디렉토리·열린 포트·최근 알림 텍스트가 워크스페이스마다 표시된다.
창업자 본인의 표현 그대로: "cmux는 솔루션이 아니라 프리미티브다." 터미널·브라우저·알림·워크스페이스·분할·탭·CLI를 제공하지만, "이렇게 일하라"고 강제하지 않는다. 도구를 어떻게 조립할지는 사용자 몫. 이 철학이 GUI 오케스트레이터에 질린 시니어 개발자층의 호응을 얻고 있다.
Swift 85% + TypeScript 웹 백엔드 + Python/Go 보조 도구
cmux는 한 레포 안에 네이티브 macOS 앱과 웹 백엔드가 함께 산다. GitHub languages API에 따르면 Swift가 압도적이지만(약 30MB), Python·TypeScript·Go·Rust·Objective-C까지 두루 쓰는 다언어 프로젝트다.
| 레이어 | 기술 | 역할 |
|---|---|---|
| UI | AppKit + SwiftUI 일부 | 창·사이드바·탭바·분할 패널, Vertical tabs 사이드바 |
| 터미널 렌더링 | libghostty (fork) | GPU(Metal) 가속 터미널, 폰트/리거처/이모지 처리 |
| 브라우저 패널 | WKWebView | 인앱 브라우저(터미널 옆에 띄워서 dev 서버 확인) |
| CLI | Swift ArgumentParser | cmux notify, cmux feed, cmux hooks setup 등 |
| 패키지 관리 | Swift Package Manager + Xcode | 모노레포 안 70개 이상의 Swift Package |
| 업데이트 | Sparkle | 자동 업데이트 (한 번만 받으면 됨) |
| FFI | Rust (CommandPaletteNucleoFFI) | 커맨드 팔레트 fuzzy 검색 (Nucleo 매처) |
ghostty.h)를 통해 외부 앱이 "터미널 surface 하나" 단위로 임베드할 수 있다. cmux는 자체 윈도우/탭/사이드바를 가진 채로 각 패널 안에 libghostty surface를 끼워 넣는다.cmux는 cmux.com(랜딩)과 cmux.dev/docs(문서)를 위한 풀스택 Next.js 앱도 같이 운영한다. 흥미로운 점은 Effect (effect-ts)를 채택했다는 것 — 함수형 에러 처리·동시성·의존성 주입을 한 번에 처리하는 TypeScript 런타임이다.
| 분류 | 패키지 | 역할 |
|---|---|---|
| 프레임워크 | Next.js 16 + React 19 | App Router 기반 풀스택 |
| 런타임 | Bun | Node 대신 Bun으로 빌드·테스트 |
| DB ORM | Drizzle ORM 1.0 beta | 타입 안전한 SQL |
| DB | PostgreSQL (AWS RDS, IAM 인증) | 로컬은 docker-compose, 프로덕션은 RDS |
| 인증 | Stackframe (stack-auth) | 오픈소스 Clerk 대안, Swift SDK도 vendor화 |
| VM 샌드박스 | e2b + freestyle | cmux Cloud VM (Founder's Edition에 포함) |
| i18n | next-intl | README가 18개 언어로 번역됨 |
| 이메일 | Resend | 알림·인증 메일 |
| 호스팅 | Vercel | OIDC로 AWS IAM 자격증명 발급 |
| 관측 | OpenTelemetry + PostHog | 분산 트레이싱 + 프로덕트 분석 |
tests/, tests_v2/, scripts/).daemon/remote — Cloud VM에서 cmux를 원격으로 띄우는 리모트 데몬.cmux feed tui)."하나의 socket이 모든 것을 연결한다"
cmux의 모든 외부 통합(CLI 명령·에이전트 훅·이벤트 스트림·Feed 권한 요청)은 유닉스 도메인 소켓 하나로 모인다. 그래서 외부 도구는 cmux 앱이 떠 있을 때 같은 소켓에 연결하면 워크스페이스를 만들고, 패널을 분할하고, 키 입력을 보내고, 브라우저를 자동화할 수 있다.
cmux의 모든 자동화 API는 5단계 계층을 일관되게 사용한다. 이 용어가 docs/agent-browser-port-spec.md에 명시돼 있다.
| 이름 | 의미 | 비유 |
|---|---|---|
window | macOS 네이티브 윈도우 | 크롬의 "윈도우" |
workspace | 윈도우 안의 사이드바 항목 (UI에선 "tab") | 크롬의 "탭 그룹" |
pane | workspace 안의 분할 영역 | tmux의 "pane" |
surface | pane 안의 탭 (terminal 또는 browser) | iTerm의 "tab" |
panel | 내부 구현 용어, 외부 API는 surface로 표준화 | 레거시 별칭 |
window는 빌딩, workspace는 층, pane은 한 층 안의 사무실 칸막이, surface는 칸막이 안의 책상이다.
에이전트가 작업할 때는 항상 "어느 책상에서 일하는지(surface_id)"를 알아야 하므로, surface가 모든 자동화의 1급 시민이다.
cmux 알림의 핵심은 VT 터미널 escape sequence를 사용한다는 것. 에이전트(예: Claude Code)가 표준 출력으로 OSC 9(macOS 알림) 또는 OSC 777(VTE 알림)을 보내면 cmux가 가로채서 사이드바 탭에 파란 링을 띄운다.
ESC ] N ; payload BEL 형식으로 "터미널에게 OS 수준의 일을 시키는" 명령이다. OSC 9는 iTerm2가 만든 사실상의 macOS 알림 표준이고, OSC 777은 VTE 기반 리눅스 터미널의 표준. cmux는 둘 다 파싱한다.이게 똑똑한 이유 — 에이전트는 cmux를 알 필요가 없다. Claude Code/Codex가 평소처럼 OSC를 쏘기만 하면 자동으로 사이드바 알림이 뜬다. cmux를 모르고도 호환된다.
에이전트가 권한을 요청할 때(예: 셸 실행, 파일 쓰기) 보통 터미널 안에서 yes/no를 받는다. cmux는 Feed라는 별도 사이드바를 두고, 거기서 키보드만으로 권한·계획·질문을 처리할 수 있게 한다.
이게 human-in-the-loop(사람이 끼어드는 루프)를 깔끔하게 처리하는 패턴이다. 에이전트는 권한 요청을 보내고 최대 120초까지 대기한다. 사용자가 응답하면 hook은 그 결과를 stdout으로 돌려주고, 에이전트는 작업을 이어간다.
cmux의 모든 상태 변화(workspace 생성·pane 분할·notification·feed·agent hook)는 monotonic seq + boot_id로 식별되는 이벤트로 발행된다. 두 가지 경로:
events.stream 호출 후 JSONL 라인을 계속 받는다. 재연결 시 after_seq로 정확히 끊긴 지점부터 다시 받음.~/.cmuxterm/events.jsonl에 추가 전용 로그. 도구 캐치업·감사용.cmux 재시작 시 boot_id가 바뀌므로 클라이언트는 끊긴 커서를 "resume gap"으로 인식하고 다시 동기화할 수 있다.
각 에이전트마다 session hook이 실행되면서 ~/.cmuxterm/<agent>-hook-sessions.json에 세션 ID를 기록한다. 앱 재시작 시 cmux는 그 ID를 읽어 각 에이전트의 네이티브 resume 명령을 자동 실행한다.
| 에이전트 | 설치 파일 | resume 명령 |
|---|---|---|
| Claude Code | wrapper-injected settings | claude --resume <id> |
| Codex | ~/.codex/hooks.json | codex resume <id> |
| OpenCode | ~/.config/opencode/plugins/cmux-session.js | opencode --session <id> |
| Gemini | ~/.gemini/settings.json | gemini --resume <id> |
| Cursor CLI | ~/.cursor/hooks.json | cursor-agent --resume <id> |
| Amp | ~/.config/amp/plugins/cmux-session.ts | amp threads continue <id> |
중요한 보안 처리 — sanitizer가 prompt·자격증명·이전 세션 selector·noninteractive 플래그를 제거한다. 그래서 복원이 새 작업을 시작하거나 시크릿을 흘리지 않고 정확히 같은 세션을 재개한다.
모노레포 — 네이티브 앱 + 웹 백엔드 + CLI + 데몬 + Ghostty fork
주목할 만한 디자인:
cmux 코드를 읽으며 배울 수 있는 것들
SwiftUI만 알고 있다면 cmux 같은 복잡한 데스크톱 앱은 만들기 힘들다. AppKit은 NSWindow·NSView·NSWindowController·NSResponder chain 같은 OS X 시절의 강력한 저수준 API를 제공한다. cmux는 사이드바·탭 드래그·창 분할·다중 디스플레이 처리·VoiceOver 접근성까지 AppKit의 진면목을 보여준다.
실습 아이디어: "vertical tabs를 가진 미니 텍스트 에디터" — NSSplitViewController + NSTableView 사이드바로 시작.
cmux-Bridging-Header.h와 ghostty.h를 통해 Zig로 작성된 라이브러리를 Swift에서 호출한다. 이건 시스템 프로그래밍과 앱 개발의 경계가 모호한 영역의 학습 자료다.
실습 아이디어: SQLite C API를 Swift에서 직접 호출해 보기. 다음 단계로 libgit2.
cmux의 모든 외부 통합은 ~/.cmuxterm/socket 한 곳을 통한다. 이런 단일 소켓 IPC 패턴은 tmux·MPV·Docker daemon이 다 쓰는 검증된 패턴이다.
실습 아이디어: Python으로 asyncio.start_unix_server() 기반 미니 서버 만들기. request_id·method·params·result 4필드 JSON-RPC만 구현해 보면 cmux 소켓 프로토콜이 이해된다.
cmux는 Claude/Codex/OpenCode 등 12+ 에이전트를 통합하는데, 그들의 코드를 수정하지 않는다. 대신 각 에이전트의 공식 hook 설정 파일에 cmux 명령을 끼워 넣는다. 이건 "남의 도구와 잘 어울려 살기"의 좋은 예다.
실습 아이디어: 본인이 자주 쓰는 CLI 도구의 "post-execution hook"을 찾아서, 끝나면 macOS 알림을 띄우는 wrapper 만들기.
docs/ghostty-fork.md는 fork 운영의 모범 사례다. 모든 패치가 upstream 커밋 해시·해당 파일·요약·rebase 충돌 메모와 함께 나열돼 있고, fork SHA가 git submodule + 체크섬 파일로 pin된다.
실습 아이디어: 본인이 자주 쓰는 오픈소스를 fork해서, "upstream으로 PR 보낼 commit"과 "로컬에만 남길 commit"을 분리해 관리해 보기.
web/ 백엔드는 RxJS·Promise·async/await 대신 effect 라이브러리를 쓴다. Effect는 자바의 ZIO나 Cats Effect와 비슷한 "타입 안전한 효과 시스템"으로, 에러·동시성·의존성을 한 시스템에서 다룬다.
실습 아이디어: fetch + JSON.parse + error handling을 Effect로 다시 써 보기. 처음에는 무겁게 느껴지지만 큰 시스템에서 진가가 드러난다.
web/ 백엔드는 Drizzle 1.0 beta에 AWS RDS IAM 토큰 발급(@aws-sdk/rds-signer)을 통합한다. 비밀번호 대신 OIDC로 발급된 IAM 토큰으로 DB에 접속하는 모던 패턴.
실습 아이디어: Postgres + Drizzle ORM 미니 프로젝트 만들고, 거기에 IAM 토큰 인증을 얹기.
cmux는 vercel-labs/agent-browser의 명령 표면을 WKWebView 위로 포팅했다. accessibility tree 스냅샷·element ref·click·fill·evaluate JS — LLM이 안정된 핸들로 브라우저를 조작할 수 있게 한다.
실습 아이디어: Playwright나 Puppeteer로 같은 기능을 만들어 보기. cmux가 왜 native WKWebView를 골랐는지 비교할 수 있다.
macOS 14+ 권장 · Apple Silicon 또는 Intel
cmux-macos.dmg — Sparkle 자동 업데이트brew tap manaflow-ai/cmux && brew install --cask cmuxinstall-rust-ci.sh 참고)./scripts/setup.sh — submodule init + GhosttyKit 빌드./scripts/reload.sh --tag <name> — Debug 빌드 후 cmd-click 가능한 path 출력난이도별 실습 — 처음 만지는 사람부터 컨트리뷰터 지망생까지
brew로 cmux 설치 → claude 실행 → 긴 작업 시키기(예: "이 디렉토리의 모든 파일을 읽고 요약"). 작업이 완료되거나 권한 요청이 뜨면 사이드바 탭에 파란 링이 들어오는지 확인. Cmd+Shift+U로 점프되는지 확인.
에이전트 없이도 cmux 알림을 띄울 수 있다. echo로 OSC escape sequence를 쏘거나 cmux notify CLI를 쓴다. 본인의 긴 빌드 명령 끝에 후크로 붙여 보기.
cmux events로 이벤트 스트림 처리cmux 상태 변화를 JSONL로 받아 자기만의 대시보드/메트릭을 만들어 보기. 예: "오늘 내가 워크스페이스를 몇 개 만들었는지"·"AI 에이전트가 권한 요청한 횟수" 같은 통계 추출.
cmux의 브라우저 API로 dev 서버를 자동 확인하는 스크립트 만들기. 예: 코드 수정 → Vite dev server 리로드 대기 → 페이지 스크린샷 → accessibility tree 덤프 → 에이전트에 피드백.
docs/agent-browser-port-spec.md를 읽고 system.identify·page.evaluate·page.click 메서드를 조합한다.
아직 cmux가 통합 안 한 에이전트(예: 새로 나온 코딩 CLI)에 대한 hook 통합을 추가해 PR 보내기. Sources/CMUXCLI+*HookDefinitions.swift 패턴을 보고 동일한 구조로 구현. docs/agent-hooks.md에 표 한 줄 추가.
핵심은 (1) binary 존재 체크, (2) hook 설정 파일 경로, (3) session resume 명령, (4) Feed bridge 매핑, (5) sanitizer 규칙.
cmux를 읽고 만들 수 있게 되려면 — 12주 계획
| 주차 | 주제 | 학습 자료 / 실습 |
|---|---|---|
| 1~2 | Swift 기초 + Swift Concurrency | Apple "The Swift Programming Language" 책, async/await·actor·@MainActor 챕터까지 |
| 3~4 | AppKit 기본 | Hacking with macOS 책. NSWindow / NSViewController / NSResponder chain / NSTableView 데이터소스 |
| 5 | 터미널 작동 원리 | pty(pseudo-terminal), VT100 escape sequence, OSC/CSI 명령. Ghostty 블로그 글 + xterm.js docs 읽기 |
| 6 | 유닉스 도메인 소켓 + JSON-RPC | tmux의 client/server 모델 분석. man tmux + tmux 소스에서 cmd-*.c 패턴 보기 |
| 7 | C 라이브러리를 Swift에서 호출 | Bridging Header, UnsafePointer, OpaquePointer. libsqlite3로 미니 SQL 클라이언트 |
| 8 | WebExtensions vs WKWebView 자동화 | WKUserContentController, message handler, evaluateJavaScript. Playwright 비교 분석 |
| 9 | Effect TypeScript + Drizzle | effect.website 튜토리얼. 미니 fetch wrapper → 더 복잡한 effect Layer |
| 10 | 오픈소스 fork 운영 | cmux의 docs/ghostty-fork.md 정독 + 본인 프로젝트에 적용. git submodule, prebuilt artifact pin |
| 11 | 모노레포 빌드 (Swift PM) | Package.swift 작성, target dependency graph, resource bundling, xcframework |
| 12 | cmux 코드 리딩 + PR 만들기 | 이슈 리스트(2123개)에서 "good first issue" 라벨 찾기. CONTRIBUTING.md 따라 환경 세팅 |
cmux 코드와 문서에 자주 등장하는 용어
manaflow-ai/ghostty)를 submodule로 임베드한다.ghostty.h)로 노출돼 cmux 같은 외부 호스트 앱이 임베드할 수 있다.surface_id 단위로 동작한다.공식 자료 + 학습에 도움 되는 외부 리소스
docs/cli-contract.md, docs/notifications.md, docs/agent-hooks.md, docs/feed.md, docs/events.md, docs/ghostty-fork.md, docs/agent-browser-port-spec.mdCmd+Shift+U로 점프해 보기. 평소 "어디서 알림 떴지?" 짜증이 사라지는지 확인.cmux notify 한 줄이면 충분. cmux 없는 환경 대비 fallback도 1줄 추가하면 끝.+Extension 분리 방식으로 거대 파일을 어떻게 다루는지 학습.