cmux v1 vs v2 Socket API Protocols: Key Differences and Migration Guide
cmux v1 uses simple plain-text line commands while v2 uses JSON-RPC structured messages, with both protocols sharing the same Unix-domain socket but differing in authentication flows, response formats, and UI focus policy enforcement.
The manaflow-ai/cmux repository provides a Unix-domain socket automation API that maintains backward compatibility through dual protocol support. Understanding the architectural differences between cmux v1 vs v2 socket API protocols is critical for migrating existing scripts or building new integrations, as the versions handle authentication, command parsing, and focus-stealing protections through entirely different mechanisms.
Wire Format and Message Parsing
The protocols diverge immediately at the parsing layer within TerminalController.handleCommandLine.
v1 (Legacy) accepts simple UTF-8 lines terminated by \n. The raw line is split on whitespace and matched against a hard-coded command switch. In Sources/TerminalController.swift, the v1 parser operates at lines 1648–1657, treating inputs like list_windows as bare command strings without structured parameters.
v2 (JSON-RPC) requires one-line JSON objects terminated with \n. The payload must follow a JSON-RPC-like shape: { "id": 1, "method": "window.focus", "params": { "window": "uuid" } }. The JSON decoding block starts at line 2007, extracting the method field to route through the same underlying command switch.
Authentication Mechanisms
Both protocols support password authentication but use incompatible wire formats.
v1 Authentication sends a plain-text token: auth <password>. The server handles this via passwordLoginV1ResponseIfNeeded (lines 1279–1280), validating the password against the raw command string.
v2 Authentication uses a structured JSON-RPC method call: { "method": "auth.login", "params": { "password": "secret" } }. This flows through passwordLoginV2ResponseIfNeeded (lines 2028–2029), parsing the credentials from the JSON payload rather than whitespace-split strings.
Response Models and Error Handling
The response structures reflect the protocols' design philosophies.
v1 Responses return plain-text strings prefixed with OK: or ERROR:, requiring clients to parse status from string prefixes.
v2 Responses return structured JSON objects: { "ok": true, "result": … } for success or { "ok": false, "error": { "code": "…", "message": "…" } } for failures. The implementation uses helper functions v2Ok and v2Error throughout the v2 branch to ensure consistent response formatting.
Focus Policy and Command Classification
v2 introduces granular UI focus protection that v1 lacks.
In TerminalController.swift, commands are classified into two static sets: focusIntentV1Commands (lines 1818–1827) and focusIntentV2Methods (lines 1829–1844). The withSocketCommandPolicy function (lines 299–313) records whether a specific method is permitted to mutate UI focus, preventing legacy "focus-steal" bugs where automation commands unintentionally shift user attention.
All v1 commands run with the same focus mutation rules, while v2 methods respect the socketCommandAllowsInAppFocusMutations lookup, allowing fine-grained control over which automation actions can disrupt the user's current context.
Protocol Detection and Version Routing
Both protocols coexist on the same socket connection. The server distinguishes them by inspecting the first character of the payload:
- If the line begins with
{, it routes to the v2 JSON parser (lines 2020–2030) - Otherwise, it treats the payload as v1 plain text (lines 1648–1657)
This detection happens inside handleCommandLine, allowing legacy clients to operate simultaneously with modern JSON-RPC integrations. Version gating through SocketControlSettings applies to both protocols, though the v2 parser runs in all modes except when password authentication blocks unauthenticated access (line 1988–1989).
Practical Implementation Examples
Connecting via v1 (Shell)
Use netcat to send bare commands to the Unix socket:
printf 'list_windows\n' | nc -U /tmp/cmux-debug.sock
# Response: OK: [{ "id":"…", "title":"…" }, …]
Connecting via v2 (Python)
Send structured JSON-RPC requests with explicit method names and parameters:
import socket, json
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect("/tmp/cmux-debug.sock")
request = {
"id": 1,
"method": "window.focus",
"params": {"window": "e2a2f4b5-…"}
}
sock.sendall((json.dumps(request) + "\n").encode())
response = sock.recv(4096).decode().splitlines()[0]
print(json.loads(response))
# Output: {"ok": true, "result": {"focused": true}}
v2 Authentication Flow
Authenticate using the structured login method before issuing protected commands:
import socket, json
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect("/tmp/cmux-debug.sock")
login = {
"id": 2,
"method": "auth.login",
"params": {"password": "my-secret"}
}
sock.sendall((json.dumps(login) + "\n").encode())
print(json.loads(sock.recv(4096).decode()))
# Output: {"ok": true, "result": {"authenticated": true}}
Summary
- Message Format: v1 uses plain-text lines; v2 uses JSON-RPC objects with
methodandparamsfields. - Authentication: v1 sends
auth <password>as bare text; v2 usesauth.loginwith JSON credentials. - Responses: v1 returns
OK:/ERROR:strings; v2 returns structured JSON with booleanokfields. - Focus Safety: v2 implements
focusIntentV2Methodsclassification throughwithSocketCommandPolicyto prevent focus stealing; v1 commands follow legacy mutation rules. - Compatibility: Both protocols run on the same socket, distinguished by the opening character
{for v2.
Frequently Asked Questions
Can v1 and v2 clients connect to the same cmux instance simultaneously?
Yes. The TerminalController accepts both protocols on the same Unix-domain socket. The server inspects the first character of each line—if it is {, the message routes to the v2 JSON parser; otherwise, it processes as v1 plain text. This allows gradual migration without breaking existing integrations.
How does focus policy differ between v1 and v2 commands?
v1 commands execute with legacy focus mutation rules defined in focusIntentV1Commands. v2 methods respect granular policies defined in focusIntentV2Methods and enforced by withSocketCommandPolicy, which prevents automation scripts from stealing UI focus unless explicitly permitted. This fixes "focus-steal" bugs present in the legacy protocol.
Is v1 deprecated or will it be removed from future cmux releases?
While v2 is the recommended protocol for new development, v1 remains supported for backward compatibility. The source code maintains both passwordLoginV1ResponseIfNeeded and passwordLoginV2ResponseIfNeeded handlers, and the SocketControlSettings gating applies to both versions equally. However, new features and focus protections are implemented primarily in the v2 layer.
Which protocol should I use for new automation scripts?
Use v2 for all new implementations. The JSON-RPC format provides structured error handling, extensible parameters through the params object, and proper focus policy enforcement. The v2Ok and v2Error response helpers ensure consistent error codes that are easier to parse programmatically than v1's plain-text prefixes.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →