# Explain It Simply

> What cmux does in plain language: a Ghostty-powered macOS terminal that treats AI coding agents as first-class citizens, with vertical tabs, notification rings, an in-app browser, and a CLI that lets agents drive the UI over a Unix socket.

- Repository: manaflow-ai/cmux
- GitHub: https://github.com/manaflow-ai/cmux
- Human wiki: https://grok-wiki.com/public/wiki/manaflow-ai-cmux-e789cf316a9a
- Complete Markdown: https://grok-wiki.com/public/wiki/manaflow-ai-cmux-e789cf316a9a/llms-full.txt

## Source Files

- `README.md`
- `Sources/cmuxApp.swift`
- `Sources/AppDelegate.swift`
- `Sources/GhosttyTerminalView.swift`
- `ghostty.h`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:

- [README.md](README.md)
- [Sources/cmuxApp.swift](Sources/cmuxApp.swift)
- [Sources/AppDelegate.swift](Sources/AppDelegate.swift)
- [Sources/GhosttyTerminalView.swift](Sources/GhosttyTerminalView.swift)
- [ghostty.h](ghostty.h)
- [Sources/SocketControlSettings.swift](Sources/SocketControlSettings.swift)
- [Sources/TabManager.swift](Sources/TabManager.swift)
- [Sources/Workspace.swift](Sources/Workspace.swift)
- [Sources/TerminalNotificationStore.swift](Sources/TerminalNotificationStore.swift)
- [Sources/TerminalNotificationCallerResolver.swift](Sources/TerminalNotificationCallerResolver.swift)
- [Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchEnvironmentPolicy.swift](Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchEnvironmentPolicy.swift)
- [Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/HermesAgentHookConfig.swift](Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/HermesAgentHookConfig.swift)
- [Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamKind.swift](Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamKind.swift)
- [Packages/CmuxExtensionKit/README.md](Packages/CmuxExtensionKit/README.md)
</details>

# Explain It Simply

cmux is a macOS terminal app that makes running multiple AI coding agents manageable. It wraps Ghostty's GPU-accelerated terminal renderer in a native Swift/AppKit shell, then adds the layers that matter when you have ten agent sessions running at once: a sidebar with vertical tabs that each show live context (git branch, linked PR, listening ports, latest notification), a notification ring system that highlights exactly which pane needs your attention, an in-app browser agents can drive, and a Unix socket API that lets any tool — or any agent — script the whole UI from the command line.

This page explains what each of those pieces is, why it exists, and how it fits together, in plain language a new contributor would need before touching the code.

---

## The Terminal Engine: Ghostty Under the Hood

