Anpassung und VerwaltungBefehle und Aktionen
Anpassung und Verwaltung

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)
Lokale Aktionen und Befehle überschreiben globale Einträge mit derselben ID oder demselben Namen.

Bearbeite cmux.json und drücke dann Cmd+Shift+, oder führe cmux reload-config aus, um Änderungen anzuwenden.

Wenn eine Projekt- oder globale Konfiguration einen Schemafehler enthält, fällt cmux auf die nächste gültige Konfiguration zurück und zeigt in der Command Palette die Zeile cmux.json Schema Error. Wähle sie aus, um die Konfigurationsdatei zu öffnen.

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.

cmux.json
{
  "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ählen
  • command: Der Shell-Text, den cmux in das fokussierte Terminal eintippt und ausführt
  • description: Optionaler Zusatztext, der neben dem Eintrag angezeigt wird
  • keywords: Weitere Wörter, die bei einer Suche in der Command Palette auf diesen Eintrag passen sollen
  • confirm: 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.

cmux.json
{
  "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 verwendet
  • cwd: Basisverzeichnis des Workspace; das cwd jedes Tabs wird relativ dazu aufgelöst
  • layout: Der Wurzelknoten des unten beschriebenen Layout-Baums
  • color: Farbe in der Seitenleiste, als #RRGGBB-Hexwert oder Name einer Workspace-Farbe
  • env: Environment variables inherited by every shell in the workspace
  • setup: 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 sind
  • split: 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 wird
  • focus: Auf true setzen, damit dieser Tab nach dem Aufbau des Layouts den Tastaturfokus erhält
  • command: Nur Terminals: Shell-Text, der ausgeführt wird, sobald das Terminal öffnet
  • url: Nur Browser: die zu ladende Seite
  • cwd: Startverzeichnis für diesen Tab, aufgelöst nach den Regeln unten
  • env: 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

Das Aktionsregister ist eine Nightly-Funktion. Installiere den neuesten Nightly-Build, bevor du 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.

cmux.json
{
  "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.

Projektlokale Aktionen erscheinen sofort in der Surface-Tableiste und in der Command Palette. Beim ersten Ausführen wird weiterhin nach Vertrauen gefragt. Vertrauen gilt pro exaktem Aktions-Fingerprint, nicht pro Repo. Projektlokale Bildicons bleiben gesperrt, bis dieser Aktion vertraut wird.

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.

~/.config/cmux/cmux.json
{
  "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.

cmux.json
{
  "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:

cmux.json
{
  "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

cmux.json
{
  "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"
    }
  ]
}