Comandos personalizados

Define comandos personalizados y diseños de workspace añadiendo un archivo cmux.json a la raíz de tu proyecto o ~/.config/cmux/. Los comandos aparecen en la paleta de comandos.

Ubicaciones de archivos

cmux busca configuración en dos lugares:

  • Por proyecto: ./.cmux/cmux.json - se encuentra en tu directorio de proyecto, tiene prioridad
  • Local de respaldo: ./cmux.json - sigue siendo compatible con repos existentes
  • Configuración global: ~/.config/cmux/cmux.json - se aplica a todos los proyectos, completa los comandos no definidos localmente
Las acciones y comandos locales reemplazan las entradas globales con el mismo ID o nombre.
El registro de acciones es una función nightly. Instala la versión nightly más reciente antes de usar actions, shortcut o ui.surfaceTabBar.buttons.
Las acciones locales del proyecto aparecen de inmediato en la barra de pestañas de superficie y en Command Palette. La primera ejecución aún solicita confianza. La confianza se aplica a la huella exacta de la acción, no al repositorio. Los iconos de imagen locales del proyecto permanecen bloqueados hasta que se confíe en esa acción.
Si una configuración de proyecto o global tiene un error de esquema, cmux vuelve a la siguiente configuración válida y muestra una fila cmux.json Schema Error en Command Palette. Selecciónala para abrir el archivo de configuración.

Edita cmux.json y luego presiona Cmd+Shift+, o ejecuta cmux reload-config para aplicar los cambios.

Esquema

commands sigue definiendo comandos de shell reutilizables y diseños de espacios de trabajo. Las versiones nightly añaden un registro actions. Las acciones son los ID públicos compartidos por la barra de pestañas de superficie, Command Palette y los atajos de nivel de acción.

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

Registro de acciones nightly

actions asigna ID estables a comportamientos ejecutables. Usa los ID integrados cmux.newTerminal, cmux.newBrowser, cmux.splitRight y cmux.splitDown para sobrescribir los valores predeterminados. Usa tus propios ID para herramientas específicas del proyecto.

palette usa true de forma predeterminada. Cámbialo a false para ocultar una acción de Command Palette sin dejar de permitir su uso desde la barra de pestañas de superficie o un atajo. shortcut usa la misma sintaxis que los atajos de configuración, por ejemplo cmd+shift+c o ["cmd+k", "cmd+c"].

ui.surfaceTabBar.buttons reemplaza la lista predeterminada de botones cuando está presente. Omite un ID integrado para ocultarlo. Los iconos siempre usan forma de objeto: { "type": "symbol", "name": "play.circle" }, { "type": "emoji", "value": "🧪", "scale": 0.9 } o { "type": "image", "path": "./icons/codex.svg" }. Las rutas de imagen son relativas al archivo de configuración. El scale de emoji es opcional y usa 1 de forma predeterminada. Se admiten SVG, PDF, PNG, JPEG, GIF, TIFF, BMP, HEIC, HEIF, WebP, AVIF, ICO e ICNS.

Cada entrada de botón puede ser una cadena con un ID de acción o un objeto de botón. Usa un objeto de botón cuando quieras la misma acción con otra etiqueta de superficie, icono o tooltip. El título resuelto del botón también se usa como título de la solicitud de confianza.

Coloca cualquier flag de aprobación o permiso directamente en la cadena de comando que quieras ejecutar. El destino predeterminado de la acción es newTabInCurrentPane, por lo que el patrón común es abrir una nueva pestaña de terminal en el panel actual e iniciar allí Codex, Claude Code u OpenCode.

Acciones personalizadas y Command Palette

Una entrada actions es lo reutilizable que ejecuta cmux. Usa acciones cuando el mismo comportamiento deba estar disponible desde Command Palette, la barra de pestañas de superficie, los atajos o el menú del botón más. Mantén commands para comandos de shell reutilizables y diseños de espacios de trabajo. Define palette como false cuando una acción no deba aparecer en Command Palette.

Tipos de acción

  • "builtin": Crea un alias para una acción integrada de cmux como cmux.newTerminal, cmux.newBrowser, cmux.splitRight o cmux.splitDown.
  • "command": Ejecuta texto de shell en una terminal. Usa target para elegir la terminal actual o una pestaña nueva en el panel actual.
  • "agent": Inicia un agente de programación compatible. Hoy admite codex y claude, con argumentos opcionales.
  • "workspaceCommand": Ejecuta una definición de espacio de trabajo con nombre desde commands. Úsalo para diseños multipanel, directorios de trabajo personalizados y comandos de inicio.

