คำสั่งที่กำหนดเอง

กำหนดคำสั่งที่กำหนดเองและเลย์เอาต์ workspace โดยเพิ่มไฟล์ cmux.json ลงในรากโปรเจกต์หรือ ~/.config/cmux/ คำสั่งจะปรากฏในแผงคำสั่ง

ตำแหน่งไฟล์

cmux ค้นหาการตั้งค่าจากสองที่:

  • ต่อโปรเจกต์: ./.cmux/cmux.json - อยู่ในไดเรกทอรีโปรเจกต์ของคุณ มีความสำคัญสูงกว่า
  • local fallback: ./cmux.json - ยังรองรับสำหรับ repo ที่มีอยู่
  • การตั้งค่าส่วนกลาง: ~/.config/cmux/cmux.json - ใช้กับทุกโปรเจกต์ เติมคำสั่งที่ยังไม่ได้กำหนดในท้องถิ่น
Actions และ commands แบบ local จะแทนที่ entries แบบ global ที่มี ID หรือชื่อเดียวกัน
รีจิสทรีของแอ็กชันเป็นฟีเจอร์ nightly โปรดติดตั้ง nightly build ล่าสุดก่อนใช้ actions, shortcut หรือ ui.surfaceTabBar.buttons
แอ็กชันเฉพาะโปรเจกต์จะแสดงในแถบแท็บ surface และ Command Palette ทันที การรันครั้งแรกยังคงถามเรื่องความเชื่อถือ ความเชื่อถือผูกกับ fingerprint ของแอ็กชันที่ตรงกันแบบเป๊ะ ไม่ได้ผูกกับ repo ไอคอนรูปภาพเฉพาะโปรเจกต์จะยังถูกล็อกจนกว่าแอ็กชันนั้นจะได้รับความเชื่อถือ
ถ้า config ของโปรเจกต์หรือ global มี schema error, cmux จะ fallback ไปยัง config ที่ถูกต้องถัดไปและแสดงแถว cmux.json Schema Error ใน Command Palette เลือกแถวนั้นเพื่อเปิดไฟล์ config

แก้ไข cmux.json แล้วกด Cmd+Shift+, หรือรัน cmux reload-config เพื่อใช้การเปลี่ยนแปลง

สคีมา

commands ยังคงใช้กำหนด shell commands และ workspace layouts ที่นำกลับมาใช้ซ้ำได้ Nightly builds เพิ่มรีจิสทรี actions แอ็กชันคือ public IDs ที่ใช้ร่วมกันระหว่างแถบแท็บ surface, Command Palette และ shortcuts ระดับแอ็กชัน

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 แมป stable IDs เข้ากับ behavior ที่รันได้ ใช้ built-in IDs cmux.newTerminal, cmux.newBrowser, cmux.splitRight และ cmux.splitDown เพื่อ override ค่าเริ่มต้น ใช้ IDs ของคุณเองสำหรับเครื่องมือเฉพาะโปรเจกต์

palette มีค่าเริ่มต้นเป็น true ตั้งเป็น false เพื่อซ่อนแอ็กชันจาก Command Palette แต่ยังให้เรียกจากแถบแท็บ surface หรือ shortcut ได้ shortcut ใช้ syntax เดียวกับ shortcuts ใน settings เช่น cmd+shift+c หรือ ["cmd+k", "cmd+c"]

ui.surfaceTabBar.buttons จะแทนที่รายการปุ่มเริ่มต้นเมื่อมีค่าอยู่ ไม่ใส่ built-in ID เพื่อซ่อนรายการนั้น ไอคอนใช้รูปแบบ object เสมอ: { "type": "symbol", "name": "play.circle" }, { "type": "emoji", "value": "🧪", "scale": 0.9 } หรือ { "type": "image", "path": "./icons/codex.svg" } path ของรูปภาพอ้างอิงจากไฟล์ config ค่า emoji scale เป็น optional และมีค่าเริ่มต้น 1 รองรับ SVG, PDF, PNG, JPEG, GIF, TIFF, BMP, HEIC, HEIF, WebP, AVIF, ICO และ ICNS

