repos / zmx

session persistence for terminal processes
git clone https://github.com/neurosnap/zmx.git

commit
10c30ff
parent
90e6a30
author
Eric Bower
date
2025-10-13 11:16:35 -0400 EDT
docs(protocol): pty binary format
1 files changed,  +35, -18
M specs/protocol.md
+35, -18
 1@@ -18,14 +18,23 @@ The protocol implementation is centralized in `src/protocol.zig`, which provides
 2 - Helper functions: `writeJson()`, `parseMessage()`, `parseMessageType()`
 3 - `LineBuffer` for efficient NDJSON line buffering
 4 
 5-### Future: Binary Frame Support
 6+### Binary Frame Support
 7 
 8-The protocol module includes infrastructure for future binary framing to optimize PTY data throughput:
 9-- Frame format: `[4-byte length][2-byte type][payload...]`
10-- Type 1: JSON control messages (current)
11-- Type 2: Binary PTY data (future optimization)
12+The protocol uses a hybrid approach: JSON for control messages and binary frames for PTY output to avoid encoding overhead and improve throughput.
13 
14-This hybrid approach would keep control messages in human-readable JSON while allowing raw binary PTY data when profiling shows JSON is a bottleneck.
15+**Frame Format:**
16+```
17+[4-byte length (little-endian)][2-byte type (little-endian)][payload...]
18+```
19+
20+**Frame Types:**
21+- Type 1 (`json_control`): JSON control messages (not currently used in framing)
22+- Type 2 (`pty_binary`): Raw PTY output bytes
23+
24+**Current Usage:**
25+- Control messages (attach, detach, kill, etc.): NDJSON format
26+- PTY output from daemon to client: Binary frames (type 2)
27+- PTY input from client to daemon: JSON `pty_in` messages (may be optimized to binary frames in future)
28 
29 ## Message Structure
30 
31@@ -104,22 +113,30 @@ Responses are sent from the daemon to the client in response to a request. Every
32     - `status`: `ok` or `error`
33     - `error_message`: string (if status is `error`)
34 
35-### `pty_input`
36+### `pty_in`
37 
38 - **Direction**: Client -> Daemon
39-- **Request Type**: `pty_input`
40-- **Request Payload**:
41-    - `session_name`: string
42-    - `data`: string (base64 encoded)
43+- **Message Type**: `pty_in`
44+- **Format**: NDJSON
45+- **Payload**:
46+    - `text`: string (raw UTF-8 text from terminal input)
47 
48-This message does not have a direct response. It is a fire-and-forget message from the client.
49+This message is sent when a client wants to send user input to the PTY. It is a fire-and-forget message with no direct response. The input is forwarded to the shell running in the session's PTY.
50 
51-### `pty_output`
52+### `pty_out`
53 
54 - **Direction**: Daemon -> Client
55-- **Request Type**: `pty_output`
56-- **Request Payload**:
57-    - `session_name`: string
58-    - `data`: string (base64 encoded)
59+- **Message Type**: `pty_out`
60+- **Format**: NDJSON (used only for control sequences like screen clear)
61+- **Payload**:
62+    - `text`: string (escape sequences or control output)
63+
64+This JSON message is sent for special control output like initial screen clearing. Regular PTY output uses binary frames (see below).
65+
66+### PTY Binary Output
67+
68+- **Direction**: Daemon -> Client
69+- **Format**: Binary frame (type 2: `pty_binary`)
70+- **Payload**: Raw bytes from PTY output
71 
72-This message is sent from the daemon to an attached client whenever there is output from the PTY.
73+The majority of PTY output is sent using binary frames to avoid JSON encoding overhead. The frame consists of a 6-byte header (4-byte length + 2-byte type) followed by raw PTY bytes. This allows efficient streaming of terminal output without escaping or encoding.