Architecture
Overview
ccmux is ~2,800 lines of Rust, organized into 6 modules:
src/
├── main.rs # Entry point, event loop, panic hook
├── app.rs # Workspace/tab state, layout tree, input handling
├── pane.rs # PTY management, vt100 emulation, shell detection
├── ui.rs # ratatui rendering, theme, layout
├── filetree.rs # File tree scanning, navigation
└── preview.rs # File preview with syntax highlightingTerminal Emulation
ccmux uses the vt100 crate for terminal emulation — not simple ANSI stripping. This is critical because Claude Code uses complex terminal features (cursor movement, colors, alternate screen buffer, spinners).
PTY Reader Thread Main Thread
┌──────────────┐ ┌──────────────┐
│ read(PTY) │ │ poll events │
│ ↓ │ mpsc │ ↓ │
│ vt100.parse()│ ──────→ │ check dirty │
│ ↓ │ channel │ ↓ │
│ send event │ │ render UI │
└──────────────┘ └──────────────┘Each pane has its own reader thread that reads from the PTY, feeds bytes into a vt100::Parser, and notifies the main thread via an mpsc channel.
Layout Tree
Pane layout is represented as a binary tree:
enum LayoutNode {
Leaf { pane_id: usize },
Split {
direction: Vertical | Horizontal,
ratio: f32, // 0.0..1.0
first: Box<LayoutNode>,
second: Box<LayoutNode>,
},
}This naturally supports recursive splitting and makes layout calculation straightforward. The ratio field allows mouse-drag resizing of pane borders.
Rendering Pipeline
- Dirty flag check — Only render when something changed (PTY output, key press, mouse event, resize)
- Layout calculation — Compute
Rectfor each pane from the binary tree - PTY resize — Update PTY size only if it changed (cached)
- Cell-by-cell rendering — Read vt100 screen buffer, map to ratatui cells with zero heap allocation
- Selection overlay — Apply blue highlight on selected text
Performance
- Binary size: ~2 MB
- Startup time: ~0.5 seconds
- Idle CPU: ~0% (dirty-flag diff rendering)
- Cell rendering: zero heap allocation
- npm package: 1.9 KB (binary downloaded on first install)
- Scrollback: 10,000 lines per pane (~1 MB/pane)
OSC Detection
ccmux injects PROMPT_COMMAND into bash to emit OSC 7 (current directory notification) after each command. The PTY reader thread scans for these sequences:
- OSC 7 (
\x1b]7;file://HOST/PATH\x07) → Updates file tree and tab name - OSC 0/2 (
\x1b]0;TITLE\x07) → Detects Claude Code running (title contains “claude”)
Dependencies
| Crate | Purpose |
|---|---|
ratatui + crossterm | TUI framework + terminal backend |
portable-pty | Cross-platform PTY (ConPTY on Windows) |
vt100 | Terminal emulation |
syntect | Syntax highlighting |
arboard | Clipboard access |
unicode-width | CJK character width calculation |
anyhow | Error handling |
Security
- OOM protection — File preview limited to 10MB, binary detection reads only 8KB
- Symlink guard — File tree skips symbolic links
- Mutex poison recovery — Uses
unwrap_or_else(|e| e.into_inner()) - Panic hook — Restores terminal state on crash
- Resource limits — Max 16 panes, 500 entries per directory