自訂與管理命令與動作
自訂與管理

自訂命令與動作

cmux.json 是讓 cmux 學會你自己工作流程的地方:經常執行的 shell 命令、開啟時就依預設排好終端機和瀏覽器的工作區,以及可以綁定到快速鍵、分頁列按鈕和 Command Palette 的動作。可以放在專案內的 .cmux/cmux.json、適用於所有專案的 ~/.config/cmux/cmux.json,或兩處都放。

cmux 從哪裡讀取 cmux.json

項目可以來自專案檔案、使用者層級檔案,或兩者同時提供。對於專案檔案,cmux 會從目前目錄開始尋找,並逐一檢查其上方的每一層上層目錄。

  • 專案層級: ./.cmux/cmux.json (從工作目錄往上尋找而得;優先於使用者層級檔案)
  • 本機回退: ./cmux.json (仍支援現有 repo)
  • 使用者層級: ~/.config/cmux/cmux.json (由所有專案共用;補上專案檔案中未定義的內容)
本機動作與命令會覆寫具有相同 ID 或名稱的全域項目。

編輯 cmux.json 後,按 Cmd+Shift+, 或執行 cmux reload-config 來套用變更。

如果專案設定或全域設定有 schema 錯誤,cmux 會退回到下一個有效設定,並在 Command Palette 中顯示 cmux.json Schema Error 列。選取它即可開啟設定檔。

shell 命令

最簡單的項目只需一個名稱和一個命令字串。在 Command Palette 中選取它,就會把該字串輸入到目前聚焦的終端機並執行。

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

shell 命令欄位

  • name: 必填且不可空白的標籤,用於在 Command Palette 中選取
  • command: cmux 輸入到目前聚焦的終端機並執行的 shell 文字
  • description: 選用的次要文字,顯示在項目旁邊
  • keywords: 在 Command Palette 中搜尋時也應符合此項目的其他字詞
  • confirm: 設為 true 後,每次執行前都會顯示確認提示

shell 命令會在目前聚焦的終端機所在位置執行。如果命令需要確定的起始位置,可以在開頭加上 cd "$(git rev-parse --show-toplevel)" && 來移至 Git 儲存庫的最上層,或加上 cd /some/folder && 固定在某個資料夾。

開啟工作區的命令

為命令提供 workspace 物件來取代命令字串,它就會改為開啟一個新的工作區,排列成一棵由分割窗格組成的樹,內含終端機和瀏覽器。每個項目必須且只能包含兩者之一。

cmux.json
{
  "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 十六進位值或工作區顏色名稱
  • env: Environment variables inherited by every shell in the workspace
  • setup: Bootstrap command sent to the workspace's first terminal before that terminal's own command

當工作區已經開啟時

在命令上設定 restart,決定已有同名工作區時的行為:

  • "new": 建立新的 workspace(預設)
  • "confirm": 先詢問,你同意後再取代
  • "recreate": 不詢問,立即取代
  • "ignore": 切換至現有 workspace

描述配置

配置是一棵樹。每個內部節點會把自己的區域一分為二,每個葉節點都是一個容納分頁的窗格。

分割節點

分割會把自己的區域分成兩部分:

  • direction: "horizontal" 或 "vertical"
  • children: 剛好包含兩個節點的陣列,每個節點是另一個分割或一個窗格
  • split: 分隔線的位置,以區域的比例表示。預設為 0.5;超出 0.1 到 0.9 範圍的值會被限制在此範圍內

窗格節點

窗格是樹的葉節點。它的 surfaces 陣列列出開啟時包含的分頁,且至少要有一個項目。

Surface

窗格 surfaces 陣列中的每個項目都會開啟一個分頁,可以是終端機或瀏覽器:

  • type: "terminal" 或 "browser"
  • name: 取代預設標題顯示的分頁標題
  • focus: 設為 true 後,配置建立完成時鍵盤焦點會落在此分頁上
  • command: 僅限終端機:終端機開啟後立即執行的 shell 文字
  • url: 僅限瀏覽器:要載入的頁面
  • cwd: 此分頁的起始目錄,依下方規則解析
  • env: 包含額外環境變數名稱與值的物件

cwd 值的解析方式

  • ~/path: 在你的個人資料夾內解析
  • 以 / 開頭的路徑: 照原樣使用
  • ./subdir: 接在工作區目錄之後
  • . 或 未設定: 沿用工作區目錄

檔案結構

動作註冊表是 nightly 功能。使用 actions、shortcut 或 ui.surfaceTabBar.buttons 前,請安裝最新 nightly 建置。

commands 仍用來定義可重複使用的 shell 命令和 workspace 版面。Nightly 建置會加入 actions 註冊表。動作是 surface 分頁列、Command Palette 和動作層級快捷鍵共用的公開 ID。

cmux.json
{
  "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 可讓動作不顯示在 Command Palette 中,但仍能從 surface 分頁列或快捷鍵呼叫。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 時,請使用按鈕物件。解析後的按鈕標題也會作為信任提示標題。

請把任何 approval 或 permission flags 直接放進你真正想執行的命令字串中。預設動作目標是 newTabInCurrentPane,所以常見模式是在目前 pane 中開啟新的終端分頁,並在其中啟動 Codex、Claude Code 或 OpenCode。

專案本機動作會立即顯示在 surface 分頁列和 Command Palette 中。第一次執行仍會要求信任。信任是依精確的動作 fingerprint 計算,而不是依 repo 計算。專案本機圖片圖示會保持鎖定,直到該動作被信任。

自訂動作與 Command Palette

actions 項目是 cmux 執行的可重複使用行為。當同一個行為需要從 Command Palette、表面分頁列、快捷鍵或加號按鈕選單觸發時,請使用動作。將 commands 保留給可重複使用的 shell 命令與工作區配置。如果某個動作不應出現在 Command Palette,請將 palette 設為 false。

動作類型

  • "command": 在終端機中執行 shell 文字。使用 target 選擇目前終端機或目前面板中的新分頁。
  • "agent": 啟動支援的程式碼代理。現在支援 codex 與 claude,並可使用選用引數。
  • "builtin": 為內建 cmux 動作建立別名,例如 cmux.newTerminal、cmux.newBrowser、cmux.splitRight 或 cmux.splitDown。 複製類內建動作: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: 選用的動作快捷鍵,使用與設定快捷鍵相同的單鍵或兩段式按鍵序列語法。
  • 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 在儲存前會依 schema 檢查每項變更,保留你的註解與其他鍵,並立即套用變更。設定動作與預設組只能從全域 cmux.json 及其參照的套件中執行,專案設定無法宣告它們。

~/.config/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)定義有順序的右鍵選單。選單項目可以是動作 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。

cmux.json
{
  "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:

cmux.json
{
  "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.

完整範例

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"
    }
  ]
}
這個頁面對你有幫助嗎?
提交 Issue