Ghostty-based macOS terminal with vertical tabs and notifications for AI coding agents https://cmux.com
Find a file
Lawrence Chen dd54927cb9
Add React Grab inject button to browser toolbar (#2373)
* Add React Grab inject button to browser toolbar

Adds a toolbar button (cursor click icon) that injects the react-grab
script (unpkg.com/react-grab/dist/index.global.js) into the current
page. Hover over React elements and Cmd+C to copy component context
(file, component name, line number) for AI agents.

Button highlights when active, resets on navigation.

* Auto-activate selection mode on React Grab inject

First click: injects the script and auto-activates selection mode via
the react-grab:init event. Subsequent clicks toggle selection mode
on/off via window.__REACT_GRAB__.toggle().

* Bridge React Grab state back to Swift via WKScriptMessageHandler

Register a cmux-bridge plugin after injecting react-grab that posts
state changes back to Swift via webkit.messageHandlers. The button
now highlights accent color only when selection mode is actually
active (not just when the script is loaded), and deactivates when
the user exits selection mode via Escape or the react-grab toolbar.

* Fetch react-grab script via URLSession to bypass CSP

Sites like vercel.com block loading external scripts via CSP headers.
Fetch the script with URLSession (not subject to page CSP), cache it,
and inject inline via evaluateJavaScript. Also guard against duplicate
injection on repeated clicks.

* Prefetch react-grab script on first browser panel init

Kick off a low-priority background fetch of the react-grab script
when the first BrowserPanel is created. The script is cached
statically so clicking the button is instant.

* Eliminate react-grab button and callback lag

Three changes:
1. Fire-and-forget: use evaluateJavaScript with completionHandler
   instead of await, so button taps return immediately.
2. Single JS payload: combine bootstrap listener + script source
   into one evaluateJavaScript call (one IPC round-trip, not two).
3. Dedupe state callbacks: only post webkit message when isActive
   actually changes, not on every hover/drag state update.

* Fix duplicate state callback on react-grab toggle

toggleReactGrab was sending an explicit postMessage AND the plugin's
onStateChange hook was firing too, causing two @Published updates per
toggle. Remove the explicit postMessage since the plugin hook handles
it. Also add dlog instrumentation for debugging.

* Add Cmd+Shift+G shortcut for React Grab (configurable)

- Add toggleReactGrab to KeyboardShortcutSettings with Cmd+Shift+G default
- Add View menu item with customizable shortcut
- Add command palette entry (searchable as "react grab" or "inspect element")
- Simplify button to use toggleOrInjectReactGrab, remove local state tracking

* Fix Codex review findings: pin version, verify hash, fix retry and state

1. Pin react-grab to exact version (0.1.29) with SHA-256 integrity
   check. Script is verified before evaluation to prevent supply-chain
   attacks via compromised CDN responses.
2. Clear prefetchTask on failure so subsequent attempts retry the
   download instead of reusing a permanently failed task.
3. Remove premature isReactGrabActive=true. State is now only set
   by the onStateChange message handler callback after confirmed
   initialization, or explicitly reset on evaluation error.

* Extract React Grab into own file, make version configurable

Move all react-grab logic (settings, script loader, message handler,
BrowserPanel extension) into Sources/Panels/ReactGrab.swift.

Add a "React Grab Version" text field in Settings > Browser that lets
the user pin which npm version is fetched. Only versions with a known
SHA-256 integrity hash in ReactGrabSettings.knownHashes are accepted.
The cache invalidates when the configured version changes.

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-30 18:00:45 -07:00
.claude/commands Add contributor credits to release skills (#319) 2026-02-22 16:18:44 -08:00
.github Switch nightly Sparkle feed URL to R2 (#2366) 2026-03-30 14:48:50 -07:00
AppIcon.icon Regenerate app icons from Icon Composer (#1005) 2026-03-06 04:30:54 -08:00
Assets.xcassets Regenerate app icons from Icon Composer (#1005) 2026-03-06 04:30:54 -08:00
CLI Fix tmux-compat split-window surface resolution (#2351) 2026-03-30 03:28:25 -07:00
cmuxTests Fix Dock persistence for manual app icons (#2360) 2026-03-30 03:34:35 -07:00
cmuxUITests Keep cmux browser Find shortcuts authoritative (#2356) 2026-03-30 03:16:10 -07:00
daemon/remote Fix tmux-compat split-window surface resolution (#2351) 2026-03-30 03:28:25 -07:00
design Regenerate app icons from Icon Composer (#1005) 2026-03-06 04:30:54 -08:00
docs docs: Add localized assets for Korean README (#1811) 2026-03-26 21:24:36 -07:00
ghostty@bc9be90a21 Merge origin/main into feat-cmux-themes-command 2026-03-13 17:22:12 -07:00
GhosttyTabs.xcodeproj Add React Grab inject button to browser toolbar (#2373) 2026-03-30 18:00:45 -07:00
homebrew-cmux@a5f372ecfa Fix CI: remove broken tests for deleted function, fix review comments 2026-03-15 21:08:02 -07:00
node_modules Update app and tooling 2026-01-29 17:36:26 -08:00
Resources Add React Grab inject button to browser toolbar (#2373) 2026-03-30 18:00:45 -07:00
scripts Fix ARC workspace inheritance crash and native Zig helper builds (#2283) 2026-03-28 03:05:00 -07:00
skills Document browser navigation verification loop (#974) 2026-03-05 20:57:18 -08:00
Sources Add React Grab inject button to browser toolbar (#2373) 2026-03-30 18:00:45 -07:00
tests Fix tmux-compat split-window surface resolution (#2351) 2026-03-30 03:28:25 -07:00
tests_v2 Add cmux omo command for oh-my-openagent integration (#2087) 2026-03-26 16:07:59 -07:00
vendor Add hover background to split action buttons (#2271) 2026-03-30 17:02:53 -07:00
web Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
.gitignore Add homepage wall of love, FAQ, blog post, footer redesign, and SEO improvements 2026-02-21 06:16:38 -08:00
.gitkeep chore: update release skill metadata 2026-02-21 04:21:11 -08:00
.gitmodules Fix frozen terminals after split churn (#12) 2026-02-13 16:45:31 -08:00
.vercelignore Add Vercel ignore 2026-01-29 17:50:35 -08:00
AGENTS.md agents 2026-01-22 03:18:02 -08:00
bun.lock Update app and tooling 2026-01-29 17:36:26 -08:00
CHANGELOG.md Bump version to 0.63.1 (#2310) 2026-03-28 15:05:03 -07:00
CLAUDE.md Add hover background to split action buttons (#2271) 2026-03-30 17:02:53 -07:00
cmux-Bridging-Header.h Rename to cmux and add About panel 2026-01-26 03:05:03 -08:00
cmux.entitlements fix: remove restricted web-browser entitlement (#1727) 2026-03-18 02:32:58 -07:00
CONTRIBUTING.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
ghostty.h Update ghostty to v1.3.0 (#1142) 2026-03-09 21:32:54 -07:00
LICENSE Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
package.json Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
Package.resolved Initial commit: macOS terminal app with vertical tabs using libghostty 2026-01-22 01:16:24 -08:00
Package.swift Rename to cmux and add About panel 2026-01-26 03:05:03 -08:00
PROJECTS.md Reversion all 1.x.x to 0.x.x for pre-launch versioning 2026-02-17 18:31:05 -08:00
README.ar.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.bs.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.da.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.de.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.es.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.fr.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.it.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.ja.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.km.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.ko.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.no.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.pl.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.pt-BR.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.ru.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.th.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.tr.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.uk.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.vi.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.zh-CN.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
README.zh-TW.md Relicense from AGPL-3.0 to GPL-3.0 (#2364) 2026-03-30 04:54:00 -07:00
THIRD_PARTY_LICENSES.md add third-party licenses and update bonsplit submodule 2026-02-14 20:33:40 -08:00
TODO.md Reapply "Merge pull request #239 from manaflow-ai/issue-151-ssh-remote-port-proxying" 2026-03-12 15:54:26 -07:00

cmux

A Ghostty-based macOS terminal with vertical tabs and notifications for AI coding agents

Download cmux for macOS

English | 日本語 | Tiếng Việt | 简体中文 | 繁體中文 | 한국어 | Deutsch | Español | Français | Italiano | Dansk | Polski | Русский | Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | ភាសាខ្មែរ | Українська

X / Twitter Discord

cmux screenshot

▶ Demo video · The Zen of cmux

Features

Notification rings

Panes get a blue ring and tabs light up when coding agents need your attention
Notification rings

Notification panel

See all pending notifications in one place, jump to the most recent unread
Sidebar notification badge

In-app browser

Split a browser alongside your terminal with a scriptable API ported from agent-browser
Built-in browser

Vertical + horizontal tabs

Sidebar shows git branch, linked PR status/number, working directory, listening ports, and latest notification text. Split horizontally and vertically.
Vertical tabs and split panes
  • Scriptable — CLI and socket API to create workspaces, split panes, send keystrokes, and automate the browser
  • Native macOS app — Built with Swift and AppKit, not Electron. Fast startup, low memory.
  • Ghostty compatible — Reads your existing ~/.config/ghostty/config for themes, fonts, and colors
  • GPU-accelerated — Powered by libghostty for smooth rendering

Install

Download cmux for macOS

Open the .dmg and drag cmux to your Applications folder. cmux auto-updates via Sparkle, so you only need to download once.

Homebrew

brew tap manaflow-ai/cmux
brew install --cask cmux

To update later:

brew upgrade --cask cmux

On first launch, macOS may ask you to confirm opening an app from an identified developer. Click Open to proceed.

Why cmux?

I run a lot of Claude Code and Codex sessions in parallel. I was using Ghostty with a bunch of split panes, and relying on native macOS notifications to know when an agent needed me. But Claude Code's notification body is always just "Claude is waiting for your input" with no context, and with enough tabs open I couldn't even read the titles anymore.

I tried a few coding orchestrators but most of them were Electron/Tauri apps and the performance bugged me. I also just prefer the terminal since GUI orchestrators lock you into their workflow. So I built cmux as a native macOS app in Swift/AppKit. It uses libghostty for terminal rendering and reads your existing Ghostty config for themes, fonts, and colors.

The main additions are the sidebar and notification system. The sidebar has vertical tabs that show git branch, linked PR status/number, working directory, listening ports, and the latest notification text for each workspace. The notification system picks up terminal sequences (OSC 9/99/777) and has a CLI (cmux notify) you can wire into agent hooks for Claude Code, OpenCode, etc. When an agent is waiting, its pane gets a blue ring and the tab lights up in the sidebar, so I can tell which one needs me across splits and tabs. Cmd+Shift+U jumps to the most recent unread.

The in-app browser has a scriptable API ported from agent-browser. Agents can snapshot the accessibility tree, get element refs, click, fill forms, and evaluate JS. You can split a browser pane next to your terminal and have Claude Code interact with your dev server directly.

Everything is scriptable through the CLI and socket API — create workspaces/tabs, split panes, send keystrokes, open URLs in the browser.

The Zen of cmux

cmux is not prescriptive about how developers hold their tools. It's a terminal and browser with a CLI, and the rest is up to you.

cmux is a primitive, not a solution. It gives you a terminal, a browser, notifications, workspaces, splits, tabs, and a CLI to control all of it. cmux doesn't force you into an opinionated way to use coding agents. What you build with the primitives is yours.

The best developers have always built their own tools. Nobody has figured out the best way to work with agents yet, and the teams building closed products definitely haven't either. The developers closest to their own codebases will figure it out first.

Give a million developers composable primitives and they'll collectively find the most efficient workflows faster than any product team could design top-down.

Documentation

For more info on how to configure cmux, head over to our docs.

Keyboard Shortcuts

Workspaces

Shortcut Action
⌘ N New workspace
⌘ 18 Jump to workspace 18
⌘ 9 Jump to last workspace
⌃ ⌘ ] Next workspace
⌃ ⌘ [ Previous workspace
⌘ ⇧ W Close workspace
⌘ ⇧ R Rename workspace
⌘ B Toggle sidebar

Surfaces

Shortcut Action
⌘ T New surface
⌘ ⇧ ] Next surface
⌘ ⇧ [ Previous surface
⌃ Tab Next surface
⌃ ⇧ Tab Previous surface
⌃ 18 Jump to surface 18
⌃ 9 Jump to last surface
⌘ W Close surface

Split Panes

Shortcut Action
⌘ D Split right
⌘ ⇧ D Split down
⌥ ⌘ ← → ↑ ↓ Focus pane directionally
⌘ ⇧ H Flash focused panel

Browser

Browser developer-tool shortcuts follow Safari defaults and are customizable in Settings → Keyboard Shortcuts.

Shortcut Action
⌘ ⇧ L Open browser in split
⌘ L Focus address bar
⌘ [ Back
⌘ ] Forward
⌘ R Reload page
⌥ ⌘ I Toggle Developer Tools (Safari default)
⌥ ⌘ C Show JavaScript Console (Safari default)

Notifications

Shortcut Action
⌘ I Show notifications panel
⌘ ⇧ U Jump to latest unread

Find

Shortcut Action
⌘ F Find
⌘ G / ⌘ ⇧ G Find next / previous
⌘ ⇧ F Hide find bar
⌘ E Use selection for find

Terminal

Shortcut Action
⌘ K Clear scrollback
⌘ C Copy (with selection)
⌘ V Paste
⌘ + / ⌘ - Increase / decrease font size
⌘ 0 Reset font size

Window

Shortcut Action
⌘ ⇧ N New window
⌘ , Settings
⌘ ⇧ , Reload configuration
⌘ Q Quit

Nightly Builds

Download cmux NIGHTLY

cmux NIGHTLY is a separate app with its own bundle ID, so it runs alongside the stable version. Built automatically from the latest main commit and auto-updates via its own Sparkle feed.

Report nightly bugs on GitHub Issues or in #nightly-bugs on Discord.

Session restore (current behavior)

On relaunch, cmux currently restores app layout and metadata only:

  • Window/workspace/pane layout
  • Working directories
  • Terminal scrollback (best effort)
  • Browser URL and navigation history

cmux does not restore live process state inside terminal apps. For example, active Claude Code/tmux/vim sessions are not resumed after restart yet.

Star History

Star History Chart

Contributing

Ways to get involved:

Community

Founder's Edition

cmux is free, open source, and always will be. If you'd like to support development and get early access to what's coming next:

Get Founder's Edition

  • Prioritized feature requests/bug fixes
  • Early access: cmux AI that gives you context on every workspace, tab and panel
  • Early access: iOS app with terminals synced between desktop and phone
  • Early access: Cloud VMs
  • Early access: Voice mode
  • My personal iMessage/WhatsApp

License

cmux is open source under GPL-3.0-or-later.

If your organization cannot comply with GPL, a commercial license is available. Contact founders@manaflow.com for details.