Built from Oracle research over ~/dev/cmux source. Every shortcut, file path, and JSON key in this doc is derived directly from Sources/KeyboardShortcutSettings.swift, the CLI handlers in CLI/cmux.swift, and the docs under ~/dev/cmux/docs/.
After deeper source inspection (Sources/App/TerminalDirectoryOpenSupport.swift), cmux already ships a Command Palette command:
Open Current Directory in Zed
…plus the same for Cursor, VS Code, VS Code (Inline), IntelliJ, Android Studio, Antigravity, Xcode, Tower, Warp, Windsurf, Ghostty, iTerm2, Terminal, Finder. They auto-detect installed apps and only show when available.
So the zero-config workflow is literally:
- ⌘⇧P (Command Palette)
- Type
zed - Press Enter — Zed opens at the focused terminal's directory.
It uses focusedTerminalDirectoryURL() which reads workspace.panelDirectories[focusedPanelId] first (the panel's live pwd) and falls back to workspace.currentDirectory. So it follows your terminal's cd, not just the workspace root.
cmux.json shortcuts.actions[] supports a shortcut: field that registers a real in-app hotkey (see AppDelegate.handleConfiguredCmuxShortcut → executeConfiguredCmuxAction). Pair that with type: "command" and target newTabInCurrentPane — the new tab inherits the workspace cwd, so zed . opens the workspace folder:
Then cmux reload-config. ⌘⇧Z inside cmux now opens the focused workspace in Zed. No Karabiner, no Python receiver, no external scripts.
Caveats:
- This hotkey only fires while cmux is frontmost. For a global ⌘⇧Z (works from any app), use the Karabiner recipe below.
- The command spawns a transient terminal surface to launch zed. If that's noisy, you can instead set
app.preferredEditor: "zed"and ⌘-click files in the explorer.
| Scope | Mechanism |
|---|---|
| Inside cmux only, no extra deps | cmux.json shortcuts.actions[] with shortcut: "cmd+shift+z" |
| Global hotkey (any app) | Karabiner shell_command → cmux rpc workspace.current |
cmux is a Ghostty-based macOS terminal multiplexer with:
- Vertical Workspaces (left sidebar) — one per repo / task / agent run.
- Surfaces (horizontal tabs in a workspace) — terminal, browser, markdown, file preview.
- Panes (splits inside a workspace).
- A Right Sidebar with five modes: Files, Find, Vault, Feed, Dock.
- A scriptable CLI over a Unix socket (
cmux <command>/cmux rpc <method>). - A native in-app browser with an automation API.
- Agent hooks (Claude Code, Codex, OpenCode, Cursor, Gemini, …) wired into the Feed.
Your ⌘⇧Z question, one-line answer:
zed "$(cmux rpc workspace.current | jq -r '.workspace.current_directory')"cmux does not have a third-party plugin runtime, but it has two real extension points:
cmux.jsoncustom actions — show up in the Command Palette (⌘⇧P) and can run shell commands in a terminal target.- The
cmuxCLI — invoke from Karabiner, Raycast, Alfred, Hammerspoon, etc.
For a system-wide ⌘⇧Z, Karabiner + cmux rpc workspace.current is the right tool. The .cmux.json custom action would only get you a palette entry that runs a shell command — not a global hotkey.
Save as ~/.config/scripts/cmux_open_zed.sh and chmod +x it:
#!/usr/bin/env bash
# Open the currently focused cmux workspace's cwd in Zed.
set -euo pipefail
CMUX="${CMUX_BIN:-/usr/local/bin/cmux}"
[[ -x "$CMUX" ]] || CMUX="$(command -v cmux || true)"
[[ -n "$CMUX" ]] || { osascript -e 'display notification "cmux CLI not found" with title "Open in Zed"'; exit 1; }
# Prefer rpc workspace.current (returns current_directory directly).
JSON="$("$CMUX" rpc workspace.current 2>/dev/null || true)"
CWD=""
if [[ -n "$JSON" ]] && command -v jq >/dev/null 2>&1; then
CWD="$(printf '%s' "$JSON" | jq -r '.workspace.current_directory // empty')"
fi
# Fallback: parse list-workspaces for the selected workspace.
if [[ -z "$CWD" ]]; then
CWD="$("$CMUX" rpc workspace.list 2>/dev/null \
| jq -r '.workspaces[] | select(.ref == ($ref|tostring)) | .current_directory' \
--arg ref "$("$CMUX" current-workspace 2>/dev/null)" 2>/dev/null || true)"
fi
[[ -n "$CWD" && -d "$CWD" ]] || { osascript -e "display notification \"No focused cmux cwd\" with title \"Open in Zed\""; exit 1; }
# Open in Zed, with graceful fallbacks.
if command -v zed >/dev/null 2>&1; then exec zed "$CWD"
elif [[ -x /usr/local/bin/zed ]]; then exec /usr/local/bin/zed "$CWD"
elif [[ -x /opt/homebrew/bin/zed ]]; then exec /opt/homebrew/bin/zed "$CWD"
else exec open -a "Zed" "$CWD"
fiTest it standalone:
~/.config/scripts/cmux_open_zed.shYou already have a kar-migration/config.ts with a stub for this rule. The minimal complex modification:
// inside your karabiner.ts rule list
{
description: "cmux: ⌘⇧Z → Open Zed at focused cmux cwd",
manipulators: [
{
type: "basic",
from: {
key_code: "z",
modifiers: { mandatory: ["left_command", "left_shift"] },
},
to: [
{
shell_command:
"/bin/bash -lc '~/.config/scripts/cmux_open_zed.sh'",
},
],
// Optional: only fire while cmux is frontmost.
conditions: [
{
type: "frontmost_application_if",
bundle_identifiers: ["^com\\.cmuxterm\\.app$"],
},
],
},
],
}Drop the conditions block if you want the shortcut global.
If you're editing ~/.config/karabiner/karabiner.json directly, add this to a complex_modifications.rules[] entry:
{
"description": "cmux: cmd+shift+z → Open Zed at focused cmux cwd",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "z",
"modifiers": { "mandatory": ["left_command", "left_shift"] }
},
"to": [
{ "shell_command": "/bin/bash -lc '$HOME/.config/scripts/cmux_open_zed.sh'" }
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": ["^com\\.cmuxterm\\.app$"]
}
]
}
]
}Reload Karabiner after editing (the menubar app does this on save automatically).
All defaults below come straight from Sources/KeyboardShortcutSettings.swift defaultShortcut. Modifier glyphs: ⌘ Cmd · ⇧ Shift · ⌥ Option · ⌃ Ctrl.
| Action | Action ID | Default |
|---|---|---|
| Settings | openSettings |
⌘, |
| Reload Configuration | reloadConfiguration |
⌘⇧, |
| Show / Hide All Windows (global) | showHideAllWindows |
⌃⌥⌘. |
| New Window | newWindow |
⌘⇧N |
| Close Window | closeWindow |
⌃⌘W |
| Toggle Full Screen | toggleFullScreen |
⌃⌘F |
| Quit cmux | quit |
⌘Q |
| Toggle Left Sidebar | toggleSidebar |
⌘B |
| Send Feedback | sendFeedback |
⌘⌥F |
| Action | Action ID | Default |
|---|---|---|
| New Workspace | newTab |
⌘N |
| Open Folder | openFolder |
⌘O |
| Reopen Previous Session | reopenPreviousSession |
⌘⇧O |
| Go to Workspace… | goToWorkspace |
⌘P |
| Next Workspace | nextSidebarTab |
⌃⌘] |
| Previous Workspace | prevSidebarTab |
⌃⌘[ |
| Select Workspace 1…9 | selectWorkspaceByNumber |
⌘1 … ⌘9 |
| Rename Workspace | renameWorkspace |
⌘⇧R |
| Edit Workspace Description | editWorkspaceDescription |
⌘⌥E |
| Close Workspace | closeWorkspace |
⌘⇧W |
| Action | Action ID | Default |
|---|---|---|
| New Surface (tab) | newSurface |
⌘T |
| Next Surface | nextSurface |
⌘⇧] |
| Previous Surface | prevSurface |
⌘⇧[ |
| Select Surface 1…9 | selectSurfaceByNumber |
⌃1 … ⌃9 |
| Rename Tab | renameTab |
⌘R |
| Close Tab | closeTab |
⌘W |
| Close Other Tabs in Pane | closeOtherTabsInPane |
⌘⌥T |
| Toggle Terminal Copy Mode | toggleTerminalCopyMode |
⌘⇧M |
| Focus Pane Left/Right/Up/Down | focusLeft/Right/Up/Down |
⌘⌥← / → / ↑ / ↓ |
| Split Right | splitRight |
⌘D |
| Split Down | splitDown |
⌘⇧D |
| Toggle Pane Zoom | toggleSplitZoom |
⌘⇧↩ |
| Equalize Splits | equalizeSplits |
⌃⌘= |
| Action | Action ID | Default |
|---|---|---|
| Toggle Right Sidebar | toggleFileExplorer |
⌘⌥B |
| Focus Right Sidebar | focusRightSidebar |
⌘⇧E |
| Show Files | switchRightSidebarToFiles |
⌃1 |
| Show Find | switchRightSidebarToFind |
⌃2 |
| Show Vault | switchRightSidebarToSessions |
⌃3 |
| Show Feed | switchRightSidebarToFeed |
⌃4 |
| Show Dock | switchRightSidebarToDock |
⌃5 |
toggleFileExplorer (legacy). Use that key name when overriding it in cmux.json.
The right-sidebar number shortcuts overlap with selectSurfaceByNumber on ⌃1…⌃9. cmux resolves this contextually — surface selection only fires when the sidebar isn't capturing.
| Action | Action ID | Default |
|---|---|---|
| Split Browser Right | splitBrowserRight |
⌘⌥D |
| Split Browser Down | splitBrowserDown |
⌘⌥⇧D |
| Open Browser | openBrowser |
⌘⇧L |
| Focus Address Bar | focusBrowserAddressBar |
⌘L |
| Back | browserBack |
⌘[ |
| Forward | browserForward |
⌘] |
| Reload | browserReload |
⌘R |
| Zoom In / Out / Reset | browserZoomIn/Out/Reset |
⌘= / ⌘- / ⌘0 |
| Developer Tools | toggleBrowserDeveloperTools |
⌘⌥I |
| JavaScript Console | showBrowserJavaScriptConsole |
⌘⌥C |
| Toggle React Grab | toggleReactGrab |
⌘⇧G |
| Reopen Closed Browser Panel | reopenClosedBrowserPanel |
⌘⇧T |
| Action | Action ID | Default |
|---|---|---|
| Find | find |
⌘F |
| Find in Directory | findInDirectory |
⌘⇧F |
| Find Next | findNext |
⌘G |
| Find Previous | findPrevious |
⌘⌥G |
| Hide Find Bar | hideFind |
⌘⌥⇧F |
| Use Selection for Find | useSelectionForFind |
⌘E |
| Action | Action ID | Default |
|---|---|---|
| Command Palette | commandPalette |
⌘⇧P |
| Palette: Next | commandPaletteNext |
⌃N |
| Palette: Previous | commandPalettePrevious |
⌃P |
| Action | Action ID | Default |
|---|---|---|
| Show Notifications | showNotifications |
⌘I |
| Jump to Latest Unread | jumpToUnread |
⌘⇧U |
| Flash Focused Panel | triggerFlash |
⌘⇧H |
| Save File Preview | saveFilePreview |
⌘S |
No default is a chord, but chord bindings are supported via cmux.json (next section).
cmux reads ~/.config/cmux/cmux.json first (JSONC — comments allowed), with ~/.config/cmux/settings.json and the Application Support copy as fallbacks. The template lives at ~/.config/cmux/cmux.json and is created on first launch.
Modifier tokens the parser accepts: cmd / command / ⌘, shift / ⇧, opt / option / alt / ⌥, ctrl / control / ctl / ⌃.
A binding value can be:
- A string:
"cmd+shift+p" - An array of one or two strokes (chord):
["cmd+k", "t"] nullor"none"to unbind
Example:
{
"$schema": "https://raw.githubusercontent.com/manaflow-ai/cmux/main/web/data/cmux.schema.json",
"schemaVersion": 1,
"shortcuts": {
"bindings": {
"newSurface": "cmd+t",
"selectSurfaceByNumber": "ctrl+1", // means ⌃1…⌃9
"toggleFileExplorer": "cmd+alt+b", // the right sidebar toggle
"focusRightSidebar": "cmd+shift+e",
"jumpToUnread": "cmd+shift+u",
"reloadConfiguration": ["cmd+k", "r"],
"sendFeedback": "none"
}
}
}Reload without restarting cmux:
cmux reload-configRules:
- Use action IDs, not labels (e.g.
toggleFileExplorer, nottoggleRightSidebar). - For numbered shortcuts, bind only the first digit.
"ctrl+1"expands to ⌃1…⌃9. - Settings-file shortcuts override UserDefaults and defaults.
- No third-party Swift plugin ABI.
- No Lua / JS scripting host.
- No way to register a custom keyboard shortcut that runs an arbitrary shell command on a global hotkey from within cmux. (Use Karabiner / Hammerspoon for that.)
cmux.json custom actions — the Command Palette appends cmuxConfigStore.paletteCustomActions() to its corpus, so anything you declare here shows up in ⌘⇧P. Each action can have type "command" (run a shell command), "agent", or "workspaceCommand", plus a title, subtitle, keywords, icon, palette visibility, optional shortcut metadata, and a terminal target (currentTerminal or newTabInCurrentPane, default newTabInCurrentPane).
Palette-visible "Open in Zed" action:
{
"shortcuts": {
"actions": [
{
"id": "open-cwd-in-zed",
"type": "command",
"title": "Open Workspace in Zed",
"subtitle": "zed $(pwd) of the focused terminal",
"keywords": ["zed", "editor", "open"],
"showInCommandPalette": true,
"command": "zed \"$(pwd)\"",
"terminal": "currentTerminal"
}
]
}
}Limitation: this runs in the focused terminal's shell, so its pwd only matches the workspace cwd if you haven't cd'd inside it. For a deterministic "open the workspace's cwd" command, query the RPC:
{
"id": "open-workspace-in-zed",
"type": "command",
"title": "Open Workspace in Zed (via RPC)",
"keywords": ["zed", "workspace"],
"showInCommandPalette": true,
"command": "zed \"$(cmux rpc workspace.current | jq -r '.workspace.current_directory')\"",
"terminal": "newTabInCurrentPane"
}For a system-wide ⌘⇧Z, you still need Karabiner — cmux.json actions don't bind global hotkeys.
cmux.json accepts "app": { "preferredEditor": "zed" }. This is consumed by cmux's own "open in editor" flows (e.g. opening the settings file or a file from the explorer), not a generic hotkey. Setting it makes ⌘-double-click in the file explorer open files in Zed.
{ "app": { "preferredEditor": "zed" } }Five modes mapped to ⌃1–⌃5:
| Mode | Shortcut | Purpose |
|---|---|---|
| Files | ⌃1 | Workspace-scoped file explorer (local + SSH) |
| Find | ⌃2 | Find-in-directory (ripgrep-style) |
| Vault | ⌃3 | Agent session resume |
| Feed | ⌃4 | Agent approvals / questions queue |
| Dock | ⌃5 | Pinned terminal controls |
Global sidebar controls:
| Action | Shortcut |
|---|---|
| Toggle right sidebar | ⌘⌥B |
| Focus right sidebar | ⌘⇧E |
| Find in directory | ⌘⇧F |
- Auto-roots to the selected workspace's cwd. For SSH workspaces it switches to a remote tree when the daemon is connected.
- Double-click a directory: expand/collapse. Double-click a file: open as a file-preview surface.
- Drag files out as preview drag items.
- Right-click a file: Open in default editor, Reveal in Finder, Insert path, Insert relative path, Copy path, Copy relative path.
- No built-in rename/delete from the explorer (use the terminal).
File explorer features most people miss (verified in Sources/FileExplorerView.swift):
- Drag a file into the tab strip — it becomes a
file-previewsurface (a tab) alongside terminals and browsers. Implemented viaFilePreviewDragPasteboardWriteronpasteboardWriterForItem. Great for keeping a reference file open next to a shell. - Double-click a file — same thing, opens an in-cmux file preview surface. Markdown gets a real rendered viewer (see
cmux markdown open). - Right-click → Insert Path / Insert Relative Path — types the path directly into the focused terminal. Faster than copy-paste when you're constructing a command.
- Open in Default Editor — routes through
PreferredEditorSettings.open. Set"app": { "preferredEditor": "zed" }incmux.jsonand the explorer's "Open in Default Editor" becomes "Open in Zed". Cmd-click on a file in cmux output also uses this path. - SSH workspaces — the same Files panel switches to a remote file tree over the cmux daemon when the workspace is SSH-attached. No second tool.
- Workspace cwd auto-sync — switch workspaces and the explorer re-roots. The
currentDirectoryfield on each workspace (visible incmux rpc workspace.list) is the source of truth.
Searches the workspace cwd. Result actions: open in cmux, open in default editor, reveal in Finder, insert into terminal, copy full/relative path. ⌃N / ⌃P navigate results.
Lists resumable agent sessions. Reads built-in agents plus cmux.json agents[] registrations — each entry declares detection rules, how to extract a session ID, resume command, cwd policy, and session directory.
Human-approval inbox. Agents push events via cmux hooks feed --source <agent> → cmux emits feed.push → sidebar item + notification → user decides → cmux returns the expected JSON to the agent. Use ⌘⇧U to jump straight to the latest unread.
Pin terminals into the sidebar. Project-level config first (.cmux/dock.json in the workspace), user fallback (~/.config/cmux/dock.json).
{
"controls": [
{ "id": "lazygit", "title": "git", "command": "lazygit" },
{ "id": "test", "title": "test", "command": "bun test --watch" },
{ "id": "server", "title": "dev", "command": "bun dev" }
]
}Each control gets its own ghostty-backed mini-terminal. Great for lazygit, htop, log tails, test watchers, queue inspectors.
cmux's browser is a real WebKit-backed surface with an automation API mirroring agent-browser.
| Action | Shortcut |
|---|---|
| Split browser right | ⌘⌥D |
| Split browser down | ⌘⌥⇧D |
| Open browser | ⌘⇧L |
| Focus address bar | ⌘L |
| Back / Forward | ⌘[ / ⌘] |
| Reload | ⌘R |
| Reopen closed | ⌘⇧T |
| DevTools / JS console | ⌘⌥I / ⌘⌥C |
| React Grab | ⌘⇧G |
| Zoom in / out / reset | ⌘= / ⌘- / ⌘0 |
CLI automation examples (full list under cmux browser ...):
cmux browser open https://example.com
cmux browser goto https://github.com/search?q=cmux
cmux browser snapshot --interactive --max-depth 4
cmux browser click 'button:has-text("Sign in")' --snapshot-after
cmux browser fill '#email' me@example.com
cmux browser get url
cmux browser eval 'document.title'
cmux browser screenshot --out /tmp/page.png
cmux browser console list
cmux browser cookies get .github.comBind the browser to the same workspace as your editor and you get a clean "code on left, web on right" rig without leaving the terminal app.
Mental model:
- Window = macOS window
- Workspace = vertical sidebar slot (one repo / agent run)
- Pane = a split cell inside a workspace
- Surface = a tab (terminal, browser, markdown, file preview) inside a pane
Top-line workflow shortcuts:
| Task | Shortcut |
|---|---|
| Command Palette | ⌘⇧P |
| Palette next / previous | ⌃N / ⌃P |
| Go to Workspace (name picker) | ⌘P |
| New Workspace | ⌘N |
| New Surface | ⌘T |
| Select Workspace 1…9 | ⌘1…⌘9 |
| Select Surface 1…9 | ⌃1…⌃9 |
| Reopen Previous Session | ⌘⇧O |
| Trigger Flash (find current pane) | ⌘⇧H |
| Jump to Latest Unread | ⌘⇧U |
Power-user habits:
- ⌘P when you know which workspace you want by name.
- ⌘⇧P when you want a verb (split, open browser, settings, custom action, reload, rename).
- ⌘1…9 for vertical (workspace) muscle memory; ⌃1…9 for horizontal (surface) muscle memory.
- ⌘⇧H = "where am I?" flash when splits get dense.
- ⌘⇧U = the agent-attention panic button — jumps to the most recent unread notification.
- Rebinding
commandPaletteNext/Previousincmux.jsonalso changes palette in-search navigation; the palette field reads the live binding.
cmux hooks is an agent integration subsystem, not a generic plugin host.
Supported agents (see CLI/CMUXCLI+AgentHookDefinitions.swift): Claude Code, Codex, OpenCode, Pi, Cursor CLI, Gemini, Rovo Dev, Copilot, CodeBuddy, Factory, Qoder.
Use cases:
- Show "agent running" badges.
- Restore agent sessions after relaunch.
- Bridge agent permission prompts / plan-mode decisions / questions into the Feed.
Install / uninstall:
cmux hooks setup # install supported set
cmux hooks setup --agent claude-code # one agent only
cmux hooks uninstall --agent codex
cmux hooks claude-code install
cmux hooks feed --source claude-code # how an agent pipes events into the FeedDo not repurpose hooks for arbitrary "press X to run Y" automation — they're shaped around per-agent event protocols and Feed approval semantics, not generic keybinds.
| Task | Shortcut |
|---|---|
| Command Palette | ⌘⇧P |
| Go to Workspace | ⌘P |
| New Workspace | ⌘N |
| New Surface | ⌘T |
| Split Right / Down | ⌘D / ⌘⇧D |
| Split Browser Right | ⌘⌥D |
| Open Browser | ⌘⇧L |
| Toggle Right Sidebar | ⌘⌥B |
| Focus Right Sidebar | ⌘⇧E |
| Files / Find / Vault / Feed / Dock | ⌃1 / ⌃2 / ⌃3 / ⌃4 / ⌃5 |
| Find in Directory | ⌘⇧F |
| Jump to Latest Unread | ⌘⇧U |
| Trigger Flash | ⌘⇧H |
| Reopen Previous Session | ⌘⇧O |
| Select Workspace 1–9 / Surface 1–9 | ⌘1–9 / ⌃1–9 |
| Focus Pane (l/r/u/d) | ⌘⌥←→↑↓ |
| Toggle Pane Zoom | ⌘⇧↩ |
| Toggle Terminal Copy Mode | ⌘⇧M |
| Reload Configuration | ⌘⇧, |
| Toggle Left Sidebar | ⌘B |
# Focused workspace cwd (the one you want for Zed):
cmux rpc workspace.current | jq -r '.workspace.current_directory'
# All workspaces in current window:
cmux rpc workspace.list | jq '.workspaces[] | {ref, name: .description, cwd: .current_directory}'
# Who am I (window/workspace/surface refs):
cmux identify
# Send text to the focused surface:
cmux send "echo hello"
# Open a folder in a new workspace:
cmux ~/dev/some-repo
# Open URL in cmux's browser:
cmux browser open https://example.com
# Reload settings without restart:
cmux reload-config
# List all running cmux events (good for debugging):
cmux events --limit 50| Goal | Best mechanism |
|---|---|
| Global/app hotkey to open Zed | Karabiner shell_command + cmux rpc workspace.current |
| Palette-visible custom command | cmux.json → shortcuts.actions[] |
| Project-scoped pinned controls | .cmux/dock.json |
| Resume agent sessions | Vault + agents[] in cmux.json |
| Approve/deny agent actions | cmux hooks feed → Feed sidebar |
| Arbitrary 3rd-party plugin runtime | Not present today |
Generated by Oracle (gpt-5.5-pro browser, ~520k-token cmux source bundle). Source-of-truth files in ~/dev/cmux/: Sources/KeyboardShortcutSettings.swift, Sources/KeyboardShortcutSettingsFileStore.swift, Sources/CmuxConfig.swift, Sources/CommandPalette/CommandPaletteSearch.swift, Sources/FileExplorerView.swift, Sources/RightSidebarPanelView.swift, CLI/cmux.swift, CLI/CMUXCLI+AgentHookDefinitions.swift, docs/*.md.
{ "$schema": "https://raw.githubusercontent.com/manaflow-ai/cmux/main/web/data/cmux.schema.json", "schemaVersion": 1, "shortcuts": { "actions": [ { "id": "open-cwd-in-zed", "type": "command", "title": "Open Workspace in Zed", "keywords": ["zed", "editor"], "palette": true, "shortcut": "cmd+shift+z", "command": "zed . && exit", "target": "newTabInCurrentPane" } ] } }