รายการปุ่มแต่ละรายการอาจเป็น string ของ action ID หรือ button object ใช้ button object เมื่อคุณต้องการแอ็กชันเดียวกันแต่มี surface label, icon หรือ tooltip ต่างกัน ชื่อปุ่มที่ resolve แล้วจะถูกใช้เป็นชื่อของ trust prompt ด้วย

ใส่ approval หรือ permission flags ไว้ใน command string ที่คุณต้องการรันจริงโดยตรง target เริ่มต้นของแอ็กชันคือ newTabInCurrentPane ดังนั้น pattern ทั่วไปคือเปิด terminal tab ใหม่ใน pane ปัจจุบันแล้วเริ่ม Codex, Claude Code หรือ OpenCode ที่นั่น

Custom actions และ Command Palette

actions คือรายการที่ cmux ใช้รันซ้ำได้ ใช้ actions เมื่อ behavior เดียวกันควรเรียกได้จาก Command Palette, surface tab bar, shortcuts หรือเมนูของปุ่มบวก เก็บ commands ไว้สำหรับ shell commands และ workspace layouts ที่ใช้ซ้ำได้ ตั้ง palette เป็น false เมื่อไม่ต้องการให้ action แสดงใน Command Palette

ประเภท action

  • "builtin": สร้าง alias ให้ built-in cmux action เช่น cmux.newTerminal, cmux.newBrowser, cmux.splitRight หรือ cmux.splitDown
  • "command": รันข้อความ shell ใน terminal ใช้ target เพื่อเลือก terminal ปัจจุบันหรือ tab ใหม่ใน pane ปัจจุบัน
  • "agent": เริ่ม coding agent ที่รองรับ ปัจจุบันรองรับ codex และ claude พร้อม args แบบเลือกได้
  • "workspaceCommand": รัน workspace definition ที่มีชื่อจาก commands ใช้สำหรับเลย์เอาต์หลาย pane, working directory แบบกำหนดเอง และ startup commands

ฟิลด์ของ action

  • title: ชื่อแถวใน Command Palette, label ของปุ่ม, ชื่อ item ในเมนู และชื่อ trust prompt เว้นแต่ entry จะ override ค่าไว้
  • subtitle / description: ข้อความรองใน Command Palette โดย description ใช้เป็น alias ของ subtitle ได้
  • keywords: คำค้นหาเพิ่มเติมสำหรับ Command Palette
  • palette: ค่าเริ่มต้นคือ true สำหรับ custom actions ตั้งเป็น false เพื่อซ่อน action จาก Command Palette แต่ยังเรียกจากที่อื่นได้
  • shortcut: shortcut ของ action แบบเลือกได้ ใช้ syntax แบบ single-stroke หรือ two-stroke chord เหมือน shortcuts ใน settings
  • target: สำหรับ command และ agent actions เท่านั้น ใช้ currentTerminal หรือ newTabInCurrentPane
  • confirm: ถามยืนยันก่อนรัน action

พฤติกรรมของ Command Palette

Command Palette อ่าน action registry ที่ resolve แล้ว Custom action IDs จะถูกเพิ่มเป็นแถวเมื่อ palette ไม่ใช่ false ส่วน commands แบบเดิมจะถูกเพิ่มเป็นแถว custom โดยอัตโนมัติ เว้นแต่มี action ที่ใช้ generated ID เดียวกันอยู่แล้ว Built-in commands ยังใช้ labels ปกติ แต่การ override built-in ID เช่น cmux.newTerminal จะเปลี่ยน behavior หลัง entrypoint ร่วมนั้น

แอ็กชันกำหนดเองของปุ่มบวก

ใช้ ui.newWorkspace.action เพื่อ override สิ่งที่ปุ่มบวกทำ ใช้ ui.newWorkspace.contextMenu (หรือ alias rightClick) เพื่อกำหนดเมนูคลิกขวาที่เรียงลำดับแล้ว รายการเมนูอาจเป็น action IDs, action objects หรือ { "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"
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }
    }
  ]
}