cmux does not write its own terminal emulator. It uses **libghostty**, the C library behind the open-source [Ghostty](https://github.com/ghostty-org/ghostty) terminal, linked in as an XCFramework through a git submodule.

The bridge is deliberately thin. `ghostty.h` at the repo root is just a single-line re-export of Ghostty's canonical C API header:

```c
// ghostty.h
#include "ghostty/include/ghostty.h"
```

This keeps Swift's ABI bridge and the bundled `GhosttyKit.xcframework` in sync automatically as the submodule is updated.

`GhosttyTerminalView.swift` holds the AppKit view that hosts each terminal surface. It calls into the C API (`ghostty_surface_clear_selection`, `ghostty_surface_select_cursor_cell`, etc.) using Swift's `@_silgen_name` mechanism to resolve the C symbols directly. Metal and QuartzCore handle compositing; the terminal renders at GPU speed.

Because cmux reads the user's existing `~/.config/ghostty/config`, any Ghostty theme, font, or color preference carries over automatically — no duplicate configuration.

Sources: [ghostty.h:1-8](), [Sources/GhosttyTerminalView.swift:1-20]()

---

## Workspaces, Tabs, and Splits

The core organizational unit is the **Workspace** (the type alias `Tab = Workspace` in `TabManager.swift` shows the historical name change). Each workspace maps to one "project context": a working directory, a git branch, and a set of panes.

Within a workspace you can split panes **horizontally** (⌘D) or **vertically** (⌘⇧D). This is handled by the **Bonsplit** Swift package, imported in nearly every top-level file. Bonsplit owns the recursive split-tree layout; cmux owns the workspace model on top of it.

The sidebar on the left shows one row per workspace. Each row is live-updated via `FSEventStream` watches (`WorkspaceGitMetadataWatcher` in `TabManager.swift`) and displays:

- **Git branch** — updated from filesystem events on `.git/HEAD`
- **Linked PR status and number** — polled from GitHub
- **Working directory** — path of the shell in focus
- **Listening ports** — network services the shell has open
- **Latest notification text** — the most recent agent message

```
┌─────────────────────────────────────┐
│  Sidebar                            │
│  ┌────────────────────────────────┐ │
│  │ 🔵 my-feature   main  #234     │ │
│  │    ~/projects/app  :3000       │ │
│  │    Claude is waiting…          │ │
│  ├────────────────────────────────┤ │
│  │    other-task   dev-branch     │ │
│  └────────────────────────────────┘ │
└─────────────────────────────────────┘
```

The blue ring (🔵) appears when an agent in that workspace is waiting.

Sources: [Sources/TabManager.swift:1-50](), [Sources/Workspace.swift:43-60]()

---

## Notification Rings: Knowing Which Agent Needs You

When you run five Claude Code sessions in parallel, every macOS notification reads "Claude is waiting for your input" — no way to know which one. cmux replaces this with a targeted visual system.

### How it works

Agents emit notifications through one of two paths:

1. **Terminal escape sequences** — OSC 9, OSC 99, or OSC 777 sequences in terminal output are intercepted by `TerminalController` and handed to `TerminalNotificationStore`.
2. **The `cmux notify` CLI command** — agents run this from a hook script. It connects to the Unix socket and calls `v2NotificationCreateForCaller`, which resolves the correct workspace using the calling process's TTY, or explicit workspace/surface IDs if provided.

The `TerminalNotificationCallerResolver` logic uses the TTY of the process that sent the command to find the right workspace automatically — so an agent running inside pane X always highlights pane X, not a random one.

```
Agent hook fires
       │
       ▼
cmux notify "Claude needs input" (CLI)
       │
       ▼  (Unix socket)
TerminalController.v2NotificationCreateForCaller()
       │
       ├─ resolves workspace by TTY or explicit ID
       │
       ▼
TerminalNotificationStore.deliverNotificationSynchronously()
       │
       ├─ blue ring on pane
       ├─ tab highlight in sidebar
       └─ macOS UNUserNotification (optional sound)
```

**⌘⇧U** jumps focus to the most recent unread pane across all workspaces.

Sources: [Sources/TerminalNotificationCallerResolver.swift:1-50](), [Sources/TerminalNotificationStore.swift:1-60]()

---

## The In-App Browser

A browser pane can be opened alongside any terminal split (⌘⇧L). This is a WKWebView embedded in AppKit (imported in `AppDelegate.swift`), not a separate Electron window.

The browser is **scriptable**: its API is ported from Vercel's open-source `agent-browser` project, so agents can:

- Snapshot the accessibility tree
- Get references to page elements
- Click, fill forms, and evaluate JavaScript
- Navigate to URLs

This means a Claude Code session can open a dev server in the browser pane and interact with the running application directly — clicking buttons, reading results — without leaving cmux.

Cookie import from Chrome, Firefox, Arc, and 20+ other browsers means browser sessions start pre-authenticated.

For **SSH workspaces** (`cmux ssh user@remote`), browser panes route through the remote network so `localhost` URLs resolve on the remote machine. Drag-and-drop uploads images via `scp`.

Sources: [README.md:50-90](), [Sources/AppDelegate.swift:1-10]()

---

## The Socket API: Agents as First-Class Drivers

cmux runs a **Unix domain socket** that any local process can talk to. The socket path and access model are controlled by a five-level permission enum in `SocketControlSettings.swift`:

| Mode | Who can connect |
|------|----------------|
| `off` | Nobody — socket is disabled |
| `cmuxOnly` | Processes spawned inside cmux terminals only (ancestry check) |
| `automation` | Any process owned by this macOS user (no ancestry check) |
| `password` | Any local process with the right password from a local file |
| `allowAll` | Any process and user — no auth (unsafe) |

The default for agents running inside cmux terminals is `cmuxOnly`: a Claude Code session inside cmux can drive the UI; a random external process cannot.

Through the socket, a script or agent can:

- Create or close workspaces and panes
- Send keystrokes to any surface
- Send notifications to specific workspaces
- Open URLs in the in-app browser
- Query workspace/surface state

Sources: [Sources/SocketControlSettings.swift:1-60]()

---

## Claude Code Teams and Agent Launch

Running `cmux claude-teams` launches Claude Code's "teammate" multi-agent mode natively. Each teammate spawns as a real split pane with its own sidebar metadata and notification ring — no tmux, no wrappers.

The `CMUXAgentLaunch` package manages the environment that agents inherit. `AgentLaunchEnvironmentPolicy` keeps a strict allowlist of environment variables that flow into agent processes. API keys (`AMP_API_KEY` is explicitly blocked) do not pass through; only safe configuration variables like `ANTHROPIC_BASE_URL`, `CLAUDE_CONFIG_DIR`, `CODEX_HOME`, and equivalents for other agents (Copilot, RovoDev, CodeBuddy) are forwarded.

This approach is **provider-neutral by design**: the same launch path works for Claude Code, OpenCode, Amp, GitHub Copilot, and any other agent that reads standard config environment variables.

Sources: [Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchEnvironmentPolicy.swift:27-55]()

---

## The Workstream Feed

`CMUXWorkstream` is an internal package that captures structured events from running agent sessions into a persistent feed. Events are classified into two groups:

**Actionable** (shown by default in the Feed panel):
- `permissionRequest` — agent is asking for user approval
- `exitPlan` — agent has finished a planning step
- `question` — agent is asking the user something

**Telemetry** (stored, hidden behind an "All" filter):
- `toolUse`, `toolResult`, `userPrompt`, `assistantMessage`, `sessionStart`, `sessionEnd`, `stop`, `todos`

This gives the user a concise "needs attention" view without drowning in every tool call an agent makes.

Sources: [Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamKind.swift:1-30]()

---

## Extension Sidebars

`CmuxExtensionKit` is a prototype API for custom sidebar panels. A sidebar provider is a Swift struct conforming to `CmuxExtensionSidebarProvider`. It receives a snapshot of workspace state and returns a render model; the host (cmux) owns selection, popovers, and mutation dispatch.

State stays cheap because rows receive immutable value snapshots and action closures — not live `ObservableObject` references — avoiding the re-render feedback loops that caused 100% CPU spin bugs in earlier designs.

Extensions persist their own grouping state to `~/.config/cmux/extensions/<extension>/state.json`.

Sources: [Packages/CmuxExtensionKit/README.md:1-65]()

---

## How the Pieces Fit Together

```text
┌──────────────────────────────────────────────────────────┐
│                  cmux macOS App (Swift/AppKit)            │
│                                                          │
│  ┌─────────────┐  ┌────────────────┐  ┌──────────────┐  │
│  │  Sidebar    │  │ Terminal Panes │  │  Browser     │  │
│  │ (vertical   │  │  (Bonsplit +   │  │  (WKWebView) │  │
│  │  tabs, git, │  │   libghostty)  │  │              │  │
│  │  notifs)    │  │                │  │              │  │
│  └──────┬──────┘  └───────┬────────┘  └──────┬───────┘  │
│         │                 │                   │          │
│  ┌──────▼─────────────────▼───────────────────▼───────┐  │
│  │         TabManager / Workspace model               │  │
│  │    (git watch, ports, notification state)          │  │
│  └──────────────────────────┬─────────────────────────┘  │
│                             │                            │
│  ┌──────────────────────────▼─────────────────────────┐  │
│  │         Unix Socket (SocketControlMode)             │  │
│  │  cmuxOnly | automation | password | allowAll        │  │
│  └──────────────────────────┬─────────────────────────┘  │
└─────────────────────────────┼────────────────────────────┘
                              │
              ┌───────────────┼────────────────┐
              │               │                │
         cmux CLI        Claude Code      Any agent
        (cmux notify,   (teammate mode,   (via socket
         cmux ssh…)      hooks wired)      or CLI)
```

---

## Quick-Reference Feature Table

| Feature | What it gives you | Where in the code |
|---|---|---|
| Ghostty rendering | GPU-accelerated terminal, reads your existing config | `GhosttyTerminalView.swift`, `ghostty.h` |
| Vertical tabs + sidebar | Per-workspace git/PR/port/notification status | `TabManager.swift`, `Workspace.swift` |
| Notification rings | Visual pane highlight when an agent is waiting | `TerminalNotificationStore.swift`, `TerminalNotificationCallerResolver.swift` |
| `cmux notify` CLI | Agents push targeted notifications from hook scripts | `TerminalController` socket handler |
| In-app browser | WKWebView split pane with scriptable accessibility API | `AppDelegate.swift`, browser panel sources |
| Socket API | Programmatic control over the whole UI | `SocketControlSettings.swift` |
| Claude Code Teams | Native splits for multi-agent teammate sessions | `CMUXAgentLaunch` package |
| Workstream feed | Structured actionable-vs-telemetry event feed | `CMUXWorkstream` package |
| Extension sidebars | Custom Swift sidebar providers | `CmuxExtensionKit` package |

---

## Summary

cmux is a native macOS terminal built for the era of parallel AI agents. Its core insight is simple: when you run many agents at once, you need a terminal that treats notifications, context metadata, and programmability as first-class features — not afterthoughts. By wrapping libghostty for rendering (preserving GPU speed and Ghostty config compatibility), layering a live-updating sidebar with per-workspace git and notification state, and exposing a Unix socket API that agents can talk to from inside their own session, cmux gives developers composable primitives rather than an opinionated orchestrator. The `SocketControlMode` enum (off → cmuxOnly → automation → password → allowAll) makes the trust boundary explicit, and the agent-launch environment allowlist keeps secrets out of child processes regardless of which agent tool you use.

Sources: [Sources/SocketControlSettings.swift:8-48](), [README.md:119-138]()
