사용자 정의 명령어

프로젝트 루트 또는 ~/.config/cmux/에 cmux.json 파일을 추가하여 사용자 정의 명령어와 워크스페이스 레이아웃을 정의합니다. 명령어는 명령어 팔레트에 표시됩니다.

파일 위치

cmux는 두 곳에서 설정을 찾습니다:

  • 프로젝트별: ./.cmux/cmux.json - 프로젝트 디렉터리에 위치하며 우선순위를 가집니다
  • fallback 로컬: ./cmux.json - 기존 repo를 위해 계속 지원됩니다
  • 전역: ~/.config/cmux/cmux.json - 모든 프로젝트에 적용되며 로컬에서 정의되지 않은 명령어를 보완합니다
로컬 액션과 명령은 같은 ID 또는 이름을 가진 전역 항목보다 우선합니다.
액션 레지스트리는 nightly 기능입니다. actions, shortcut, ui.surfaceTabBar.buttons를 사용하기 전에 최신 nightly 빌드를 설치하세요.
프로젝트 로컬 액션은 surface 탭 바와 Command Palette에 즉시 표시됩니다. 첫 실행 시에는 여전히 신뢰 확인이 표시됩니다. 신뢰는 저장소 단위가 아니라 정확히 일치하는 액션 fingerprint 단위입니다. 프로젝트 로컬 이미지 아이콘은 해당 액션을 신뢰할 때까지 잠겨 있습니다.
프로젝트 또는 전역 설정에 스키마 오류가 있으면 cmux는 다음 유효한 설정으로 fallback하고 Command Palette에 cmux.json Schema Error 행을 표시합니다. 선택하면 설정 파일을 엽니다.

cmux.json을 편집한 뒤 Cmd+Shift+, 를 누르거나 cmux reload-config를 실행해 변경 사항을 적용하세요.

스키마

commands는 계속 재사용 가능한 shell 명령과 workspace 레이아웃을 정의합니다. Nightly 빌드는 actions 레지스트리를 추가합니다. 액션은 surface 탭 바, Command Palette, 액션 단위 shortcut이 공유하는 공개 ID입니다.

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

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로 설정합니다.

액션 유형

  • "builtin": cmux.newTerminal, cmux.newBrowser, cmux.splitRight, cmux.splitDown 같은 내장 cmux 액션의 별칭입니다.
  • "command": 터미널에서 셸 텍스트를 실행합니다. target으로 현재 터미널 또는 현재 패널의 새 탭을 선택합니다.
  • "agent": 지원되는 코딩 에이전트를 시작합니다. 현재 codex와 claude를 지원하며 선택적 인수를 줄 수 있습니다.
  • "workspaceCommand": commands의 이름 있는 워크스페이스 정의를 실행합니다. 여러 패널 레이아웃, 사용자 지정 작업 디렉터리, 시작 명령에 사용합니다.

액션 필드

  • 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: 액션을 실행하기 전에 확인합니다.

Command Palette 동작

Command Palette는 해석된 액션 레지스트리를 읽습니다. palette가 false가 아니면 사용자 지정 액션 ID가 행으로 추가됩니다. 기존 commands는 같은 생성 ID를 가진 액션이 이미 없을 때 자동으로 사용자 지정 행으로 추가됩니다. 내장 명령은 일반 팔레트 레이블을 유지하지만 cmux.newTerminal 같은 내장 ID를 재정의하면 그 공용 진입점 뒤의 동작이 바뀝니다.

플러스 버튼 사용자 지정 액션

ui.newWorkspace.action으로 플러스 버튼의 동작을 재정의합니다. ui.newWorkspace.contextMenu(또는 rightClick alias)로 정렬된 right-click 메뉴를 정의합니다. 메뉴 항목은 액션 ID, 액션 객체 또는 { "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"
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }
    }
  ]
}

이 예시는 일반 플러스 클릭이 worktree-agents 액션을 실행하게 합니다. commands의 워크스페이스 명령은 보이는 설정 터미널을 사용해 먼저 Git worktree를 만듭니다. Codex와 Claude는 동시에 시작해 워크스페이스별 상태 파일을 기다린 다음, exec 전에 생성된 디렉터리로 이동합니다.

단순 명령어

단순 명령어는 현재 포커스된 터미널에서 셸 명령어를 실행합니다:

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

필드

  • name: 명령어 팔레트에 표시됩니다 (필수)
  • description: 선택적 설명
  • keywords: 명령어 팔레트용 추가 검색어
  • command: 포커스된 터미널에서 실행할 셸 명령어
  • confirm: 실행 전 확인 대화상자 표시

단순 명령어는 포커스된 터미널의 현재 작업 디렉토리에서 실행됩니다. 프로젝트 상대 경로에 의존하는 명령어의 경우 앞에 cd "$(git rev-parse --show-toplevel)" && 를 붙여 저장소 루트에서 실행하거나 cd /your/path && 로 특정 디렉토리를 지정할 수 있습니다.

워크스페이스 명령어

워크스페이스 명령어는 분할, 터미널, 브라우저 패널의 사용자 정의 레이아웃으로 새 워크스페이스를 만듭니다:

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

워크스페이스 필드

  • name: 워크스페이스 탭 이름 (기본값은 명령어 이름)
  • cwd: 워크스페이스의 작업 디렉터리
  • color: 워크스페이스 탭 색상
  • layout: 분할과 패널을 정의하는 레이아웃 트리

재시작 동작

동일한 이름의 워크스페이스가 이미 존재할 때 발생하는 동작을 제어합니다:

  • "new": 새 워크스페이스 만들기 (기본값)
  • "ignore": 기존 워크스페이스로 전환
  • "recreate": 묻지 않고 닫고 다시 만들기
  • "confirm": 다시 만들기 전에 사용자에게 확인

레이아웃 트리

레이아웃 트리는 재귀적인 분할 노드를 사용하여 패널 배치를 정의합니다:

분할 노드

공간을 두 개의 자식으로 나눕니다:

  • direction: "horizontal" 또는 "vertical"
  • split: 0.1에서 0.9 사이의 분할기 위치 (기본값 0.5)
  • children: 정확히 두 개의 자식 노드 (분할 또는 패널)

패널 노드

하나 이상의 서피스(패널 내 탭)를 포함하는 리프 노드.

서피스 정의

패널 내 각 서피스는 터미널 또는 브라우저가 될 수 있습니다:

  • type: "terminal" 또는 "browser"
  • name: 사용자 정의 탭 제목
  • command: 생성 시 자동 실행할 셸 명령어 (터미널 전용)
  • cwd: 이 서피스의 작업 디렉터리
  • env: 키-값 쌍으로 된 환경 변수
  • url: 열 URL (브라우저 전용)
  • focus: 생성 후 이 서피스에 포커스

작업 디렉터리 해석

  • . 또는 생략됨: 워크스페이스 작업 디렉터리
  • ./subdir: 워크스페이스 작업 디렉터리 기준 상대 경로
  • ~/path: 홈 디렉터리로 확장
  • 절대 경로: 있는 그대로 사용

전체 예시

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