사용자 지정 명령과 액션
cmux.json은 cmux에 나만의 작업 루틴을 가르치는 곳입니다. 자주 실행하는 셸 명령, 터미널과 브라우저가 미리 배치된 채로 열리는 워크스페이스, 단축키나 탭 바 버튼, Command Palette에 연결할 수 있는 액션을 정의할 수 있습니다. 프로젝트 안의 .cmux/cmux.json, 모든 프로젝트에 적용되는 ~/.config/cmux/cmux.json, 또는 두 곳 모두에 둘 수 있습니다.
cmux가 cmux.json을 읽는 위치
항목은 프로젝트 파일, 사용자 전체 파일, 또는 둘 모두에서 가져올 수 있습니다. 프로젝트 파일의 경우 cmux는 현재 디렉터리에서 시작해 그 위에 있는 상위 디렉터리도 차례로 확인합니다.
- 프로젝트:
./.cmux/cmux.json(작업 디렉터리에서 위쪽으로 검색해 찾으며, 사용자 전체 파일보다 우선합니다) - fallback 로컬:
./cmux.json(기존 repo를 위해 계속 지원됩니다) - 사용자 전체:
~/.config/cmux/cmux.json(모든 프로젝트가 공유하며, 프로젝트 파일에서 정의하지 않은 부분을 채웁니다)
cmux.json을 편집한 뒤 Cmd+Shift+, 를 누르거나 cmux reload-config를 실행해 변경 사항을 적용하세요.
셸 명령
가장 작은 항목은 이름과 명령 문자열뿐입니다. Command Palette에서 이 항목을 선택하면 해당 문자열이 포커스된 터미널에 입력되고 실행됩니다.
{
"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
}
]
}셸 명령 필드
name: Command Palette에서 선택할 때 쓰는 필수 레이블(빈 값 불가)command: cmux가 포커스된 터미널에 입력하고 실행하는 셸 텍스트description: 항목 옆에 표시되는 선택적 보조 텍스트keywords: Command Palette에서 검색할 때 이 항목과 일치해야 하는 추가 단어confirm: true로 설정하면 실행할 때마다 먼저 확인 프롬프트가 표시됩니다
셸 명령은 포커스된 터미널이 그 시점에 있는 위치에서 실행됩니다. 명령에 예측 가능한 시작 위치가 필요하다면 맨 앞에 cd "$(git rev-parse --show-toplevel)" && 명령을 붙여 Git 저장소의 최상위로 이동하거나, cd /some/folder && 명령을 붙여 고정된 폴더에서 시작하게 하세요.
워크스페이스를 여는 명령
명령에 명령 문자열 대신 workspace 객체를 지정하면 새 워크스페이스를 여는 명령이 됩니다. 워크스페이스는 터미널과 브라우저를 담은 분할 패널의 트리로 배치됩니다. 각 항목에는 둘 중 정확히 하나만 있어야 합니다.
{
"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"
}
]
}
}
]
}
}
}
]
}workspace 객체의 필드
name: 워크스페이스 제목이며, 없으면 명령 이름을 사용합니다cwd: 워크스페이스의 기준 디렉터리이며, 각 탭의 cwd는 이를 기준으로 해석됩니다layout: 아래에서 설명하는 레이아웃 트리의 루트 노드color: 사이드바 색상. #RRGGBB 16진수 값이나 워크스페이스 색상 이름으로 지정합니다env: Environment variables inherited by every shell in the workspacesetup: Bootstrap command sent to the workspace's first terminal before that terminal's own command
워크스페이스가 이미 열려 있을 때
명령에 restart를 설정하면 같은 이름의 워크스페이스가 이미 있을 때의 동작을 정할 수 있습니다:
"new": 새 워크스페이스 만들기 (기본값)"confirm": 먼저 묻고, 동의하면 교체"recreate": 묻지 않고 즉시 교체"ignore": 기존 워크스페이스로 전환
레이아웃 기술하기
레이아웃은 트리입니다. 모든 내부 노드는 자기 영역을 둘로 나누고, 모든 리프는 탭을 담는 패널입니다.
분할 노드
분할은 자기 영역을 두 부분으로 나눕니다:
direction:"horizontal"또는"vertical"children: 정확히 두 개의 노드로 이루어진 배열이며, 각 노드는 또 다른 분할이나 패널입니다split: 구분선의 위치를 영역에 대한 비율로 나타냅니다. 기본값은 0.5이며, 0.1~0.9 범위를 벗어난 값은 범위 안으로 조정됩니다
패널 노드
패널은 트리의 리프입니다. surfaces 배열에는 처음 열 때의 탭을 나열하며, 항목이 하나 이상 있어야 합니다.
서피스
패널의 surfaces 배열에 있는 각 항목은 터미널 또는 브라우저 탭을 하나씩 엽니다:
type:"terminal"또는"browser"name: 기본값 대신 표시할 탭 제목focus: true로 설정하면 레이아웃이 만들어진 뒤 이 탭에 키보드 포커스를 둡니다command: 터미널 전용: 터미널이 열리자마자 실행할 셸 텍스트url: 브라우저 전용: 불러올 페이지cwd: 이 탭의 시작 디렉터리이며, 아래 규칙에 따라 해석됩니다env: 추가 환경 변수의 이름과 값을 담은 객체
cwd 값을 해석하는 방법
~/path: 홈 폴더 안에서 해석됩니다- /로 시작하는 경로: 그대로 사용됩니다
./subdir: 워크스페이스 디렉터리 뒤에 이어 붙습니다.또는 설정하지 않음: 워크스페이스 디렉터리를 이어받습니다
파일 구조
actions, shortcut, ui.surfaceTabBar.buttons를 사용하기 전에 최신 nightly 빌드를 설치하세요.commands는 계속 재사용 가능한 shell 명령과 workspace 레이아웃을 정의합니다. Nightly 빌드는 actions 레지스트리를 추가합니다. 액션은 surface 탭 바, Command Palette, 액션 단위 shortcut이 공유하는 공개 ID입니다.
{
"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 액션 레지스트리
actions는 안정적인 ID를 실행 가능한 동작에 매핑합니다. 기본값을 재정의하려면 내장 ID cmux.newTerminal, cmux.newBrowser, cmux.splitRight, cmux.splitDown을 사용하세요. 프로젝트 전용 도구에는 자체 ID를 사용하세요.
palette는 기본적으로 true입니다. false로 설정하면 surface 탭 바나 shortcut에서는 계속 사용할 수 있지만 Command Palette에서는 숨깁니다. shortcut은 설정 shortcut과 같은 문법을 사용합니다. 예: cmd+shift+c 또는 ["cmd+k", "cmd+c"].
ui.surfaceTabBar.buttons가 있으면 기본 버튼 목록을 대체합니다. 내장 ID를 빼면 숨겨집니다. 아이콘은 항상 객체 형태를 사용합니다: { "type": "symbol", "name": "play.circle" }, { "type": "emoji", "value": "🧪", "scale": 0.9 }, 또는 { "type": "image", "path": "./icons/codex.svg" }. 이미지 경로는 설정 파일 기준 상대 경로입니다. Emoji scale은 선택 사항이며 기본값은 1입니다. SVG, PDF, PNG, JPEG, GIF, TIFF, BMP, HEIC, HEIF, WebP, AVIF, ICO, ICNS를 지원합니다.
각 버튼 항목은 액션 ID 문자열 또는 버튼 객체가 될 수 있습니다. 같은 액션에 다른 surface 라벨, 아이콘, tooltip을 주고 싶을 때 버튼 객체를 사용하세요. 해석된 버튼 제목은 신뢰 확인 제목으로도 사용됩니다.
승인 또는 권한 플래그는 실제로 실행하려는 명령 문자열에 직접 넣으세요. 기본 액션 대상은 newTabInCurrentPane이므로 일반적인 패턴은 현재 pane에 새 terminal 탭을 열고 그 안에서 Codex, Claude Code, OpenCode를 시작하는 것입니다.
사용자 지정 액션과 Command Palette
actions 항목은 cmux가 실행하는 재사용 가능한 동작입니다. 같은 동작을 Command Palette, 서피스 탭 바, 단축키 또는 플러스 버튼 메뉴에서 사용할 때 액션을 사용하세요. 재사용 가능한 셸 명령과 워크스페이스 레이아웃에는 commands를 계속 사용하세요. Command Palette에서 숨길 액션은 palette를 false로 설정합니다.
액션 유형
"command": 터미널에서 셸 텍스트를 실행합니다. target으로 현재 터미널 또는 현재 패널의 새 탭을 선택합니다."agent": 지원되는 코딩 에이전트를 시작합니다. 현재 codex와 claude를 지원하며 선택적 인수를 줄 수 있습니다."builtin": cmux.newTerminal, cmux.newBrowser, cmux.splitRight, cmux.splitDown 같은 내장 cmux 액션의 별칭입니다. 복사용 내장 동작: cmux.copyWorkingDirectory는 터미널의 작업 디렉터리를, cmux.copyProjectRoot는 Git 저장소의 루트(저장소 밖에서는 작업 디렉터리)를, cmux.copyScreen은 보이는 화면을 복사합니다. SSH, 클라우드, 원격 tmux 워크스페이스에서는 cmux가 다른 호스트의 Git 저장소를 확인할 수 없으므로 cmux.copyProjectRoot가 원격 작업 디렉터리를 복사합니다."workspaceCommand": commands의 이름 있는 워크스페이스 정의를 실행합니다. 여러 패널 레이아웃, 사용자 지정 작업 디렉터리, 시작 명령에 사용합니다."workspace": Create a workspace from an inline workspace definition, with optional restart behavior. Offered in the new-workspace plus-button menu automatically."setting": 전역 cmux.json의 설정 하나를 변경합니다. 예를 들어 true/false 설정을 전환하거나 값 목록을 순환할 수 있습니다. 아래 설정 액션을 참고하세요."settingPreset": settingPresets에 있는 이름 있는 설정 그룹을 한 번에 적용합니다.
액션 필드
title: Command Palette 행 제목, 서피스 버튼 레이블, 메뉴 항목 제목, 신뢰 프롬프트 제목입니다. 항목에서 재정의할 수 있습니다.subtitle/description: Command Palette의 보조 텍스트입니다. description은 subtitle의 별칭으로 사용할 수 있습니다.keywords: Command Palette 검색을 위한 추가 키워드입니다.palette: 사용자 지정 액션의 기본값은 true입니다. false로 설정하면 다른 곳에서는 호출할 수 있지만 Command Palette에서는 숨깁니다.shortcut: 선택적 액션 단축키입니다. 설정 단축키와 같은 단일 입력 또는 2단계 코드 구문을 사용합니다.target: command 및 agent 액션 전용입니다. currentTerminal 또는 newTabInCurrentPane을 사용합니다.confirm: 액션을 실행하기 전에 확인합니다.newWorkspaceMenu: Set true to offer any action in the new-workspace plus-button menu, or false to hide a workspace action from it.
Command Palette 동작
Command Palette는 해석된 액션 레지스트리를 읽습니다. palette가 false가 아니면 사용자 지정 액션 ID가 행으로 추가됩니다. 기존 commands는 같은 생성 ID를 가진 액션이 이미 없을 때 자동으로 사용자 지정 행으로 추가됩니다. 내장 명령은 일반 팔레트 레이블을 유지하지만 cmux.newTerminal 같은 내장 ID를 재정의하면 그 공용 진입점 뒤의 동작이 바뀝니다.
설정 액션
설정 액션은 설정 path와 다음 중 정확히 하나를 지정합니다: set(값 쓰기), toggle: true(true/false 설정 전환), cycle(목록의 다음 값으로 이동하고 마지막 값 다음에는 처음으로 돌아감), unset: true(cmux.json에서 키를 제거해 설정 창의 값이나 기본값이 적용되게 함). toggle과 cycle은 설정 창에서 지정한 값을 포함해 cmux가 현재 사용 중인 값에서 시작합니다. settingPreset 액션은 settingPresets의 항목을 적용합니다. 각 항목은 부분 cmux.json이며 중첩 객체는 키 단위로 병합됩니다. 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 }
}
}
}같은 변경은 터미널에서도 할 수 있습니다: cmux config set terminal.scrollSpeed 1.4, cmux config toggle fileEditor.wordWrap, cmux config preset sidebar.quiet.
confirm: true를 지정하면 cmux가 저장하기 전에 확인하고 같은 변경을 하는 cmux config 명령을 보여줍니다. 경로는 모든 "."에서 나뉘므로 키 자체에 "."가 들어 있으면(예: ~/src/app.web에 대한 workspaceGroups.byCwd 항목) 이 방법으로 변경할 수 없습니다. cmux.json에서 직접 편집하세요.
플러스 버튼 사용자 지정 액션
ui.newWorkspace.action으로 플러스 버튼의 동작을 재정의합니다. ui.newWorkspace.contextMenu(또는 rightClick alias)로 정렬된 right-click 메뉴를 정의합니다. 메뉴 항목은 액션 ID, 액션 객체 또는 { "type": "separator" }일 수 있습니다. 설정하지 않으면 메뉴에 cmux.newWorkspace (⌘N), cmux.newCloudWorkspace (⌘Y), cmux.newCloudMachine (⇧⌘Y), cmux.newTerminal (⌘T), cmux.newBrowser (⇧⌘L)가 현재 단축키와 함께 표시됩니다. 클라우드 항목은 Cloud Machines가 활성화된 경우에만 표시됩니다. New Cloud Workspace는 마지막으로 선택한 Cloud 워크스페이스의 머신을 사용한 뒤 오른쪽 사이드바의 첫 번째 머신을 사용합니다. 사용 가능한 머신이 없으면 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
}
]
}
}
]
}
}
}
]
}이 예시는 일반 플러스 클릭이 worktree-agents 액션을 실행하게 합니다. commands의 워크스페이스 명령은 보이는 설정 터미널을 사용해 먼저 Git worktree를 만듭니다. Codex와 Claude는 동시에 시작해 워크스페이스별 상태 파일을 기다린 다음, 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.
전체 예시
{
"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"
}
]
}