How cmux Integrates with AppleScript and System Automation

TLDR: cmux exposes a comprehensive AppleScript API through Swift scripting objects, allowing macOS automation tools to programmatically create windows, manage tabs, split panes, and inject text into terminals.

The manaflow-ai/cmux terminal multiplexer provides deep system automation capabilities through native AppleScript integration. By implementing scriptable objects in Swift, cmux allows macOS automation tools like Shortcuts and Keyboard Maestro to control terminal sessions without launching external binaries. This integration relies on three core architectural components that bridge the gap between AppleScript commands and the application's UI state.

Architecture Overview

The cmux AppleScript integration rests on three Swift components that expose the terminal multiplexer’s internal state to macOS automation frameworks.

NSApplication Extension

In Sources/AppleScriptSupport.swift (lines 81‑115), the NSApplication extension provides global scripting entry points such as scriptWindows, terminals, and validateScript. This extension registers custom script commands and acts as the primary bridge that macOS uses when AppleScript targets the cmux application.

AppDelegate Helpers

The AppDelegate.swift file (lines 4432‑4476) maintains the list of scriptable windows, tabs, and terminals through helper methods including scriptableMainWindows(), scriptableMainWindow(windowId:), and scriptableMainWindowForTab(_:). These functions supply the concrete model objects that back the scripting layer’s object graph.

Scripting Objects

The ScriptWindow, ScriptTab, and ScriptTerminal classes — defined in Sources/AppleScriptSupport.swift (lines 120‑290) — are NSObject subclasses that map directly to cmux UI elements. These classes implement NSScriptCommand selectors such as handleActivateWindowCommand:, handleCloseCommand:, and handlePerformActionScriptCommand:, exposing properties like id, title, and terminals as AppleScript-compatible selectors.

How the Scripting Bridge Works

The integration follows a six-step architecture that translates AppleScript instructions into UI actions.

1. Enabling the Bridge

The NSApplication.isAppleScriptEnabled property always returns true (lines 84‑90), ensuring the scripting bridge is active. This flag gates every scriptable property and command in the application.

2. Discoverable Object Hierarchies

The scriptWindows property returns an array of ScriptWindow objects gathered from AppDelegate.shared?.scriptableMainWindows() (line 106). The terminals property flattens all terminals across every window and tab (lines 129‑138).

3. Object Specifiers

Each scripting class overrides objectSpecifier to provide a unique NSUniqueIDSpecifier keyed by the underlying model object’s UUID. This allows AppleScript to resolve objects via selectors like valueInScriptWindowsWithUniqueID: (lines 194‑202, 236‑244).

4. Command Handling

Custom NSScriptCommand subclasses implement the actual work:

  • handleNewWindowScriptCommand: creates a new cmux window via AppDelegate.shared?.createMainWindow() (line 182)
  • handleNewTabScriptCommand: adds a new workspace (tab) to a specified or frontmost window
  • handlePerformActionScriptCommand: forwards string actions (such as Ghostty bindings) to a terminal
  • handleSplitCommand: performs pane splits within a terminal
  • handleFocusCommand: brings a terminal to the foreground
  • ScriptInputTextCommand reads the direct parameter as text and sends it to the target terminal (lines 662‑686)

5. Error Handling

When scripts request invalid objects or missing parameters, the code populates command.scriptErrorNumber and command.scriptErrorString using localized strings from AppleScriptStrings (lines 94‑99, 165‑172).

6. Security and Focus Policy

All script commands first call NSApp.validateScript(command:) to verify AppleScript is enabled. Commands that could steal focus, such as handleActivateWindowCommand:, explicitly check focusScriptableMainWindow(..., bringToFront: true) before executing.

Practical AppleScript Examples

Creating Windows and Typing Commands

tell application "cmux"
    set newWin to make new script window
    set termList to terminals of newWin
    set firstTerm to item 1 of termList
    input text "ls -la" to firstTerm
end tell

This script invokes NSApplication.handleNewWindowScriptCommand: (line 182), retrieves terminals via NSApplication.terminals (lines 129‑138), and executes ScriptInputTextCommand (lines 662‑686) to inject text.

Splitting Terminal Panes

tell application "cmux"
    set frontTerm to first terminal of front window
    split frontTerm direction "GSdn"
end tell

The split command resolves the terminal via valueInTerminalsWithUniqueID: (line 206), then maps "GSdn" to SplitDirection.down using ScriptSplitDirection (lines 90‑104) before executing ScriptTerminal.handleSplitCommand: (lines 620‑665).

Focusing Tabs by UUID

set targetID to "A1B2C3D4-E5F6-7890-1234-56789ABCDEF0"
tell application "cmux"
    set targetTab to value in tabs with unique ID targetID
    select targetTab
end tell

This resolves the tab via ScriptWindow.valueInTabs(uniqueID:) (lines 296‑304), then invokes ScriptTab.handleSelectTabCommand: (lines 446‑459) to activate it.

Closing Windows

tell application "cmux"
    close front window
end tell

The close command triggers ScriptWindow.handleCloseWindowCommand: (lines 334‑352) to dismiss the frontmost window.

Key Implementation Files

File Purpose Key Lines
Sources/AppleScriptSupport.swift Scripting objects, command handlers, error strings, and NSApplication extension 81‑115, 120‑290, 662‑686
Sources/AppDelegate.swift Helper methods mapping UI state to scriptable objects 4432‑4476
Sources/TerminalController.swift Internal usage of scriptableMainWindows() for command broadcasting ~5154
Resources/Info.plist Declares AppleScript terminology and class names (CmuxScriptWindow, CmuxScriptTab, CmuxScriptTerminal) for runtime resolution N/A

Summary

  • cmux implements three core Swift components — an NSApplication extension, AppDelegate helpers, and scripting objects — to expose its UI to AppleScript.
  • Object specifiers use UUID-based NSUniqueIDSpecifier instances to ensure reliable script-to-object resolution.
  • Command handlers translate high-level AppleScript commands like make new script window or split into concrete cmux actions.
  • Security checks via validateScript: and focus policies prevent unauthorized automation actions.
  • The integration supports Shortcuts, Keyboard Maestro, and any macOS tool that drives scriptable applications.

Frequently Asked Questions

How do I enable AppleScript support for cmux?

AppleScript support is always enabled in cmux. The NSApplication.isAppleScriptEnabled property returns true by default (lines 84‑90 in AppleScriptSupport.swift), meaning the application immediately responds to AppleScript commands without requiring additional configuration or preferences changes.

Which cmux objects can I control via AppleScript?

You can control three primary object types: ScriptWindow (top-level windows), ScriptTab (workspace tabs), and ScriptTerminal (individual terminal panes). Each exposes properties like id, title, and collections of child objects (e.g., terminals of newWin), allowing you to navigate the entire window hierarchy programmatically.

How does cmux handle AppleScript errors?

When a script provides invalid parameters or requests non-existent objects, cmux populates command.scriptErrorNumber and command.scriptErrorString with localized error descriptions from the AppleScriptStrings table (lines 94‑99 and 165‑172). These error messages surface directly in the macOS Script Editor or calling automation tool, providing clear feedback about what went wrong.

Can I use the macOS Shortcuts app with cmux?

Yes. Because cmux exposes a standard AppleScript dictionary, you can use the Run AppleScript action in Shortcuts, or any automation tool like Keyboard Maestro, Hammerspoon, or Alfred, to drive cmux. The validateScript: security check ensures that only authorized scripts can execute focus-stealing commands, making the integration safe for automated workflows.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →