Skip to Content
ReferenceSocket Protocol

Socket Protocol

The hty CLI is a thin client over a Unix domain socket protocol. Every command you run — hty snapshot, hty send, hty wait — serializes a JSON request, sends it to the server over a local socket, and parses the JSON response. You can build your own clients or integrations by speaking this same protocol directly.

The CLI covers all common operations. This reference is for building custom clients or integrations that need direct socket access.

Connection

Connect to the Unix domain socket at the path determined by $HTY_SOCKET or the default XDG path. See Environment Variables for the full path resolution rules.

The protocol is request-response over newline-delimited JSON (JSONL):

  1. Send one JSON object terminated by \n.
  2. Receive one JSON object terminated by \n.

The attach operation is the exception — it keeps the connection open and streams frames in both directions after the initial acknowledgement.

Request format

Every request is a JSON object with an "op" field naming the operation, plus any operation-specific fields.

{"op": "<operation>", "session": "<id-or-name>", ...fields}

You can include an optional integer "id" field on any request. The server echoes it back in the response for request-response correlation.

Response format

Every response is a JSON object with a boolean "ok" field. A successful response may include a "snapshot", "event", "session", or "sessions" field depending on the operation. A failed response includes an "error" string.

{"ok": true, "id": 1, "snapshot": {...}} {"ok": false, "error": "session not found"} {"ok": true, "timed_out": true}

Operations

spawn — start a new session

Start a new terminal session running the specified program.

FieldTypeRequiredDescription
opstringyes"spawn"
programstringyesPath or name of the program to run
argsstring[]noArguments to pass to the program
namestringnoHuman-readable name for the session
rowsintegernoTerminal rows (default: 24)
colsintegernoTerminal columns (default: 80)
scrollbackintegernoScrollback buffer lines (default: 10000)
cwdstringnoWorking directory for the spawned process
env{key, value}[]noAdditional environment variables
// Request {"op": "spawn", "program": "bash", "args": ["-c", "echo hello"], "name": "my-session", "rows": 24, "cols": 80} // Response {"ok": true, "session": {"id": "019612ab-...", "name": "my-session", "program": "bash", "status": "running"}}

list — list all sessions

// Request {"op": "list"} // Response {"ok": true, "sessions": [{"id": "019612ab-...", "name": "my-session", "program": "bash", "status": "running"}]}

snapshot — read the current screen

FieldTypeRequiredDescription
opstringyes"snapshot"
sessionstringnoSession ID, name, or UUID prefix. Omit if only one session exists.
// Request {"op": "snapshot", "session": "my-session"} // Response {"ok": true, "snapshot": {"rows": 24, "cols": 80, "cursor_row": 1, "cursor_col": 6, "buffer": "hello\n...", "lines": ["hello", ""], "status": "running"}}

send_text — send text input

FieldTypeRequiredDescription
opstringyes"send_text"
sessionstringnoSession reference
textstringyesText to send
{"op": "send_text", "session": "my-session", "text": "ls -la\n"}

send_key — send a named key

FieldTypeRequiredDescription
opstringyes"send_key"
sessionstringnoSession reference
keystringyesKey name (see keys)
{"op": "send_key", "session": "my-session", "key": "ctrl-c"}

send_bytes_hex — send raw bytes

FieldTypeRequiredDescription
opstringyes"send_bytes_hex"
sessionstringnoSession reference
bytes_hexstringyesHex-encoded bytes to send
{"op": "send_bytes_hex", "session": "my-session", "bytes_hex": "0d"}

resize — resize the PTY

FieldTypeRequiredDescription
opstringyes"resize"
sessionstringnoSession reference
rowsintegeryesNew row count
colsintegeryesNew column count

wait_for_text — block until text appears

FieldTypeRequiredDescription
opstringyes"wait_for_text"
sessionstringnoSession reference
textstringyesNeedle string or regex pattern
regexbooleannoTreat text as a POSIX regex (default: false)
timeout_msintegernoTimeout in milliseconds (default: 10000)

Returns a snapshot on match, or {"ok": true, "timed_out": true} on timeout.

wait_for_idle — block until the screen stops changing

FieldTypeRequiredDescription
opstringyes"wait_for_idle"
sessionstringnoSession reference
idle_msintegernoQuiet period required in milliseconds (default: 250)
timeout_msintegernoTimeout in milliseconds (default: 10000)

wait_for_exit — block until the process exits

FieldTypeRequiredDescription
opstringyes"wait_for_exit"
sessionstringnoSession reference
timeout_msintegernoTimeout in milliseconds (default: 10000)

Returns {"ok": true, "event": {"kind": "exited", "code": 0}} on exit.

kill — terminate the process

{"op": "kill", "session": "my-session"}

delete — remove session and log

{"op": "delete", "session": "my-session"}

attach — bidirectional streaming

Unlike other operations, attach keeps the connection open and uses a streaming frame protocol after the initial acknowledgement.

Initial request:

{"op": "attach", "session": "my-session", "rows": 24, "cols": 80}

Server sends ack, then streams frames:

{"ok": true} {"kind": "output", "bytes_hex": "68656c6c6f"} {"kind": "exited", "code": 0}

Client can send at any time after ack:

{"op": "input", "bytes_hex": "6c73200a"} {"op": "resize", "rows": 40, "cols": 120} {"op": "detach"}

The socket protocol may evolve between versions. Prefer the hty CLI for day-to-day use and long-term script stability. Use the socket protocol directly only when you need capabilities not exposed by the CLI.

Last updated on