Comandos e ações personalizados
No cmux.json você ensina ao cmux suas rotinas: comandos de shell frequentes, workspaces com terminais e navegadores já organizados e ações próprias. Você pode associar essas ações a atalhos, a botões da barra de abas e à Command Palette. Mantenha um em .cmux/cmux.json dentro de um projeto, em ~/.config/cmux/cmux.json para todos os projetos, ou nos dois lugares.
Onde o cmux lê o cmux.json
As entradas podem vir de um arquivo de projeto, de um arquivo do usuário ou de ambos. Para arquivos de projeto, o cmux começa no diretório atual e também verifica cada diretório pai acima dele.
- Projeto:
./.cmux/cmux.json(encontrado buscando para cima a partir do diretório de trabalho; tem prioridade sobre o arquivo do usuário) - Local de fallback:
./cmux.json(ainda compatível com repositórios existentes) - Do usuário:
~/.config/cmux/cmux.json(compartilhado por todos os projetos; fornece tudo o que um arquivo de projeto deixa indefinido)
Edite cmux.json e depois pressione Cmd+Shift+, ou execute cmux reload-config para aplicar as alterações.
Comandos de shell
A menor entrada é um nome mais uma string command. Ao escolhê-la na Command Palette, essa string é digitada no terminal que está em foco e executada.
{
"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
}
]
}Campos de comando de shell
name: Rótulo obrigatório e não vazio que você escolhe na Command Palettecommand: O texto de shell que o cmux digita no terminal em foco e executadescription: Texto secundário opcional exibido ao lado da entradakeywords: Palavras extras que devem corresponder a esta entrada quando você pesquisa na Command Paletteconfirm: Defina como true para receber um pedido de confirmação antes de cada execução
Um comando de shell é executado onde quer que o terminal em foco esteja no momento. Quando o comando precisa de um ponto de partida previsível, comece-o com cd "$(git rev-parse --show-toplevel)" && para ir à raiz do repositório Git, ou com cd /some/folder && para fixá-lo em uma pasta específica.
Comandos que abrem um workspace
Dê a um comando um objeto workspace no lugar de uma string command e ele abrirá um novo workspace, organizado como uma árvore de painéis divididos com terminais e navegadores. Cada entrada precisa de exatamente um dos dois.
{
"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"
}
]
}
}
]
}
}
}
]
}Campos de um objeto workspace
name: Título do workspace; na ausência dele, usa o nome do comandocwd: Diretório base do workspace; o cwd de cada aba é resolvido em relação a elelayout: O nó raiz da árvore de layout descrita abaixocolor: Cor na barra lateral, em hexadecimal #RRGGBB ou como nome de uma cor de workspaceenv: Environment variables inherited by every shell in the workspacesetup: Bootstrap command sent to the workspace's first terminal before that terminal's own command
Quando o workspace já está aberto
Defina restart no comando para decidir o que acontece se já existir um workspace com o mesmo nome:
"new": Criar um novo workspace (padrão)"confirm": Perguntar primeiro e substituí-lo se você concordar"recreate": Substituí-lo imediatamente, sem perguntar"ignore": Mudar para o workspace existente
Descrevendo um layout
Um layout é uma árvore. Cada nó interno divide sua área em duas, e cada folha é um painel que contém abas.
Nós de divisão
Uma divisão separa sua área em duas partes:
direction:"horizontal"ou"vertical"children: Um array com exatamente dois nós, cada um sendo outra divisão ou um painelsplit: Onde fica o divisor, como fração da área. O padrão é 0.5; valores fora do intervalo de 0.1 a 0.9 são ajustados a esses limites
Nós de painel
Um painel é uma folha da árvore. Seu array surfaces lista as abas com que ele abre e precisa conter pelo menos uma entrada.
Superfícies
Cada entrada no array surfaces de um painel abre uma aba, que é um terminal ou um navegador:
type:"terminal"ou"browser"name: Título da aba exibido no lugar do padrãofocus: Defina como true para dar o foco do teclado a esta aba depois que o layout for montadocommand: Somente terminais: texto de shell a executar assim que o terminal abrirurl: Somente navegadores: a página a carregarcwd: Diretório inicial desta aba, resolvido pelas regras abaixoenv: Um objeto com nomes e valores de variáveis de ambiente adicionais
Como os valores de cwd são resolvidos
~/path: resolvido dentro da sua pasta pessoal- Um caminho que começa com /: usado literalmente
./subdir: anexado ao diretório do workspace.ou não definido: herda o diretório do workspace
Estrutura do arquivo
actions, shortcut ou ui.surfaceTabBar.buttons.commands ainda define comandos shell reutilizáveis e layouts de workspace. Builds nightly adicionam um registro actions. Ações são os IDs públicos compartilhados pela barra de abas de superfície, Command Palette e atalhos no nível da ação.
{
"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"
}
]
}
}
}
}
]
}Registro de ações nightly
actions mapeia IDs estáveis para comportamentos executáveis. Use os IDs integrados cmux.newTerminal, cmux.newBrowser, cmux.splitRight e cmux.splitDown para sobrescrever os padrões. Use seus próprios IDs para ferramentas específicas do projeto.
palette usa true por padrão. Defina como false para ocultar uma ação da Command Palette, mantendo-a disponível na barra de abas de superfície ou por um atalho. shortcut usa a mesma sintaxe dos atalhos de configurações, por exemplo cmd+shift+c ou ["cmd+k", "cmd+c"].
ui.surfaceTabBar.buttons substitui a lista padrão de botões quando está presente. Omita um ID integrado para ocultá-lo. Ícones sempre usam formato de objeto: { "type": "symbol", "name": "play.circle" }, { "type": "emoji", "value": "🧪", "scale": 0.9 } ou { "type": "image", "path": "./icons/codex.svg" }. Caminhos de imagem são relativos ao arquivo de configuração. O scale de emoji é opcional e o padrão é 1. SVG, PDF, PNG, JPEG, GIF, TIFF, BMP, HEIC, HEIF, WebP, AVIF, ICO e ICNS são compatíveis.
Cada entrada de botão pode ser uma string de ID de ação ou um objeto de botão. Use um objeto de botão quando quiser a mesma ação com outro rótulo de superfície, ícone ou tooltip. O título resolvido do botão também é usado como título do prompt de confiança.
Coloque qualquer flag de aprovação ou permissão diretamente na string de comando que você realmente quer executar. O destino padrão da ação é newTabInCurrentPane, então o padrão comum é abrir uma nova aba de terminal no painel atual e iniciar Codex, Claude Code ou OpenCode ali.
Ações personalizadas e Command Palette
Uma entrada actions é a unidade reutilizável que o cmux executa. Use ações quando o mesmo comportamento deve estar disponível na Command Palette, na barra de abas de superfície, em atalhos ou no menu do botão de mais. Mantenha commands para comandos shell reutilizáveis e layouts de workspace. Defina palette como false quando uma ação não deve aparecer na Command Palette.
Tipos de ação
"command": Executa texto shell em um terminal. Use target para escolher o terminal atual ou uma nova aba no painel atual."agent": Inicia um agente de programação compatível. Hoje oferece suporte a codex e claude, com argumentos opcionais."builtin": Cria um alias para uma ação integrada do cmux, como cmux.newTerminal, cmux.newBrowser, cmux.splitRight ou cmux.splitDown. Ações integradas de cópia: cmux.copyWorkingDirectory copia o diretório de trabalho do terminal, cmux.copyProjectRoot copia a raiz do repositório git (ou o diretório de trabalho fora de um repositório) e cmux.copyScreen copia a tela visível. Em um workspace SSH, na nuvem ou de tmux remoto, cmux.copyProjectRoot copia o diretório de trabalho remoto, porque o cmux não consegue consultar o repositório git no outro host."workspaceCommand": Executa uma definição de workspace nomeada em commands. Use para layouts com vários painéis, diretórios de trabalho personalizados e comandos de inicialização."workspace": Create a workspace from an inline workspace definition, with optional restart behavior. Offered in the new-workspace plus-button menu automatically."setting": Altera uma configuração no seu cmux.json global, por exemplo para alternar uma configuração true/false ou percorrer uma lista de valores. Veja Ações de configuração abaixo."settingPreset": Aplica de uma vez um grupo nomeado de configurações definido em settingPresets.
Campos da ação
title: Título da linha na Command Palette, rótulo do botão, título do item de menu e título do prompt de confiança, a menos que uma entrada substitua.subtitle/description: Texto secundário na Command Palette. description é aceito como alias de subtitle.keywords: Termos de busca adicionais para a Command Palette.palette: O padrão é true para ações personalizadas. Defina false para ocultar a ação da Command Palette mantendo-a chamável de outros lugares.shortcut: Atalho opcional da ação, usando a mesma sintaxe de tecla única ou acorde de dois passos dos atalhos das configurações.target: Somente para ações command e agent. Use currentTerminal ou newTabInCurrentPane.confirm: Pede confirmação antes de executar a ação.newWorkspaceMenu: Set true to offer any action in the new-workspace plus-button menu, or false to hide a workspace action from it.
Comportamento da Command Palette
A Command Palette lê o registro de ações resolvido. IDs de ações personalizadas são adicionados como linhas quando palette não é false. commands legados são adicionados automaticamente como linhas personalizadas, a menos que uma ação com o mesmo ID gerado já exista. Comandos integrados mantêm seus rótulos normais, mas substituir um ID integrado como cmux.newTerminal altera o comportamento por trás dessa entrada compartilhada.
Ações de configuração
Uma ação de configuração indica o path de uma configuração e exatamente um entre set (grava um valor), toggle: true (alterna uma configuração true/false), cycle (avança para o próximo valor de uma lista, voltando ao primeiro depois do último) ou unset: true (remove a chave do cmux.json, para que valha o valor da janela Configurações ou o padrão). toggle e cycle partem do valor que o cmux está usando, inclusive um definido na janela Configurações. Uma ação settingPreset aplica uma entrada de settingPresets, um cmux.json parcial cujos objetos aninhados são mesclados chave por chave. O cmux valida cada alteração com o esquema antes de salvar, mantém seus comentários e as demais chaves e aplica a alteração na hora. Ações de configuração e presets só rodam a partir do seu cmux.json global e dos pacotes que ele referencia; configurações de projeto não podem declará-los.
{
"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 }
}
}
}As mesmas alterações funcionam a partir de um terminal: cmux config set terminal.scrollSpeed 1.4, cmux config toggle fileEditor.wordWrap e cmux config preset sidebar.quiet.
Com confirm: true, o cmux pergunta antes de salvar e mostra o comando cmux config equivalente. Os caminhos são divididos em cada ".", então uma chave que contém "." (como uma entrada de workspaceGroups.byCwd para ~/src/app.web) não pode ser alterada dessa forma. Edite-a diretamente no cmux.json.
Ações personalizadas do botão de mais
Use ui.newWorkspace.action para sobrescrever o que o botão de mais faz. Use ui.newWorkspace.contextMenu (ou o alias rightClick) para definir o menu ordenado do clique direito. Entradas de menu podem ser IDs de ação, objetos de ação ou { "type": "separator" }. Quando não definido, o menu lista cmux.newWorkspace (⌘N), cmux.newCloudWorkspace (⌘Y), cmux.newCloudMachine (⇧⌘Y), cmux.newTerminal (⌘T), cmux.newBrowser (⇧⌘L), cada um com seu atalho atual. As opções de nuvem aparecem apenas quando Cloud Machines está habilitado. New Cloud Workspace usa a máquina do espaço de trabalho Cloud selecionado mais recentemente e depois a primeira na barra lateral direita; se não houver uma máquina utilizável, abre o New Cloud Machine.
{
"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
}
]
}
}
]
}
}
}
]
}Este exemplo faz o clique normal no botão de mais executar a ação worktree-agents. O comando de workspace em commands usa um terminal de preparação visível para criar primeiro o worktree do Git. Codex e Claude iniciam ao mesmo tempo, esperam o arquivo de estado específico do workspace e então entram no diretório criado antes de exec.
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.
Exemplo completo
{
"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"
}
]
}