Ghostty-based macOS terminal with vertical tabs and notifications for AI coding agents https://cmux.com
Find a file
Ismail Pelaseyed d72b014d6d
feat: add markdown viewer panel with live file watching (#883)
* Add markdown viewer panel with live file watching

Introduce a new PanelType.markdown that renders .md files in a dedicated
panel using MarkdownUI (SwiftUI), with live file watching via DispatchSource
so content auto-updates when the file changes on disk.

- New MarkdownPanel class with file system watcher (write/delete/rename/extend)
- New MarkdownPanelView with custom cmux theme (headings, code blocks, tables,
  blockquotes, inline code, lists, horizontal rules, light/dark mode)
- Full workspace integration: SurfaceKind, creation methods, tab subscription
- Session persistence: snapshot/restore across app restarts
- V2 socket command: markdown.open (validates path, resolves workspace, splits)
- CLI command: cmux markdown open <path> with routing flags and help text
- Agent skill: skills/cmux-markdown/ with SKILL.md, openai.yaml, and references
- Cross-link from skills/cmux/SKILL.md to the new markdown skill
- SPM dependency: gonzalezreal/swift-markdown-ui 2.4.1

* Fix unreachable guard in markdown subcommand dispatch

Use looksLikePath() to distinguish subcommands from path arguments
so the guard can catch unknown subcommands and future subcommands
are parsed correctly.

* Use .isoLatin1 fallback instead of .ascii for encoding recovery

ASCII is a strict subset of UTF-8, so falling back to .ascii after
UTF-8 fails is dead code. Use .isoLatin1 which accepts all 256 byte
values and covers legacy encodings like Windows-1252.

* Mark fileWatchSource as nonisolated(unsafe) for deinit safety

deinit is not guaranteed to run on the main actor, so accessing
@MainActor-isolated storage is a data race under strict concurrency.
DispatchSource.cancel() is thread-safe, so nonisolated(unsafe) is
sufficient with a documented invariant that writes only occur on main.

* Fix file watcher reattach: retry loop with cancellation guard

- Replace one-shot 500ms retry with up to 6 attempts (3s total window)
  so files that reappear after a slow atomic replace are picked up
- Add isClosed flag checked before each retry to prevent restarting
  the watcher after close()/deinit

* Harden path validation in markdown.open command

Reject directories and non-absolute paths before panel creation
to prevent ambiguous behavior and generic downstream failures.

* Always reattach file watcher on delete/rename events

After an atomic save (delete old + create new), the DispatchSource still
points to the old inode. Previously we only reattached when the file was
unreadable, so successful atomic saves left the watcher on a stale inode
and live updates silently stopped. Now we always stop and reattach:
immediately if the new file is readable, via retry loop if not.

* Restore markdown panels even when file is missing at launch

MarkdownPanel already handles unavailable files gracefully (shows
'file unavailable' UI and retries via the reattach loop). Dropping
the panel on restore lost the user's layout for files that may
reappear shortly after (network drives, build artifacts, etc.).

* Harden markdown CLI parsing and startup reconnect behavior

---------

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
2026-03-04 17:48:28 -08:00
.claude/commands Add contributor credits to release skills (#319) 2026-02-22 16:18:44 -08:00
.github Remove hourly cron and skipped job from nightly workflow (#817) 2026-03-03 15:42:09 -08:00
Assets.xcassets Add dark mode app icon for macOS Sequoia (#702) 2026-03-01 03:57:09 -08:00
CLI feat: add markdown viewer panel with live file watching (#883) 2026-03-04 17:48:28 -08:00
cmuxTests Fix voice dictation text insertion path in GhosttyNSView. (#857) 2026-03-04 17:25:39 -08:00
cmuxUITests Stabilize UI keyboard/focus regressions and flaky omnibar/sidebar tests (#689) 2026-02-28 07:09:37 -08:00
design Add dark mode app icon for macOS Sequoia (#702) 2026-03-01 03:57:09 -08:00
docs Mark socket focus audit checklist complete 2026-02-21 02:22:03 -08:00
ghostty@7dd589824d Add keyboard copy mode for terminal scrollback (#792) 2026-03-03 19:01:21 -08:00
GhosttyTabs.xcodeproj feat: add markdown viewer panel with live file watching (#883) 2026-03-04 17:48:28 -08:00
homebrew-cmux@dcfaa081e5 Update homebrew-cmux submodule to latest 2026-02-19 21:36:15 -08:00
node_modules Update app and tooling 2026-01-29 17:36:26 -08:00
Resources Add Language setting for per-app locale override (#886) 2026-03-04 16:03:33 -08:00
scripts Add E2E test workflow with video recording (#778) 2026-03-02 22:16:38 -08:00
skills feat: add markdown viewer panel with live file watching (#883) 2026-03-04 17:48:28 -08:00
Sources feat: add markdown viewer panel with live file watching (#883) 2026-03-04 17:48:28 -08:00
tests feat: add markdown viewer panel with live file watching (#883) 2026-03-04 17:48:28 -08:00
tests_v2 Fix ghost terminal surface rebind after close (#808) 2026-03-03 15:20:42 -08:00
vendor Add setting to hide Cmd-hold shortcut hints (#765) 2026-03-02 19:56:27 -08:00
web Add prev/next nav to blog posts, reduce index gap (#859) 2026-03-04 01:52:56 -08: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 Tweak session restore changelog wording (#473) 2026-02-25 03:23:45 -08:00
CLAUDE.md Add Language setting for per-app locale override (#886) 2026-03-04 16:03:33 -08:00
cmux-Bridging-Header.h Rename to cmux and add About panel 2026-01-26 03:05:03 -08:00
cmux.entitlements Add microphone permission metadata for voice transcription 2026-02-25 18:20:10 -08:00
CONTRIBUTING.md Rename test targets to cmuxTests and cmuxUITests 2026-02-18 21:19:56 -08:00
ghostty.h Add keyboard copy mode for terminal scrollback (#792) 2026-03-03 19:01:21 -08:00
LICENSE Add nightly update channel workflow and adopt AGPL licensing 2026-02-14 02:43:03 -08:00
package.json Add nightly update channel workflow and adopt AGPL licensing 2026-02-14 02:43:03 -08: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 update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.bs.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.da.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.de.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.es.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.fr.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.it.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.ja.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.ko.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.md Add "The Zen of cmux" blog post (#624) 2026-02-27 00:24:47 -08:00
README.no.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.pl.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.pt-BR.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.ru.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.th.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.tr.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.zh-CN.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
README.zh-TW.md update keyboard shortcuts in README and translations 2026-02-15 21:49:54 -08:00
THIRD_PARTY_LICENSES.md add third-party licenses and update bonsplit submodule 2026-02-14 20:33:40 -08:00
TODO.md todos 2026-02-19 18:36:53 -08:00

cmux

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

Download cmux for macOS

English | 简体中文 | 繁體中文 | 한국어 | 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.

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.

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

This project is licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later).

See LICENSE for the full text.