Commandes personnalisées

Définissez des commandes personnalisées et des mises en page d'espace de travail en ajoutant un fichier cmux.json à la racine de votre projet ou ~/.config/cmux/. Les commandes apparaissent dans la palette de commandes.

Emplacements des fichiers

cmux recherche la configuration à deux endroits :

  • Par projet : ./.cmux/cmux.json - se trouve dans votre répertoire de projet, a la priorité
  • Repli local : ./cmux.json - toujours pris en charge pour les dépôts existants
  • Global : ~/.config/cmux/cmux.json - s'applique à tous les projets, complète les commandes non définies localement
Les actions et commandes locales remplacent les entrées globales qui ont le même ID ou nom.
Le registre d’actions est une fonctionnalité nightly. Installe la dernière build nightly avant d’utiliser actions, shortcut ou ui.surfaceTabBar.buttons.
Les actions locales au projet apparaissent immédiatement dans la barre d’onglets de surface et dans Command Palette. La première exécution demande toujours l’approbation. L’approbation est liée à l’empreinte exacte de l’action, pas au dépôt. Les icônes image locales au projet restent verrouillées tant que cette action n’est pas approuvée.
Si une configuration de projet ou globale contient une erreur de schéma, cmux revient à la configuration valide suivante et affiche une ligne cmux.json Schema Error dans Command Palette. Sélectionne-la pour ouvrir le fichier de configuration.

Modifiez cmux.json, puis appuyez sur Cmd+Shift+, ou exécutez cmux reload-config pour appliquer les changements.

Schéma

commands définit toujours les commandes shell réutilisables et les dispositions de workspace. Les builds nightly ajoutent un registre actions. Les actions sont les ID publics partagés par la barre d’onglets de surface, Command Palette et les raccourcis d’action.

cmux.json
{
  "actions": {
    "cmux.newTerminal": {
      "type": "command",
      "title": "Codex",
      "subtitle": "Open Codex in a new terminal tab",
      "command": "codex --dangerously-bypass-approvals-and-sandbox",
      "target": "newTabInCurrentPane",
      "shortcut": "cmd+t",
      "icon": { "type": "image", "path": "./icons/codex.svg" }
    },
    "claude": {
      "type": "command",
      "title": "Claude Code",
      "command": "claude --dangerously-skip-permissions",
      "target": "newTabInCurrentPane",
      "shortcut": "cmd+shift+c",
      "icon": { "type": "image", "path": "./icons/claude.svg" }
    },
    "opencode": {
      "type": "command",
      "title": "OpenCode",
      "command": "opencode",
      "target": "newTabInCurrentPane",
      "palette": false,
      "icon": { "type": "emoji", "value": "🧪", "scale": 0.9 }
    },
    "web-dev": {
      "type": "workspaceCommand",
      "title": "Web Dev",
      "commandName": "Web Dev"
    }
  },
  "ui": {
    "surfaceTabBar": {
      "buttons": [
        "cmux.newTerminal",
        "cmux.newBrowser",
        "cmux.splitRight",
        "cmux.splitDown",
        "claude"
      ]
    }
  },
  "commands": [
    {
      "name": "Web Dev",
      "keywords": ["dev", "start"],
      "workspace": { ... }
    }
  ]
}

Registre d’actions nightly

actions associe des ID stables à des comportements exécutables. Utilise les ID intégrés cmux.newTerminal, cmux.newBrowser, cmux.splitRight et cmux.splitDown pour remplacer les valeurs par défaut. Utilise tes propres ID pour les outils propres au projet.

palette vaut true par défaut. Mets-le à false pour masquer une action dans Command Palette tout en la gardant disponible dans la barre d’onglets de surface ou via un raccourci. shortcut utilise la même syntaxe que les raccourcis des paramètres, par exemple cmd+shift+c ou ["cmd+k", "cmd+c"].

ui.surfaceTabBar.buttons remplace la liste de boutons par défaut lorsqu’il est présent. Omettre un ID intégré permet de le masquer. Les icônes utilisent toujours une forme objet : { "type": "symbol", "name": "play.circle" }, { "type": "emoji", "value": "🧪", "scale": 0.9 } ou { "type": "image", "path": "./icons/codex.svg" }. Les chemins d’image sont relatifs au fichier de configuration. Le scale d’un emoji est facultatif et vaut 1 par défaut. SVG, PDF, PNG, JPEG, GIF, TIFF, BMP, HEIC, HEIF, WebP, AVIF, ICO et ICNS sont pris en charge.

