Agent-readable wiki
tmux and cmux Repository Comparison Wiki
A fast, source-anchored comparison of tmux as a portable terminal multiplexer daemon and cmux as a native macOS terminal, browser, and agent workflow shell. The structure emphasizes reusable design ideas, BYOC/BYOK-friendly automation surfaces, and differences that matter when porting concepts between repositories.
Pages
- Comparison FrameThe comparison lens: tmux optimizes a cross-platform C daemon and terminal protocol core, while cmux builds a macOS-native orchestration surface around terminals, browser panes, notifications, and agent hooks. No local STRATEGY.md or docs/solutions context was present, so repository code and tests are the source of truth.
- Platform & Build BoundariesHow each repository encodes portability: tmux uses autotools, feature checks, compat sources, and C dependencies; cmux uses Xcode targets, Swift packages, bundled app resources, and a separate web backend surface.
- Lifecycle & Socket ControlContrasts tmux's client-server fork, lock, imsg, and Unix socket lifecycle with cmux's in-app socket listener, access modes, CLI client behavior, and local automation guardrails.
- Panes, Workspaces & LayoutCompares tmux's sessions, windows, panes, split commands, and layout tree mechanics with cmux's workspaces, panels, Bonsplit-backed layout state, terminal panels, and persisted surface snapshots.
- Command & Config SurfacesShows how tmux exposes a grammar, command queue, options, key bindings, and config loading, while cmux layers JSONC project config, command execution, Ghostty config compatibility, and CLI configuration commands.
- Agent Notifications & HooksExplains the shift from tmux's terminal alerts and control notifications to cmux's agent-aware notification queue, unread state, CLI hook definitions, and extensible hook formats for multiple coding agents.
- Browser Automation vs Terminal ControlContrasts tmux's terminal-only control and capture model with cmux's browser pane automation, WebKit-backed panels, screenshots, profiles, and socket-addressable browser actions for local dev workflows.
- Remote SSH & Provider NeutralityCompares tmux's shell, job, and spawn portability with cmux's SSH workspace, remote PTY attach, loopback routing, and daemon bridge design. The portable lesson is to keep orchestration file, socket, and repository based so BYOC/BYOK workflows do not depend on one model provider or hosted connector.
- Regression & Fuzz BoundariesMaps the quality signals that make each project maintainable: tmux has shell regressions and fuzzers around command parsing, input, style, and formats; cmux has Swift unit and UI tests around sockets, browser panes, sessions, hooks, and app regressions.
- Comparison VerdictThe closing synthesis: tmux is strongest as a small, portable, protocol-deep multiplexer; cmux is strongest as a native agent-workflow shell that combines terminal, browser, notifications, remote access, and local automation. The most portable ideas are explicit socket contracts, source-backed command/config schemas, provider-neutral hooks, and focused regression boundaries.
Complete Markdown
# tmux and cmux Repository Comparison Wiki
> A fast, source-anchored comparison of tmux as a portable terminal multiplexer daemon and cmux as a native macOS terminal, browser, and agent workflow shell. The structure emphasizes reusable design ideas, BYOC/BYOK-friendly automation surfaces, and differences that matter when porting concepts between repositories.
## Context Links
- [Agent index](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/llms.txt)
- [Human interactive wiki](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc)
- [GitHub repository](https://github.com/tmux/tmux)
## Repository Metadata
- Repository: tmux/tmux-with-manaflow-ai-cmux
- Generated: 2026-05-24T19:18:32.447Z
- Updated: 2026-05-24T19:31:16.130Z
- Runtime: Codex CLI
- Format: Repo Comparison
- Pages: 10
## Page Index
- 01. [Comparison Frame](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/01-comparison-frame.md) - The comparison lens: tmux optimizes a cross-platform C daemon and terminal protocol core, while cmux builds a macOS-native orchestration surface around terminals, browser panes, notifications, and agent hooks. No local STRATEGY.md or docs/solutions context was present, so repository code and tests are the source of truth.
- 02. [Platform & Build Boundaries](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/02-platform-build-boundaries.md) - How each repository encodes portability: tmux uses autotools, feature checks, compat sources, and C dependencies; cmux uses Xcode targets, Swift packages, bundled app resources, and a separate web backend surface.
- 03. [Lifecycle & Socket Control](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/03-lifecycle-socket-control.md) - Contrasts tmux's client-server fork, lock, imsg, and Unix socket lifecycle with cmux's in-app socket listener, access modes, CLI client behavior, and local automation guardrails.
- 04. [Panes, Workspaces & Layout](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/04-panes-workspaces-layout.md) - Compares tmux's sessions, windows, panes, split commands, and layout tree mechanics with cmux's workspaces, panels, Bonsplit-backed layout state, terminal panels, and persisted surface snapshots.
- 05. [Command & Config Surfaces](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/05-command-config-surfaces.md) - Shows how tmux exposes a grammar, command queue, options, key bindings, and config loading, while cmux layers JSONC project config, command execution, Ghostty config compatibility, and CLI configuration commands.
- 06. [Agent Notifications & Hooks](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/06-agent-notifications-hooks.md) - Explains the shift from tmux's terminal alerts and control notifications to cmux's agent-aware notification queue, unread state, CLI hook definitions, and extensible hook formats for multiple coding agents.
- 07. [Browser Automation vs Terminal Control](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/07-browser-automation-vs-terminal-control.md) - Contrasts tmux's terminal-only control and capture model with cmux's browser pane automation, WebKit-backed panels, screenshots, profiles, and socket-addressable browser actions for local dev workflows.
- 08. [Remote SSH & Provider Neutrality](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/08-remote-ssh-provider-neutrality.md) - Compares tmux's shell, job, and spawn portability with cmux's SSH workspace, remote PTY attach, loopback routing, and daemon bridge design. The portable lesson is to keep orchestration file, socket, and repository based so BYOC/BYOK workflows do not depend on one model provider or hosted connector.
- 09. [Regression & Fuzz Boundaries](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/09-regression-fuzz-boundaries.md) - Maps the quality signals that make each project maintainable: tmux has shell regressions and fuzzers around command parsing, input, style, and formats; cmux has Swift unit and UI tests around sockets, browser panes, sessions, hooks, and app regressions.
- 10. [Comparison Verdict](https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/10-comparison-verdict.md) - The closing synthesis: tmux is strongest as a small, portable, protocol-deep multiplexer; cmux is strongest as a native agent-workflow shell that combines terminal, browser, notifications, remote access, and local automation. The most portable ideas are explicit socket contracts, source-backed command/config schemas, provider-neutral hooks, and focused regression boundaries.
## Source File Index
- `manaflow-ai-cmux:CLI/cmux.swift`
- `manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift`
- `manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj`
- `manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift`
- `manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift`
- `manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift`
- `manaflow-ai-cmux:cmuxUITests/AutomationSocketUITests.swift`
- `manaflow-ai-cmux:Packages/CMUXAgentLaunch/Package.swift`
- `manaflow-ai-cmux:Packages/CMUXWorkstream/Package.swift`
- `manaflow-ai-cmux:README.md`
- `manaflow-ai-cmux:Sources/cmuxApp.swift`
- `manaflow-ai-cmux:Sources/CmuxConfig.swift`
- `manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift`
- `manaflow-ai-cmux:Sources/GhosttyConfig.swift`
- `manaflow-ai-cmux:Sources/NotificationsPage.swift`
- `manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift`
- `manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift`
- `manaflow-ai-cmux:Sources/Panels/BrowserScreenshotPipeline.swift`
- `manaflow-ai-cmux:Sources/Panels/CmuxWebView.swift`
- `manaflow-ai-cmux:Sources/Panels/TerminalPanel.swift`
- `manaflow-ai-cmux:Sources/RemoteLoopbackRuntimeBridge.swift`
- `manaflow-ai-cmux:Sources/RemoteRelayZshBootstrap.swift`
- `manaflow-ai-cmux:Sources/SocketControlSettings.swift`
- `manaflow-ai-cmux:Sources/TabManager.swift`
- `manaflow-ai-cmux:Sources/TerminalController.swift`
- `manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift`
- `manaflow-ai-cmux:Sources/TerminalNotificationStore.swift`
- `manaflow-ai-cmux:Sources/Workspace.swift`
- `manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift`
- `manaflow-ai-cmux:Sources/WorkspaceRemoteSSHBatchCommandBuilder.swift`
- `manaflow-ai-cmux:web/README.md`
- `tmux-tmux:alerts.c`
- `tmux-tmux:cfg.c`
- `tmux-tmux:client.c`
- `tmux-tmux:cmd-capture-pane.c`
- `tmux-tmux:cmd-new-session.c`
- `tmux-tmux:cmd-parse.y`
- `tmux-tmux:cmd-queue.c`
- `tmux-tmux:cmd-split-window.c`
- `tmux-tmux:compat.h`
- `tmux-tmux:configure.ac`
- `tmux-tmux:control-notify.c`
- `tmux-tmux:control.c`
- `tmux-tmux:environ.c`
- `tmux-tmux:fuzz/cmd-parse-fuzzer.c`
- `tmux-tmux:fuzz/input-fuzzer.c`
- `tmux-tmux:input-keys.c`
- `tmux-tmux:input.c`
- `tmux-tmux:job.c`
- `tmux-tmux:key-bindings.c`
- `tmux-tmux:layout-set.c`
- `tmux-tmux:layout.c`
- `tmux-tmux:Makefile.am`
- `tmux-tmux:notify.c`
- `tmux-tmux:options.c`
- `tmux-tmux:proc.c`
- `tmux-tmux:README`
- `tmux-tmux:regress/control-client-sanity.sh`
- `tmux-tmux:regress/input-keys.sh`
- `tmux-tmux:server.c`
- `tmux-tmux:spawn.c`
- `tmux-tmux:tmux.h`
- `tmux-tmux:window.c`
---
## 01. Comparison Frame
> The comparison lens: tmux optimizes a cross-platform C daemon and terminal protocol core, while cmux builds a macOS-native orchestration surface around terminals, browser panes, notifications, and agent hooks. No local STRATEGY.md or docs/solutions context was present, so repository code and tests are the source of truth.
- Page Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/01-comparison-frame.md
- Generated: 2026-05-24T19:14:33.538Z
### Source Files
- `tmux-tmux:README`
- `tmux-tmux:tmux.h`
- `tmux-tmux:server.c`
- `manaflow-ai-cmux:README.md`
- `manaflow-ai-cmux:Sources/cmuxApp.swift`
- `manaflow-ai-cmux:Sources/Workspace.swift`
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:README](tmux-tmux/README)
- [tmux-tmux:configure.ac](tmux-tmux/configure.ac)
- [tmux-tmux:compat.h](tmux-tmux/compat.h)
- [tmux-tmux:tmux.h](tmux-tmux/tmux.h)
- [tmux-tmux:tmux-protocol.h](tmux-tmux/tmux-protocol.h)
- [tmux-tmux:server.c](tmux-tmux/server.c)
- [tmux-tmux:client.c](tmux-tmux/client.c)
- [tmux-tmux:cmd-queue.c](tmux-tmux/cmd-queue.c)
- [tmux-tmux:input.c](tmux-tmux/input.c)
- [tmux-tmux:tty-features.c](tmux-tmux/tty-features.c)
- [manaflow-ai-cmux:README.md](manaflow-ai-cmux/README.md)
- [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj](manaflow-ai-cmux/cmux.xcodeproj/project.pbxproj)
- [manaflow-ai-cmux:Sources/cmuxApp.swift](manaflow-ai-cmux/Sources/cmuxApp.swift)
- [manaflow-ai-cmux:Sources/TabManager.swift](manaflow-ai-cmux/Sources/TabManager.swift)
- [manaflow-ai-cmux:Sources/Workspace.swift](manaflow-ai-cmux/Sources/Workspace.swift)
- [manaflow-ai-cmux:Sources/GhosttyTerminalView.swift](manaflow-ai-cmux/Sources/GhosttyTerminalView.swift)
- [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift)
- [manaflow-ai-cmux:Sources/TerminalController.swift](manaflow-ai-cmux/Sources/TerminalController.swift)
- [manaflow-ai-cmux:Sources/SocketControlSettings.swift](manaflow-ai-cmux/Sources/SocketControlSettings.swift)
- [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift](manaflow-ai-cmux/Sources/Panels/BrowserPanel.swift)
- [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift)
</details>
# Comparison Frame
This page compares two terminal-oriented repositories through the lens of implementation ownership. `tmux` optimizes a portable C daemon, terminal protocol core, command queue, and client/server lifecycle. `cmux` builds a macOS-native orchestration surface around terminal panes, browser panes, sidebar metadata, notifications, remote sessions, and agent-facing automation.
No local `STRATEGY.md` or `docs/solutions/**` context was present in the workspace search, so the comparison treats repository code and tests as the source of truth. The provided Page Shape and QA Review guidance was used as portable wiki-routing context; no installed local Compound Engineering skill was proven or executed.
## Executive Comparison
| Lens | tmux-tmux | manaflow-ai-cmux |
|---|---|---|
| Primary product shape | Terminal multiplexer that creates, controls, detaches, and reattaches terminal sessions. | macOS terminal app with vertical tabs, split panes, notifications, in-app browser, SSH/remote support, and automation hooks. |
| Core runtime | C client/server daemon over a Unix socket, using libevent and terminal protocol parsing. | Swift/AppKit/SwiftUI app using Ghostty/libghostty for terminal rendering, Bonsplit for split layout, WebKit for browser surfaces, and local socket control. |
| Portability target | Cross-platform Unix-like systems: OpenBSD, FreeBSD, NetBSD, Linux, macOS, Solaris. | macOS app target with macOS 14 deployment settings and native macOS APIs. |
| Extension surface | Commands, key bindings, control mode, terminal feature negotiation, panes/windows/sessions. | CLI/socket RPC, workspace commands, browser automation surfaces, notification hooks, remote PTY bridge, sidebar metadata. |
| Agent posture | Vendor-agnostic because it is a terminal multiplexer and protocol engine, not an AI-agent product. | Agent-friendly but still provider-neutral: hooks and resume/index code can target multiple agents without requiring a specific model provider. |
Sources: [tmux-tmux:README:3-7](tmux-tmux/README#L3-L7), [tmux-tmux:compat.h:30-49](tmux-tmux/compat.h#L30-L49), [manaflow-ai-cmux:README.md:119-129](manaflow-ai-cmux/README.md#L119-L129), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1694-1720](manaflow-ai-cmux/cmux.xcodeproj/project.pbxproj#L1694-L1720), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:2519-2663](manaflow-ai-cmux/cmux.xcodeproj/project.pbxproj#L2519-L2663)
## Runtime Ownership Model
```text
tmux-tmux
client process -> Unix socket -> server daemon -> sessions/windows/panes
-> command queue
-> terminal parser/features
manaflow-ai-cmux
macOS app -> TabManager -> Workspace -> Bonsplit panes -> TerminalPanel/Ghostty
-> BrowserPanel/WKWebView
-> NotificationStore
-> socket RPC / remote bridge
```
`tmux` makes the daemon the center of gravity. The client connects to a Unix socket, starts the server when allowed, sends identify information, and then the server owns session state. The server creates and listens on an `AF_UNIX` socket, initializes windows, panes, sessions, key bindings, and message logs, then runs `proc_loop(server_proc, server_loop)`. The command queue is explicit infrastructure: global and per-client queues execute commands and callbacks, wait on external events, and emit control-mode guards.
`cmux` makes the application state tree the center of gravity. `cmuxApp` creates shared `TabManager`, `TerminalNotificationStore`, and sidebar state, configures Ghostty environment variables, and wires the AppDelegate before the main window scene appears. `TabManager` owns workspace selection and creation; `Workspace` owns Bonsplit pane layout and panel maps. Browser and terminal panels are sibling surface types inside that workspace model rather than separate daemon-owned panes.
Sources: [tmux-tmux:client.c:103-140](tmux-tmux/client.c#L103-L140), [tmux-tmux:client.c:283-323](tmux-tmux/client.c#L283-L323), [tmux-tmux:server.c:174-254](tmux-tmux/server.c#L174-L254), [tmux-tmux:server.c:262-305](tmux-tmux/server.c#L262-L305), [tmux-tmux:cmd-queue.c:31-120](tmux-tmux/cmd-queue.c#L31-L120), [tmux-tmux:cmd-queue.c:728-837](tmux-tmux/cmd-queue.c#L728-L837), [manaflow-ai-cmux:Sources/cmuxApp.swift:25-86](manaflow-ai-cmux/Sources/cmuxApp.swift#L25-L86), [manaflow-ai-cmux:Sources/TabManager.swift:898-1015](manaflow-ai-cmux/Sources/TabManager.swift#L898-L1015), [manaflow-ai-cmux:Sources/Workspace.swift:8973-9033](manaflow-ai-cmux/Sources/Workspace.swift#L8973-L9033)
## Terminal Core Versus Terminal Host
`tmux` implements terminal behavior deeply. `tmux.h` defines defaults for config paths, socket roots, TERM, pane/window minimums, key-code masks, Unicode/user/function/mouse key types, and mouse locations. `input.c` contains a terminal input parser based on a DEC/ANSI parser model with UTF-8, OSC, APC, DCS, rename handling, parser buffers, request tracking, and screen-write context. `tty-features.c` maps terminal capabilities such as title setting, OSC 7, mouse, OSC 52 clipboard, OSC 8 hyperlinks, sixel, and OSC 9;4 progress bar.
`cmux` delegates terminal emulation/rendering to Ghostty/libghostty and wraps it in macOS application behavior. `cmuxApp` resolves Ghostty resources, TERM, COLORTERM, and TERM_PROGRAM during launch. `GhosttyApp` is described in code as a minimal Ghostty wrapper using `GhosttyKit.xcframework` for terminal emulation; it owns one process-lifetime Ghostty app and config. The Xcode project links `GhosttyKit.xcframework`, Bonsplit, and Sparkle into the app target.
```c
/* tmux-tmux:server.c */
server_fd = server_create_socket(flags, &cause);
server_add_accept(0);
proc_loop(server_proc, server_loop);
```
```swift
// manaflow-ai-cmux:Sources/Workspace.swift
/// Workspace represents a sidebar tab.
/// Each workspace contains one BonsplitController that manages split panes and nested surfaces.
```
Sources: [tmux-tmux:tmux.h:82-118](tmux-tmux/tmux.h#L82-L118), [tmux-tmux:tmux.h:121-220](tmux-tmux/tmux.h#L121-L220), [tmux-tmux:input.c:31-52](tmux-tmux/input.c#L31-L52), [tmux-tmux:input.c:98-148](tmux-tmux/input.c#L98-L148), [tmux-tmux:tty-features.c:44-115](tmux-tmux/tty-features.c#L44-L115), [tmux-tmux:tty-features.c:350-470](tmux-tmux/tty-features.c#L350-L470), [manaflow-ai-cmux:Sources/cmuxApp.swift:96-143](manaflow-ai-cmux/Sources/cmuxApp.swift#L96-L143), [manaflow-ai-cmux:Sources/GhosttyTerminalView.swift:1673-1724](manaflow-ai-cmux/Sources/GhosttyTerminalView.swift#L1673-L1724), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:204-258](manaflow-ai-cmux/cmux.xcodeproj/project.pbxproj#L204-L258)
## Orchestration And Attention
`tmux` treats panes, clients, windows, jobs, and command execution as the core orchestration units. The server loop repeatedly drains the global queue and identified client queues, runs the client loop, and exits only when configured exit conditions, clients, sessions, and jobs allow it. That design is durable for terminal multiplexing because command execution and session lifetime are independent of the visible terminal client.
`cmux` adds a higher-level attention model on top of terminal surfaces. `TerminalNotification` stores workspace ID, surface ID, panel ID, title, subtitle, body, read state, pane-flash state, and click action. `TerminalNotificationStore` indexes unread state by workspace and surface, exposes latest notifications, and routes additions through policy hooks when configured. Ghostty desktop notification actions are converted into `TerminalNotificationStore.addNotification`, and remote errors can also become sidebar log entries plus notifications.
Sources: [tmux-tmux:server.c:262-305](tmux-tmux/server.c#L262-L305), [tmux-tmux:server.c:484-507](tmux-tmux/server.c#L484-L507), [tmux-tmux:cmd-queue.c:597-680](tmux-tmux/cmd-queue.c#L597-L680), [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:694-790](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift#L694-L790), [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:1118-1265](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift#L1118-L1265), [manaflow-ai-cmux:Sources/GhosttyTerminalView.swift:4248-4305](manaflow-ai-cmux/Sources/GhosttyTerminalView.swift#L4248-L4305), [manaflow-ai-cmux:Sources/GhosttyTerminalView.swift:4528-4570](manaflow-ai-cmux/Sources/GhosttyTerminalView.swift#L4528-L4570), [manaflow-ai-cmux:Sources/Workspace.swift:12000-12035](manaflow-ai-cmux/Sources/Workspace.swift#L12000-L12035)
## Browser And Workspace Surface Model
This is the biggest product-level difference. `tmux` has no browser-pane concept in the inspected core; its extensibility is terminal-native. `cmux` explicitly models browser surfaces beside terminal surfaces. `BrowserPanel.swift` imports WebKit and defines browser settings, search engines, proxy status, and theme behavior. `TabManager.openBrowser` can open a browser in the current workspace, reuse a target pane, split right, create a new browser surface, and remember focus. `Workspace` contains a panel map of `any Panel`, so terminal and browser panels share the same split container.
This makes `cmux` better suited for agent workflows that need to inspect a local web app while also driving terminal commands. It also raises UI-specific complexity that `tmux` avoids: focus routing, WebKit lifecycle, drag/drop, browser profiles, and split layout state.
Sources: [manaflow-ai-cmux:README.md:51-56](manaflow-ai-cmux/README.md#L51-L56), [manaflow-ai-cmux:README.md:127-129](manaflow-ai-cmux/README.md#L127-L129), [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift:1-16](manaflow-ai-cmux/Sources/Panels/BrowserPanel.swift#L1-L16), [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift:91-157](manaflow-ai-cmux/Sources/Panels/BrowserPanel.swift#L91-L157), [manaflow-ai-cmux:Sources/TabManager.swift:7262-7276](manaflow-ai-cmux/Sources/TabManager.swift#L7262-L7276), [manaflow-ai-cmux:Sources/TabManager.swift:7600-7685](manaflow-ai-cmux/Sources/TabManager.swift#L7600-L7685), [manaflow-ai-cmux:Sources/Workspace.swift:9031-9067](manaflow-ai-cmux/Sources/Workspace.swift#L9031-L9067)
## Automation, BYOC, And BYOK Neutrality
Both projects can support BYOC/BYOK-friendly architectures, but at different layers.
`tmux` is naturally provider-neutral because it knows about terminals, clients, sockets, commands, and terminal protocols rather than AI providers. The protocol header defines internal message types for versioning, identify, command, detach, resize, shell, shutdown, exec, file read/write, and related lifecycle messages. Nothing in the inspected tmux core assumes a hosted model provider, proprietary key format, or agent runtime.
`cmux` is agent-aware but should be integrated as a portable orchestration layer, not as a model-provider dependency. Its README names Claude Code, Codex, OpenCode, and agent hooks as examples, while the code exposes local socket modes (`off`, `cmuxOnly`, `automation`, `password`, `allowAll`) and RPC-style notification/workspace methods. The remote configuration supports SSH, local socket paths, relay fields, and a daemon WebSocket endpoint, so integrations should treat file, repository, or catalog-provided skills as replaceable inputs. BYOK stays outside the UI primitive: agent credentials and model choices should remain owned by the agent/tool process, while `cmux` receives terminal events, notifications, and socket commands.
Sources: [tmux-tmux:tmux-protocol.h:22-71](tmux-tmux/tmux-protocol.h#L22-L71), [tmux-tmux:tmux-protocol.h:73-119](tmux-tmux/tmux-protocol.h#L73-L119), [manaflow-ai-cmux:README.md:78-90](manaflow-ai-cmux/README.md#L78-L90), [manaflow-ai-cmux:README.md:133-139](manaflow-ai-cmux/README.md#L133-L139), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:8-62](manaflow-ai-cmux/Sources/SocketControlSettings.swift#L8-L62), [manaflow-ai-cmux:Sources/TerminalController.swift:10215-10252](manaflow-ai-cmux/Sources/TerminalController.swift#L10215-L10252), [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:66-81](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift#L66-L81), [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:275-328](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift#L275-L328)
## What Each Project Does Better
### tmux strengths
`tmux` is the stronger reference for daemon durability, protocol ownership, and portable terminal semantics. Its Autoconf setup detects compilers, yacc, pkg-config, headers, platform functions, static-build constraints, fuzzing flags, and replacement functions. Its compatibility header wraps libevent and system differences. The implementation is compactly optimized around terminal sessions rather than app chrome.
Sources: [tmux-tmux:README:9-20](tmux-tmux/README#L9-L20), [tmux-tmux:configure.ac:44-83](tmux-tmux/configure.ac#L44-L83), [tmux-tmux:configure.ac:85-117](tmux-tmux/configure.ac#L85-L117), [tmux-tmux:configure.ac:135-180](tmux-tmux/configure.ac#L135-L180), [tmux-tmux:compat.h:170-285](tmux-tmux/compat.h#L170-L285)
### cmux strengths
`cmux` is the stronger reference for native desktop orchestration around terminals. It understands workspace metadata, Git branch and PR sidebar state, listening ports, browser panes, notifications, remote connection state, session snapshots, and local automation controls. Its workspace creation path carries initial commands, inputs, environment, inherited directory, terminal config, placement, and port ordinal metadata.
Sources: [manaflow-ai-cmux:README.md:119-129](manaflow-ai-cmux/README.md#L119-L129), [manaflow-ai-cmux:Sources/TabManager.swift:2500-2565](manaflow-ai-cmux/Sources/TabManager.swift#L2500-L2565), [manaflow-ai-cmux:Sources/TabManager.swift:1110-1245](manaflow-ai-cmux/Sources/TabManager.swift#L1110-L1245), [manaflow-ai-cmux:Sources/Workspace.swift:9121-9165](manaflow-ai-cmux/Sources/Workspace.swift#L9121-L9165), [manaflow-ai-cmux:Sources/Workspace.swift:15479-15543](manaflow-ai-cmux/Sources/Workspace.swift#L15479-L15543)
## Portable Ideas
| Portable idea | Source repo | How to reuse it |
|---|---|---|
| Keep command execution separate from UI attachment. | tmux | Use a queue or job model so automation can continue when a visual surface is absent. |
| Treat terminal capability support as negotiated feature data. | tmux | Avoid hard-coding terminal behavior into UI-only code; expose feature flags or adapters. |
| Model user attention as structured state. | cmux | Store read/unread, target workspace/surface, flash behavior, and click actions separately from delivery. |
| Keep browser and terminal panes under one workspace/split abstraction. | cmux | Useful when agents need both CLI and web-app inspection in the same task context. |
| Keep provider choice out of orchestration primitives. | both | Make files, repositories, socket commands, hooks, and catalogs portable inputs; do not tie workflow state to one hosted model or API key source. |
Sources: [tmux-tmux:cmd-queue.c:71-92](tmux-tmux/cmd-queue.c#L71-L92), [tmux-tmux:tty-features.c:371-470](tmux-tmux/tty-features.c#L371-L470), [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:694-739](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift#L694-L739), [manaflow-ai-cmux:Sources/Workspace.swift:8973-9033](manaflow-ai-cmux/Sources/Workspace.swift#L8973-L9033), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:35-62](manaflow-ai-cmux/Sources/SocketControlSettings.swift#L35-L62)
## Closing Summary
The short comparison is: `tmux` is a cross-platform terminal daemon and protocol engine; `cmux` is a macOS-native terminal-orchestration app that composes Ghostty rendering, Bonsplit panes, WebKit browser surfaces, notifications, socket automation, and remote-session machinery. The most reusable architecture lesson is to keep orchestration provider-neutral: terminal/session state, browser actions, notifications, skills, repositories, and model credentials should remain separable so BYOC/BYOK workflows can swap agents, skill sources, or model providers without rewriting the terminal surface. Sources: [tmux-tmux:server.c:105-154](tmux-tmux/server.c#L105-L154), [tmux-tmux:server.c:174-254](tmux-tmux/server.c#L174-L254), [manaflow-ai-cmux:Sources/cmuxApp.swift:206-248](manaflow-ai-cmux/Sources/cmuxApp.swift#L206-L248), [manaflow-ai-cmux:Sources/TerminalController.swift:10467-10530](manaflow-ai-cmux/Sources/TerminalController.swift#L10467-L10530)
---
## 02. Platform & Build Boundaries
> How each repository encodes portability: tmux uses autotools, feature checks, compat sources, and C dependencies; cmux uses Xcode targets, Swift packages, bundled app resources, and a separate web backend surface.
- Page Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/02-platform-build-boundaries.md
- Generated: 2026-05-24T19:14:38.690Z
### Source Files
- `tmux-tmux:configure.ac`
- `tmux-tmux:Makefile.am`
- `tmux-tmux:compat.h`
- `manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj`
- `manaflow-ai-cmux:Packages/CMUXWorkstream/Package.swift`
- `manaflow-ai-cmux:Packages/CMUXAgentLaunch/Package.swift`
- `manaflow-ai-cmux:web/README.md`
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:configure.ac](tmux-tmux/configure.ac)
- [tmux-tmux:Makefile.am](tmux-tmux/Makefile.am)
- [tmux-tmux:compat.h](tmux-tmux/compat.h)
- [tmux-tmux:autogen.sh](tmux-tmux/autogen.sh)
- [tmux-tmux:osdep-linux.c](tmux-tmux/osdep-linux.c)
- [tmux-tmux:osdep-darwin.c](tmux-tmux/osdep-darwin.c)
- [tmux-tmux:compat/forkpty-sunos.c](tmux-tmux/compat/forkpty-sunos.c)
- [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj](manaflow-ai-cmux/cmux.xcodeproj/project.pbxproj)
- [manaflow-ai-cmux:Packages/CMUXWorkstream/Package.swift](manaflow-ai-cmux/Packages/CMUXWorkstream/Package.swift)
- [manaflow-ai-cmux:Packages/CMUXAgentLaunch/Package.swift](manaflow-ai-cmux/Packages/CMUXAgentLaunch/Package.swift)
- [manaflow-ai-cmux:Packages/CMUXAgentVault/Package.swift](manaflow-ai-cmux/Packages/CMUXAgentVault/Package.swift)
- [manaflow-ai-cmux:Packages/CMUXAuthCore/Package.swift](manaflow-ai-cmux/Packages/CMUXAuthCore/Package.swift)
- [manaflow-ai-cmux:Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamTransport.swift](manaflow-ai-cmux/Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamTransport.swift)
- [manaflow-ai-cmux:Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchEnvironmentPolicy.swift](manaflow-ai-cmux/Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchEnvironmentPolicy.swift)
- [manaflow-ai-cmux:web/README.md](manaflow-ai-cmux/web/README.md)
- [manaflow-ai-cmux:web/package.json](manaflow-ai-cmux/web/package.json)
- [manaflow-ai-cmux:web/scripts/dev-local.sh](manaflow-ai-cmux/web/scripts/dev-local.sh)
- [manaflow-ai-cmux:web/db/schema.ts](manaflow-ai-cmux/web/db/schema.ts)
- [manaflow-ai-cmux:web/app/api/vm/route.ts](manaflow-ai-cmux/web/app/api/vm/route.ts)
- [manaflow-ai-cmux:web/app/api/vm/[id]/route.ts](manaflow-ai-cmux/web/app/api/vm/[id]/route.ts)
- [manaflow-ai-cmux:web/services/vms/drivers/types.ts](manaflow-ai-cmux/web/services/vms/drivers/types.ts)
- [manaflow-ai-cmux:web/services/vms/drivers/index.ts](manaflow-ai-cmux/web/services/vms/drivers/index.ts)
- [manaflow-ai-cmux:web/services/vms/providerGateway.ts](manaflow-ai-cmux/web/services/vms/providerGateway.ts)
- [manaflow-ai-cmux:web/services/vms/workflows.ts](manaflow-ai-cmux/web/services/vms/workflows.ts)
</details>
# Platform & Build Boundaries
This page compares how `tmux-tmux` and `manaflow-ai-cmux` encode portability. `tmux-tmux` is a C project that pushes platform differences into Autotools probes, conditional source selection, compatibility implementations, and small OS-specific files. `manaflow-ai-cmux` is a macOS/iOS-adjacent application that uses Xcode targets, Swift package manifests, bundled resources, and a separate Next.js backend surface.
Generation note: this comparison follows the prompt-supplied bundled Compound Engineering wiki recipe as page-shape guidance. No local `STRATEGY.md` or `docs/solutions/**` context was found in the prepared workspace, so repository code and config are treated as the source of truth.
## Boundary Model
```text
tmux-tmux
configure.ac -> detects host, libraries, headers, functions
Makefile.am -> selects flags, sources, compat objects
compat.h + compat/ -> normalizes missing APIs for C callers
osdep-*.c -> isolates OS behavior behind common functions
manaflow-ai-cmux
cmux.xcodeproj -> app, CLI, plugin, test targets, resources
Packages/* -> Swift module/platform boundaries
Resources/scripts -> bundled terminal, shell, FFI, helper assets
web/ -> Next.js backend, DB, provider-driver API
```
The main difference is where portability is decided. `tmux-tmux` makes portability a configure-time contract: the generated build knows what the host lacks and adds replacement objects. `manaflow-ai-cmux` makes portability a product-surface contract: native app pieces are separated into Xcode targets and Swift packages, while web/cloud behavior is delegated to the `web/` backend.
Sources: [tmux-tmux:configure.ac:135-197](), [tmux-tmux:configure.ac:895-1005](), [tmux-tmux:Makefile.am:84-241](), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1694-1813](), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1849-1874](), [manaflow-ai-cmux:web/README.md:1-5]()
## tmux: Autotools As The Portability Front Door
`tmux-tmux` starts by canonicalizing the host, setting compiler tools, and checking headers, functions, and libraries. Its `configure.ac` checks for headers such as `libutil.h`, `pty.h`, `sys/tree.h`, and `util.h`, then separately checks for functions that may be present, missing, or replaced by local compatibility code. That means platform support is mostly encoded as capability detection, not by assuming a particular Unix variant.
Key build-time decisions include:
| Concern | Where encoded | Effect |
|---|---|---|
| Compiler/build modes | `--enable-debug`, `--enable-optimizations`, `--enable-asan`, `--enable-static`, fuzzing | Produces conditional Automake flags and, for static builds, rejects unsupported macOS static linking |
| Core C dependencies | `libevent`, `ncurses`/`curses`, `yacc` | Fails configuration if required runtime/build libraries are unavailable |
| Optional integrations | `utempter`, `utf8proc`, `systemd`, `sixel` | Adds `HAVE_*`/`ENABLE_*` defines and conditional sources only when enabled |
| Host platform | `case "$host_os"` | Maps host OS to `PLATFORM`, then exposes Automake conditionals |
Sources: [tmux-tmux:configure.ac:44-99](), [tmux-tmux:configure.ac:242-289](), [tmux-tmux:configure.ac:291-373](), [tmux-tmux:configure.ac:379-481](), [tmux-tmux:configure.ac:895-1017]()
### Compatibility Sources And Headers
The compatibility layer has two parts. First, `configure.ac` uses `AC_REPLACE_FUNCS` and `AC_LIBOBJ` for missing or unsuitable functions such as `asprintf`, `getline`, `strlcpy`, `strtonum`, `reallocarray`, `imsg`, `daemon`, `vis`, `fdforkpty`, and `base64`. Second, `compat.h` gives callers stable declarations, fallback includes, and fallback macros such as `pledge(s, p) (0)` outside OpenBSD.
This keeps most tmux code from branching directly on OS names. A caller includes `compat.h` and relies on the build to provide either the native API or the compat object.
```c
/* tmux-tmux:compat.h */
#ifdef HAVE_QUEUE_H
#include <sys/queue.h>
#else
#include "compat/queue.h"
#endif
#ifdef HAVE_TREE_H
#include <sys/tree.h>
#else
#include "compat/tree.h"
#endif
```
Sources: [tmux-tmux:configure.ac:173-240](), [tmux-tmux:configure.ac:648-728](), [tmux-tmux:compat.h:133-187](), [tmux-tmux:compat.h:388-415]()
### OS-Specific Files Stay Narrow
`Makefile.am` includes the shared tmux source list and then adds `osdep-@PLATFORM@.c`, with conditional extras for `forkpty`, systemd, utf8proc, and sixel. The OS files themselves are targeted: Linux reads `/proc` paths and disables epoll for `/dev/null`; Darwin uses `proc_pidinfo`/`sysctl` and disables libevent kqueue/poll. Solaris has a dedicated `forkpty` implementation for `/dev/ptmx`.
Sources: [tmux-tmux:Makefile.am:221-241](), [tmux-tmux:osdep-linux.c:29-102](), [tmux-tmux:osdep-darwin.c:37-109](), [tmux-tmux:compat/forkpty-sunos.c:32-92]()
## cmux: Xcode Targets And Swift Packages As Native Boundaries
`manaflow-ai-cmux` encodes native boundaries through Xcode targets. The project defines an application target, a CLI tool target, UI tests, a Dock Tile plugin bundle, and unit tests. The main app target depends on the CLI and Dock Tile plugin targets, and it links local and remote Swift package products.
This is a different portability shape from tmux: instead of detecting many host Unix capabilities, the project pins a macOS app environment and isolates product surfaces by target.
| Native surface | Evidence | Boundary role |
|---|---|---|
| `cmux.app` | `productType = "com.apple.product-type.application"` | Main desktop app bundle |
| `cmux-cli` | `productType = "com.apple.product-type.tool"` | Separate command-line tool shipped with the app |
| `CmuxDockTilePlugin` | `productType = "com.apple.product-type.bundle"` | Dock/plugin extension surface |
| `cmuxTests`, `cmuxUITests` | XCTest bundle target types | Test-only build surfaces |
| Local Swift packages | `Packages/CMUX*`, `vendor/bonsplit`, `vendor/stack-auth...` | In-repo or vendored module boundaries |
| Remote Swift packages | Sparkle, Sentry, PostHog, MarkdownUI | External app dependencies |
Sources: [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1694-1813](), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1849-1874](), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:2873-3022]()
### Deployment And App Configuration
The Xcode build settings pin the native project to `SDKROOT = macosx` and `MACOSX_DEPLOYMENT_TARGET = 14.0` in the shared Debug/Release build configurations. The app target also distinguishes Debug and Release identity: Debug uses `cmux DEV`, a development callback scheme, and no entitlements file, while Release uses `cmux`, `Resources/cmux.entitlements`, and the production callback scheme.
Sources: [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:2512-2589](), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:2591-2669]()
### Bundled Resources Are Part Of The Platform Contract
The main app resources include assets, `xterm-ghostty`, third-party licenses, localized strings, an AppleScript definition, `opencode-plugin.js`, `feed-tui`, and `markdown-viewer`. A shell build phase copies Ghostty resources, terminfo, shell integration files, and builds a Ghostty CLI helper for `arm64`, `x86_64`, or universal architectures.
This is portability by bundling: the app carries terminal/runtime assets it needs, rather than relying entirely on the user’s machine.
Sources: [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1878-1894](), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1918-1955]()
## cmux Swift Packages: Platform Pins And Module Scope
The Swift package manifests show that cmux is not one monolithic app module. `CMUXWorkstream` supports both iOS 18 and macOS 14. `CMUXAuthCore` follows the same iOS/macOS split. `CMUXAgentLaunch` is macOS-only and depends on `CMUXAgentVault`; `CMUXAgentVault` is macOS 13+ and links SQLite.
This structure lets portable domain code live in packages that can compile for iOS and macOS, while process-launch and local agent/session code remains macOS-specific.
Sources: [manaflow-ai-cmux:Packages/CMUXWorkstream/Package.swift:1-24](), [manaflow-ai-cmux:Packages/CMUXAuthCore/Package.swift:1-25](), [manaflow-ai-cmux:Packages/CMUXAgentLaunch/Package.swift:1-28](), [manaflow-ai-cmux:Packages/CMUXAgentVault/Package.swift:1-30]()
### Portable Interfaces Inside Packages
`CMUXWorkstream`’s `WorkstreamTransport` is a small example of provider-neutral interface design: the store can use a Unix socket on macOS, an in-memory pipe in tests, or a relay WebSocket on iOS without changing store code. `CMUXAgentLaunch` takes a different approach: it allowlists selected environment keys and sanitizes values before launching/resuming agents, which keeps BYOK-style environment configuration possible without forwarding arbitrary secrets.
Sources: [manaflow-ai-cmux:Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamTransport.swift:3-17](), [manaflow-ai-cmux:Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchEnvironmentPolicy.swift:26-96]()
## cmux Web Backend: Separate Runtime Surface
The `web/` directory is a Next.js app that serves the website, Stack Auth handlers, feedback endpoint, and Cloud VM backend routes. Its scripts use Bun, Next.js, Drizzle, local Docker Postgres helpers, and cloud-VM preflight/smoke/stress scripts. Local dev sources secrets from user-local files, derives ports from `CMUX_PORT`, starts/migrates Postgres, and runs `next dev` on the selected port.
That makes web/cloud portability distinct from the native app. The native app can ship app resources and CLI tools, while cloud VM creation, provider credentials, auth, billing, and database state stay behind server-side route handlers and services.
Sources: [manaflow-ai-cmux:web/README.md:1-26](), [manaflow-ai-cmux:web/README.md:40-94](), [manaflow-ai-cmux:web/package.json:6-30](), [manaflow-ai-cmux:web/scripts/dev-local.sh:126-153]()
### Provider-Neutral VM Boundary
The web VM subsystem is explicitly driver-based. `ProviderId` is currently `"e2b" | "freestyle"`, but callers consume a `VMProvider` interface with operations such as `create`, `destroy`, `exec`, `snapshot`, `restore`, `openAttach`, `openSSH`, and `revokeSSHIdentity`. A registry maps provider ids to concrete providers, and `VmProviderGateway` wraps provider calls as typed Effect services.
The route layer validates provider overrides before creating a VM, resolves the image for the selected provider, and calls `createVm` through `runVmWorkflow`. The workflow then composes repository, provider gateway, and billing gateway services. This keeps BYOC/BYOK direction intact: provider credentials and implementation details stay server-side, while the API deals in provider ids, images, leases, and typed workflow errors.
Sources: [manaflow-ai-cmux:web/services/vms/drivers/types.ts:1-104](), [manaflow-ai-cmux:web/services/vms/drivers/index.ts:8-30](), [manaflow-ai-cmux:web/services/vms/providerGateway.ts:17-76](), [manaflow-ai-cmux:web/app/api/vm/route.ts:93-190](), [manaflow-ai-cmux:web/app/api/vm/route.ts:261-327](), [manaflow-ai-cmux:web/services/vms/workflows.ts:50-60](), [manaflow-ai-cmux:web/services/vms/workflows.ts:70-170]()
### Persistence Boundary
The backend uses Drizzle schema definitions for Cloud VM state, leases, usage events, and billing grants. Provider is stored as a database enum, VM status has a lifecycle enum, and idempotency/provider identifiers are protected by partial unique indexes. The delete route shows the API boundary: a request is authenticated, a VM id is read from the route, and `destroyVm` runs through the workflow layer.
Sources: [manaflow-ai-cmux:web/db/schema.ts:14-55](), [manaflow-ai-cmux:web/db/schema.ts:57-126](), [manaflow-ai-cmux:web/app/api/vm/[id]/route.ts:12-32]()
## Comparison: What Each Repository Does Better
| Dimension | `tmux-tmux` | `manaflow-ai-cmux` | Portable idea |
|---|---|---|---|
| Host portability | Strong compile-time probing for Unix variants, libraries, and broken APIs | Mostly pinned to Apple native platforms for the app, with web runtime separated | Put platform decisions at a small number of explicit boundaries |
| Dependency handling | Required C deps are discovered at configure time; optional deps are enabled by flags | Native dependencies are Swift package products; web dependencies live in `web/package.json` | Keep dependency graphs scoped to the runtime that needs them |
| Compatibility | Missing C APIs are normalized through `compat.h` and `compat/` sources | Cross-surface behavior is normalized through Swift protocols and web service interfaces | Prefer stable local contracts over scattered platform/provider checks |
| Bundling | Builds a single `tmux` binary plus selected compat/platform objects | Ships app resources, CLI helper, plugin bundle, and packaged terminal assets | Bundle only what the runtime cannot safely assume from the host |
| BYOC/BYOK posture | Vendor-neutral in the Unix/C sense: depends on system libraries and detected host capabilities | Provider-aware but gateway-based: VM providers are behind driver/service contracts and credentials remain backend-owned | Treat providers as replaceable adapters, not as product-wide assumptions |
Sources: [tmux-tmux:Makefile.am:18-47](), [tmux-tmux:Makefile.am:50-82](), [tmux-tmux:Makefile.am:221-241](), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1715-1734](), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1736-1755](), [manaflow-ai-cmux:web/services/vms/drivers/types.ts:76-104]()
## Maintenance Guidance
For tmux-style changes, ask: is this a missing host capability, a broken host capability, or a genuinely different OS behavior? Missing or broken APIs belong in `configure.ac`, `compat.h`, and `compat/`; OS behavior belongs in `osdep-*.c`; user-facing build modes belong in Autoconf options and Automake conditionals.
For cmux-style changes, ask: is this native app behavior, reusable Swift domain code, bundled runtime asset, CLI behavior, or backend/provider behavior? Native product shape belongs in Xcode targets and build phases; reusable Swift contracts belong in `Packages/`; cloud/provider work belongs in `web/services/**` and thin Next route handlers. Keep provider-specific logic behind typed adapters so BYOC/BYOK support remains portable across file, repository, or catalog-sourced integrations.
Sources: [tmux-tmux:configure.ac:717-728](), [tmux-tmux:Makefile.am:221-241](), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1694-1813](), [manaflow-ai-cmux:Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamTransport.swift:3-17](), [manaflow-ai-cmux:web/app/api/vm/route.ts:99-190](), [manaflow-ai-cmux:web/services/vms/providerGateway.ts:55-76]()
In short, `tmux-tmux` optimizes for broad Unix source portability through configure-time evidence and compatibility code, while `manaflow-ai-cmux` optimizes for product-surface separation: Apple-native targets and packages on one side, a provider-gateway web backend on the other. Both patterns are portable when the boundary stays explicit and narrow. Sources: [tmux-tmux:configure.ac:993-1005](), [manaflow-ai-cmux:cmux.xcodeproj/project.pbxproj:1849-1874](), [manaflow-ai-cmux:web/services/vms/drivers/types.ts:1-4]()
---
## 03. Lifecycle & Socket Control
> Contrasts tmux's client-server fork, lock, imsg, and Unix socket lifecycle with cmux's in-app socket listener, access modes, CLI client behavior, and local automation guardrails.
- Page Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/03-lifecycle-socket-control.md
- Generated: 2026-05-24T19:14:30.619Z
### Source Files
- `tmux-tmux:server.c`
- `tmux-tmux:client.c`
- `tmux-tmux:proc.c`
- `tmux-tmux:control.c`
- `manaflow-ai-cmux:Sources/TerminalController.swift`
- `manaflow-ai-cmux:Sources/SocketControlSettings.swift`
- `manaflow-ai-cmux:CLI/cmux.swift`
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:server.c](tmux-tmux/server.c)
- [tmux-tmux:client.c](tmux-tmux/client.c)
- [tmux-tmux:proc.c](tmux-tmux/proc.c)
- [tmux-tmux:control.c](tmux-tmux/control.c)
- [tmux-tmux:server-acl.c](tmux-tmux/server-acl.c)
- [manaflow-ai-cmux:Sources/TerminalController.swift](manaflow-ai-cmux/Sources/TerminalController.swift)
- [manaflow-ai-cmux:Sources/SocketControlSettings.swift](manaflow-ai-cmux/Sources/SocketControlSettings.swift)
- [manaflow-ai-cmux:Sources/SocketControlSettings+SocketPathMarkers.swift](manaflow-ai-cmux/Sources/SocketControlSettings+SocketPathMarkers.swift)
- [manaflow-ai-cmux:Sources/cmuxApp.swift](manaflow-ai-cmux/Sources/cmuxApp.swift)
- [manaflow-ai-cmux:Sources/AppDelegate.swift](manaflow-ai-cmux/Sources/AppDelegate.swift)
- [manaflow-ai-cmux:CLI/cmux.swift](manaflow-ai-cmux/CLI/cmux.swift)
- [manaflow-ai-cmux:CLI/CLISocketPathResolver.swift](manaflow-ai-cmux/CLI/CLISocketPathResolver.swift)
</details>
# Lifecycle & Socket Control
This page compares two local-control models. tmux treats the Unix socket as the entrance to a long-lived, forked server process. cmux treats the socket as an in-app listener owned by the macOS app, with explicit modes for local automation, password access, and open access.
The difference matters because both systems solve the same product problem, "let a local CLI control a terminal workspace," but they assign trust and lifecycle ownership differently. tmux optimizes for a durable multiplexer daemon; cmux optimizes for app-mediated control, UI-aware automation, and guardrails around local agents.
## Runtime Ownership Model
tmux starts from a client process that either connects to an existing Unix-domain socket or starts the server. On connect failure, the client uses a `.lock` file with `flock`, retries to avoid racing another starter, unlinks a stale socket, and calls `server_start`. The server path can fork and daemonize through `proc_fork_and_daemon`, then initializes the server process, socket, clients, sessions, and accept loop.
cmux starts socket control from app state. The app computes the effective socket mode, chooses an active path, and calls `TerminalController.shared.start(...)`; if the mode is off, it stops the listener. AppDelegate has a similar startup/restart path, including reservation of an initial socket path before the listener starts.
Sources: [tmux-tmux:client.c:73-180](), [tmux-tmux:server.c:176-235](), [tmux-tmux:proc.c:359-380](), [manaflow-ai-cmux:Sources/cmuxApp.swift:851-865](), [manaflow-ai-cmux:Sources/AppDelegate.swift:3464-3507]()
```mermaid
sequenceDiagram
participant TmuxCLI as tmux client
participant TmuxServer as tmux server process
participant CmuxApp as cmux app
participant CmuxCLI as cmux CLI
TmuxCLI->>TmuxServer: connect AF_UNIX socket
alt socket missing or refused and start allowed
TmuxCLI->>TmuxCLI: lock socket.lock, retry, unlink stale path
TmuxCLI->>TmuxServer: fork/daemonize server_start
end
TmuxServer->>TmuxCLI: imsg protocol replies
CmuxApp->>CmuxApp: compute effective SocketControlMode
CmuxApp->>CmuxApp: bind/listen DispatchSource socket listener
CmuxCLI->>CmuxApp: newline-delimited command or JSON
CmuxApp->>CmuxCLI: text or JSON response
```
## Socket Creation, Binding, and Cleanup
tmux creates an `AF_UNIX` stream socket at `socket_path`, unlinks any previous path first, binds with a restrictive `umask`, listens with backlog 128, and makes the server socket nonblocking. The server also updates socket execute bits based on whether any session is attached. On `SIGUSR1`, it recreates the socket and re-adds the accept event.
cmux also creates an `AF_UNIX` stream socket and listens with backlog 128, but it does this inside `TerminalController`. The start path acquires or consumes a socket-path lock, binds the listener, falls back after bind failures when configured to do so, applies permissions from the selected access mode, configures the socket nonblocking, records the last socket path, and posts a listener-start notification. Stop cancels the read source and monitor, shuts down and closes the socket, conditionally unlinks only if the current path identity matches the listener's bound identity, and releases the path lock.
Sources: [tmux-tmux:server.c:105-150](), [tmux-tmux:server.c:331-365](), [tmux-tmux:server.c:431-454](), [manaflow-ai-cmux:Sources/TerminalController.swift:1539-1782](), [manaflow-ai-cmux:Sources/TerminalController.swift:2030-2121](), [manaflow-ai-cmux:Sources/SocketControlSettings+SocketPathMarkers.swift:4-39]()
| Concern | tmux | cmux |
|---|---|---|
| Owner | Forked server process | macOS app singleton controller |
| Socket path cleanup | `unlink` before bind | identity-aware unlink on failed start or stop |
| Backlog | 128 | 128 |
| Permission model | `umask` at bind plus execute-bit updates | explicit mode-derived `chmod` |
| Restart | signal-driven socket recreation | app setting/startup/restart paths |
## Accept Loop and Message Protocol
tmux accepts clients in the server event loop, creates a server-side client object, and checks ACL admission. Once a peer exists, `proc.c` owns the imsg event machinery: it reads messages, checks protocol version, dispatches callbacks, writes queued messages, supports fd passing, and stores peer UID from `getpeereid`. Client startup sends identify messages including flags, terminal name, cwd, stdin/stdout fds, pid, and environment, then sends the initial command over imsg.
cmux uses a `DispatchSourceRead` on the listener socket. Accept drains pending clients in a loop, treats transient accept errors separately from rearm/backoff failures, then hands each client to a socket handler. The protocol is line-oriented: the handler reads newline-delimited UTF-8, supports event-stream requests, dispatches V1 text commands or V2 JSON commands, and writes one response per line.
Sources: [tmux-tmux:server.c:367-408](), [tmux-tmux:proc.c:70-176](), [tmux-tmux:proc.c:301-336](), [tmux-tmux:client.c:343-401](), [tmux-tmux:client.c:448-494](), [manaflow-ai-cmux:Sources/TerminalController.swift:2399-2468](), [manaflow-ai-cmux:Sources/TerminalController.swift:2680-2758](), [manaflow-ai-cmux:Sources/TerminalController.swift:2877-2918]()
## Control Mode Versus cmux CLI Commands
tmux control mode is a protocol mode for clients. It creates per-client control state, bufferevents, pane output queues, and subscriptions. Input lines are parsed as tmux commands, while output ordering is carefully preserved so `%output` blocks can hold later notifications until the pane output has been written.
cmux exposes a much wider CLI surface over its app socket: workspace, pane, browser, feed, auth, notification, and tmux-compatibility commands. The CLI resolves a socket path, connects, authenticates if a socket password is available, and sends newline-terminated text or JSON. It also has special no-socket paths for help, docs, and some settings/config commands, so users can inspect or configure without a running socket.
Sources: [tmux-tmux:control.c:30-44](), [tmux-tmux:control.c:553-583](), [tmux-tmux:control.c:769-817](), [tmux-tmux:control.c:831-854](), [manaflow-ai-cmux:CLI/cmux.swift:2690-3060](), [manaflow-ai-cmux:CLI/cmux.swift:29454-29644]()
## Access Modes and Local Trust
tmux access is UID-based once a peer connects. Server ACL initialization allows root, when the server owner is not root, and the server owner's UID. New clients are admitted only if their peer UID is present; read-only state is copied to the client when the ACL user is marked read-only. The accept callback rejects disallowed clients with `access not allowed`.
cmux exposes access as product modes. `off` disables the listener. `cmuxOnly` allows only processes started inside cmux terminals. `automation` allows external local automation clients from the same macOS user without the ancestry check. `password` requires socket authentication. `allowAll` sets the socket file to `0666` and is explicitly described as unsafe. All non-open modes use `0600` socket permissions.
Sources: [tmux-tmux:server.c:396-400](), [tmux-tmux:server-acl.c:52-63](), [tmux-tmux:server-acl.c:96-119](), [tmux-tmux:server-acl.c:122-179](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:8-62](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:760-776]()
## cmux Automation Guardrails
cmux's default mode is `cmuxOnly`. In that mode, the socket handler verifies the peer PID with `LOCAL_PEERPID` and walks the process tree to confirm the caller descends from the cmux process. If the PID cannot be read, it falls back to `LOCAL_PEERCRED` and requires the same UID. Password mode gates both V1 `auth <password>` and V2 `auth.login` before dispatching commands. The password can come from `CMUX_SOCKET_PASSWORD`, a local Application Support file, or a legacy keychain fallback.
The CLI mirrors those guardrails from the client side. Before connecting to a local socket, it verifies the path exists, is a Unix socket, and is owned by the current user to avoid fake-socket attacks. The CLI also resolves passwords from explicit `--password`, environment, local file, or keychain, then sends `auth <password>` before normal commands.
Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:818-856](), [manaflow-ai-cmux:Sources/TerminalController.swift:2153-2234](), [manaflow-ai-cmux:Sources/TerminalController.swift:2680-2758](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:64-132](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:164-212](), [manaflow-ai-cmux:CLI/cmux.swift:1328-1450](), [manaflow-ai-cmux:CLI/cmux.swift:1710-1764](), [manaflow-ai-cmux:CLI/cmux.swift:4833-4848]()
## Socket Path Discovery
tmux clients target the configured `socket_path` and rely on lock/retry/start behavior when the path is missing or refused. cmux has more path-discovery logic because app variants, debug tags, and stable releases can coexist. `SocketControlSettings.socketPath` honors `CMUX_SOCKET_PATH` only under controlled conditions, reserves stable release paths, and falls back to user-scoped stable paths when another user owns the stable socket. The CLI resolver prefers connectable candidates, then existing socket files, then discovered tagged debug sockets.
Sources: [tmux-tmux:client.c:103-180](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:293-355](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:421-492](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:601-640](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:644-670](), [manaflow-ai-cmux:CLI/CLISocketPathResolver.swift:82-160](), [manaflow-ai-cmux:CLI/CLISocketPathResolver.swift:216-321](), [manaflow-ai-cmux:CLI/CLISocketPathResolver.swift:433-449]()
## Portable Design Lessons
tmux's strongest portable idea is making server startup race-safe: connect, lock, retry, clean stale paths, then start one owner. cmux's strongest portable idea is turning socket exposure into a user-visible access mode, with stricter defaults and client-side fake-socket checks. These ideas are provider-neutral: neither requires a particular AI model, hosted service, or proprietary connector. They can be applied to BYOC/BYOK systems as local process, file, repository, or catalog-level policies around a Unix socket protocol.
A Grok-Wiki or local-agent integration should preserve that neutrality by treating socket control as a local capability boundary: discover a socket path, verify ownership, select an access mode, authenticate only when required, and send explicit commands. Do not couple socket access to a model provider; couple it to local identity, process ancestry, file permissions, and user-approved automation scope.
Sources: [tmux-tmux:client.c:121-165](), [tmux-tmux:server.c:105-144](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:8-62](), [manaflow-ai-cmux:CLI/cmux.swift:1716-1726]()
## Summary
tmux makes the socket a daemon gateway: the client may bootstrap the server, the server owns accept and imsg dispatch, and ACLs are UID-based. cmux makes the socket an app-controlled automation surface: app settings decide whether the listener runs, access modes shape permissions and authentication, and the CLI adds path discovery plus ownership checks before sending newline-delimited commands. The shared pattern is local Unix socket control; the main architectural difference is whether lifecycle belongs to a detached server or the foreground application runtime. Sources: [tmux-tmux:server.c:176-235](), [manaflow-ai-cmux:Sources/TerminalController.swift:1539-1782]()
---
## 04. Panes, Workspaces & Layout
> Compares tmux's sessions, windows, panes, split commands, and layout tree mechanics with cmux's workspaces, panels, Bonsplit-backed layout state, terminal panels, and persisted surface snapshots.
- Page Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/04-panes-workspaces-layout.md
- Generated: 2026-05-24T19:14:10.516Z
### Source Files
- `tmux-tmux:window.c`
- `tmux-tmux:layout.c`
- `tmux-tmux:layout-set.c`
- `tmux-tmux:cmd-split-window.c`
- `tmux-tmux:spawn.c`
- `manaflow-ai-cmux:Sources/Workspace.swift`
- `manaflow-ai-cmux:Sources/TabManager.swift`
- `manaflow-ai-cmux:Sources/Panels/TerminalPanel.swift`
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:window.c](tmux-tmux/window.c)
- [tmux-tmux:layout.c](tmux-tmux/layout.c)
- [tmux-tmux:layout-set.c](tmux-tmux/layout-set.c)
- [tmux-tmux:cmd-split-window.c](tmux-tmux/cmd-split-window.c)
- [tmux-tmux:spawn.c](tmux-tmux/spawn.c)
- [tmux-tmux:tmux.h](tmux-tmux/tmux.h)
- [manaflow-ai-cmux:Sources/Workspace.swift](manaflow-ai-cmux/Sources/Workspace.swift)
- [manaflow-ai-cmux:Sources/TabManager.swift](manaflow-ai-cmux/Sources/TabManager.swift)
- [manaflow-ai-cmux:Sources/Panels/TerminalPanel.swift](manaflow-ai-cmux/Sources/Panels/TerminalPanel.swift)
- [manaflow-ai-cmux:Sources/Panels/Panel.swift](manaflow-ai-cmux/Sources/Panels/Panel.swift)
- [manaflow-ai-cmux:Sources/SessionPersistence.swift](manaflow-ai-cmux/Sources/SessionPersistence.swift)
- [manaflow-ai-cmux:Sources/TerminalController.swift](manaflow-ai-cmux/Sources/TerminalController.swift)
</details>
# Panes, Workspaces & Layout
This page compares tmux's terminal-native model of sessions, windows, panes, split commands, and mutable layout cells with cmux's app-level model of workspaces, panels, Bonsplit panes, surface tabs, and persisted session snapshots.
The useful contrast is ownership. tmux owns pseudo-terminals and screen geometry directly inside a server process. cmux owns higher-level UI surfaces, maps them onto Bonsplit layout state, and persists enough metadata to reconstruct the user workspace after restart.
## Mental Model
```text
tmux cmux
session TabManager
winlink index -> window Workspace[]
window Workspace
panes[] panels[UUID]
active pane surfaceIdToPanelId[TabID]
layout_root BonsplitController tree
```
tmux separates a globally stored `window` from per-session `winlink` entries, so the same window can be linked into session-local window trees. cmux treats a `Workspace` as the sidebar tab and gives each workspace one `BonsplitController`; panels are app objects addressed by stable UUIDs while Bonsplit tabs are the layout/tab-strip handles.
Sources: [tmux-tmux:window.c:45-52](), [tmux-tmux:tmux.h:1509-1524](), [tmux-tmux:tmux.h:1350-1408](), [tmux-tmux:tmux.h:1412-1429](), [manaflow-ai-cmux:Sources/Workspace.swift:8973-9033](), [manaflow-ai-cmux:Sources/Workspace.swift:9921-10025]()
## Object Ownership
| Concern | tmux | cmux |
|---|---|---|
| Top-level user container | `session`, with current window and a tree of `winlink` entries. | `TabManager` owns `Workspace` tabs. |
| Layout container | `window`, with pane list, active pane, and `layout_root`. | `Workspace`, with one `BonsplitController`. |
| Leaf content | `window_pane`, containing PTY/process state, screen state, size, offsets, and layout cell pointer. | `Panel` implementations such as `TerminalPanel`, `BrowserPanel`, markdown, file preview, and right sidebar tool. |
| Layout identity | `layout_cell` tree points directly at panes. | Bonsplit pane/tab IDs are mapped to stable panel UUIDs through `surfaceIdToPanelId`. |
Sources: [tmux-tmux:tmux.h:1250-1345](), [tmux-tmux:tmux.h:1350-1488](), [manaflow-ai-cmux:Sources/Panels/Panel.swift:5-37](), [manaflow-ai-cmux:Sources/Panels/TerminalPanel.swift:6-23](), [manaflow-ai-cmux:Sources/Workspace.swift:9018-9033](), [manaflow-ai-cmux:Sources/Workspace.swift:10010-10025]()
## Splitting Panes
### tmux
`split-window` first resolves geometry into either a tiled or floating layout cell. For normal tiled panes, it refuses to split floating panes, computes split geometry, pushes zoom state, calls `layout_split_pane`, then passes a `spawn_context` to `spawn_pane`. `spawn_pane` creates or reuses a `window_pane`, assigns the prepared layout cell, and forks the process through a PTY.
Sources: [tmux-tmux:cmd-split-window.c:72-127](), [tmux-tmux:cmd-split-window.c:160-195](), [tmux-tmux:spawn.c:249-280](), [tmux-tmux:spawn.c:363-405]()
### cmux
cmux splitting is panel-first and Bonsplit-backed. `newTerminalSplit` finds the source panel's Bonsplit tab and pane, creates a new `TerminalPanel`, pre-generates a `Bonsplit.Tab`, installs the surface-to-panel mapping before layout mutation, then calls `bonsplitController.splitPane`. This is explicitly done to avoid transient empty-panel flashes while the layout changes.
Sources: [manaflow-ai-cmux:Sources/Workspace.swift:12312-12345](), [manaflow-ai-cmux:Sources/Workspace.swift:12396-12418](), [manaflow-ai-cmux:Sources/Workspace.swift:12427-12458](), [manaflow-ai-cmux:Sources/Workspace.swift:12615-12690]()
## Layout Trees
tmux's layout tree is internal C state. A `layout_cell` is either a split node (`LAYOUT_LEFTRIGHT`, `LAYOUT_TOPBOTTOM`, `LAYOUT_FLOATING`) or a `LAYOUT_WINDOWPANE` leaf. Split operations may insert into an existing same-orientation parent, create a new root, or resize an existing full-size root before inserting a child.
```c
/* tmux-tmux:tmux.h */
struct layout_cell {
enum layout_type type;
struct layout_cell *parent;
u_int sx, sy;
int xoff, yoff;
struct window_pane *wp;
struct layout_cells cells;
};
```
cmux persists a higher-level tree shape. A `SessionWorkspaceLayoutSnapshot` is either a pane containing ordered panel IDs and a selected panel ID, or a split containing orientation, divider position, and two children. That makes persisted layout state independent of live AppKit view objects and Bonsplit runtime IDs.
Sources: [tmux-tmux:tmux.h:1460-1488](), [tmux-tmux:layout.c:203-237](), [tmux-tmux:layout.c:984-1158](), [manaflow-ai-cmux:Sources/SessionPersistence.swift:1473-1519](), [manaflow-ai-cmux:Sources/Workspace.swift:352-373]()
## Resizing And Presets
tmux has built-in layout arrangers: even horizontal, even vertical, main-horizontal, main-vertical, mirrored variants, and tiled. These rebuild or redistribute the layout tree, then fix offsets and pane sizes. The tiled layout computes rows and columns, skips floating panes, builds row/column cells, and adjusts the final row or column to fill available space.
cmux delegates interactive split geometry to Bonsplit, but it snapshots divider positions and can reapply them during session restore with `setDividerPosition`. Debug tooling also asks Bonsplit for a `layoutSnapshot`, then correlates pane frames with selected panels and live AppKit view frames.
Sources: [tmux-tmux:layout-set.c:31-121](), [tmux-tmux:layout-set.c:139-185](), [tmux-tmux:layout-set.c:615-726](), [manaflow-ai-cmux:Sources/Workspace.swift:1199-1217](), [manaflow-ai-cmux:Sources/TerminalController.swift:17590-17758]()
## Persistence And Restore
tmux keeps pane state in the server process: panes carry PTY/process fields, screen buffers, size, offsets, and the current layout cell. Reattaching clients redisplays the virtual screen state, but this code path is not a structured app-session snapshot format.
cmux has explicit session persistence. A workspace snapshot stores title/custom metadata, current directory, focused panel, layout tree, panels, status/log/progress/git metadata, and optional remote configuration. Restore rebuilds the Bonsplit tree first, creates panels into each restored pane, prunes stale metadata, reapplies divider positions, and restores focus through old-to-new panel ID mapping.
Sources: [tmux-tmux:window.c:45-47](), [tmux-tmux:tmux.h:1250-1326](), [manaflow-ai-cmux:Sources/SessionPersistence.swift:1232-1256](), [manaflow-ai-cmux:Sources/SessionPersistence.swift:1429-1539](), [manaflow-ai-cmux:Sources/Workspace.swift:163-250](), [manaflow-ai-cmux:Sources/Workspace.swift:253-350](), [manaflow-ai-cmux:Sources/Workspace.swift:799-890]()
## Focus And Close Semantics
tmux focus is window-local: `window_set_active_pane` unzooms if needed, updates the last-pane stack, marks the active pane changed, sends focus events when enabled, updates window offsets, redraws, and emits `window-pane-changed`.
cmux focus crosses model and UI boundaries. `focusPanel` maps a panel UUID back to a Bonsplit tab, finds the containing pane, focuses that pane if needed, selects the tab, and then applies AppKit focus intent so keyboard input reaches the intended surface. Closing similarly begins from stable panel IDs but routes through Bonsplit tab close requests.
Sources: [tmux-tmux:window.c:524-554](), [tmux-tmux:window.c:804-833](), [manaflow-ai-cmux:Sources/Workspace.swift:13253-13297](), [manaflow-ai-cmux:Sources/Workspace.swift:14019-14120](), [manaflow-ai-cmux:Sources/TabManager.swift:6264-6335]()
## Portable Design Lessons
tmux is stronger as a compact terminal multiplexer core: geometry, PTYs, process lifetime, pane focus, and screen buffers are tightly integrated. cmux is stronger as an application workspace surface: multiple panel types, UI focus repair, browser/terminal surfaces, session snapshots, and layout restore are explicit product concerns.
The portable idea is to keep layout state provider-neutral. Neither system's layout model requires a model provider or hosted service: tmux uses C structs and PTYs; cmux uses file-serializable `Codable` snapshots, stable UUID panel IDs, and a layout adapter boundary around Bonsplit. That keeps BYOC/BYOK-friendly integrations possible because agents, terminals, browser panels, and future skill sources can remain panel payloads rather than hard dependencies of the layout tree.
Sources: [tmux-tmux:layout.c:595-662](), [tmux-tmux:layout.c:1161-1177](), [manaflow-ai-cmux:Sources/Panels/Panel.swift:5-37](), [manaflow-ai-cmux:Sources/SessionPersistence.swift:1473-1539](), [manaflow-ai-cmux:Sources/Workspace.swift:10010-10025]()
## Source And Method Note
No local `STRATEGY.md` or `docs/solutions/**` source was found in the prepared workspace during this focused pass. The selected Compound Engineering guidance was treated as bundled page-shape and QA routing context only; implementation claims above are grounded in repository code rather than an installed local workflow or any model-provider-specific tool.
In short: tmux makes panes the primitive and grows session/window semantics around them; cmux makes workspaces and panels the primitive, then projects them into Bonsplit layout state and persisted snapshots. The architectural bridge is the tree: tmux's tree is live geometry over panes, while cmux's tree is restorable UI structure over stable panel identities. Sources: [tmux-tmux:tmux.h:1250-1488](), [manaflow-ai-cmux:Sources/SessionPersistence.swift:1473-1539]()
---
## 05. Command & Config Surfaces
> Shows how tmux exposes a grammar, command queue, options, key bindings, and config loading, while cmux layers JSONC project config, command execution, Ghostty config compatibility, and CLI configuration commands.
- Page Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/05-command-config-surfaces.md
- Generated: 2026-05-24T19:16:11.184Z
### Source Files
- `tmux-tmux:cmd-parse.y`
- `tmux-tmux:cmd-queue.c`
- `tmux-tmux:cfg.c`
- `tmux-tmux:options.c`
- `tmux-tmux:key-bindings.c`
- `manaflow-ai-cmux:Sources/CmuxConfig.swift`
- `manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift`
- `manaflow-ai-cmux:Sources/GhosttyConfig.swift`
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:cmd-parse.y](tmux-tmux/cmd-parse.y)
- [tmux-tmux:cmd-queue.c](tmux-tmux/cmd-queue.c)
- [tmux-tmux:cfg.c](tmux-tmux/cfg.c)
- [tmux-tmux:options.c](tmux-tmux/options.c)
- [tmux-tmux:key-bindings.c](tmux-tmux/key-bindings.c)
- [tmux-tmux:cmd-bind-key.c](tmux-tmux/cmd-bind-key.c)
- [tmux-tmux:cmd-set-option.c](tmux-tmux/cmd-set-option.c)
- [manaflow-ai-cmux:Sources/CmuxConfig.swift](manaflow-ai-cmux/Sources/CmuxConfig.swift)
- [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift)
- [manaflow-ai-cmux:Sources/GhosttyConfig.swift](manaflow-ai-cmux/Sources/GhosttyConfig.swift)
- [manaflow-ai-cmux:Sources/CmuxWorkspaceDefinition.swift](manaflow-ai-cmux/Sources/CmuxWorkspaceDefinition.swift)
- [manaflow-ai-cmux:Sources/JSONCParser.swift](manaflow-ai-cmux/Sources/JSONCParser.swift)
- [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift)
- [manaflow-ai-cmux:cmuxTests/CmuxConfigTests.swift](manaflow-ai-cmux/cmuxTests/CmuxConfigTests.swift)
</details>
# Command & Config Surfaces
tmux and cmux both expose user-programmable command surfaces, but they choose different center points. tmux treats configuration, key bindings, hooks, and command prompts as one command language: parse text into command lists, enqueue command items, and execute them through a shared queue. cmux uses JSONC as the product-facing config shape, resolves actions and commands into UI or workspace behavior, then uses shell input, workspace creation, Ghostty-compatible parsing, and CLI helpers as execution/configuration surfaces.
This matters because both projects need extensibility without hard-wiring one automation vendor or hosted service. tmux stays portable by making the terminal multiplexer itself the grammar and runtime. cmux stays BYOC/BYOK-friendly by making config files, shell commands, local paths, and app-owned trust decisions the boundaries rather than assuming a particular model provider.
## Surface Map
| Area | tmux | cmux |
| --- | --- | --- |
| Primary config language | tmux command grammar in `cmd-parse.y` | JSONC decoded into `CmuxConfigFile` and related Codable structs |
| Execution unit | `struct cmdq_item` containing command/callback state | `CmuxResolvedConfigAction` or `CmuxCommandDefinition` executed by `CmuxConfigExecutor` |
| Config load | Config files parse into command lists and append to the global command queue | Global and local `cmux.json` files are parsed, merged, cached, and watched |
| Options | Runtime option tree with parent lookup, type parsing, arrays, and command-valued options | Structured fields for UI, actions, notifications, vault, commands, and workspace definitions |
| Key/action binding | Key tables store key-to-`cmd_list` bindings | Surface tab buttons, palette actions, shortcuts, workspace commands, and terminal commands |
| Compatibility layer | Native tmux command syntax | Ghostty config load order and key-value parser for terminal appearance/behavior |
Sources: [tmux-tmux:cmd-parse.y:42-90](tmux-tmux/cmd-parse.y#L42-L90), [tmux-tmux:cmd-queue.c:35-94](tmux-tmux/cmd-queue.c#L35-L94), [manaflow-ai-cmux:Sources/CmuxConfig.swift:10-85](manaflow-ai-cmux/Sources/CmuxConfig.swift#L10-L85), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:8-65](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L8-L65), [manaflow-ai-cmux:Sources/GhosttyConfig.swift:183-240](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L183-L240)
## tmux: Grammar First, Queue Second
tmux’s command parser builds an intermediate parse tree with command arguments that can be strings, nested commands, or already-parsed command lists. The yacc grammar handles statements, conditions, expanded formats, and command arguments before `cmd_parse_build_command` converts the parsed arguments into `args_value` entries and calls `cmd_parse`. Alias expansion is also part of the parser path, so aliases are resolved before the final command list is built.
```text
tmux config/key/prompt text
|
v
cmd-parse.y grammar + aliases
|
v
struct cmd_list
|
v
cmdq_get_command -> cmdq_append / cmdq_insert_after
|
v
cmdq_next -> cmdq_fire_command -> entry->exec
```
The command queue is the runtime boundary. A `cmdq_item` holds the command or callback, shared queue state, source/target find states, client references, grouping, and waiting/fired flags. `cmdq_get_command` expands a `cmd_list` into linked queue items, and `cmdq_next` fires command or callback items until the queue is empty or a command returns wait. Errors remove later commands in the same group.
Sources: [tmux-tmux:cmd-parse.y:120-215](tmux-tmux/cmd-parse.y#L120-L215), [tmux-tmux:cmd-parse.y:438-470](tmux-tmux/cmd-parse.y#L438-L470), [tmux-tmux:cmd-parse.y:768-865](tmux-tmux/cmd-parse.y#L768-L865), [tmux-tmux:cmd-queue.c:493-537](tmux-tmux/cmd-queue.c#L493-L537), [tmux-tmux:cmd-queue.c:730-800](tmux-tmux/cmd-queue.c#L730-L800)
### Config Files Are Command Sources
tmux does not give config files a separate object model. `start_cfg` loads configured files without a client and appends a completion callback to the global queue. `load_cfg` opens the file, sets parse metadata such as file, line, client, and current item, parses via `cmd_parse_from_file`, and turns the resulting command list into queue items. Buffer-backed config loading follows the same pattern via `cmd_parse_from_buffer`.
The key design consequence: config loading, command strings, key bindings, hooks, and source-file behavior all share the same command grammar and queue semantics.
Sources: [tmux-tmux:cfg.c:64-92](tmux-tmux/cfg.c#L64-L92), [tmux-tmux:cfg.c:95-150](tmux-tmux/cfg.c#L95-L150), [tmux-tmux:cfg.c:155-202](tmux-tmux/cfg.c#L155-L202), [tmux-tmux:cmd-parse.y:938-1032](tmux-tmux/cmd-parse.y#L938-L1032)
### Options and Hooks Reuse the Parser
tmux options are stored in red-black trees with parent lookup. Option names support direct lookup, mapped names, array indexes like `name[3]`, prefix matching, and user options beginning with `@`. Command-valued options are parsed through `cmd_parse_from_string`, both for defaults and for `options_from_string`.
`set-option`, `set-window-option`, and `set-hook` all share `cmd_set_option_exec`. That command expands the option name, resolves the option scope, validates indexes and `-o` behavior, parses typed values, updates arrays or scalar options, and pushes option changes.
Sources: [tmux-tmux:options.c:50-68](tmux-tmux/options.c#L50-L68), [tmux-tmux:options.c:216-240](tmux-tmux/options.c#L216-L240), [tmux-tmux:options.c:257-296](tmux-tmux/options.c#L257-L296), [tmux-tmux:options.c:624-727](tmux-tmux/options.c#L624-L727), [tmux-tmux:options.c:1098-1176](tmux-tmux/options.c#L1098-L1176), [tmux-tmux:cmd-set-option.c:83-205](tmux-tmux/cmd-set-option.c#L83-L205), [tmux-tmux:cmd-set-option.c:203-260](tmux-tmux/cmd-set-option.c#L203-L260)
### Key Bindings Store Command Lists
`bind-key` accepts either parsed command arguments or a string that is parsed into a command list. `key_bindings_add` stores the resulting `cmd_list` in a key table. Defaults are themselves strings parsed through `cmd_parse_from_string` and appended to the global queue during key binding initialization. Dispatching a key builds a new command queue state from the current key event and target state, then appends or inserts the bound command list.
Sources: [tmux-tmux:cmd-bind-key.c:35-106](tmux-tmux/cmd-bind-key.c#L35-L106), [tmux-tmux:key-bindings.c:106-124](tmux-tmux/key-bindings.c#L106-L124), [tmux-tmux:key-bindings.c:191-226](tmux-tmux/key-bindings.c#L191-L226), [tmux-tmux:key-bindings.c:650-679](tmux-tmux/key-bindings.c#L650-L679), [tmux-tmux:key-bindings.c:690-719](tmux-tmux/key-bindings.c#L690-L719)
## cmux: JSONC Model, Resolved Actions, Explicit Trust
cmux starts with structured config. `CmuxConfigFile` contains actions, UI, notifications, `newWorkspaceCommand`, surface tab bar buttons, commands, and vault configuration. Commands are stricter than tmux command strings: a `CmuxCommandDefinition` must have a non-blank name and exactly one runnable form, either `workspace` or `command`. A workspace command can carry name, cwd, color, and layout through `CmuxWorkspaceDefinition`.
```swift
// manaflow-ai-cmux:Sources/CmuxConfig.swift
struct CmuxCommandDefinition: Codable, Sendable, Identifiable {
var name: String
var workspace: CmuxWorkspaceDefinition?
var command: String?
var confirm: Bool?
}
```
Sources: [manaflow-ai-cmux:Sources/CmuxConfig.swift:10-85](manaflow-ai-cmux/Sources/CmuxConfig.swift#L10-L85), [manaflow-ai-cmux:Sources/CmuxConfig.swift:1563-1638](manaflow-ai-cmux/Sources/CmuxConfig.swift#L1563-L1638), [manaflow-ai-cmux:Sources/CmuxWorkspaceDefinition.swift:3-36](manaflow-ai-cmux/Sources/CmuxWorkspaceDefinition.swift#L3-L36), [manaflow-ai-cmux:cmuxTests/CmuxConfigTests.swift:36-100](manaflow-ai-cmux/cmuxTests/CmuxConfigTests.swift#L36-L100)
### Global and Local Config Resolution
cmux has a layered config model rather than one global command queue. The default global path is `~/.config/cmux/cmux.json`. Local project config is discovered by walking upward and checking `.cmux/cmux.json` and `cmux.json`, with hierarchy results reversed so parent configs can be considered before deeper configs. During `loadAll`, local config takes precedence for workspace action, context menu, new workspace command, surface buttons, and command names; global config fills missing pieces.
Actions are then resolved into a registry seeded with built-ins. Global actions are applied first, local actions second, and commands become custom resolved actions when no action with the same command id exists.
Sources: [manaflow-ai-cmux:Sources/CmuxConfig.swift:1854-1862](manaflow-ai-cmux/Sources/CmuxConfig.swift#L1854-L1862), [manaflow-ai-cmux:Sources/CmuxConfig.swift:2021-2088](manaflow-ai-cmux/Sources/CmuxConfig.swift#L2021-L2088), [manaflow-ai-cmux:Sources/CmuxConfig.swift:2120-2250](manaflow-ai-cmux/Sources/CmuxConfig.swift#L2120-L2250), [manaflow-ai-cmux:Sources/CmuxConfig.swift:2375-2430](manaflow-ai-cmux/Sources/CmuxConfig.swift#L2375-L2430), [manaflow-ai-cmux:cmuxTests/CmuxConfigTests.swift:337-380](manaflow-ai-cmux/cmuxTests/CmuxConfigTests.swift#L337-L380)
### JSONC Parsing Is a Compatibility Layer, Not a Runtime
cmux accepts JSONC by preprocessing files before `JSONDecoder` sees them. The parser detects common JSON encodings, strips a BOM, removes line and block comments outside strings, removes legal trailing commas, and reports malformed trailing commas or unterminated block comments. `parseConfig` caches by file size, modification date, and workspace color palette fingerprint, then stores either decoded config or a schema issue.
This keeps the product surface friendly for hand-edited config files while preserving a typed Swift runtime model.
Sources: [manaflow-ai-cmux:Sources/JSONCParser.swift:3-10](manaflow-ai-cmux/Sources/JSONCParser.swift#L3-L10), [manaflow-ai-cmux:Sources/JSONCParser.swift:12-78](manaflow-ai-cmux/Sources/JSONCParser.swift#L12-L78), [manaflow-ai-cmux:Sources/JSONCParser.swift:80-146](manaflow-ai-cmux/Sources/JSONCParser.swift#L80-L146), [manaflow-ai-cmux:Sources/JSONCParser.swift:148-220](manaflow-ai-cmux/Sources/JSONCParser.swift#L148-L220), [manaflow-ai-cmux:Sources/CmuxConfig.swift:2829-2897](manaflow-ai-cmux/Sources/CmuxConfig.swift#L2829-L2897)
## cmux Execution Surfaces
`CmuxConfigExecutor` separates two runnable forms. Workspace commands create or select workspaces, resolve cwd relative to a base cwd, set custom title/color, and apply layout. Terminal commands are sanitized, authorized, suffixed with a newline, and sent either to the current terminal or a new tab in the current pane.
Project-local config is treated as a trust boundary. If the action comes from the global config path, it runs directly. If it comes from a project path, cmux checks a trust descriptor and optional confirmation before executing. This is the main difference from tmux: tmux trusts its command stream once parsed, while cmux distinguishes global/user-owned config from project-local automation.
Sources: [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:8-65](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L8-L65), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:68-118](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L68-L118), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:125-160](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L125-L160), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:188-241](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L188-L241), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:454-515](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L454-L515)
## Ghostty Compatibility as Config Input
cmux also reads Ghostty config for terminal behavior and appearance. The loader matches Ghostty’s macOS load order, including XDG paths, Application Support paths, conditional legacy config inclusion, and cmux app-support config paths. The parser handles simple `key=value` directives for font, font size, theme, working directory, scrollback, background/foreground/cursor colors, opacity, and blur.
Recursive `config-file` directives are collected after each file is parsed. Included paths are expanded for `~`, resolved relative to the parent directory when needed, and read with a loaded-path set for recursive includes. This makes Ghostty compatibility an adapter layer around local files rather than a separate remote dependency.
Sources: [manaflow-ai-cmux:Sources/GhosttyConfig.swift:82-130](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L82-L130), [manaflow-ai-cmux:Sources/GhosttyConfig.swift:183-240](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L183-L240), [manaflow-ai-cmux:Sources/GhosttyConfig.swift:370-455](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L370-L455), [manaflow-ai-cmux:Sources/GhosttyConfig.swift:510-646](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L510-L646), [manaflow-ai-cmux:Sources/GhosttyConfig.swift:962-968](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L962-L968)
## CLI Configuration Commands
cmux exposes config operations through `cmux config`. The CLI supports path/docs output, `doctor|check|validate`, and `reload`. `reload` connects to a socket-backed app command path and sends `reload_config`; the non-socket subcommands can run without a running app. `config doctor` validates JSONC syntax by preprocessing, requiring a top-level JSON object, and reporting keys, bytes, status, and errors.
This is a more explicit support surface than tmux’s config parser: tmux reports config parse/runtime causes through command queue output and control mode, while cmux gives users a separate inspection and validation command for config files before reload.
Sources: [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift:3-67](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift#L3-L67), [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift:69-136](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift#L69-L136), [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift:198-210](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift#L198-L210), [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift:300-325](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift#L300-L325), [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift:327-423](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift#L327-L423), [tmux-tmux:cfg.c:222-258](tmux-tmux/cfg.c#L222-L258)
## Portable Design Lessons
| Lesson | tmux evidence | cmux evidence | Portable idea |
| --- | --- | --- | --- |
| Keep one runtime command representation | Parsed text becomes `cmd_list`, then `cmdq_item` | JSONC becomes resolved actions/commands before execution | Normalize inputs before executing them |
| Treat config as code only when the language is the product | `.tmux.conf` is tmux command syntax | `cmux.json` is typed config, not a shell script | Choose grammar when scripting is the feature; choose schema when UX and validation matter |
| Preserve local-first control | Config files are local and queued in-process | JSONC, Ghostty config, shell commands, and paths are local surfaces | BYOC/BYOK-friendly systems should accept file and process boundaries without requiring hosted providers |
| Make unsafe/project-local automation visible | tmux has no project-local trust layer in these files | cmux checks trust descriptors for non-global config before action execution | Project config should be considered a different trust surface from user global config |
Sources: [tmux-tmux:cmd-parse.y:983-1032](tmux-tmux/cmd-parse.y#L983-L1032), [tmux-tmux:cmd-queue.c:597-684](tmux-tmux/cmd-queue.c#L597-L684), [manaflow-ai-cmux:Sources/CmuxConfig.swift:1563-1638](manaflow-ai-cmux/Sources/CmuxConfig.swift#L1563-L1638), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:188-241](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L188-L241)
## Summary
tmux is strongest when every user-facing surface can be expressed as tmux commands: config files, hooks, options, and key bindings all converge on `cmd_parse` and `cmdq`. cmux is strongest when product configuration must be inspectable, mergeable, project-aware, and safer for local automation: JSONC is decoded into typed definitions, resolved into app actions, guarded at project boundaries, and supported by CLI validation plus Ghostty config compatibility. Both designs are provider-neutral because their extension points are local grammar, files, commands, paths, and process execution rather than a required cloud or model provider. Sources: [tmux-tmux:key-bindings.c:690-719](tmux-tmux/key-bindings.c#L690-L719), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:125-160](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L125-L160)
---
## 06. Agent Notifications & Hooks
> Explains the shift from tmux's terminal alerts and control notifications to cmux's agent-aware notification queue, unread state, CLI hook definitions, and extensible hook formats for multiple coding agents.
- Page Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/06-agent-notifications-hooks.md
- Generated: 2026-05-24T19:16:38.129Z
### Source Files
- `tmux-tmux:notify.c`
- `tmux-tmux:alerts.c`
- `tmux-tmux:control-notify.c`
- `tmux-tmux:input.c`
- `manaflow-ai-cmux:Sources/TerminalNotificationStore.swift`
- `manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift`
- `manaflow-ai-cmux:Sources/NotificationsPage.swift`
- `manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift`
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:notify.c](tmux-tmux/notify.c)
- [tmux-tmux:alerts.c](tmux-tmux/alerts.c)
- [tmux-tmux:control-notify.c](tmux-tmux/control-notify.c)
- [tmux-tmux:input.c](tmux-tmux/input.c)
- [tmux-tmux:window.c](tmux-tmux/window.c)
- [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift)
- [manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift](manaflow-ai-cmux/Sources/TerminalNotificationQueue.swift)
- [manaflow-ai-cmux:Sources/NotificationsPage.swift](manaflow-ai-cmux/Sources/NotificationsPage.swift)
- [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift)
- [manaflow-ai-cmux:Sources/CmuxConfig.swift](manaflow-ai-cmux/Sources/CmuxConfig.swift)
- [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift)
- [manaflow-ai-cmux:CLI/cmux.swift](manaflow-ai-cmux/CLI/cmux.swift)
- [manaflow-ai-cmux:Sources/KeyboardShortcutSettingsFileStore+Template.swift](manaflow-ai-cmux/Sources/KeyboardShortcutSettingsFileStore+Template.swift)
</details>
# Agent Notifications & Hooks
This page compares tmux's notification model with cmux's agent-oriented model. tmux treats notification as terminal/session state: bells, activity, silence, control-mode protocol messages, and server hooks. cmux keeps those terminal ideas but adds an application-level queue, unread state, desktop delivery, notification policy hooks, and CLI-generated integrations for multiple coding agents.
The useful architectural shift is from "a terminal event happened" to "an agent or terminal surface produced an actionable item for a workspace." That shift lets cmux preserve state across UI views, apply user or project policy, and remain BYOC/BYOK-friendly: hooks are local commands and config files, not tied to a hosted model provider.
## tmux: Alerts, Control Notifications, And Hooks
tmux has three related but distinct paths:
| Path | What it does | Evidence |
| --- | --- | --- |
| Terminal alerts | BEL, activity, and silence set window flags and schedule an alert check. | `input_c0_dispatch` queues `WINDOW_BELL`; `window_update_activity` queues `WINDOW_ACTIVITY`; `alerts_queue` coalesces work through `alerts_list`. |
| User-facing alert output | Depending on options, attached non-control clients get terminal bell output and/or status messages. | `alerts_set_message` skips control clients, sends `TTYC_BEL`, and sets status messages. |
| Control-mode notifications and hooks | Named notifications are routed to control clients and then to configured tmux hooks. | `notify_callback` calls `control_notify_*` functions and then `notify_insert_hook`. |
Sources: [tmux-tmux:input.c:1294-1300](tmux-tmux/input.c), [tmux-tmux:window.c:287-292](tmux-tmux/window.c), [tmux-tmux:alerts.c:157-180](tmux-tmux/alerts.c), [tmux-tmux:alerts.c:292-324](tmux-tmux/alerts.c), [tmux-tmux:notify.c:122-158](tmux-tmux/notify.c)
tmux's alert checks are window-centric. `alerts_check_bell`, `alerts_check_activity`, and `alerts_check_silence` inspect window flags, apply per-session action options, call `notify_winlink` with names such as `alert-bell`, and then decide whether to surface a bell/message to clients. The state is compact and terminal-native, but it is not an inbox with per-workspace unread semantics.
Sources: [tmux-tmux:alerts.c:182-215](tmux-tmux/alerts.c), [tmux-tmux:alerts.c:220-251](tmux-tmux/alerts.c), [tmux-tmux:alerts.c:257-289](tmux-tmux/alerts.c), [tmux-tmux:notify.c:278-285](tmux-tmux/notify.c)
tmux control notifications are protocol lines for clients running in control mode. The control path filters to `CLIENT_CONTROL` clients with initialized control state, then writes records such as `%pane-mode-changed`, `%window-pane-changed`, `%session-changed`, and `%paste-buffer-changed`.
Sources: [tmux-tmux:control-notify.c:26-40](tmux-tmux/control-notify.c), [tmux-tmux:control-notify.c:75-89](tmux-tmux/control-notify.c), [tmux-tmux:control-notify.c:148-169](tmux-tmux/control-notify.c), [tmux-tmux:control-notify.c:236-259](tmux-tmux/control-notify.c)
## cmux: Notification As Workspace State
cmux promotes notifications into a first-class app model. `TerminalNotification` stores identifiers for workspace tab, optional surface/panel, title/subtitle/body, creation time, read state, pane flash state, and optional click action. `TerminalNotificationStore` publishes the notification list and derives indexes for unread count, unread counts by tab, unread surfaces, and latest notification lookup.
Sources: [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:694-739](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift), [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:742-787](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift), [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:873-895](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift)
The store records new notifications by removing older notifications for the same tab/surface, inserting the new one at the front, refreshing unread presentation, and then delivering side effects. Read state is explicit: cmux can mark one notification, one tab, one tab/surface, or all notifications as read, and it removes delivered or pending system notification requests when clearing read state.
Sources: [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:1368-1423](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift), [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:1425-1472](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift), [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:1558-1610](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift), [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:1665-1687](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift)
The UI is built around review, not only interruption. `NotificationsPage` reads the store, shows empty and workspace-unread states, renders rows with unread dots, opens the originating notification target, supports "Jump to Latest Unread," and clears individual or all notifications.
Sources: [manaflow-ai-cmux:Sources/NotificationsPage.swift:4-54](manaflow-ai-cmux/Sources/NotificationsPage.swift), [manaflow-ai-cmux:Sources/NotificationsPage.swift:69-88](manaflow-ai-cmux/Sources/NotificationsPage.swift), [manaflow-ai-cmux:Sources/NotificationsPage.swift:115-156](manaflow-ai-cmux/Sources/NotificationsPage.swift), [manaflow-ai-cmux:Sources/NotificationsPage.swift:185-253](manaflow-ai-cmux/Sources/NotificationsPage.swift)
```text
tmux
pane/window event
-> window alert flags
-> control protocol line or terminal bell/status
-> optional tmux hook command
cmux
agent/terminal event
-> queued workspace/surface notification mutation
-> policy hook envelope
-> recorded unread notification
-> UI state + desktop/sound/custom command effects
```
## Queueing And Coalescing
cmux separates cross-thread event intake from main-actor UI mutation with `TerminalMutationBus`. It queues notification delivery and clear operations, assigns sequence numbers, coalesces pending notifications by generation and target key, and drains batches on the main actor. Clear operations can remove pending delivery entries before they hit the store.
Sources: [manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift:35-62](manaflow-ai-cmux/Sources/TerminalNotificationQueue.swift), [manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift:122-166](manaflow-ai-cmux/Sources/TerminalNotificationQueue.swift), [manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift:168-195](manaflow-ai-cmux/Sources/TerminalNotificationQueue.swift), [manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift:217-233](manaflow-ai-cmux/Sources/TerminalNotificationQueue.swift)
Delivery is guarded against stale targets. Before queued delivery reaches `addNotification`, cmux checks whether the target tab or surface still exists. There is also a synchronous delivery path that discards pending notifications for the same target before immediately adding a notification.
Sources: [manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift:326-354](manaflow-ai-cmux/Sources/TerminalNotificationQueue.swift), [manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift:357-378](manaflow-ai-cmux/Sources/TerminalNotificationQueue.swift), [manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift:381-419](manaflow-ai-cmux/Sources/TerminalNotificationQueue.swift)
## Notification Policy Hooks
cmux lets notification behavior be shaped by configured local commands. The config schema supports `notifications.hooks`, `hooksMode`, per-hook `id`, `command`, `timeoutSeconds`, and `enabled`. Global hooks are loaded first, local hooks are appended by default, and local config can replace inherited hooks with `hooksMode: "replace"`.
Sources: [manaflow-ai-cmux:Sources/CmuxConfig.swift:146-217](manaflow-ai-cmux/Sources/CmuxConfig.swift), [manaflow-ai-cmux:Sources/CmuxConfig.swift:2005-2019](manaflow-ai-cmux/Sources/CmuxConfig.swift), [manaflow-ai-cmux:Sources/CmuxConfig.swift:2282-2307](manaflow-ai-cmux/Sources/CmuxConfig.swift), [manaflow-ai-cmux:Sources/KeyboardShortcutSettingsFileStore+Template.swift:91-102](manaflow-ai-cmux/Sources/KeyboardShortcutSettingsFileStore+Template.swift)
A notification policy hook receives a JSON envelope with notification payload, context, and effect flags. Defaults are enabled for recording, unread marking, workspace reorder, desktop delivery, sound, custom command, and pane flash. Hooks can return JSON patches to modify the envelope or stop later hooks.
```swift
// manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift
struct TerminalNotificationPolicyEffects: Codable, Sendable, Equatable {
var record: Bool = true
var markUnread: Bool = true
var reorderWorkspace: Bool = true
var desktop: Bool = true
var sound: Bool = true
var command: Bool = true
var paneFlash: Bool = true
}
```
Sources: [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift:5-28](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift), [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift:180-186](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift), [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift:255-279](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift), [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift:913-929](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift)
Hooks are executed as local `/bin/sh -c` commands in the resolved hook working directory. cmux passes notification fields both as environment variables and as JSON on stdin, enforces a timeout, limits stdout size, treats non-zero exit status as failure, and decodes non-empty stdout as a JSON patch.
Sources: [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift:459-551](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift), [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift:553-562](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift), [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift:644-689](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift), [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift:776-817](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift)
## Agent Hook Definitions
cmux's CLI hook layer is explicitly multi-agent. `AgentHookDef` records the agent name, config location, environment overrides, disable environment variable, hook marker, binary name, supported events, feed-hook events, and hook format. This makes adding an agent a data-definition problem when the target agent fits an existing format.
```swift
// manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift
enum HookFormat {
case flat
case nested(timeoutMs: Int)
case antigravityJSON(timeoutSeconds: Int)
case rovoDevYAML
case hermesAgentYAML
}
```
Sources: [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:6-47](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:49-73](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:104-118](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift)
The current definitions cover Codex, Grok, OpenCode, Pi, Amp, Cursor, Gemini, Antigravity, Rovo Dev, Hermes Agent, Copilot, CodeBuddy, Factory, and Qoder. Different agents map their native lifecycle names to cmux subcommands such as `session-start`, `prompt-submit`, `stop`, `notification`, and `session-end`.
Sources: [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:122-152](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:153-187](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:188-245](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:246-297](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift)
The generated shell command stays portable: it finds a bundled CLI path or `cmux` on `PATH`, respects `CMUX_SOCKET_PATH`, requires `CMUX_SURFACE_ID` for normal dispatch, and returns `{}` when disabled or unavailable. Grok and Antigravity use pinned dispatch with extra marker and trace support.
Sources: [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:304-320](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:323-370](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:384-433](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift)
## Format Adapters Preserve User Config
For JSON-based agents, cmux builds hook dictionaries differently for flat, nested, and Antigravity schemas. Feed bridge hooks get a longer timeout so interactive approvals or plan/question waits do not hit the agent's shorter default timeout.
Sources: [manaflow-ai-cmux:CLI/cmux.swift:23148-23208](manaflow-ai-cmux/CLI/cmux.swift), [manaflow-ai-cmux:CLI/cmux.swift:23210-23239](manaflow-ai-cmux/CLI/cmux.swift)
Installation is careful about ownership. cmux removes only cmux-owned entries from existing hook config, preserves unknown or user-owned data, and then inserts new cmux entries. Specialized adapters handle OpenCode, Pi, Amp, Rovo Dev, Hermes Agent, and Antigravity before the generic JSON installer runs.
Sources: [manaflow-ai-cmux:CLI/cmux.swift:24115-24140](manaflow-ai-cmux/CLI/cmux.swift), [manaflow-ai-cmux:CLI/cmux.swift:24176-24249](manaflow-ai-cmux/CLI/cmux.swift), [manaflow-ai-cmux:CLI/cmux.swift:24252-24282](manaflow-ai-cmux/CLI/cmux.swift), [manaflow-ai-cmux:CLI/cmux.swift:28898-28925](manaflow-ai-cmux/CLI/cmux.swift)
## Portable Design Takeaways
| Design question | tmux answer | cmux answer | Portable idea |
| --- | --- | --- | --- |
| What is the notification target? | Window, winlink, session, control client. | Workspace tab, surface/panel, notification record. | Keep low-level events, but normalize them into product objects. |
| Is unread state first-class? | No, alert flags/status are transient terminal state. | Yes, `isRead`, unread indexes, manual/restored/panel-derived workspace indicators. | Treat "needs attention" separately from "should interrupt." |
| Can policy change delivery? | tmux options choose bell/activity/silence behavior and hooks run commands. | Configured hooks can patch record/unread/desktop/sound/command/paneFlash effects. | Use local command hooks for provider-neutral extension. |
| How are agents integrated? | Not agent-specific. | Agent definitions map native hook events to cmux subcommands and config formats. | Model integrations as data plus format adapters. |
Sources: [tmux-tmux:alerts.c:70-89](tmux-tmux/alerts.c), [tmux-tmux:notify.c:178-230](tmux-tmux/notify.c), [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:749-787](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift), [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift:21-28](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:6-47](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift)
## BYOC/BYOK Implications
cmux's architecture stays vendor-agnostic because notification policy is a local shell-command contract and agent integration is driven by config files, environment variables, socket paths, and CLI subcommands. No notification path in the inspected code requires a specific model provider or hosted connector. A Grok-Wiki integration should keep that property: skill packs, generated wiki context, and hook definitions should be portable file, repository, or catalog sources, with repository code remaining the source of truth.
Sources: [manaflow-ai-cmux:Sources/CmuxConfig.swift:236-277](manaflow-ai-cmux/Sources/CmuxConfig.swift), [manaflow-ai-cmux:Sources/TerminalNotificationPolicy.swift:524-562](manaflow-ai-cmux/Sources/TerminalNotificationPolicy.swift), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:315-320](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift)
## Generation Context
This page used repository code as source of truth. The selected Compound Engineering guidance was applied as page-shaping metadata from the provided bundled snapshot description; no local `STRATEGY.md`, `AGENTS.md`, or `docs/solutions/**` files were found in the two repository folders during this focused pass.
## Summary
tmux provides a robust terminal multiplexer notification substrate: alert flags, visual/audible terminal feedback, control-mode protocol events, and hook dispatch. cmux builds a product workflow above that kind of substrate: queued workspace notifications, explicit unread state, review UI, desktop/sound/custom command effects, local policy hooks, and multi-agent CLI hook definitions. The portable lesson is to keep raw terminal and agent events simple, then normalize them into an application-owned notification record before applying policy or UI behavior.
Sources: [tmux-tmux:notify.c:122-158](tmux-tmux/notify.c), [manaflow-ai-cmux:Sources/TerminalNotificationQueue.swift:326-354](manaflow-ai-cmux/Sources/TerminalNotificationQueue.swift), [manaflow-ai-cmux:Sources/TerminalNotificationStore.swift:1425-1472](manaflow-ai-cmux/Sources/TerminalNotificationStore.swift), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:122-297](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift)
---
## 07. Browser Automation vs Terminal Control
> Contrasts tmux's terminal-only control and capture model with cmux's browser pane automation, WebKit-backed panels, screenshots, profiles, and socket-addressable browser actions for local dev workflows.
- Page Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/07-browser-automation-vs-terminal-control.md
- Generated: 2026-05-24T19:16:26.579Z
### Source Files
- `tmux-tmux:control.c`
- `tmux-tmux:cmd-capture-pane.c`
- `tmux-tmux:input-keys.c`
- `manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift`
- `manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift`
- `manaflow-ai-cmux:Sources/Panels/CmuxWebView.swift`
- `manaflow-ai-cmux:Sources/Panels/BrowserScreenshotPipeline.swift`
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:control.c](tmux-tmux/control.c)
- [tmux-tmux:cmd-capture-pane.c](tmux-tmux/cmd-capture-pane.c)
- [tmux-tmux:input-keys.c](tmux-tmux/input-keys.c)
- [tmux-tmux:cmd-send-keys.c](tmux-tmux/cmd-send-keys.c)
- [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift](manaflow-ai-cmux/Sources/Panels/BrowserPanel.swift)
- [manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift](manaflow-ai-cmux/Sources/Panels/BrowserAutomation.swift)
- [manaflow-ai-cmux:Sources/Panels/CmuxWebView.swift](manaflow-ai-cmux/Sources/Panels/CmuxWebView.swift)
- [manaflow-ai-cmux:Sources/Panels/BrowserScreenshotPipeline.swift](manaflow-ai-cmux/Sources/Panels/BrowserScreenshotPipeline.swift)
- [manaflow-ai-cmux:Sources/Panels/BrowserScreenshotSnapshotter.swift](manaflow-ai-cmux/Sources/Panels/BrowserScreenshotSnapshotter.swift)
- [manaflow-ai-cmux:Sources/TerminalController.swift](manaflow-ai-cmux/Sources/TerminalController.swift)
- [manaflow-ai-cmux:Sources/KeyboardShortcutSettings.swift](manaflow-ai-cmux/Sources/KeyboardShortcutSettings.swift)
- [manaflow-ai-cmux:cmuxTests/CMUXCLIErrorOutputRegressionTests.swift](manaflow-ai-cmux/cmuxTests/CMUXCLIErrorOutputRegressionTests.swift)
</details>
# Browser Automation vs Terminal Control
This page contrasts two local-dev control models. tmux exposes terminal panes as command-addressable PTYs: clients can send keys, capture scrollback or pending output, and consume ordered control-mode output. cmux keeps that terminal idea, but adds browser panes backed by WebKit and a socket API for navigation, DOM snapshots, clicks, form input, screenshots, downloads, profiles, and browser state.
No `STRATEGY.md` or `docs/solutions/**` sources were present in this workspace, so this page uses repository code as the source of truth. The Compound Engineering guidance was treated as bundled wiki-shaping guidance only, not as an installed local workflow. The comparison is provider-neutral: neither model requires a specific LLM vendor, hosted agent, or proprietary model API.
## Core Difference
| Capability | tmux | cmux |
|---|---|---|
| Primary surface | Terminal pane / PTY | Terminal plus browser panel |
| Output model | `%output` and `%extended-output` lines, pane history capture | DOM/accessibility-like snapshots, JS eval results, screenshot PNGs, browser state |
| Input model | Encoded terminal keys and mouse escape sequences | Browser navigation, DOM selector actions, synthetic DOM events, WebKit methods |
| Automation address | tmux command queue and control-mode client | JSON socket methods plus legacy browser commands |
| Browser profile state | Not in scope | Named browser profiles, website data stores, history files, import/clear/delete automation |
Sources: [tmux-tmux:control.c:30-42](), [tmux-tmux:control.c:615-729](), [tmux-tmux:input-keys.c:398-419](), [manaflow-ai-cmux:Sources/TerminalController.swift:3521-3578](), [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift:334-390]()
## tmux: Terminal-Only Control
tmux control mode is a line protocol around terminal state. Incoming control lines are parsed into tmux commands, while outgoing data is buffered and ordered so pane output does not overtake later notifications. The code comments describe one queue per client plus pane queues for `%output` blocks, and `control_read_callback` turns newline-delimited client input into command queue work.
Sources: [tmux-tmux:control.c:30-42](), [tmux-tmux:control.c:553-580](), [tmux-tmux:control.c:771-809]()
```text
control client
-> newline command
-> cmd_parse_and_append(...)
-> pane/session/window command effects
window pane output
-> window_pane_get_new_data(...)
-> %output / %extended-output
-> control client
```
`capture-pane` works from tmux's terminal screen model. It chooses the base screen, alternate screen, or mode screen, extracts grid lines, and either writes to a paste buffer or prints to the client; in control mode, printable capture output is sent with `control_write`. That is powerful for shell transcripts, compiler output, REPL logs, and terminal UIs, but it is still text/grid capture rather than DOM or pixel capture.
Sources: [tmux-tmux:cmd-capture-pane.c:39-49](), [tmux-tmux:cmd-capture-pane.c:107-151](), [tmux-tmux:cmd-capture-pane.c:213-247]()
Input follows the same terminal boundary. `send-keys` resolves key names or literal strings, injects keys into a pane, and delegates to `window_pane_key`; `input_key` then encodes characters, VT10x keys, extended keys, and mouse events into bytes written to the pane bufferevent.
Sources: [tmux-tmux:cmd-send-keys.c:74-128](), [tmux-tmux:cmd-send-keys.c:193-240](), [tmux-tmux:input-keys.c:574-713](), [tmux-tmux:input-keys.c:797-815]()
## cmux: Browser Pane Automation
cmux's browser surface is a real `WKWebView`. `BrowserPanel` configures WebKit with persistent website data, JavaScript enabled, user scripts, developer extras, navigation delegates, download state, history state, and a Safari user agent. `CmuxWebView` extends `WKWebView` behavior for focus routing, JavaScript checks, mouse back/forward buttons, and drag routing inside the pane system.
Sources: [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift:3368-3415](), [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift:2758-2788](), [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift:3638-3655](), [manaflow-ai-cmux:Sources/Panels/CmuxWebView.swift:1-16](), [manaflow-ai-cmux:Sources/Panels/CmuxWebView.swift:720-771]()
The socket API makes browser panels addressable by workspace, pane, or surface. `TerminalController` dispatches JSON methods such as `browser.navigate`, `browser.snapshot`, `browser.eval`, `browser.click`, `browser.type`, `browser.screenshot`, and many `browser.find.*` / `browser.get.*` calls. `v2BrowserWithPanel` resolves the target browser panel before each operation, so actions are scoped to the selected or explicitly requested surface.
Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:10923-10980](), [manaflow-ai-cmux:Sources/TerminalController.swift:3521-3578](), [manaflow-ai-cmux:Sources/TerminalController.swift:3580-3628](), [manaflow-ai-cmux:Sources/TerminalController.swift:3888-3948]()
### DOM-Level Actions
For browser automation, cmux does not just send keystrokes to a terminal process. It executes JavaScript inside the page. `browser.snapshot` builds a structured page payload with title, URL, ready state, text, HTML, and element entries with selectors, roles, names, and refs. Selector actions retry lookup, run a generated script, and can append a post-action snapshot.
Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:11912-11950](), [manaflow-ai-cmux:Sources/TerminalController.swift:12015-12215](), [manaflow-ai-cmux:Sources/TerminalController.swift:12221-12250]()
Clicks and text entry are selector-based. `browser.click` scrolls an element into view and calls `el.click()` or dispatches a mouse event. `browser.type` focuses the element, appends text, updates React-compatible values, and dispatches `input` and `change`. This is a browser automation model, not a terminal escape-sequence model.
Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:12391-12450](), [manaflow-ai-cmux:Sources/TerminalController.swift:12473-12515](), [manaflow-ai-cmux:Sources/TerminalController.swift:12525-12556]()
## Screenshots and Visual Feedback
tmux capture is terminal-grid text. cmux has both visible browser snapshots and full-page screenshot plumbing. The socket screenshot path asks a `BrowserPanel` for a snapshot and returns base64 PNG data, with a best-effort temporary file path. The screenshot pipeline supports full-page and selected-section modes, crops selected regions, and writes PNG/TIFF data to the pasteboard.
Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:12735-12756](), [manaflow-ai-cmux:Sources/TerminalController.swift:12758-12775](), [manaflow-ai-cmux:Sources/Panels/BrowserScreenshotPipeline.swift:45-65](), [manaflow-ai-cmux:Sources/Panels/BrowserScreenshotPipeline.swift:71-113](), [manaflow-ai-cmux:Sources/Panels/BrowserScreenshotPipeline.swift:145-192]()
Full-page capture is bounded and WebKit-aware. `BrowserScreenshotWebViewSnapshotter` first tries a single full-content `WKSnapshotConfiguration`, validates the result against content dimensions, and falls back to scrolling and stitching viewport tiles. It also caps full-page size at `100_000_000` pixels.
Sources: [manaflow-ai-cmux:Sources/Panels/BrowserScreenshotSnapshotter.swift:43-78](), [manaflow-ai-cmux:Sources/Panels/BrowserScreenshotSnapshotter.swift:80-109](), [manaflow-ai-cmux:Sources/Panels/BrowserScreenshotSnapshotter.swift:120-156]()
## Profiles, Cookies, and Local Dev Sessions
tmux has no browser profile concept because it does not host a browser engine. cmux models browser profiles directly: each profile has an id, display name, built-in default flag, slug, website data store, and history store. Automation can list, create, rename, clear, and delete profiles, and profile deletion is blocked while live browser panels are using that profile.
Sources: [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift:334-390](), [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift:530-570](), [manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift:183-223](), [manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift:233-288](), [manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift:306-356]()
Browser import automation can select installed browser profiles, default to a detected default profile, merge or map source profiles into cmux profiles, and create a destination profile when explicitly allowed. This is useful for local dev workflows where a browser pane should already carry cookies or history from an existing browser, without tying the workflow to any model provider.
Sources: [manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift:378-421](), [manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift:442-498]()
## Socket Addressability
cmux has two browser command layers in `TerminalController`: JSON v2 socket methods and legacy string commands. The v2 dispatcher covers browser automation broadly; the legacy commands include `openBrowser`, `navigateBrowser`, `browserBack`, `browserForward`, and `browserReload`. Tests also verify browser-related CLI socket behavior through `CMUX_SOCKET_PATH`.
Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:2248-2372](), [manaflow-ai-cmux:Sources/TerminalController.swift:18288-18405](), [manaflow-ai-cmux:cmuxTests/CMUXCLIErrorOutputRegressionTests.swift:783-842]()
The socket model is portable across agents because the integration boundary is local JSON or CLI command execution. A BYOC/BYOK architecture can let any local or remote coding agent call these primitives, as long as it can reach the local socket or CLI; the browser surface does not require a specific hosted model or vendor connector.
Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:2280-2297](), [manaflow-ai-cmux:Sources/TerminalController.swift:2300-2308](), [manaflow-ai-cmux:Sources/TerminalController.swift:3518-3578]()
## Important Limits
cmux's browser automation is WebKit-backed, not Chrome DevTools Protocol. The code explicitly reports CDP-style screencast and raw mouse/keyboard/touch input as unsupported, and points callers toward higher-level browser actions such as `browser.click`, `browser.hover`, `browser.scroll`, `browser.press`, `browser.keydown`, and `browser.keyup`.
Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:14890-14903]()
tmux's corresponding limit is that it controls terminal applications through bytes and terminal state. That makes it stable and broadly compatible for shell workflows, but it cannot inspect page roles, fill DOM inputs, preserve browser cookies, or capture browser pixels unless an external browser/tool is layered on top.
Sources: [tmux-tmux:input-keys.c:414-419](), [tmux-tmux:input-keys.c:574-713](), [tmux-tmux:cmd-capture-pane.c:107-151]()
## Portable Design Takeaway
tmux is the better primitive when the task is terminal-native: run commands, drive TUIs, capture scrollback, and stream ordered pane output. cmux is the broader local-dev surface when the task spans terminal plus browser: open a dev server beside the shell, preserve authenticated browser state, inspect a page, click through UI, fill forms, take screenshots, and wait for downloads.
The portable pattern is not "choose a model provider"; it is "keep the control plane local and explicit." tmux demonstrates a durable terminal protocol, while cmux extends that idea with browser panels and socket-addressable browser actions. A Grok-Wiki or agent workflow can stay BYOC/BYOK-friendly by treating skill packs, repository files, and catalog entries as portable sources, then issuing local CLI/socket actions without assuming any specific LLM vendor or hosted automation backend. Sources: [tmux-tmux:control.c:553-580](), [tmux-tmux:control.c:615-729](), [manaflow-ai-cmux:Sources/TerminalController.swift:10923-10980](), [manaflow-ai-cmux:Sources/TerminalController.swift:12735-12775]()
---
## 08. Remote SSH & Provider Neutrality
> Compares tmux's shell, job, and spawn portability with cmux's SSH workspace, remote PTY attach, loopback routing, and daemon bridge design. The portable lesson is to keep orchestration file, socket, and repository based so BYOC/BYOK workflows do not depend on one model provider or hosted connector.
- Page Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/08-remote-ssh-provider-neutrality.md
- Generated: 2026-05-24T19:16:41.943Z
### Source Files
- `tmux-tmux:spawn.c`
- `tmux-tmux:job.c`
- `tmux-tmux:cmd-new-session.c`
- `tmux-tmux:environ.c`
- `manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift`
- `manaflow-ai-cmux:Sources/WorkspaceRemoteSSHBatchCommandBuilder.swift`
- `manaflow-ai-cmux:Sources/RemoteLoopbackRuntimeBridge.swift`
- `manaflow-ai-cmux:Sources/RemoteRelayZshBootstrap.swift`
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:spawn.c](tmux-tmux/spawn.c)
- [tmux-tmux:job.c](tmux-tmux/job.c)
- [tmux-tmux:cmd-new-session.c](tmux-tmux/cmd-new-session.c)
- [tmux-tmux:environ.c](tmux-tmux/environ.c)
- [tmux-tmux:regress/new-session-size.sh](tmux-tmux/regress/new-session-size.sh)
- [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift)
- [manaflow-ai-cmux:Sources/WorkspaceRemoteSSHBatchCommandBuilder.swift](manaflow-ai-cmux/Sources/WorkspaceRemoteSSHBatchCommandBuilder.swift)
- [manaflow-ai-cmux:Sources/RemoteLoopbackRuntimeBridge.swift](manaflow-ai-cmux/Sources/RemoteLoopbackRuntimeBridge.swift)
- [manaflow-ai-cmux:Sources/RemoteRelayZshBootstrap.swift](manaflow-ai-cmux/Sources/RemoteRelayZshBootstrap.swift)
- [manaflow-ai-cmux:Sources/RemoteLoopbackProxyAlias.swift](manaflow-ai-cmux/Sources/RemoteLoopbackProxyAlias.swift)
- [manaflow-ai-cmux:Sources/Workspace.swift](manaflow-ai-cmux/Sources/Workspace.swift)
- [manaflow-ai-cmux:Sources/CmuxSSHURLRequest.swift](manaflow-ai-cmux/Sources/CmuxSSHURLRequest.swift)
- [manaflow-ai-cmux:Sources/AppDelegate+CmuxSSHURL.swift](manaflow-ai-cmux/Sources/AppDelegate+CmuxSSHURL.swift)
- [manaflow-ai-cmux:cmuxTests/WorkspaceRemoteConnectionTests.swift](manaflow-ai-cmux/cmuxTests/WorkspaceRemoteConnectionTests.swift)
- [manaflow-ai-cmux:cmuxTests/CmuxSSHURLRequestTests.swift](manaflow-ai-cmux/cmuxTests/CmuxSSHURLRequestTests.swift)
</details>
# Remote SSH & Provider Neutrality
This page compares two different portability layers. `tmux` keeps terminal orchestration portable by treating shells, jobs, PTYs, working directories, and environment variables as local Unix process concerns. `cmux` builds a remote workspace layer around SSH, remote daemon transport, local socket forwarding, persistent PTY attach, loopback rewriting, and external-link guarding.
The shared architecture lesson is not “use one hosted connector.” It is to keep orchestration file-, socket-, process-, and repository-based so BYOC/BYOK workflows can move across machines, SSH configurations, keys, agents, and model providers without recoding the runtime boundary.
## Boundary Model
```text
tmux local process model
client/session env + cwd + shell
-> forkpty/fork
-> execvp or $SHELL -c
-> pane/job fd events
cmux remote workspace model
workspace config + SSH options + socket path
-> ssh stdio daemon OR ssh local-forwarded daemon socket OR websocket daemon
-> daemon RPC/proxy/PTY bridge
-> browser loopback alias + terminal attach/retry
```
`tmux` is narrower and lower-level: it launches local children correctly and portably. `cmux` is broader: it preserves local workspace UX while moving execution and PTY ownership behind SSH or another daemon transport. The provider-neutral takeaway is that neither boundary needs to be a model-provider API; both are organized around shells, sockets, process arguments, and runtime capabilities.
Sources: [tmux-tmux:spawn.c:30-48](tmux-tmux/spawn.c), [tmux-tmux:job.c:70-116](tmux-tmux/job.c), [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:51-63](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift), [manaflow-ai-cmux:Sources/Workspace.swift:1757-1795](manaflow-ai-cmux/Sources/Workspace.swift)
## tmux: Shell, Job, and Spawn Portability
### Session launch is environment-first
`new-session` accepts a start directory, explicit environment entries, session naming, sizing, and an optional shell command. It creates a session environment, optionally updates it from the client environment, applies `-e` overrides, creates the session, and then passes a `spawn_context` into `spawn_window`.
Sources: [tmux-tmux:cmd-new-session.c:38-51](tmux-tmux/cmd-new-session.c), [tmux-tmux:cmd-new-session.c:262-296](tmux-tmux/cmd-new-session.c)
### Spawn normalizes cwd, PATH, shell, PTY, and exec form
`spawn_pane` builds a child environment from the session, adds pane identity, preserves useful client `PATH` behavior for unattached clients, falls back to `_PATH_DEFPATH`, validates `default-shell`, sets `SHELL`, then forks a PTY. In the child, it pushes the prepared environment and chooses between `execvp(argv)` for multi-argument commands, `$SHELL -c` for one command string, or a login shell when no command is supplied.
Sources: [tmux-tmux:spawn.c:207-240](tmux-tmux/spawn.c), [tmux-tmux:spawn.c:323-353](tmux-tmux/spawn.c), [tmux-tmux:spawn.c:393-489](tmux-tmux/spawn.c)
### Jobs reuse the same portability pattern
`job_run` also builds an environment via `environ_for_session`, chooses a shell from defaults when requested, forks either a PTY job or pipe-backed job, pushes the environment, and executes either shell command text or an argv vector. Job state is fd/event driven, with explicit PTY resize support and a closed/dead lifecycle.
Sources: [tmux-tmux:job.c:70-116](tmux-tmux/job.c), [tmux-tmux:job.c:120-190](tmux-tmux/job.c), [tmux-tmux:job.c:198-231](tmux-tmux/job.c), [tmux-tmux:job.c:291-307](tmux-tmux/job.c), [tmux-tmux:job.c:339-384](tmux-tmux/job.c)
### Environment is a controlled handoff, not global magic
`environ_update` copies only variables selected by `update-environment`; `environ_push` materializes the prepared environment after fork; `environ_for_session` merges global and session environment, sets terminal variables, clears inherited systemd socket activation variables, and writes `TMUX` with the socket path, server pid, and session id.
Sources: [tmux-tmux:environ.c:185-228](tmux-tmux/environ.c), [tmux-tmux:environ.c:250-282](tmux-tmux/environ.c)
## cmux: Remote SSH Workspace Layers
### Remote configuration is transport-neutral at the workspace boundary
`WorkspaceRemoteTransport` supports both `ssh` and `websocket`. The remote configuration records destination, port, identity file, SSH options, local proxy port, relay metadata, local socket path, terminal startup command, foreground auth token, daemon websocket endpoint, PTY preservation, and daemon bootstrap mode. That field set describes connection mechanics and capabilities, not a specific AI provider.
Sources: [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:51-80](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift), [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:276-327](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift)
### SSH startup supports both simple reconnect and persistent PTY attach
For normal SSH workspaces, `workspaceConfiguration()` normalizes destination, validates port range, normalizes SSH options, and chooses either a persistent PTY startup command or a plain reconnect command. Persistent PTY mode adds SSH control defaults, checks whether foreground auth is reusable, mints a foreground token, and uses `ssh-pty-attach` through the local cmux socket.
Sources: [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:365-411](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift), [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:83-150](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift), [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:154-215](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift)
### Batch SSH commands isolate background transport from interactive sessions
`WorkspaceRemoteSSHBatchCommandBuilder` has three distinct command shapes:
| Command shape | Purpose | Portability detail |
| --- | --- | --- |
| `daemonTransportArguments` | Run remote daemon over stdio | Uses `ssh -T` and `sh -c 'exec remotePath serve --stdio'` |
| `daemonSocketForwardArguments` | Forward a local loopback port to a remote Unix socket | Uses `-N -T -S none` and `-L 127.0.0.1:localPort:remoteSocketPath` |
| `reverseRelayControlMasterArguments` | Ask an existing control master to add/cancel reverse forwarding | Requires a configured `ControlPath` |
The builder adds timeouts, keepalives, `BatchMode=yes`, default `StrictHostKeyChecking=accept-new` when absent, and `ControlMaster=no` so helpers may reuse configured control sockets without negotiating a new master.
Sources: [manaflow-ai-cmux:Sources/WorkspaceRemoteSSHBatchCommandBuilder.swift:3-76](manaflow-ai-cmux/Sources/WorkspaceRemoteSSHBatchCommandBuilder.swift), [manaflow-ai-cmux:Sources/WorkspaceRemoteSSHBatchCommandBuilder.swift:96-130](manaflow-ai-cmux/Sources/WorkspaceRemoteSSHBatchCommandBuilder.swift), [manaflow-ai-cmux:cmuxTests/WorkspaceRemoteConnectionTests.swift:1976-2064](manaflow-ai-cmux/cmuxTests/WorkspaceRemoteConnectionTests.swift)
### The daemon bridge can run through SSH stdio, socket forward, or websocket
`WorkspaceRemoteDaemonRPCClient.start()` chooses websocket, baked-VM socket forward, or SSH exec. SSH exec launches `/usr/bin/ssh` with daemon arguments and wires stdin/stdout/stderr pipes as the RPC transport. Baked VM mode launches SSH local forwarding to `/run/cmuxd-remote.sock`, then connects to the allocated loopback socket. Capability negotiation checks for proxy streaming and, when PTY preservation is requested, PTY session/token support.
Sources: [manaflow-ai-cmux:Sources/Workspace.swift:1757-1795](manaflow-ai-cmux/Sources/Workspace.swift), [manaflow-ai-cmux:Sources/Workspace.swift:1827-1877](manaflow-ai-cmux/Sources/Workspace.swift), [manaflow-ai-cmux:Sources/Workspace.swift:1879-1948](manaflow-ai-cmux/Sources/Workspace.swift), [manaflow-ai-cmux:Sources/Workspace.swift:2660-2680](manaflow-ai-cmux/Sources/Workspace.swift)
### PTY attach is routed through the daemon proxy broker
The remote proxy broker keys tunnels by `proxyBrokerTransportKey`, shares a tunnel across subscribers, exposes PTY list/close/resize/detach/start bridge operations, and reports a local browser proxy endpoint on `127.0.0.1`. This keeps terminal lifecycle and browser proxy lifecycle attached to a workspace transport key rather than a hosted provider session.
Sources: [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:335-346](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift), [manaflow-ai-cmux:Sources/Workspace.swift:3840-3897](manaflow-ai-cmux/Sources/Workspace.swift), [manaflow-ai-cmux:Sources/Workspace.swift:3900-3975](manaflow-ai-cmux/Sources/Workspace.swift), [manaflow-ai-cmux:Sources/Workspace.swift:3978-4025](manaflow-ai-cmux/Sources/Workspace.swift)
## Loopback Routing and Remote Browser UX
Remote development servers often bind to `localhost`, `127.0.0.1`, `::1`, or `0.0.0.0` on the remote host, but browser code in a local web view needs a routable alias. `RemoteLoopbackProxyAlias` defines `cmux-loopback.localtest.me`, maps localhost-family names to that alias, and maps aliases back to localhost-family hosts. `RemoteLoopbackRuntimeBridge` injects a document-start script that rewrites `http:` and `ws:` loopback requests for `fetch`, `XMLHttpRequest`, and `WebSocket`, deliberately leaving `https:` and `wss:` untouched because TLS certificate/SNI expectations would change.
Sources: [manaflow-ai-cmux:Sources/RemoteLoopbackProxyAlias.swift:3-54](manaflow-ai-cmux/Sources/RemoteLoopbackProxyAlias.swift), [manaflow-ai-cmux:Sources/RemoteLoopbackRuntimeBridge.swift:3-72](manaflow-ai-cmux/Sources/RemoteLoopbackRuntimeBridge.swift), [manaflow-ai-cmux:Sources/RemoteLoopbackRuntimeBridge.swift:74-105](manaflow-ai-cmux/Sources/RemoteLoopbackRuntimeBridge.swift), [manaflow-ai-cmux:Sources/Panels/BrowserPanel.swift:3412-3418](manaflow-ai-cmux/Sources/Panels/BrowserPanel.swift)
## External SSH Entry Points and Guardrails
`CmuxSSHURLRequest` turns supported `cmux://ssh`-style URLs into CLI arguments such as `cmux ssh --port ... --name ... destination`. The parser only allows a narrow query set, rejects unsafe destination forms, validates ports, and converts selected knobs into SSH options. The app delegate launches the bundled CLI through the resolved cmux socket and warns that SSH may use local SSH config, keys, agent settings, `ProxyCommand`, `LocalCommand`, and forwarding rules.
Sources: [manaflow-ai-cmux:Sources/CmuxSSHURLRequest.swift:21-65](manaflow-ai-cmux/Sources/CmuxSSHURLRequest.swift), [manaflow-ai-cmux:Sources/CmuxSSHURLRequest.swift:80-198](manaflow-ai-cmux/Sources/CmuxSSHURLRequest.swift), [manaflow-ai-cmux:Sources/AppDelegate+CmuxSSHURL.swift:22-70](manaflow-ai-cmux/Sources/AppDelegate+CmuxSSHURL.swift), [manaflow-ai-cmux:Sources/AppDelegate+CmuxSSHURL.swift:216-275](manaflow-ai-cmux/Sources/AppDelegate+CmuxSSHURL.swift), [manaflow-ai-cmux:cmuxTests/CmuxSSHURLRequestTests.swift:17-70](manaflow-ai-cmux/cmuxTests/CmuxSSHURLRequestTests.swift), [manaflow-ai-cmux:cmuxTests/CmuxSSHURLRequestTests.swift:279-335](manaflow-ai-cmux/cmuxTests/CmuxSSHURLRequestTests.swift)
## Comparison Brief
| Concern | tmux approach | cmux approach | Portable lesson |
| --- | --- | --- | --- |
| Process launch | Local `forkpty`/`fork`, `execvp`, `$SHELL -c`, login shell | Local app launches `/usr/bin/ssh`, remote daemon, socket forward, or websocket | Keep launch mechanics explicit and argument-based |
| Environment | Session/client env merge, `PATH`, `SHELL`, `TERM`, `TMUX` socket | Workspace config, SSH options, socket path, foreground auth token | Treat environment and socket paths as durable orchestration inputs |
| PTY lifecycle | Pane/job owns PTY fd and resize | Remote daemon exposes PTY list/resize/detach/start bridge | Put PTY operations behind capability-checked boundaries |
| Remote routing | Out of scope in these files | Loopback alias and browser runtime rewriting | Route local dev servers without hardcoding a vendor tunnel |
| BYOC/BYOK fit | Uses user shell, cwd, env, and local socket | Uses user SSH destination, key path, SSH config/options, socket, daemon capabilities | Let users bring compute, SSH keys, config, and model keys independently |
Sources: [tmux-tmux:spawn.c:323-489](tmux-tmux/spawn.c), [tmux-tmux:environ.c:250-282](tmux-tmux/environ.c), [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:276-327](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift), [manaflow-ai-cmux:Sources/WorkspaceRemoteSSHBatchCommandBuilder.swift:9-76](manaflow-ai-cmux/Sources/WorkspaceRemoteSSHBatchCommandBuilder.swift), [manaflow-ai-cmux:Sources/Workspace.swift:3900-3975](manaflow-ai-cmux/Sources/Workspace.swift)
## Design Implications for Provider-Neutral Workspaces
A provider-neutral remote workspace should keep these boundaries stable:
1. **Repository and filesystem first.** The durable unit is the workspace checkout plus its configuration, not a hosted model session.
2. **Sockets and stdio for orchestration.** Local socket paths, SSH stdio, SSH port forwards, and daemon RPC make the bridge portable across clouds and local machines.
3. **Keys remain user-controlled.** SSH identity files, agent behavior, and SSH config are local user inputs. Model API keys can follow the same BYOK pattern through environment or repo configuration without changing the transport.
4. **Capabilities over assumptions.** cmux checks daemon capabilities before relying on proxy streaming or persistent PTY features; this is the right pattern for optional remote features.
5. **External connectors are adapters.** A hosted connector can create or discover a workspace, but the runtime should still reduce to files, sockets, SSH/websocket transport, and repository state.
Sources: [manaflow-ai-cmux:Sources/Workspace.swift:1770-1795](manaflow-ai-cmux/Sources/Workspace.swift), [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:462-473](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift), [manaflow-ai-cmux:cmuxTests/WorkspaceRemoteConnectionTests.swift:260-290](manaflow-ai-cmux/cmuxTests/WorkspaceRemoteConnectionTests.swift), [manaflow-ai-cmux:cmuxTests/WorkspaceRemoteConnectionTests.swift:383-430](manaflow-ai-cmux/cmuxTests/WorkspaceRemoteConnectionTests.swift)
## Closing Summary
`tmux` shows the durable Unix core: build the right environment, fork the right kind of child, attach it to a PTY or pipe, and keep sockets visible through environment. `cmux` extends that lesson to remote workspaces by making SSH, daemon RPC, loopback routing, and PTY attach explicit transport layers. The portable architecture is BYOC/BYOK friendly because compute, keys, sockets, repositories, and model-provider choices remain separable rather than being fused into one hosted connector. Sources: [tmux-tmux:environ.c:213-282](tmux-tmux/environ.c), [manaflow-ai-cmux:Sources/WorkspaceRemoteConfiguration.swift:276-327](manaflow-ai-cmux/Sources/WorkspaceRemoteConfiguration.swift), [manaflow-ai-cmux:Sources/Workspace.swift:11513-11650](manaflow-ai-cmux/Sources/Workspace.swift)
---
## 09. Regression & Fuzz Boundaries
> Maps the quality signals that make each project maintainable: tmux has shell regressions and fuzzers around command parsing, input, style, and formats; cmux has Swift unit and UI tests around sockets, browser panes, sessions, hooks, and app regressions.
- Page Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/09-regression-fuzz-boundaries.md
- Generated: 2026-05-24T19:17:51.769Z
### Source Files
- `tmux-tmux:fuzz/input-fuzzer.c`
- `tmux-tmux:fuzz/cmd-parse-fuzzer.c`
- `tmux-tmux:regress/control-client-sanity.sh`
- `tmux-tmux:regress/input-keys.sh`
- `manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift`
- `manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift`
- `manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift`
- `manaflow-ai-cmux:cmuxUITests/AutomationSocketUITests.swift`
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:fuzz/input-fuzzer.c](tmux-tmux/fuzz/input-fuzzer.c)
- [tmux-tmux:fuzz/cmd-parse-fuzzer.c](tmux-tmux/fuzz/cmd-parse-fuzzer.c)
- [tmux-tmux:fuzz/format-fuzzer.c](tmux-tmux/fuzz/format-fuzzer.c)
- [tmux-tmux:fuzz/style-fuzzer.c](tmux-tmux/fuzz/style-fuzzer.c)
- [tmux-tmux:Makefile.am](tmux-tmux/Makefile.am)
- [tmux-tmux:regress/control-client-sanity.sh](tmux-tmux/regress/control-client-sanity.sh)
- [tmux-tmux:regress/input-keys.sh](tmux-tmux/regress/input-keys.sh)
- [tmux-tmux:regress/format-strings.sh](tmux-tmux/regress/format-strings.sh)
- [tmux-tmux:regress/style-trim.sh](tmux-tmux/regress/style-trim.sh)
- [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift](manaflow-ai-cmux/cmuxTests/TerminalControllerSocketSecurityTests.swift)
- [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift](manaflow-ai-cmux/cmuxTests/BrowserPanelTests.swift)
- [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift](manaflow-ai-cmux/cmuxTests/CLIGenericHookPersistenceTests.swift)
- [manaflow-ai-cmux:cmuxUITests/AutomationSocketUITests.swift](manaflow-ai-cmux/cmuxUITests/AutomationSocketUITests.swift)
- [manaflow-ai-cmux:cmux.xcodeproj/xcshareddata/xcschemes/cmux-ci.xcscheme](manaflow-ai-cmux/cmux.xcodeproj/xcshareddata/xcschemes/cmux-ci.xcscheme)
- [manaflow-ai-cmux:scripts/test-unit.sh](manaflow-ai-cmux/scripts/test-unit.sh)
</details>
# Regression & Fuzz Boundaries
This page compares how `tmux` and `cmux` keep risky behavior maintainable. `tmux` leans on small shell regressions plus fuzzers around parser-like surfaces: terminal input, command parsing, formats, and style strings. `cmux` leans on XCTest unit and UI coverage around app-facing state: sockets, browser panes, session restoration, hooks, and app regression behavior.
The useful contrast is not “which project has more tests.” It is where each project draws its quality boundary. `tmux` hardens compact C entry points and executable CLI behavior; `cmux` hardens macOS application contracts, socket control policy, UI lifecycle, and provider-neutral agent hook persistence.
## Boundary Map
| Project | Main quality signal | Boundary being protected | Why it fits |
|---|---|---|---|
| `tmux` | Shell regressions and libFuzzer binaries | CLI/server behavior, terminal input bytes, command parser, format and style parsers | Core behavior is mostly process, parser, and terminal-state driven. |
| `cmux` | Swift unit tests, UI tests, Xcode schemes, helper scripts | App socket modes, JSON-RPC command routing, browser/WebKit pane behavior, generic agent hook persistence | Core behavior crosses UI, app state, sockets, and external CLI agents. |
Sources: [tmux-tmux:Makefile.am:243-256](), [tmux-tmux:regress/control-client-sanity.sh:13-39](), [manaflow-ai-cmux:cmux.xcodeproj/xcshareddata/xcschemes/cmux-ci.xcscheme:13-27](), [manaflow-ai-cmux:scripts/test-unit.sh:6-21]()
```text
tmux quality boundary
bytes / CLI commands
-> parser or tmux server
-> exact shell-visible output, layout, or no-crash invariant
cmux quality boundary
app/UI/socket/hook event
-> Swift controller, pane, workspace, or CLI hook
-> XCTest assertion over policy, state, persistence, or UI socket behavior
```
## tmux: Fuzzers Guard Parser-Like Surfaces
The `tmux` fuzz boundary is deliberately narrow and direct. `Makefile.am` wires four fuzz targets when fuzzing is enabled: `input-fuzzer`, `cmd-parse-fuzzer`, `format-fuzzer`, and `style-fuzzer`. That list mirrors high-risk string/byte interpreters rather than broad end-to-end application flows.
Sources: [tmux-tmux:Makefile.am:243-256]()
### Terminal Input Bytes
`input-fuzzer.c` creates an 80x25 window and pane, attaches a bufferevent pair, feeds arbitrary input bytes into `input_parse_buffer`, drains the command queue, runs a nonblocking libevent loop, and asserts the window reference count returns to one. The invariant is less about a specific rendered result and more about “random terminal input should not corrupt lifecycle ownership or crash the parser path.”
Sources: [tmux-tmux:fuzz/input-fuzzer.c:23-63](), [tmux-tmux:fuzz/input-fuzzer.c:71-95]()
```c
/* tmux-tmux:fuzz/input-fuzzer.c */
if (size > FUZZER_MAXLEN)
return 0;
w = window_create(PANE_WIDTH, PANE_HEIGHT, 0, 0);
wp = window_add_pane(w, NULL, 0, 0);
...
input_parse_buffer(wp, (u_char *)data, size);
while (cmdq_next(NULL) != 0)
;
...
assert(w->references == 1);
```
### Command Parsing
`cmd-parse-fuzzer.c` targets `cmd_parse_from_buffer` with quiet parsing. The file comment names the intended blast radius: yacc grammar and lexer, command lookup and validation, argument parsing, target resolution, and option lookup. The test frees successful command lists and parse errors, so the fuzzer also exercises cleanup paths for both accepted and rejected command buffers.
Sources: [tmux-tmux:fuzz/cmd-parse-fuzzer.c:17-26](), [tmux-tmux:fuzz/cmd-parse-fuzzer.c:35-59]()
### Formats And Styles
`format-fuzzer.c` null-terminates fuzz input, creates a `format_tree`, seeds realistic format variables such as `session_name`, `window_index`, `pane_id`, dimensions, and host, then calls `format_expand`. `style-fuzzer.c` similarly null-terminates input, initializes a style and grid cell, and calls `style_parse`. These are parser fuzzers with small fake worlds: enough context to enter real parsing logic, not enough to require a running tmux server.
Sources: [tmux-tmux:fuzz/format-fuzzer.c:17-24](), [tmux-tmux:fuzz/format-fuzzer.c:33-64](), [tmux-tmux:fuzz/style-fuzzer.c:17-23](), [tmux-tmux:fuzz/style-fuzzer.c:32-55]()
## tmux: Shell Regressions Encode Observable Contracts
The shell regression tests complement fuzzing by checking exact behavior that random input cannot define. `control-client-sanity.sh` launches tmux with a 200x200 server, drives a control client through pane/window mutations, then compares the final `pane_id` and `window_layout` output exactly. This protects the control-client/layout contract at the CLI boundary.
Sources: [tmux-tmux:regress/control-client-sanity.sh:13-39]()
`input-keys.sh` builds a raw `cat -tv` target and defines `assert_key`, which sends keys through tmux, captures pane output, and compares exact escape/control sequences. The table of assertions covers control keys, meta combinations, function keys, insert/delete, page keys, arrows, and keypad cases.
Sources: [tmux-tmux:regress/input-keys.sh:17-45](), [tmux-tmux:regress/input-keys.sh:47-80](), [tmux-tmux:regress/input-keys.sh:175-220]()
`format-strings.sh` checks user-visible `display-message -p` expansion behavior, including conditionals, escapes, comma handling, nested conditionals, and style fragments inside formats. `style-trim.sh` goes one step further by comparing both `display -p` values and captured terminal rendering after setting status formats with escaped style sequences.
Sources: [tmux-tmux:regress/format-strings.sh:11-24](), [tmux-tmux:regress/format-strings.sh:71-98](), [tmux-tmux:regress/format-strings.sh:139-157](), [tmux-tmux:regress/style-trim.sh:29-40](), [tmux-tmux:regress/style-trim.sh:42-88]()
## cmux: Swift Tests Guard Socket And App Policy
`cmux` uses Xcode test targets for both unit and UI tests: the CI scheme includes `cmuxTests.xctest` and `cmuxUITests.xctest`, while `scripts/test-unit.sh` runs the `cmux-unit` scheme through `xcodebuild`. This makes the regression boundary native to the macOS app/toolchain rather than a custom shell-only harness.
Sources: [manaflow-ai-cmux:cmux.xcodeproj/xcshareddata/xcschemes/cmux-ci.xcscheme:13-27](), [manaflow-ai-cmux:scripts/test-unit.sh:6-21]()
`TerminalControllerSocketSecurityTests.swift` covers several socket boundaries: filesystem permissions for different access modes, password-mode rejection of unauthenticated commands, focus-vs-non-focus command policy, JSON-RPC parameter validation, sensitive SSH configuration omission from remote status payloads, and remote PTY worker dispatch. The tests are written against `TerminalController.shared` and concrete socket paths, so they protect both policy and transport assumptions.
Sources: [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift:28-50](), [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift:52-75](), [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift:77-140](), [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift:143-176](), [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift:178-203](), [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift:205-241]()
`AutomationSocketUITests.swift` moves the same socket idea into launched-app behavior. It starts the app with mode-specific launch arguments and `CMUX_SOCKET_PATH`, verifies socket creation, deletion/recreation, disabled mode behavior, and uses a small Unix-domain socket client to send `ping` and expect `PONG`.
Sources: [manaflow-ai-cmux:cmuxUITests/AutomationSocketUITests.swift:20-35](), [manaflow-ai-cmux:cmuxUITests/AutomationSocketUITests.swift:37-59](), [manaflow-ai-cmux:cmuxUITests/AutomationSocketUITests.swift:61-81](), [manaflow-ai-cmux:cmuxUITests/AutomationSocketUITests.swift:106-119](), [manaflow-ai-cmux:cmuxUITests/AutomationSocketUITests.swift:184-242]()
## cmux: Browser And Pane Regressions Are Stateful
`BrowserPanelTests.swift` is broad because browser panes are stateful and AppKit/WebKit-heavy. The file includes tests for browser chrome colors, `showOpenFilePicker` bridge installation and cancellation, initial navigation preservation without rendering, profile isolation, address-bar focus requests, React grab/pasteback behavior, host view hit-testing, inspector resizing, portal lifecycle, and web view rehosting.
Sources: [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:56-88](), [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:91-211](), [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:214-228](), [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:270-364](), [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:365-557](), [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:557-890](), [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:2220-3226]()
This is a different regression shape from `tmux`. The target is not a parser accepting hostile bytes; it is a long-lived UI surface where regressions appear as stale navigation, wrong profile writes, stuck focus requests, lost pasteback targets, broken inspector dividers, or portal reparenting problems.
Sources: [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:272-317](), [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:319-364](), [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:375-532](), [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:1158-1350](), [manaflow-ai-cmux:cmuxTests/BrowserPanelTests.swift:2348-2507]()
## cmux: Hook Tests Preserve Provider-Neutral Session Restore
`CLIGenericHookPersistenceTests.swift` is the strongest BYOC/BYOK signal in the sampled tests. It defines generic hook scenarios across multiple agent names and executable locations. The expected persisted arguments keep portable launch configuration such as model, sandbox, permission, `--cwd`, or config-home paths, while initial prompts, resume identifiers, and secret API-key environment variables are excluded from the expected persisted environment.
Sources: [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift:16-73](), [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift:102-160](), [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift:161-249]()
That boundary matters architecturally: the app can support different upstream agents without hard-coding a single model provider or assuming one hosted service. The regression contract is about safe, sanitized session restoration across command shapes and environment conventions.
Sources: [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift:252-257](), [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift:277-314](), [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift:316-420]()
## Portable Lessons
| Lesson | From `tmux` | From `cmux` | Portable rule |
|---|---|---|---|
| Put fuzzers at grammar/byte boundaries | Input, command, format, and style fuzzers | Not the dominant pattern in sampled Swift tests | Fuzz compact interpreters where success is “no crash, no corrupted ownership.” |
| Put regressions at observable contracts | Exact layout, key, format, and render output | Exact socket responses, JSON-RPC errors, UI state | Use deterministic expected output where behavior is user-visible. |
| Keep fake worlds small | Fuzzers seed just enough options/window/format context | Unit tests build focused `TabManager`, `Workspace`, socket, or `BrowserPanel` state | Avoid full app boot unless the boundary requires it. |
| Stay provider-neutral | Not a central concern in sampled tmux tests | Generic hook persistence spans several agent command shapes and avoids persisting API keys | BYOC/BYOK support belongs in regression tests, not just design docs. |
Sources: [tmux-tmux:fuzz/cmd-parse-fuzzer.c:41-57](), [tmux-tmux:fuzz/format-fuzzer.c:49-61](), [tmux-tmux:regress/control-client-sanity.sh:34-39](), [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift:223-240](), [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift:61-73](), [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift:119-132]()
## Method Note
No `STRATEGY.md` or `docs/solutions/**` source was present in the prepared workspace, so this page uses repository code and test configuration as source of truth. The requested Compound Engineering profile was applied as portable page-shape guidance only; no installed local Compound Engineering skill source was executed or cited.
## Summary
`tmux` protects maintainability by separating random-input robustness from exact CLI regressions: fuzzers cover parser-like internals, while shell scripts pin observable server, key, format, and style behavior. `cmux` protects maintainability through Swift tests that encode application contracts around sockets, browser panes, session restore, hooks, and UI launch behavior. The shared pattern is boundary-first testing: choose the smallest harness that reaches the risky boundary, then assert the invariant that future maintainers must not break. Sources: [tmux-tmux:Makefile.am:243-256](), [tmux-tmux:regress/input-keys.sh:17-45](), [manaflow-ai-cmux:cmux.xcodeproj/xcshareddata/xcschemes/cmux-ci.xcscheme:13-27](), [manaflow-ai-cmux:cmuxUITests/AutomationSocketUITests.swift:37-59]()
---
## 10. Comparison Verdict
> The closing synthesis: tmux is strongest as a small, portable, protocol-deep multiplexer; cmux is strongest as a native agent-workflow shell that combines terminal, browser, notifications, remote access, and local automation. The most portable ideas are explicit socket contracts, source-backed command/config schemas, provider-neutral hooks, and focused regression boundaries.
- Page Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/pages/10-comparison-verdict.md
- Generated: 2026-05-24T19:18:32.443Z
### Source Files
- `tmux-tmux:tmux.h`
- `tmux-tmux:server.c`
- `tmux-tmux:cmd-parse.y`
- `tmux-tmux:input.c`
- `manaflow-ai-cmux:Sources/TerminalController.swift`
- `manaflow-ai-cmux:Sources/Workspace.swift`
- `manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift`
- `manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift`
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:tmux.h](tmux-tmux/tmux.h)
- [tmux-tmux:tmux-protocol.h](tmux-tmux/tmux-protocol.h)
- [tmux-tmux:server.c](tmux-tmux/server.c)
- [tmux-tmux:cmd-parse.y](tmux-tmux/cmd-parse.y)
- [tmux-tmux:input.c](tmux-tmux/input.c)
- [tmux-tmux:regress/conf-syntax.sh](tmux-tmux/regress/conf-syntax.sh)
- [tmux-tmux:regress/control-client-sanity.sh](tmux-tmux/regress/control-client-sanity.sh)
- [manaflow-ai-cmux:Sources/TerminalController.swift](manaflow-ai-cmux/Sources/TerminalController.swift)
- [manaflow-ai-cmux:Sources/Workspace.swift](manaflow-ai-cmux/Sources/Workspace.swift)
- [manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift](manaflow-ai-cmux/Sources/Panels/BrowserAutomation.swift)
- [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift](manaflow-ai-cmux/CLI/CMUXCLI+AgentHookDefinitions.swift)
- [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift](manaflow-ai-cmux/cmuxTests/TerminalControllerSocketSecurityTests.swift)
- [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift](manaflow-ai-cmux/cmuxTests/CLIGenericHookPersistenceTests.swift)
- [manaflow-ai-cmux:tests_v2/test_browser_api_p0.py](manaflow-ai-cmux/tests_v2/test_browser_api_p0.py)
</details>
# Comparison Verdict
This page closes the comparison between `tmux-tmux` and `manaflow-ai-cmux`. The verdict is not that one replaces the other: tmux is strongest where a terminal multiplexer must stay compact, portable, and protocol-deep; cmux is strongest where the terminal is one surface inside a local agent-workflow shell.
The reusable lesson is architectural, not vendor-specific. The most portable ideas are explicit socket contracts, source-backed command/config schemas, provider-neutral hooks, and regression boundaries around protocols rather than only UI behavior. No `STRATEGY.md` or `docs/solutions/` source was present in the prepared repository scan, so this synthesis uses repository code and tests as the source of truth. The Compound Engineering profile was used only as bundled page-shape and QA guidance, not as executed project code.
## Verdict At A Glance
| Dimension | tmux is stronger when... | cmux is stronger when... | Portable idea |
|---|---|---|---|
| Runtime boundary | A long-lived server owns sessions over a Unix socket. | A native app exposes local automation over a Unix socket. | Make the socket contract explicit and testable. |
| Protocol depth | Terminal input, escape sequences, control clients, and tmux commands are the product. | Terminal, browser, notifications, remote PTY, and agent hooks all need one command surface. | Keep protocol verbs source-backed, not README-only. |
| Configuration | Users compose command language, formats, and conditionals. | Integrations install hooks into many agent-specific config locations. | Parse and validate config with owned schemas. |
| Portability | The core needs few assumptions beyond C/POSIX-style process, socket, and terminal primitives. | The app can depend on macOS-native surfaces and WebKit to deliver richer workflows. | Separate durable contracts from platform-specific UI. |
| Regression surface | Protocol, parser, control-client, and terminal behavior must not drift. | Socket security, browser automation, remote workflows, and hook persistence must not drift. | Regression tests should pin external contracts. |
Sources: [tmux-tmux:tmux.h:82-94](), [tmux-tmux:tmux-protocol.h:22-77](), [tmux-tmux:server.c:105-154](), [manaflow-ai-cmux:Sources/TerminalController.swift:1536-1815](), [manaflow-ai-cmux:Sources/TerminalController.swift:3335-3698](), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:122-297]()
## What tmux Optimizes For
tmux’s center of gravity is a small server process with a stable Unix-socket boundary and a deep terminal protocol implementation. Its defaults define configuration paths, socket roots, socket permissions, and terminal identity in one shared header, while the server creates an `AF_UNIX` stream socket, binds it to `socket_path`, listens with backlog `128`, and switches the descriptor to nonblocking mode.
The protocol is intentionally narrow and explicit: `PROTOCOL_VERSION` and `enum msgtype` define client/server messages for identify, command, detach, resize, file read/write, and lifecycle events. That is the shape of a mature multiplexer: small surface, strong contract, careful compatibility pressure.
Sources: [tmux-tmux:tmux.h:82-94](), [tmux-tmux:tmux-protocol.h:22-77](), [tmux-tmux:server.c:105-154]()
### tmux Runtime Boundary
```text
tmux client
|
| Unix socket + typed protocol messages
v
tmux server
|
+-- command queue
+-- sessions/windows/panes
+-- terminal input parser
```
The server loop drains command queues globally and per identified client, then runs the client loop and exits only after session/client/job conditions allow it. Socket execute permissions are updated based on whether sessions are attached, and accepted clients pass through ACL checks before they become active clients.
Sources: [tmux-tmux:server.c:264-305](), [tmux-tmux:server.c:331-401](), [tmux-tmux:server.c:407-427]()
### tmux Command And Terminal Depth
The command parser is not a thin string splitter. `cmd-parse.y` models command parse state, arguments, nested command lists, scope stacks, conditional forms, format expansion, environment assignment, and parse-only behavior. That explains why tmux configuration is powerful without needing a separate app-level automation framework.
The terminal side is similarly deep. `input.c` documents a DEC/ANSI-derived parser, adds UTF-8, OSC, APC, rename-sequence, and DCS handling, then carries parser context for panes, screen writing, palette, input buffers, parameters, UTF-8 state, outstanding requests, and control-client replay since ground state.
Sources: [tmux-tmux:cmd-parse.y:71-100](), [tmux-tmux:cmd-parse.y:197-243](), [tmux-tmux:cmd-parse.y:268-390](), [tmux-tmux:input.c:31-52](), [tmux-tmux:input.c:98-148]()
## What cmux Optimizes For
cmux’s center of gravity is a native agent-workflow shell. Its socket listener looks tmux-like at the boundary, but the commands behind it are broader: windows, workspaces, panes, surfaces, remote workspaces, notifications, feed events, files, browser automation, browser profiles, and VM-like methods all share the v2 JSON command plane.
This is why cmux is strongest when “terminal multiplexer” is not enough. A workflow can open a browser split, drive WebKit, persist browser profile state, surface notifications, track agent sessions, and reconnect remote PTYs through one local automation channel.
Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:1536-1815](), [manaflow-ai-cmux:Sources/TerminalController.swift:2242-2278](), [manaflow-ai-cmux:Sources/TerminalController.swift:3335-3698]()
### cmux Runtime Boundary
```text
cmux CLI / agent hooks / local automation
|
| Unix socket + line JSON / v1 commands
v
TerminalController
|
+-- windows / workspaces / panes / surfaces
+-- terminal input and remote PTY methods
+-- browser automation and profiles
+-- notifications / feed / files
```
The socket listener has product-grade operational mechanics: it tracks listener identity, path locks, fallback socket paths, nonblocking setup, permission application, listener health, port scanner callbacks, and a dispatch source accept loop. Password mode supports both v1 text commands and v2 JSON `auth.login`, while worker-routed v2 methods keep selected operations off the main actor.
Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:1536-1815](), [manaflow-ai-cmux:Sources/TerminalController.swift:2148-2235](), [manaflow-ai-cmux:Sources/TerminalController.swift:2242-2311](), [manaflow-ai-cmux:Sources/TerminalController.swift:2399-2491]()
### cmux Workspace And Browser Scope
`Workspace` snapshots include terminal scrollback, restorable agents, tmux start commands, browser URL/profile/history/zoom/devtools state, markdown panels, file previews, right-sidebar tools, notifications, git branch, listening ports, TTY names, and remote configuration. Restore logic distinguishes local startup, agent auto-resume, remote PTY replay, scrollback replay, and manual resume states.
Browser automation is first-class rather than incidental. cmux exposes profile list/create/rename/clear/delete operations, guards destructive profile operations when live browser panels use a profile, imports cookies from installed browsers, and tests browser v2 methods such as `browser.open_split`, `browser.navigate`, `browser.fill`, `browser.click`, `browser.snapshot`, and `browser.screenshot`.
Sources: [manaflow-ai-cmux:Sources/Workspace.swift:163-250](), [manaflow-ai-cmux:Sources/Workspace.swift:470-605](), [manaflow-ai-cmux:Sources/Workspace.swift:934-1045](), [manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift:183-364](), [manaflow-ai-cmux:Sources/Panels/BrowserAutomation.swift:366-468](), [manaflow-ai-cmux:tests_v2/test_browser_api_p0.py:22-113]()
## Provider-Neutral Agent Integration Is cmux's Most Portable Idea
cmux’s hook model is explicitly multi-agent. `AgentHookDef` abstracts CLI name, display name, status key, config directory/file, environment override, session store suffix, disable environment variable, hook marker, binary name, hook format, event mapping, aliases, feed-hook events, and post-install action. The concrete definitions cover Codex, Grok, OpenCode, Pi, Amp, Cursor, Gemini, Antigravity, Rovo Dev, Hermes Agent, Copilot, CodeBuddy, Factory, and Qoder without hard-coding the whole product to one model provider.
That matters for BYOC/BYOK architecture. The hook contract is a local file/config/socket integration pattern. Providers can vary, credentials can stay in each tool’s own environment, and cmux only needs stable event-to-command mappings plus sanitized persistence. The tests reinforce this: generic hook persistence expects launch commands to drop resume IDs and initial prompts while preserving non-secret config homes such as `GEMINI_CLI_HOME`, `GROK_HOME`, `COPILOT_HOME`, or `CODEBUDDY_CONFIG_DIR`.
Sources: [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:7-47](), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:49-102](), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:122-297](), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:315-433](), [manaflow-ai-cmux:cmuxTests/CLIGenericHookPersistenceTests.swift:16-190]()
## Regression Boundaries
tmux’s regression boundaries match its product shape. `conf-syntax.sh` starts tmux with `/dev/null` config and runs `source -n` against repository config examples, pinning config syntax. `control-client-sanity.sh` drives `tmux -C` with pane/window/layout commands and compares exact pane layout output, pinning control-client behavior.
cmux’s boundaries are broader because its surface is broader. Socket security tests verify permission modes, password-mode rejection, focus-intent policy, remote status redaction, and worker routing for remote PTY resize. Browser v2 tests verify interactive browser control and ref-handle behavior. This is the right split: tmux protects protocol and terminal semantics; cmux protects local automation workflows crossing terminal, browser, notification, and remote surfaces.
Sources: [tmux-tmux:regress/conf-syntax.sh:1-14](), [tmux-tmux:regress/control-client-sanity.sh:13-40](), [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift:28-75](), [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift:77-141](), [manaflow-ai-cmux:cmuxTests/TerminalControllerSocketSecurityTests.swift:178-220](), [manaflow-ai-cmux:tests_v2/test_browser_api_p0.py:30-112]()
## Design Guidance For Future Grok-Wiki Integration
For a Grok-Wiki or Ask/Wiki workflow, borrow the parts that travel:
| Pattern | How to apply it | Provider-neutral constraint |
|---|---|---|
| Explicit socket contract | Treat local automation as a documented request/response protocol with health checks and auth modes. | Do not bind the protocol to one hosted model or connector. |
| Source-backed schemas | Generate command/config pages from code-owned definitions like tmux parser grammar or cmux hook definitions. | Skill packs can come from files, repositories, or catalogs; the schema should not require one vendor. |
| Hook adapters | Model agent integrations as event mappings plus environment/config resolution. | Keep credentials in BYOK tool environments; do not centralize provider secrets in the wiki layer. |
| Focused regression pages | Link wiki claims to tests that pin behavior: parser syntax, control client layout, socket security, browser API, hook persistence. | Tests should validate local contracts, not only provider-specific happy paths. |
Sources: [tmux-tmux:cmd-parse.y:103-134](), [tmux-tmux:cmd-parse.y:268-390](), [manaflow-ai-cmux:Sources/TerminalController.swift:2242-2278](), [manaflow-ai-cmux:Sources/TerminalController.swift:3335-3698](), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:7-47](), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:122-297]()
## Closing Summary
tmux wins on being a compact, portable, protocol-deep multiplexer: its source centers on a Unix socket, typed protocol messages, command parsing, and terminal input semantics. cmux wins on being a native agent-workflow shell: its source centers on a richer local socket API that joins terminal surfaces, browser control, notifications, remote PTYs, workspace persistence, and provider-neutral agent hooks. The shared lesson is to keep contracts explicit, source-backed, and regression-tested at the boundary where external tools depend on them.
Sources: [tmux-tmux:tmux-protocol.h:22-77](), [tmux-tmux:input.c:31-52](), [manaflow-ai-cmux:Sources/TerminalController.swift:3335-3698](), [manaflow-ai-cmux:Sources/Workspace.swift:231-250](), [manaflow-ai-cmux:CLI/CMUXCLI+AgentHookDefinitions.swift:122-297]()
---