Campos de acción

  • title: Título de la fila en Command Palette, etiqueta del botón, título del elemento de menú y título del aviso de confianza, salvo que una entrada lo reemplace.
  • subtitle / description: Texto secundario en Command Palette. description se acepta como alias de subtitle.
  • keywords: Términos de búsqueda adicionales para Command Palette.
  • palette: El valor predeterminado es true para acciones personalizadas. Define false para ocultar la acción de Command Palette y mantenerla invocable desde otros lugares.
  • shortcut: Atajo opcional de acción, con la misma sintaxis de una tecla o acorde de dos pasos que los atajos de configuración.
  • target: Solo para acciones command y agent. Usa currentTerminal o newTabInCurrentPane.
  • confirm: Pide confirmación antes de ejecutar la acción.

Comportamiento de Command Palette

Command Palette lee el registro de acciones resuelto. Los ID de acciones personalizadas se agregan como filas cuando palette no es false. Los commands heredados se agregan automáticamente como filas personalizadas, salvo que ya exista una acción con el mismo ID generado. Los comandos integrados conservan sus etiquetas normales, pero reemplazar un ID integrado como cmux.newTerminal cambia el comportamiento detrás de esa entrada compartida.

Acciones personalizadas del botón de suma

Usa ui.newWorkspace.action para sobrescribir lo que hace el botón de suma. Usa ui.newWorkspace.contextMenu (o el alias rightClick) para definir el menú ordenado del clic derecho. Las entradas del menú pueden ser ID de acción, objetos de acción o { "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"
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }
    }
  ]
}

Este ejemplo hace que el clic normal en el botón más ejecute la acción worktree-agents. El comando de espacio de trabajo de commands usa una terminal de preparación visible para crear primero el worktree de Git. Codex y Claude se inician al mismo tiempo, esperan el archivo de estado específico del espacio de trabajo y luego entran en el directorio creado antes de exec.

Comandos simples

Un comando simple ejecuta un comando de shell en el terminal actualmente enfocado:

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

Campos

  • name: Se muestra en la paleta de comandos (requerido)
  • description: Descripción opcional
  • keywords: Términos de búsqueda adicionales para la paleta de comandos
  • command: Comando de shell para ejecutar en el terminal enfocado
  • confirm: Mostrar un diálogo de confirmación antes de ejecutar

Los comandos simples se ejecutan en el directorio de trabajo actual de la terminal enfocada. Si tu comando depende de rutas relativas al proyecto, prefija con cd "$(git rev-parse --show-toplevel)" && para ejecutar desde la raíz del repositorio, o cd /your/path && para cualquier directorio específico.

Comandos de workspace

Un comando de workspace crea un nuevo workspace con un diseño personalizado de divisiones, terminales y paneles de navegador:

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" }
                  }
                ]
              }
            }
          ]
        }
      }
    }
  ]
}

Campos de workspace

  • name: Nombre de la pestaña del workspace (por defecto es el nombre del comando)
  • cwd: Directorio de trabajo del workspace
  • color: Color de la pestaña del workspace
  • layout: Árbol de diseño que define divisiones y paneles

Comportamiento de reinicio

Controla qué sucede cuando ya existe un workspace con el mismo nombre:

  • "new": Crear un workspace nuevo (por defecto)
  • "ignore": Cambiar al workspace existente
  • "recreate": Cerrar y recrear sin preguntar
  • "confirm": Preguntar al usuario antes de recrear

Árbol de diseño

El árbol de diseño define cómo se organizan los paneles usando nodos de división recursivos:

Nodo de división

Divide el espacio en dos hijos:

  • direction: "horizontal" o "vertical"
  • split: Posición del divisor de 0.1 a 0.9 (por defecto 0.5)
  • children: Exactamente dos nodos hijos (división o panel)

Nodo de panel

Un nodo hoja que contiene una o más superficies (pestañas dentro del panel).

Definición de superficie

Cada superficie en un panel puede ser un terminal o un navegador:

  • type: "terminal" o "browser"
  • name: Título de pestaña personalizado
  • command: Comando de shell para ejecutar automáticamente al crear (solo terminal)
  • cwd: Directorio de trabajo para esta superficie
  • env: Variables de entorno como pares clave-valor
  • url: URL para abrir (solo navegador)
  • focus: Enfocar esta superficie después de crearla

Resolución del directorio de trabajo

  • . o omitido: directorio de trabajo del workspace
  • ./subdir: relativo al directorio de trabajo del workspace
  • ~/path: expandido al directorio home
  • Ruta absoluta: se usa tal cual

Ejemplo completo

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
    }
  ]
}