Chaque entrée de bouton peut être une chaîne d’ID d’action ou un objet bouton. Utilise un objet bouton lorsque tu veux la même action avec un autre libellé de surface, une autre icône ou une autre infobulle. Le titre résolu du bouton sert aussi de titre à la demande d’approbation.

Place les flags d’approbation ou de permission directement dans la chaîne de commande que tu veux réellement exécuter. La cible d’action par défaut est newTabInCurrentPane, donc le schéma courant consiste à ouvrir un nouvel onglet de terminal dans le panneau actuel et à y démarrer Codex, Claude Code ou OpenCode.

Actions personnalisées et Command Palette

Une entrée actions est l’élément réutilisable exécuté par cmux. Utilisez les actions quand le même comportement doit être disponible depuis Command Palette, la barre d’onglets de surface, les raccourcis ou le menu du bouton plus. Gardez commands pour les commandes shell réutilisables et les dispositions d’espace de travail. Définissez palette sur false quand une action ne doit pas apparaître dans Command Palette.

Types d’action

  • "builtin": Crée un alias vers une action cmux intégrée comme cmux.newTerminal, cmux.newBrowser, cmux.splitRight ou cmux.splitDown.
  • "command": Exécute du texte shell dans un terminal. Utilisez target pour choisir le terminal courant ou un nouvel onglet dans le panneau courant.
  • "agent": Lance un agent de codage pris en charge. Aujourd’hui, codex et claude sont pris en charge, avec des arguments optionnels.
  • "workspaceCommand": Exécute une définition d’espace de travail nommée depuis commands. Utilisez-le pour les dispositions multi-panneaux, les dossiers de travail personnalisés et les commandes de démarrage.

Champs d’action

  • title: Titre de ligne dans Command Palette, libellé du bouton, titre de l’élément de menu et titre de l’invite de confiance, sauf si une entrée le remplace.
  • subtitle / description: Texte secondaire dans Command Palette. description est accepté comme alias de subtitle.
  • keywords: Termes de recherche supplémentaires pour Command Palette.
  • palette: Vaut true par défaut pour les actions personnalisées. Définissez false pour masquer l’action dans Command Palette tout en la laissant appelable ailleurs.
  • shortcut: Raccourci d’action optionnel, avec la même syntaxe de touche unique ou d’accord en deux temps que les raccourcis des réglages.
  • target: Pour les actions command et agent uniquement. Utilisez currentTerminal ou newTabInCurrentPane.
  • confirm: Demande confirmation avant d’exécuter l’action.

Comportement de Command Palette

Command Palette lit le registre d’actions résolu. Les ID d’actions personnalisées sont ajoutés comme lignes quand palette n’est pas false. Les anciens commands sont ajoutés automatiquement comme lignes personnalisées, sauf si une action avec le même ID généré existe déjà. Les commandes intégrées gardent leurs libellés habituels, mais remplacer un ID intégré comme cmux.newTerminal change le comportement derrière ce point d’entrée partagé.

Actions personnalisées du bouton plus

Utilise ui.newWorkspace.action pour remplacer ce que fait le bouton plus. Utilise ui.newWorkspace.contextMenu (ou l’alias rightClick) pour définir le menu contextuel ordonné. Les entrées de menu peuvent être des ID d’action, des objets d’action ou { "type": "separator" }.

