Benutzerdefinierte Befehle und Aktionen
In der cmux.json bringen Sie cmux Ihre Abläufe bei: häufige Shell-Befehle, vorab angeordnete Workspaces mit Terminals und Browsern sowie eigene Aktionen. Diese Aktionen lassen sich an Tastenkürzel, Tab-Leisten-Schaltflächen und die Command Palette binden. Legen Sie eine Datei unter .cmux/cmux.json in einem Projekt ab, unter ~/.config/cmux/cmux.json für alle Projekte oder an beiden Orten.
Wo cmux die cmux.json liest
Einträge können aus einer Projektdatei, einer benutzerweiten Datei oder aus beiden stammen. Für Projektdateien beginnt cmux im aktuellen Verzeichnis und prüft zusätzlich jedes übergeordnete Verzeichnis darüber.
- Projekt:
./.cmux/cmux.json(wird durch Aufwärtssuche ab dem Arbeitsverzeichnis gefunden; hat Vorrang vor der benutzerweiten Datei) - Lokaler Fallback:
./cmux.json(wird für bestehende Repos weiterhin unterstützt) - Benutzerweit:
~/.config/cmux/cmux.json(gilt für alle Projekte; liefert alles, was eine Projektdatei nicht festlegt)
Bearbeite cmux.json und drücke dann Cmd+Shift+, oder führe cmux reload-config aus, um Änderungen anzuwenden.
Shell-Befehle
Der kleinste Eintrag besteht aus einem Namen und einem command-String. Wenn Sie ihn in der Command Palette auswählen, wird dieser String in das Terminal mit dem Fokus eingetippt und ausgeführt.
{
"commands": [
{
"name": "Format Changed Files",
"description": "Run the formatter on files that differ from main",
"keywords": [
"fmt",
"prettier",
"style"
],
"command": "git diff --name-only main -- '*.ts' '*.tsx' | xargs npx prettier --write"
},
{
"name": "Reset Local Database",
"keywords": [
"db",
"wipe"
],
"command": "cd \"$(git rev-parse --show-toplevel)\" && ./scripts/db-reset.sh",
"confirm": true
}
]
}Felder für Shell-Befehle
name: Erforderliche, nicht leere Bezeichnung, die Sie in der Command Palette auswählencommand: Der Shell-Text, den cmux in das fokussierte Terminal eintippt und ausführtdescription: Optionaler Zusatztext, der neben dem Eintrag angezeigt wirdkeywords: Weitere Wörter, die bei einer Suche in der Command Palette auf diesen Eintrag passen sollenconfirm: Auf true setzen, um vor jeder Ausführung eine Bestätigungsabfrage zu erhalten
Ein Shell-Befehl wird dort ausgeführt, wo sich das fokussierte Terminal gerade befindet. Braucht der Befehl einen vorhersehbaren Ausgangspunkt, beginnen Sie ihn mit cd "$(git rev-parse --show-toplevel)" && (wechselt an die oberste Ebene des Git-Repositorys) oder mit cd /some/folder && (bindet ihn an einen festen Ordner).
Befehle, die einen Workspace öffnen
Geben Sie einem Befehl statt eines command-Strings ein workspace-Objekt, dann öffnet er stattdessen einen neuen Workspace, angeordnet als Baum aus geteilten Panes mit Terminals und Browsern. Ein Eintrag braucht genau eines von beiden.
{
"commands": [
{
"name": "API Stack",
"keywords": [
"api",
"server",
"logs"
],
"restart": "confirm",
"workspace": {
"name": "API",
"cwd": "./services/api",
"color": "#10b981",
"env": {
"PORT": "8080"
},
"layout": {
"direction": "vertical",
"split": 0.65,
"children": [
{
"direction": "horizontal",
"children": [
{
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Server",
"command": "go run ./cmd/api",
"focus": true
}
]
}
},
{
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Worker",
"command": "go run ./cmd/worker",
"env": {
"QUEUE": "default"
}
}
]
}
}
]
},
{
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Logs",
"cwd": "/var/log",
"command": "tail -F system.log"
},
{
"type": "browser",
"name": "Health",
"url": "http://localhost:8080/healthz"
}
]
}
}
]
}
}
}
]
}Felder eines workspace-Objekts
name: Titel des Workspace; ohne Angabe wird der Befehlsname verwendetcwd: Basisverzeichnis des Workspace; das cwd jedes Tabs wird relativ dazu aufgelöstlayout: Der Wurzelknoten des unten beschriebenen Layout-Baumscolor: Farbe in der Seitenleiste, als #RRGGBB-Hexwert oder Name einer Workspace-Farbeenv: Environment variables inherited by every shell in the workspacesetup: Bootstrap command sent to the workspace's first terminal before that terminal's own command
Wenn der Workspace bereits geöffnet ist
Legen Sie mit restart am Befehl fest, was passiert, wenn bereits ein Workspace mit demselben Namen existiert:
"new": Neuen Workspace erstellen (Standard)"confirm": Zuerst nachfragen und ihn nach Ihrer Zustimmung ersetzen"recreate": Ihn sofort ohne Nachfrage ersetzen"ignore": Zum vorhandenen Workspace wechseln
Ein Layout beschreiben
Ein Layout ist ein Baum. Jeder innere Knoten teilt seine Fläche in zwei Teile, und jedes Blatt ist ein Pane mit Tabs.
Split-Knoten
Ein Split teilt seine Fläche in zwei Teile:
direction:"horizontal"oder"vertical"children: Ein Array aus genau zwei Knoten, die jeweils ein weiterer Split oder ein Pane sindsplit: Position des Trenners als Anteil der Fläche. Standard ist 0.5; Werte außerhalb von 0.1 bis 0.9 werden begrenzt
Pane-Knoten
Ein Pane ist ein Blatt des Baums. Sein surfaces-Array listet die Tabs auf, mit denen es öffnet, und muss mindestens einen Eintrag enthalten.
Surfaces
Jeder Eintrag im surfaces-Array eines Panes öffnet einen Tab, der entweder ein Terminal oder ein Browser ist:
type:"terminal"oder"browser"name: Tab-Titel, der anstelle des Standardtitels angezeigt wirdfocus: Auf true setzen, damit dieser Tab nach dem Aufbau des Layouts den Tastaturfokus erhältcommand: Nur Terminals: Shell-Text, der ausgeführt wird, sobald das Terminal öffneturl: Nur Browser: die zu ladende Seitecwd: Startverzeichnis für diesen Tab, aufgelöst nach den Regeln untenenv: Ein Objekt mit zusätzlichen Namen und Werten von Umgebungsvariablen
Wie cwd-Werte aufgelöst werden
~/path: wird innerhalb Ihres Home-Ordners aufgelöst- Ein Pfad, der mit / beginnt: wird unverändert übernommen
./subdir: wird an das Workspace-Verzeichnis angehängt.oder nicht gesetzt: übernimmt das Workspace-Verzeichnis
Dateistruktur
actions, shortcut oder ui.surfaceTabBar.buttons verwendest.commands definieren weiterhin wiederverwendbare Shell-Befehle und Workspace-Layouts. Nightly-Builds fügen ein actions-Register hinzu. Aktionen sind die öffentlichen IDs, die von Surface-Tableiste, Command Palette und aktionsbezogenen Kurzbefehlen gemeinsam genutzt werden.
{
"actions": {
"cmux.newTerminal": {
"type": "agent",
"agent": "claude",
"title": "Claude Code",
"subtitle": "Start Claude Code in a new tab"
},
"lint": {
"type": "command",
"title": "Lint",
"subtitle": "Run the linter in a fresh tab",
"keywords": [
"eslint",
"check"
],
"command": "npm run lint",
"shortcut": [
"cmd+k",
"cmd+l"
],
"icon": {
"type": "symbol",
"name": "checkmark.seal"
}
},
"scratch-dir": {
"type": "command",
"title": "Scratch Directory",
"command": "cd \"$(mktemp -d)\"",
"target": "currentTerminal",
"palette": false,
"icon": {
"type": "emoji",
"value": "📝",
"scale": 0.85
}
},
"api-stack": {
"type": "workspaceCommand",
"title": "API Stack",
"commandName": "API Stack"
}
},
"ui": {
"surfaceTabBar": {
"buttons": [
"cmux.newTerminal",
"cmux.splitRight",
"lint",
{
"action": "scratch-dir",
"tooltip": "cd into a new temp folder"
}
]
}
},
"commands": [
{
"name": "API Stack",
"keywords": [
"api"
],
"workspace": {
"cwd": "./services/api",
"layout": {
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Server",
"command": "go run ./cmd/api"
}
]
}
}
}
}
]
}Nightly-Aktionsregister
actions ordnet stabile IDs ausführbarem Verhalten zu. Verwende die eingebauten IDs cmux.newTerminal, cmux.newBrowser, cmux.splitRight und cmux.splitDown, um die Standardwerte zu überschreiben. Verwende eigene IDs für projektspezifische Tools.
palette ist standardmäßig true. Setze es auf false, um eine Aktion aus der Command Palette auszublenden, sie aber weiterhin für die Surface-Tableiste oder einen Kurzbefehl verfügbar zu halten. shortcut verwendet dieselbe Syntax wie Einstellungs-Kurzbefehle, zum Beispiel cmd+shift+c oder ["cmd+k", "cmd+c"].
ui.surfaceTabBar.buttons ersetzt die Standard-Buttonliste, wenn es vorhanden ist. Lasse eine eingebaute ID aus, um sie zu verbergen. Icons verwenden immer eine Objektform: { "type": "symbol", "name": "play.circle" }, { "type": "emoji", "value": "🧪", "scale": 0.9 } oder { "type": "image", "path": "./icons/codex.svg" }. Bildpfade sind relativ zur Konfigurationsdatei. Emoji-scale ist optional und standardmäßig 1. SVG, PDF, PNG, JPEG, GIF, TIFF, BMP, HEIC, HEIF, WebP, AVIF, ICO und ICNS werden unterstützt.
Jeder Buttoneintrag kann entweder eine Aktions-ID als String oder ein Buttonobjekt sein. Verwende ein Buttonobjekt, wenn dieselbe Aktion ein anderes Surface-Label, Icon oder Tooltip erhalten soll. Der aufgelöste Buttontitel wird auch als Titel der Vertrauensabfrage verwendet.
Setze alle Approval- oder Permission-Flags direkt in die Befehlszeichenfolge, die du tatsächlich ausführen möchtest. Das Standardziel einer Aktion ist newTabInCurrentPane, daher öffnet das übliche Muster einen neuen Terminaltab im aktuellen Pane und startet dort Codex, Claude Code oder OpenCode.
Benutzerdefinierte Aktionen und Command Palette
Ein actions-Eintrag ist die wiederverwendbare Aktion, die cmux ausführt. Verwende Aktionen, wenn dasselbe Verhalten in Command Palette, Oberflächen-Tableiste, Kurzbefehlen oder dem Plus-Menü verfügbar sein soll. Nutze commands weiter für wiederverwendbare Shell-Befehle und Workspace-Layouts. Setze palette auf false, wenn eine Aktion nicht in Command Palette erscheinen soll.
Aktionstypen
"command": Führt Shell-Text in einem Terminal aus. Verwende target, um das aktuelle Terminal oder einen neuen Tab im aktuellen Bereich auszuwählen."agent": Startet einen unterstützten Coding-Agenten. Aktuell werden codex und claude mit optionalen Argumenten unterstützt."builtin": Alias für eine eingebaute cmux-Aktion wie cmux.newTerminal, cmux.newBrowser, cmux.splitRight oder cmux.splitDown. Eingebaute Kopieraktionen: cmux.copyWorkingDirectory kopiert das Arbeitsverzeichnis des Terminals, cmux.copyProjectRoot das Stammverzeichnis seines Git-Repositorys (außerhalb eines Repositorys das Arbeitsverzeichnis) und cmux.copyScreen den sichtbaren Bildschirm. In einem SSH-, Cloud- oder Remote-tmux-Workspace kopiert cmux.copyProjectRoot das entfernte Arbeitsverzeichnis, weil cmux das Git-Repository auf dem anderen Host nicht ermitteln kann."workspaceCommand": Führt eine benannte Workspace-Definition aus commands aus. Nutze dies für Multi-Pane-Layouts, eigene Arbeitsverzeichnisse und Startbefehle."workspace": Create a workspace from an inline workspace definition, with optional restart behavior. Offered in the new-workspace plus-button menu automatically."setting": Ändert eine Einstellung in deiner globalen cmux.json, zum Beispiel um eine true/false-Einstellung umzuschalten oder eine Liste von Werten zu durchlaufen. Siehe Einstellungsaktionen weiter unten."settingPreset": Wendet eine benannte Gruppe von Einstellungen aus settingPresets in einem Schritt an.
Aktionsfelder
title: Titel der Command-Palette-Zeile, Beschriftung der Oberflächenschaltfläche, Menütitel und Titel des Trust-Dialogs, sofern kein Eintrag ihn überschreibt.subtitle/description: Sekundärtext in Command Palette. description wird als Alias für subtitle akzeptiert.keywords: Zusätzliche Suchbegriffe für Command Palette.palette: Standardmäßig true für benutzerdefinierte Aktionen. Setze false, um die Aktion aus Command Palette auszublenden, sie aber anderswo aufrufbar zu lassen.shortcut: Optionaler Aktionskurzbefehl mit derselben Einzel- oder Akkord-Syntax wie Einstellungs-Kurzbefehle.target: Nur für command- und agent-Aktionen. Verwende currentTerminal oder newTabInCurrentPane.confirm: Vor dem Ausführen der Aktion nachfragen.newWorkspaceMenu: Set true to offer any action in the new-workspace plus-button menu, or false to hide a workspace action from it.
Verhalten der Command Palette
Command Palette liest das aufgelöste Aktionsregister. Benutzerdefinierte Aktions-IDs werden als Zeilen hinzugefügt, wenn palette nicht false ist. Alte commands werden automatisch als benutzerdefinierte Zeilen hinzugefügt, sofern nicht bereits eine Aktion mit derselben generierten ID existiert. Eingebaute Befehle behalten ihre normalen Palettennamen, aber das Überschreiben einer eingebauten ID wie cmux.newTerminal ändert das Verhalten hinter diesem gemeinsamen Einstiegspunkt.
Einstellungsaktionen
Eine Einstellungsaktion gibt den path einer Einstellung an und genau eines von set (einen Wert schreiben), toggle: true (eine true/false-Einstellung umschalten), cycle (zum nächsten Wert einer Liste wechseln, nach dem letzten wieder zum ersten) oder unset: true (den Schlüssel aus cmux.json entfernen, sodass der Wert aus dem Einstellungsfenster oder der Standardwert gilt). toggle und cycle gehen von dem Wert aus, den cmux gerade verwendet, auch wenn du ihn im Einstellungsfenster gesetzt hast. Eine settingPreset-Aktion wendet einen Eintrag aus settingPresets an, eine unvollständige cmux.json, deren verschachtelte Objekte Schlüssel für Schlüssel zusammengeführt werden. cmux prüft jede Änderung vor dem Speichern gegen das Schema, behält deine Kommentare und übrigen Schlüssel bei und wendet die Änderung sofort an. Einstellungsaktionen und Presets laufen nur aus deiner globalen cmux.json und den Paketen, auf die sie verweist; Projektkonfigurationen können sie nicht deklarieren.
{
"actions": {
"scroll.cycle": {
"type": "setting",
"title": "Cycle Scroll Speed",
"path": "terminal.scrollSpeed",
"cycle": [1.0, 1.4, 1.8]
},
"editor.wrap": {
"type": "setting",
"title": "Toggle Editor Word Wrap",
"path": "fileEditor.wordWrap",
"toggle": true
},
"sidebar.quiet": {
"type": "settingPreset",
"title": "Quiet Sidebar",
"preset": "sidebar.quiet"
}
},
"settingPresets": {
"sidebar.quiet": {
"sidebar": { "showPorts": false, "showPullRequests": false, "showLog": false }
}
}
}Dieselben Änderungen funktionieren auch im Terminal: cmux config set terminal.scrollSpeed 1.4, cmux config toggle fileEditor.wordWrap und cmux config preset sidebar.quiet.
Mit confirm: true fragt cmux vor dem Speichern nach und zeigt den entsprechenden cmux config-Befehl. Pfade werden an jedem "." getrennt, daher lässt sich ein Schlüssel, der selbst "." enthält (etwa ein workspaceGroups.byCwd-Eintrag für ~/src/app.web), so nicht ändern. Bearbeite ihn direkt in cmux.json.
Benutzerdefinierte Aktionen für den Plus-Button
Verwende ui.newWorkspace.action, um zu überschreiben, was der Plus-Button ausführt. Verwende ui.newWorkspace.contextMenu (oder den Alias rightClick), um das geordnete Rechtsklickmenü zu definieren. Menüeinträge können Aktions-IDs, Aktionsobjekte oder { "type": "separator" } sein. Wenn nicht festgelegt, listet das Menü cmux.newWorkspace (⌘N), cmux.newCloudWorkspace (⌘Y), cmux.newCloudMachine (⇧⌘Y), cmux.newTerminal (⌘T), cmux.newBrowser (⇧⌘L), jeweils mit dem aktuellen Tastenkürzel. Cloud-Einträge erscheinen nur, wenn Cloud Machines aktiviert ist. New Cloud Workspace verwendet die Maschine des zuletzt ausgewählten Cloud-Arbeitsbereichs und danach die erste Maschine in der rechten Seitenleiste; wenn keine nutzbare Maschine vorhanden ist, wird New Cloud Machine geöffnet.
{
"actions": {
"worktree-agents": {
"type": "workspaceCommand",
"title": "Agents in New Worktree",
"commandName": "Agents in New Worktree",
"icon": {
"type": "symbol",
"name": "arrow.triangle.branch"
}
}
},
"ui": {
"newWorkspace": {
"action": "worktree-agents",
"contextMenu": [
"worktree-agents",
{
"type": "separator"
},
{
"action": "cmux.newWorkspace",
"title": "Blank Workspace"
},
{
"action": "cmux.newBrowser",
"title": "Browser"
}
]
}
},
"commands": [
{
"name": "Agents in New Worktree",
"description": "Branch off a new Git worktree, then run Codex and Claude Code in it side by side",
"workspace": {
"name": "Worktree",
"layout": {
"direction": "vertical",
"split": 0.7,
"children": [
{
"direction": "horizontal",
"children": [
{
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Codex",
"command": "marker=\"${TMPDIR:-/tmp}/cmux-wt-${CMUX_WORKSPACE_ID:-local}\"; echo \"Waiting for the worktree...\"; until [ -s \"$marker\" ]; do sleep 0.25; done; cd \"$(cat \"$marker\")\" && exec codex --yolo"
}
]
}
},
{
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Claude",
"command": "marker=\"${TMPDIR:-/tmp}/cmux-wt-${CMUX_WORKSPACE_ID:-local}\"; echo \"Waiting for the worktree...\"; until [ -s \"$marker\" ]; do sleep 0.25; done; cd \"$(cat \"$marker\")\" && exec claude --dangerously-skip-permissions"
}
]
}
}
]
},
{
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Setup",
"command": "marker=\"${TMPDIR:-/tmp}/cmux-wt-${CMUX_WORKSPACE_ID:-local}\"; rm -f \"$marker\"; root=$(git rev-parse --show-toplevel) || exit 1; branch=\"wt-$(date +%m%d-%H%M%S)\"; wt=\"$root/../$(basename \"$root\")-$branch\"; git -C \"$root\" worktree add -b \"$branch\" \"$wt\" && printf \"%s\\n\" \"$wt\" > \"$marker\" && cd \"$wt\" && exec \"${SHELL:-/bin/zsh}\" -l",
"focus": true
}
]
}
}
]
}
}
}
]
}Dieses Beispiel lässt den normalen Plus-Klick die Aktion worktree-agents ausführen. Der Workspace-Befehl aus commands nutzt ein sichtbares Setup-Terminal, um zuerst den Git-worktree zu erstellen. Codex und Claude starten gleichzeitig, warten auf die workspace-spezifische Statusdatei und wechseln dann vor exec in das erstellte Verzeichnis.
Workspace layouts
A workspace layout is stored as a workspace action, embedding a full workspace definition directly in the action so it needs no separate commands entry. It supports the same workspace fields plus setup, a bootstrap command sent to the first terminal before that terminal's own command:
{
"actions": {
"pair-review": {
"type": "workspace",
"title": "Pair Review",
"icon": {
"type": "symbol",
"name": "person.2.wave.2"
},
"restart": "ignore",
"newWorkspaceMenu": true,
"workspace": {
"name": "Review",
"cwd": "~/src/app",
"setup": "git pull --ff-only",
"layout": {
"direction": "horizontal",
"split": 0.55,
"children": [
{
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Diff",
"command": "git log -p -n 5",
"focus": true
}
]
}
},
{
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Codex",
"command": "codex"
},
{
"type": "terminal",
"name": "Shell"
}
]
}
}
]
}
}
}
}
}Workspace layouts appear in the plus-button right-click menu automatically. Set newWorkspaceMenu to false to hide one, or to true on any other action to add it to the menu.
You can also create these without writing JSON: right-click the plus button and choose Save Workspace as Layout to capture the current workspace's splits, directories, running agents, and browser tabs into ~/.config/cmux/cmux.json. They are stored as entries in the actions block. Customize Workspace Layouts opens that file in your editor.
Default for new workspaces
Use the Default for New Workspace submenu to pick which saved workspace layout plain New Workspace should run, or choose None to return to a blank terminal. The save dialog also has a Use as default for new workspaces checkbox. The setting is ui.newWorkspace.action; a project-local .cmux/cmux.json value wins over ~/.config/cmux/cmux.json.
Vollständiges Beispiel
{
"actions": {
"cmux.newTerminal": {
"type": "command",
"title": "Codex",
"command": "codex --yolo",
"shortcut": "cmd+t",
"icon": {
"type": "image",
"path": "./icons/codex.svg"
}
},
"review": {
"type": "agent",
"agent": "claude",
"args": "--permission-mode plan",
"title": "Plan with Claude",
"shortcut": "cmd+shift+p",
"icon": {
"type": "symbol",
"name": "list.bullet.clipboard"
}
},
"storybook": {
"type": "workspaceCommand",
"commandName": "Storybook",
"newWorkspaceMenu": true
},
"typecheck": {
"type": "command",
"title": "Typecheck",
"command": "npx tsc --noEmit",
"target": "newTabInCurrentPane",
"confirm": false,
"icon": {
"type": "emoji",
"value": "🔎"
}
}
},
"ui": {
"surfaceTabBar": {
"buttons": [
"cmux.newTerminal",
"review",
{
"action": "typecheck",
"title": "tsc"
},
"cmux.newBrowser",
"cmux.splitDown"
]
},
"newWorkspace": {
"contextMenu": [
"storybook",
{
"type": "separator"
},
"cmux.newTerminal",
"cmux.newBrowser"
]
}
},
"commands": [
{
"name": "Storybook",
"description": "Component explorer with a live preview beside it",
"keywords": [
"ui",
"components",
"stories"
],
"workspace": {
"name": "Storybook",
"cwd": "./packages/ui",
"color": "#a855f7",
"layout": {
"direction": "horizontal",
"split": 0.4,
"children": [
{
"direction": "vertical",
"split": 0.5,
"children": [
{
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Storybook",
"command": "npx storybook dev -p 6006 --no-open",
"focus": true
}
]
}
},
{
"pane": {
"surfaces": [
{
"type": "terminal",
"name": "Tests",
"command": "npx vitest --watch",
"env": {
"CI": "false"
}
}
]
}
}
]
},
{
"pane": {
"surfaces": [
{
"type": "browser",
"name": "Preview",
"url": "http://localhost:6006"
}
]
}
}
]
}
}
},
{
"name": "Install Dependencies",
"keywords": [
"install",
"deps"
],
"command": "npm ci",
"confirm": true
},
{
"name": "Open Changelog",
"keywords": [
"changes",
"release"
],
"command": "${EDITOR:-vi} CHANGELOG.md"
}
]
}