Skip to main content
Integrate any AI coding agent, CI/CD system, or custom workflow with cmux using the CLI and socket API. This guide shows you how to build custom integrations from scratch.

Architecture

cmux exposes two interfaces for external integrations:
  1. CLI: Shell commands like cmux notify, cmux new-workspace, cmux send
  2. Socket API: JSON-RPC protocol over a Unix domain socket at /tmp/cmux.sock
Most integrations use the CLI, which is simpler and more portable. The socket API is useful for high-performance scenarios or when you need fine-grained control.

Using the CLI

The cmux CLI binary is bundled with the app at /Applications/cmux.app/Contents/MacOS/cmux.

Environment variables

cmux sets these variables in every terminal session:
  • CMUX_WORKSPACE_ID: Current workspace ID (e.g., workspace:1)
  • CMUX_SURFACE_ID: Current surface/tab ID (e.g., surface:2)
  • CMUX_SOCKET_PATH: Path to the control socket (default: /tmp/cmux.sock)
Your integration scripts can read these to target the correct workspace.

Common CLI patterns

Example: Simple agent hook

Here’s a minimal agent integration that sends a notification when a task completes:
~/bin/agent-notify
Use it in your agent workflow:

Using the socket API

The socket API uses a JSON-RPC-like protocol. Each request is a JSON object sent over a Unix socket, followed by a newline.

Connection

1

Connect to the socket

Open a connection to /tmp/cmux.sock (or the path in $CMUX_SOCKET_PATH).
The socket is owned by your user and only accepts connections from the same user for security.
2

Send a request

Send a JSON object with id, method, and params fields, terminated by a newline:
3

Read the response

The server sends a JSON response:
Or an error:

Request format

  • id: Any unique string (used to match requests to responses)
  • method: API method name (see below)
  • params: Method-specific parameters (optional)

Response format

Success:
Error:

Available methods

  • workspace.list - List all workspaces
  • workspace.create - Create a new workspace (params: cwd)
  • workspace.select - Select a workspace (params: workspace_id)
  • workspace.close - Close a workspace (params: workspace_id)
  • workspace.rename - Rename a workspace (params: workspace_id, title)
  • workspace.current - Get current workspace ID
  • surface.list - List surfaces in a workspace (params: workspace_id)
  • surface.create - Create a new surface/tab (params: workspace_id, optional type, url)
  • surface.focus - Focus a surface (params: workspace_id, surface_id)
  • surface.close - Close a surface (params: workspace_id, surface_id)
  • surface.send_text - Send text to a surface (params: workspace_id, surface_id, text)
  • surface.send_key - Send key to a surface (params: workspace_id, surface_id, key)
  • surface.read_text - Read terminal text (params: workspace_id, surface_id, optional lines, scrollback)
  • pane.list - List panes in a workspace (params: workspace_id)
  • pane.create - Create a new pane (params: workspace_id, direction)
  • pane.focus - Focus a pane (params: workspace_id, pane_id)
  • window.list - List all windows
  • window.current - Get current window ID
  • window.focus - Focus a window (params: window_id)
  • system.capabilities - Get API capabilities
  • system.identify - Get current context (workspace, surface, pane)

Example: Python integration

Here’s a Python class for interacting with the cmux socket:
~/lib/cmux_client.py
Usage:

Building an agent integration

Here’s a complete example of integrating a custom AI agent with cmux:
1

Create a hook script

~/.myagent/cmux-hook.sh
Make it executable:
2

Call hooks from your agent

In your agent code:
3

Test the integration

Run your agent from inside a cmux workspace:
You should see:
  • Status indicator updates on the workspace tab
  • Notifications when the agent needs input
  • Blue notification rings on the sidebar

Best practices

Use environment variables

Always read CMUX_WORKSPACE_ID and CMUX_SURFACE_ID to target the correct workspace instead of hardcoding IDs.

Handle missing socket gracefully

Check if cmux is running before sending commands. Fail gracefully if the socket doesn’t exist.

Sanitize notification content

Strip newlines and control characters from notification text to avoid breaking the protocol.

Use refs instead of UUIDs

Workspace/surface refs like workspace:1 are more stable and human-readable than UUIDs.

Security considerations

  • The socket at /tmp/cmux.sock is owned by your user and only accepts connections from the same UID
  • cmux verifies socket ownership before connecting to prevent fake-socket attacks
  • No authentication is required for local socket connections (assumes filesystem permissions provide sufficient security)
  • If you need stricter access control, you can enable password-protected socket access (see --password flag in the CLI docs)

Troubleshooting

Ensure cmux is running:
If the app isn’t running, launch it and wait for the socket to appear.
Check socket ownership:
The socket must be owned by your user. If it’s owned by another user, quit cmux and restart it.
Ensure your JSON is valid and terminated with a newline:
Use a JSON linter if you’re constructing requests manually.
Add cmux to your PATH:
Add this to your shell config (~/.zshrc or ~/.bashrc) to persist it.

Further reading