cmux.json
{
  "actions": {
    "worktree-agents": {
      "type": "workspaceCommand",
      "title": "Worktree Agents",
      "commandName": "Worktree Agents",
      "icon": { "type": "symbol", "name": "folder.badge.plus" }
    }
  },
  "ui": {
    "newWorkspace": {
      "action": "worktree-agents",
      "contextMenu": [
        { "action": "worktree-agents", "title": "Worktree Agents" },
        { "type": "separator" },
        { "action": "cmux.newTerminal", "title": "New Terminal" },
        { "action": "cmux.newBrowser", "title": "New Browser" }
      ]
    }
  },
  "commands": [
    {
      "name": "Worktree Agents",
      "description": "Create a fresh Git worktree and start Codex and Claude inside it",
      "workspace": {
        "name": "Worktree Agents",
        "cwd": ".",
        "layout": {
          "direction": "horizontal",
          "split": 0.38,
          "children": [
            {
              "pane": {
                "surfaces": [
                  {
                    "type": "terminal",
                    "name": "Worktree",
                    "command": "set -euo pipefail; state=\"${TMPDIR:-/tmp}/cmux-worktree-${CMUX_WORKSPACE_ID:-manual}.dir\"; rm -f \"$state\"; repo=$(git rev-parse --show-toplevel); mkdir -p \"$repo/../worktrees\"; slug=agents-$(date +%Y%m%d-%H%M%S); dir=\"$repo/../worktrees/$slug\"; git -C \"$repo\" worktree add -b \"$slug\" \"$dir\"; printf \"%s\\n\" \"$dir\" > \"$state\"; cd \"$dir\"; exec \"${SHELL:-/bin/zsh}\" -l",
                    "focus": true
                  }
                ]
              }
            },
            {
              "direction": "vertical",
              "split": 0.5,
              "children": [
                {
                  "pane": {
                    "surfaces": [
                      {
                        "type": "terminal",
                        "name": "Codex",
                        "command": "state=\"${TMPDIR:-/tmp}/cmux-worktree-${CMUX_WORKSPACE_ID:-manual}.dir\"; echo \"Waiting for worktree...\"; while [ ! -s \"$state\" ]; do sleep 0.2; done; dir=$(cat \"$state\"); cd \"$dir\"; exec codex --dangerously-bypass-approvals-and-sandbox"
                      }
                    ]
                  }
                },
                {
                  "pane": {
                    "surfaces": [
                      {
                        "type": "terminal",
                        "name": "Claude",
                        "command": "state=\"${TMPDIR:-/tmp}/cmux-worktree-${CMUX_WORKSPACE_ID:-manual}.dir\"; echo \"Waiting for worktree...\"; while [ ! -s \"$state\" ]; do sleep 0.2; done; dir=$(cat \"$state\"); cd \"$dir\"; exec claude --dangerously-skip-permissions"
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }
    }
  ]
}

Cet exemple fait exécuter l’action worktree-agents par le clic normal sur le bouton plus. La commande d’espace de travail de commands utilise un terminal de préparation visible pour créer d’abord le worktree Git. Codex et Claude démarrent en même temps, attendent le fichier d’état propre à l’espace de travail, puis se placent dans le dossier créé avant exec.

Commandes simples

Une commande simple exécute une commande shell dans le terminal actuellement focalisé :

cmux.json
{
  "commands": [
    {
      "name": "Run Tests",
      "keywords": ["test", "check"],
      "command": "npm test",
      "confirm": true
    }
  ]
}

Champs

  • name: Affiché dans la palette de commandes (requis)
  • description: Description optionnelle
  • keywords: Termes de recherche supplémentaires pour la palette de commandes
  • command: Commande shell à exécuter dans le terminal focalisé
  • confirm: Afficher une boîte de dialogue de confirmation avant l'exécution

Les commandes simples s'exécutent dans le répertoire de travail actuel du terminal ciblé. Si votre commande utilise des chemins relatifs au projet, préfixez avec cd "$(git rev-parse --show-toplevel)" && pour exécuter depuis la racine du dépôt, ou cd /your/path && pour n'importe quel répertoire spécifique.

Commandes d'espace de travail

Une commande d'espace de travail crée un nouvel espace de travail avec une mise en page personnalisée de divisions, terminaux et panneaux de navigateur :

cmux.json
{
  "commands": [
    {
      "name": "Dev Environment",
      "keywords": ["dev", "fullstack"],
      "workspace": {
        "name": "Dev",
        "cwd": ".",
        "layout": {
          "direction": "horizontal",
          "split": 0.5,
          "children": [
            {
              "pane": {
                "surfaces": [
                  {
                    "type": "terminal",
                    "name": "Frontend",
                    "command": "npm run dev",
                    "focus": true
                  }
                ]
              }
            },
            {
              "pane": {
                "surfaces": [
                  {
                    "type": "terminal",
                    "name": "Backend",
                    "command": "cargo watch -x run",
                    "cwd": "./server",
                    "env": { "RUST_LOG": "debug" }
                  }
                ]
              }
            }
          ]
        }
      }
    }
  ]
}

Champs de l'espace de travail

  • name: Nom de l'onglet de l'espace de travail (par défaut, nom de la commande)
  • cwd: Répertoire de travail de l'espace de travail
  • color: Couleur de l'onglet de l'espace de travail
  • layout: Arbre de mise en page définissant les divisions et panneaux

Comportement au redémarrage

Contrôle ce qui se passe lorsqu'un espace de travail du même nom existe déjà :

  • "new": Créer un nouveau workspace (par défaut)
  • "ignore": Basculer vers le workspace existant
  • "recreate": Fermer et recréer sans demander
  • "confirm": Demander à l’utilisateur avant de recréer

Arbre de mise en page

L'arbre de mise en page définit comment les panneaux sont disposés à l'aide de nœuds de division récursifs :

Nœud de division

Divise l'espace en deux enfants :

  • direction: "horizontal" ou "vertical"
  • split: Position du séparateur de 0.1 à 0.9 (par défaut 0.5)
  • children: Exactement deux nœuds enfants (division ou panneau)

Nœud de panneau

Un nœud feuille contenant une ou plusieurs surfaces (onglets dans le panneau).

Définition de surface

Chaque surface dans un panneau peut être un terminal ou un navigateur :

  • type: "terminal" ou "browser"
  • name: Titre d'onglet personnalisé
  • command: Commande shell à exécuter automatiquement à la création (terminal uniquement)
  • cwd: Répertoire de travail pour cette surface
  • env: Variables d'environnement sous forme de paires clé-valeur
  • url: URL à ouvrir (navigateur uniquement)
  • focus: Focaliser cette surface après la création

Résolution du répertoire de travail

  • . ou omis: répertoire de travail de l'espace de travail
  • ./subdir: relatif au répertoire de travail de l'espace de travail
  • ~/path: développé vers le répertoire personnel
  • Chemin absolu: utilisé tel quel

Exemple complet

cmux.json
{
  "actions": {
    "web-dev": { "type": "workspaceCommand", "commandName": "Web Dev" },
    "cmux.newTerminal": {
      "type": "command",
      "title": "Codex",
      "command": "codex --dangerously-bypass-approvals-and-sandbox",
      "target": "newTabInCurrentPane",
      "shortcut": "cmd+t",
      "icon": { "type": "image", "path": "./icons/codex.svg" }
    },
    "claude": {
      "type": "command",
      "title": "Claude Code",
      "command": "claude --dangerously-skip-permissions",
      "target": "newTabInCurrentPane",
      "shortcut": "cmd+shift+c",
      "icon": { "type": "image", "path": "./icons/claude.svg" }
    },
    "start-dev": {
      "type": "command",
      "command": "npm run dev",
      "target": "newTabInCurrentPane",
      "icon": { "type": "symbol", "name": "play.circle" }
    }
  },
  "ui": {
    "surfaceTabBar": {
      "buttons": [
        "cmux.newTerminal",
        "cmux.newBrowser",
        "cmux.splitRight",
        "cmux.splitDown",
        {
          "action": "claude",
          "title": "Claude Here"
        },
        "start-dev"
      ]
    }
  },
  "commands": [
    {
      "name": "Web Dev",
      "description": "Docs site with live preview",
      "keywords": ["web", "docs", "next", "frontend"],
      "workspace": {
        "name": "Web Dev",
        "cwd": "./web",
        "color": "#3b82f6",
        "layout": {
          "direction": "horizontal",
          "split": 0.5,
          "children": [
            {
              "pane": {
                "surfaces": [
                  {
                    "type": "terminal",
                    "name": "Next.js",
                    "command": "npm run dev",
                    "focus": true
                  }
                ]
              }
            },
            {
              "direction": "vertical",
              "split": 0.6,
              "children": [
                {
                  "pane": {
                    "surfaces": [
                      {
                        "type": "browser",
                        "name": "Preview",
                        "url": "http://localhost:3777"
                      }
                    ]
                  }
                },
                {
                  "pane": {
                    "surfaces": [
                      {
                        "type": "terminal",
                        "name": "Shell",
                        "env": { "NODE_ENV": "development" }
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }
    },
    {
      "name": "Debug Log",
      "description": "Tail the debug event log from the running dev app",
      "keywords": ["log", "debug", "tail", "events"],
      "workspace": {
        "name": "Debug Log",
        "layout": {
          "direction": "horizontal",
          "split": 0.5,
          "children": [
            {
              "pane": {
                "surfaces": [
                  {
                    "type": "terminal",
                    "name": "Events",
                    "command": "tail -f /tmp/cmux-debug.log",
                    "focus": true
                  }
                ]
              }
            },
            {
              "pane": {
                "surfaces": [
                  {
                    "type": "terminal",
                    "name": "Shell"
                  }
                ]
              }
            }
          ]
        }
      }
    },
    {
      "name": "Setup",
      "description": "Initialize submodules and build dependencies",
      "keywords": ["setup", "init", "install"],
      "command": "./scripts/setup.sh",
      "confirm": true
    },
    {
      "name": "Reload",
      "description": "Build and launch the debug app tagged to the current branch",
      "keywords": ["reload", "build", "run", "launch"],
      "command": "./scripts/reload.sh --tag $(git branch --show-current)"
    },
    {
      "name": "Run Unit Tests",
      "keywords": ["test", "unit"],
      "command": "./scripts/test-unit.sh",
      "confirm": true
    }
  ]
}