Understanding the Structure of cmux v2 JSON Socket Protocol Requests and Responses
The cmux v2 JSON socket protocol uses a lightweight JSON-RPC 2.0 style API over Unix-domain sockets, requiring each request and response to be a single UTF-8 JSON line terminated by \n with specific envelope fields for routing and error handling.
The cmux v2 JSON socket protocol defines the wire format that external clients use to communicate with the terminal multiplexer daemon in the manaflow-ai/cmux repository. This protocol enables programmatic control of windows, workspaces, and terminal surfaces through a line-delimited JSON interface that follows JSON-RPC 2.0 conventions while using a simplified response envelope.
Request Envelope Structure
Every v2 protocol request must be a single line of UTF-8 JSON ending with a newline character. According to the source code in Sources/TerminalController.swift, the processV2Command method (lines 1885–2009) validates and dispatches incoming requests.
A valid request contains four required fields:
jsonrpc: Must be the string"2.0"to identify the protocol versionid: Any JSON value (typically a number or string) used to correlate responsesmethod: A dot-separated string identifying the operation (e.g.,window.list,surface.send_text)params: An optional JSON object containing method arguments; may be an empty object
{
"jsonrpc": "2.0",
"id": 1,
"method": "window.list",
"params": {}
}
The server validates that jsonrpc equals "2.0" and checks the method against an internal allow-list called focusIntentV2Methods before dispatching to the appropriate handler.
Response Format Specifications
Responses mirror the request's id field and use a boolean ok field to indicate success or failure. The v2Ok (lines 2923–2929) and v2Error (lines 2931–2939) helper functions in TerminalController.swift construct these envelopes.
Success Responses
A successful response returns ok: true with the result payload:
{
"id": 1,
"ok": true,
"result": {
"windows": [...]
}
}
Error Responses
Failed operations return ok: false with a structured error object:
{
"id": 1,
"ok": false,
"error": {
"code": "method_not_found",
"message": "Method does not exist",
"data": null
}
}
The error object always contains code (a short string identifier) and message (human-readable description), with an optional data field for additional context.
Encoding Rules
The v2Encode function (lines 2957–2966) handles serialization, ensuring that any internal newline characters within JSON values are escaped as \\n to maintain the single-line-per-message protocol invariant.
Method Taxonomy
The v2 protocol organizes commands into functional domains. The complete method dispatch table lives inside the switch method block within processV2Command.
System methods: system.ping, system.capabilities, system.identify, system.tree
Authentication: auth.login returns an object with authenticated and required boolean fields
Window management: window.list, window.current, window.focus, window.create, window.close
Workspace operations: workspace.list, workspace.create, workspace.select, workspace.current
Surface (pane) control: surface.list, surface.current, surface.focus, surface.send_text, surface.send_key, surface.refresh, surface.health
Debug utilities: debug.terminals
Protocol Implementation in Swift
The built-in ControlSocketClient class demonstrates the proper wire format. This example mirrors the implementation in TerminalControllerTests.sendV2Request:
import Foundation
let socketPath = "/tmp/cmux-debug.sock"
let client = ControlSocketClient(path: socketPath, responseTimeout: 2.0)
let request: [String: Any] = [
"jsonrpc": "2.0",
"id": 1,
"method": "window.list",
"params": [:]
]
let json = try JSONSerialization.data(withJSONObject: request)
let line = String(data: json, encoding: .utf8)! + "\n"
if let rawResponse = client.sendLine(line) {
let data = rawResponse.data(using: .utf8)!
let obj = try JSONSerialization.jsonObject(with: data) as! [String: Any]
if let ok = obj["ok"] as? Bool, ok {
print("Success →", obj["result"]!)
} else {
print("Error →", (obj["error"] as? [String: Any])?["message"] ?? "unknown")
}
}
Python Client Example
For raw socket interaction without Swift dependencies:
import socket, json
socket_path = "/tmp/cmux-debug.sock"
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(socket_path)
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "system.ping",
"params": {}
}
line = json.dumps(payload) + "\n"
sock.sendall(line.encode("utf-8"))
response = b""
while not response.endswith(b"\n"):
chunk = sock.recv(4096)
if not chunk:
break
response += chunk
resp_obj = json.loads(response.decode())
print(resp_obj) # → {'id': 1, 'ok': True, 'result': {'pong': True}}
sock.close()
Bash One-Liner with Socat
For quick debugging or shell scripts:
payload='{"jsonrpc":"2.0","id":1,"method":"window.list","params":{}}'
printf '%s\n' "$payload" | socat - UNIX-CONNECT:/tmp/cmux-debug.sock
Key Source Files
Understanding these files is essential for implementing compatible clients:
Sources/TerminalController.swift: Contains the core socket server implementation, includingprocessV2Commandfor request parsing,v2Ok/v2Errorresponse builders, and the complete method dispatch table.cmuxTests/TerminalControllerSocketSecurityTests.swift: Provides reference implementations showing valid JSON-RPC request construction and response verification.CLI/cmux.swift: Demonstrates how command-line arguments map to socket protocol invocations.Sources/SocketControlSettings.swift: Defines default socket paths and permission handling required for client connection setup.
Summary
- The cmux v2 JSON socket protocol requires single-line, newline-terminated JSON messages over Unix-domain sockets.
- Requests must include
jsonrpc: "2.0", anid, amethod, and optionalparams. - Responses use an
okboolean field to indicate success, withresultfor data orerror(containingcode,message, and optionaldata) for failures. - Internal newlines are escaped by the
v2Encodefunction to maintain the line-delimited format. - Method handlers are validated against an allow-list in
processV2Commandbefore execution.
Frequently Asked Questions
What transport layer does the cmux v2 protocol use?
The protocol communicates over Unix-domain sockets (AF_UNIX) using stream sockets (SOCK_STREAM). The default socket path is typically /tmp/cmux-debug.sock or a path specified during daemon startup, as defined in Sources/SocketControlSettings.swift.
How does the server handle malformed JSON or protocol violations?
The processV2Command function validates that the jsonrpc field equals exactly "2.0" and that the method exists in the focusIntentV2Methods allow-list. Invalid requests receive an error response with ok: false and an appropriate error code, while parse failures at the JSON level typically result in connection termination or silent dropping depending on the server's error handling context.
Can the id field be any JSON type, or must it be a number?
The id field can be any valid JSON value, including numbers, strings, or null, though the implementation typically uses integers. The server echoes this value verbatim in the response to allow clients to correlate asynchronous responses with their original requests.
Are batch requests (multiple JSON objects in one message) supported?
No, the v2 protocol does not support JSON-RPC batch requests. Each request must be a single JSON object terminated by a newline character (\n). The v2Encode function explicitly ensures responses are single-line by escaping internal newlines, and the parser reads line-by-line from the socket buffer.
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 →