ตัวอย่างนี้ทำให้การคลิกปุ่มบวกตามปกติรัน action worktree-agents คำสั่ง workspace จาก commands ใช้ terminal setup ที่มองเห็นได้เพื่อสร้าง Git worktree ก่อน Codex และ Claude เริ่มพร้อมกัน รอไฟล์ state เฉพาะ workspace แล้ว cd เข้า directory ที่สร้างขึ้นก่อน exec

คำสั่งแบบง่าย

คำสั่งแบบง่ายรันคำสั่ง shell ในเทอร์มินัลที่กำลังโฟกัสอยู่:

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

ฟิลด์

  • name: แสดงในแผงคำสั่ง (จำเป็น)
  • description: คำอธิบายเพิ่มเติม (ไม่บังคับ)
  • keywords: คำค้นหาเพิ่มเติมสำหรับแผงคำสั่ง
  • command: คำสั่ง shell ที่จะรันในเทอร์มินัลที่โฟกัส
  • confirm: แสดงกล่องโต้ตอบยืนยันก่อนรัน

คำสั่งแบบง่ายจะรันในไดเรกทอรีการทำงานปัจจุบันของเทอร์มินัลที่โฟกัสอยู่ หากคำสั่งของคุณใช้พาธสัมพัทธ์กับโปรเจกต์ ให้เพิ่มนำหน้าด้วย cd "$(git rev-parse --show-toplevel)" && เพื่อรันจากรูทของ repo หรือ cd /your/path && สำหรับไดเรกทอรีที่ต้องการ

คำสั่ง workspace

คำสั่ง workspace สร้าง workspace ใหม่ที่มีเลย์เอาต์กำหนดเองของการแบ่ง เทอร์มินัล และแผงเบราว์เซอร์:

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

ฟิลด์ workspace

  • name: ชื่อแท็บ workspace (ค่าเริ่มต้นคือชื่อคำสั่ง)
  • cwd: ไดเรกทอรีทำงานสำหรับ workspace
  • color: สีแท็บ workspace
  • layout: ต้นไม้เลย์เอาต์ที่กำหนดการแบ่งและแผง

พฤติกรรมการรีสตาร์ท

ควบคุมสิ่งที่เกิดขึ้นเมื่อ workspace ที่มีชื่อเดียวกันมีอยู่แล้ว:

  • "new": สร้าง workspace ใหม่ (ค่าเริ่มต้น)
  • "ignore": สลับไปยัง workspace ที่มีอยู่
  • "recreate": ปิดและสร้างใหม่โดยไม่ถาม
  • "confirm": ถามผู้ใช้ก่อนสร้างใหม่

ต้นไม้เลย์เอาต์

ต้นไม้เลย์เอาต์กำหนดวิธีจัดเรียงแผงโดยใช้โหนดการแบ่งแบบวนซ้ำ:

โหนดการแบ่ง

แบ่งพื้นที่ออกเป็นสองส่วน:

  • direction: "horizontal" หรือ "vertical"
  • split: ตำแหน่งตัวแบ่งตั้งแต่ 0.1 ถึง 0.9 (ค่าเริ่มต้น 0.5)
  • children: โหนดลูกสองโหนดพอดี (การแบ่งหรือแผง)

โหนดแผง

โหนดใบที่มี surface หนึ่งอันหรือมากกว่า (แท็บภายในแผง)

นิยาม surface

แต่ละ surface ในแผงสามารถเป็นเทอร์มินัลหรือเบราว์เซอร์:

  • type: "terminal" หรือ "browser"
  • name: ชื่อแท็บที่กำหนดเอง
  • command: คำสั่ง shell ที่รันอัตโนมัติเมื่อสร้าง (เฉพาะเทอร์มินัล)
  • cwd: ไดเรกทอรีทำงานสำหรับ surface นี้
  • env: ตัวแปรสภาพแวดล้อมในรูปแบบคู่คีย์-ค่า
  • url: URL ที่จะเปิด (เฉพาะเบราว์เซอร์)
  • focus: โฟกัสที่ surface นี้หลังสร้าง

การแก้ไขไดเรกทอรีทำงาน

  • . หรือ ละไว้: ไดเรกทอรีทำงานของ workspace
  • ./subdir: สัมพัทธ์กับไดเรกทอรีทำงานของ workspace
  • ~/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
    }
  ]
}