winmux

A native Windows terminal multiplexer built in Rust, designed for AI agent orchestration. Think tmux for Windows, with first-class support for programmatic pane control, structured output capture, and pattern-based synchronization.

Overview

  • Language: Rust
  • Repo: peteretelej/winmux
  • Install: Download from Releases or cargo install --git https://github.com/peteretelej/winmux winmux-client
  • Status: experimental (v0.0.1), requires Windows 10 1809+

Architecture

A six-crate workspace organized as a client-server system communicating over Named Pipes with MessagePack serialization.

Crate hierarchy:

  • winmux-client - The winmux binary. Uses clap for CLI parsing and dispatches commands to the server. Also provides tmux-compatible command aliases. Depends on all other crates
  • winmux-server - Server library and binary. The core of the system, with platform-split modules:
    • pty.rs / pty_unix.rs - ConPTY wrapper (Windows) or Unix PTY. Creates pipe pairs, a pseudo console, and spawns a child process. A dedicated OS thread reads output from the ConPTY pipe and sends it over an mpsc channel
    • screen.rs - VT terminal state machine using the vte crate. Maintains a character grid, cursor position, text attributes, scrollback buffer, and alternate screen per pane. Split into ScreenState (implements vte::Perform) and Screen (owns both parser and state) to satisfy the borrow checker
    • session.rs - The SessionManager holds the Session > Window > Pane hierarchy. Uses Arc<Mutex<...>> for concurrent access from async handlers. Defines a PtyBackend trait for testability (mock injection). Pane IDs are globally unique (%0, %1, …) via an AtomicU32 counter
    • ipc.rs / ipc_unix.rs - Named Pipe server (Windows) or Unix socket listener that accepts client connections, reads framed MessagePack requests, and dispatches to ipc_dispatch.rs
    • ipc_dispatch.rs - Routes Request variants to the appropriate handler, producing Response values
    • orchestration.rs - AI-specific commands: handle_wait() subscribes to pane screen updates and polls regex matches against screen content with configurable timeout, handle_exec() atomically sends a command and captures output
    • security.rs / security_unix.rs - DACL-based pipe ACL restricting access to the current user
    • layout.rs, layout_dsl.rs, layout_save.rs - Window layout system (tiled, horizontal, vertical, custom DSL)
    • template.rs - Session templates for predefined layouts
    • attach.rs - Visual TUI attach mode, streaming screen snapshots to the client
  • winmux-protocol - Shared types for IPC. Defines Request and Response enums (30+ variants), ServerPush/ClientInput for attach mode, plus domain types (PaneInfo, CaptureResult, CursorPos, ScreenCell, etc.). Uses rmp-serde for MessagePack framing with length-prefixed messages
  • winmux-common - Shared paths, config loading (WinmuxConfig), and template definitions
  • winmux-sdk - Async Rust SDK for controlling winmux programmatically from other Rust code, built on winmux-protocol
  • winmux-tui - Ratatui-based TUI client for the visual attach mode, with crossterm for terminal I/O, copy mode, mouse support, and theming

Data flow for a command like winmux exec -t %0 "cargo test" --wait --capture:

  1. Client parses args (clap), builds a Request::Exec message
  2. Serializes with MessagePack, sends over Named Pipe to server
  3. Server deserializes in ipc_dispatch, calls handle_exec() in orchestration.rs
  4. handle_exec sends keystrokes to the pane’s PTY backend, subscribes to screen updates, polls the VT screen state against the prompt pattern, captures the parsed screen content
  5. Response with CaptureResult (lines, cursor, dimensions, process info) sent back over the pipe

Key Design Decisions

Single binary, dual mode: winmux.exe acts as both client and server. On first use, the client spawns a detached server process. This avoids requiring a separate service installation and makes the UX similar to tmux.

ConPTY + VT parser: Rather than scraping raw bytes, each pane runs through a full VT state machine (vte crate) that maintains a grid of cells with attributes. capture returns the parsed screen state, not terminal escape sequences. This is what makes structured capture reliable for AI agents.

Named Pipe IPC with MessagePack: Windows Named Pipes provide the fastest local IPC on Windows with built-in security (DACL). MessagePack is used over JSON for compactness and speed, especially important for screen snapshot streaming in attach mode. Length-prefixed framing ensures message boundaries.

Session > Window > Pane hierarchy: Matches tmux’s model exactly, making it familiar. Pane IDs are globally unique (%0, %1, …) so any pane can be targeted directly without specifying its session/window. This simplifies agent workflows.

PtyBackend trait: The PTY interface is abstracted behind a trait, allowing mock injection for testing without actual ConPTY instances. The PtyFactory type alias lets tests supply custom backends.

AI orchestration primitives: The wait, exec, capture, and subscribe commands are designed specifically for AI agents. wait --pattern blocks until a regex matches in the screen content (checking on every screen update). exec --wait --capture atomically sends a command, waits for the prompt, and returns structured output. subscribe streams NDJSON events in real time.

Job Objects for cleanup: Each pane’s process tree is managed through a Windows Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, ensuring child processes are killed when the pane is closed. No orphaned processes.

Development

cargo build --release --workspace
cargo test --workspace

# Run integration tests (requires a running server)
cargo test -p tests-integration